diff --git a/backup.lst b/backup.lst index b4b8924c..9549ef36 100644 --- a/backup.lst +++ b/backup.lst @@ -12,14 +12,13 @@ release.bat launchers.bat change.log -client\ -client\hud\ -client\global\ +cl_dll\ +cl_dll\hl\ common\ dlls\ +dlls\wpn_shared game_shared\ game_launch\ -gameui\ engine\ engine\client\ engine\server\ @@ -29,13 +28,15 @@ launch\imagelib\ launch\soundlib\ public\ launch\ +mainui\ snd_dx\ vid_gl\ -xtools\ -xtools\xwad\ -xtools\bsplib -xtools\ripper -xtools\sprite\ -xtools\studio\ -xtools\ximage\ -xtools\extragen\ \ No newline at end of file +utils\ +utils\vgui\ +utils\xwad\ +utils\bsplib +utils\ripper +utils\sprite\ +utils\studio\ +utils\ximage\ +utils\extragen\ \ No newline at end of file diff --git a/change.log b/change.log index 41d61f94..5cd80dc1 100644 --- a/change.log +++ b/change.log @@ -1,5 +1,7 @@ build ???? +Tools: renamed xtools.dll into utils.dll +GameUI: GameUI.dll renamed to MainUI.dll to avoid conflict with original valve's GameUI.dll Engine: support for StartupVids.txt Engine: get full compatibility with hl.dll FS: recode wad resource management (now support lumps from wads with same name) diff --git a/cl_dll/GameStudioModelRenderer.cpp b/cl_dll/GameStudioModelRenderer.cpp new file mode 100644 index 00000000..56e6823d --- /dev/null +++ b/cl_dll/GameStudioModelRenderer.cpp @@ -0,0 +1,119 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// +// Override the StudioModelRender virtual member functions here to implement custom bone +// setup, blending, etc. +// + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +// The renderer object, created on the stack. +CGameStudioModelRenderer g_StudioRenderer; +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +CGameStudioModelRenderer::CGameStudioModelRenderer( void ) +{ +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel( int flags ) +{ + return g_StudioRenderer.StudioDrawModel( flags ); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ +#define DLLEXPORT __declspec( dllexport ) +extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) +{ + if ( version != STUDIO_INTERFACE_VERSION ) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} diff --git a/cl_dll/GameStudioModelRenderer.h b/cl_dll/GameStudioModelRenderer.h new file mode 100644 index 00000000..a9d2efff --- /dev/null +++ b/cl_dll/GameStudioModelRenderer.h @@ -0,0 +1,26 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( GAMESTUDIOMODELRENDERER_H ) +#define GAMESTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +class CGameStudioModelRenderer : public CStudioModelRenderer +{ +public: + CGameStudioModelRenderer( void ); +}; + +#endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/GameStudioModelRenderer_Sample.cpp b/cl_dll/GameStudioModelRenderer_Sample.cpp new file mode 100644 index 00000000..5ea50b51 --- /dev/null +++ b/cl_dll/GameStudioModelRenderer_Sample.cpp @@ -0,0 +1,992 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// Predicted values saved off in hl_weapons.cpp +void Game_GetSequence( int *seq, int *gaitseq ); +void Game_GetOrientation( float *o, float *a ); + +float g_flStartScaleTime; +int iPrevRenderState; +int iRenderStateChanged; + +// Global engine <-> studio model rendering code interface +extern engine_studio_api_t IEngineStudio; + +typedef struct +{ + vec3_t origin; + vec3_t angles; + + vec3_t realangles; + + float animtime; + float frame; + int sequence; + int gaitsequence; + float framerate; + + int m_fSequenceLoops; + int m_fSequenceFinished; + + byte controller[ 4 ]; + byte blending[ 2 ]; + + latchedvars_t lv; +} client_anim_state_t; + +static client_anim_state_t g_state; +static client_anim_state_t g_clientstate; + +// The renderer object, created on the stack. +CGameStudioModelRenderer g_StudioRenderer; +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +CGameStudioModelRenderer::CGameStudioModelRenderer( void ) +{ + // If you want to predict animations locally, set this to TRUE + // NOTE: The animation code is somewhat broken, but gives you a sense for how + // to do client side animation of the predicted player in a third person game. + m_bLocal = false; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +void CGameStudioModelRenderer::StudioSetupBones ( void ) +{ + int i; + double f; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + // Use default bone setup for nonplayers + if ( !m_pCurrentEntity->player ) + { + CStudioModelRenderer::StudioSetupBones(); + return; + } + + // Bound sequence number. + if ( m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq ) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + if ( m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0 ) + { + f = m_pPlayerInfo->gaitframe; + } + else + { + f = StudioEstimateFrame( pseqdesc ); + } + + // This game knows how to do three way blending + if ( pseqdesc->numblends == 3 ) + { + float s; + + // Get left anim + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + + // Blending is 0-127 == Left to Middle, 128 to 255 == Middle to right + if ( m_pCurrentEntity->curstate.blending[0] <= 127 ) + { + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + // Scale 0-127 blending up to 0-255 + s = m_pCurrentEntity->curstate.blending[0]; + s = ( s * 2.0 ); + } + else + { + + // Skip ahead to middle + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + // Scale 127-255 blending up to 0-255 + s = m_pCurrentEntity->curstate.blending[0]; + s = 2.0 * ( s - 127.0 ); + } + + // Normalize interpolant + s /= 255.0; + + // Go to middle or right + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + // Spherically interpolate the bones + StudioSlerpBones( q, pos, q2, pos2, s ); + } + else + { + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + } + + // Are we in the process of transitioning from one sequence to another. + if ( m_fDoInterp && + m_pCurrentEntity->latched.sequencetime && + ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + // Blending value into last sequence + unsigned char prevseqblending = m_pCurrentEntity->latched.prevseqblending[ 0 ]; + + // Point at previous sequenece + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + + // Know how to do three way blends + if ( pseqdesc->numblends == 3 ) + { + float s; + + // Get left animation + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + + if ( prevseqblending <= 127 ) + { + // Set up bones based on final frame of previous sequence + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = prevseqblending; + s = ( s * 2.0 ); + } + else + { + // Skip to middle blend + panim += m_pStudioHeader->numbones; + + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = prevseqblending; + s = 2.0 * ( s - 127.0 ); + } + + // Normalize + s /= 255.0; + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + // Interpolate bones + StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + } + else + { + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + } + + // Now blend last frame of previous sequence with current sequence. + s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + m_pCurrentEntity->latched.prevframe = f; + } + + // Now convert quaternions and bone positions into matrices + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void CGameStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = (m_clTime - m_clOldTime); + dt = max( 0.0, dt ); + dt = min( 1.0, dt ); + + if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); + if ( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = Length( est_velocity ); + if (dt <= 0 || m_flGaitMovement / dt < 5) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->velocity, est_velocity ); + m_flGaitMovement = Length( est_velocity ) * dt; + } + + if (est_velocity[1] == 0 && est_velocity[0] == 0) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0; + } + else + { + m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = 180; + if (m_pPlayerInfo->gaityaw < -180) + m_pPlayerInfo->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void CGameStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + float dt; + float flYaw; // view direction relative to movement + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + m_pCurrentEntity->angles[PITCH] = 0; + m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; + + dt = (m_clTime - m_clOldTime); + dt = max( 0.0, dt ); + dt = min( 1.0, dt ); + + StudioEstimateGait( pplayer ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + + flYaw = fmod( flYaw, 360.0 ); + + if (flYaw < -180) + { + flYaw = flYaw + 360; + } + else if (flYaw > 180) + { + flYaw = flYaw - 360; + } + + float maxyaw = 120.0; + + if (flYaw > maxyaw) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if (flYaw < -maxyaw) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + float blend_yaw = ( flYaw / 90.0 ) * 128.0 + 127.0; + blend_yaw = min( 255.0, blend_yaw ); + blend_yaw = max( 0.0, blend_yaw ); + + blend_yaw = 255.0 - blend_yaw; + + m_pCurrentEntity->curstate.blending[0] = (int)(blend_yaw); + m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; + m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; + + m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; + if (m_pCurrentEntity->angles[YAW] < -0) + { + m_pCurrentEntity->angles[YAW] += 360; + } + m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // Calc gait frame + if (pseqdesc->linearmovement[0] > 0) + { + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pPlayerInfo->gaitframe += pseqdesc->fps * dt * m_pCurrentEntity->curstate.framerate; + } + + // Do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if (m_pPlayerInfo->gaitframe < 0) + { + m_pPlayerInfo->gaitframe += pseqdesc->numframes; + } +} + +/* +============================== +SavePlayerState + +For local player, in third person, we need to store real render data and then + setup for with fake/client side animation data +============================== +*/ +void CGameStudioModelRenderer::SavePlayerState( entity_state_t *pplayer ) +{ + client_anim_state_t *st; + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + st = &g_state; + + st->angles = ent->curstate.angles; + st->origin = ent->curstate.origin; + + st->realangles = ent->angles; + + st->sequence = ent->curstate.sequence; + st->gaitsequence = pplayer->gaitsequence; + st->animtime = ent->curstate.animtime; + st->frame = ent->curstate.frame; + st->framerate = ent->curstate.framerate; + memcpy( st->blending, ent->curstate.blending, 2 ); + memcpy( st->controller, ent->curstate.controller, 4 ); + + st->lv = ent->latched; +} + +void GetSequenceInfo( void *pmodel, client_anim_state_t *pev, float *pflFrameRate, float *pflGroundSpeed ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if (! pstudiohdr) + return; + + mstudioseqdesc_t *pseqdesc; + + if (pev->sequence >= pstudiohdr->numseq) + { + *pflFrameRate = 0.0; + *pflGroundSpeed = 0.0; + return; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + + if (pseqdesc->numframes > 1) + { + *pflFrameRate = 256 * pseqdesc->fps / (pseqdesc->numframes - 1); + *pflGroundSpeed = sqrt( pseqdesc->linearmovement[0]*pseqdesc->linearmovement[0]+ pseqdesc->linearmovement[1]*pseqdesc->linearmovement[1]+ pseqdesc->linearmovement[2]*pseqdesc->linearmovement[2] ); + *pflGroundSpeed = *pflGroundSpeed * pseqdesc->fps / (pseqdesc->numframes - 1); + } + else + { + *pflFrameRate = 256.0; + *pflGroundSpeed = 0.0; + } +} + +int GetSequenceFlags( void *pmodel, client_anim_state_t *pev ) +{ + studiohdr_t *pstudiohdr; + + pstudiohdr = (studiohdr_t *)pmodel; + if ( !pstudiohdr || pev->sequence >= pstudiohdr->numseq ) + return 0; + + mstudioseqdesc_t *pseqdesc; + pseqdesc = (mstudioseqdesc_t *)((byte *)pstudiohdr + pstudiohdr->seqindex) + (int)pev->sequence; + + return pseqdesc->flags; +} + +float StudioFrameAdvance ( client_anim_state_t *st, float framerate, float flInterval ) +{ + if (flInterval == 0.0) + { + flInterval = (gEngfuncs.GetClientTime() - st->animtime); + if (flInterval <= 0.001) + { + st->animtime = gEngfuncs.GetClientTime(); + return 0.0; + } + } + if (!st->animtime) + flInterval = 0.0; + + st->frame += flInterval * framerate * st->framerate; + st->animtime = gEngfuncs.GetClientTime(); + + if (st->frame < 0.0 || st->frame >= 256.0) + { + if ( st->m_fSequenceLoops ) + st->frame -= (int)(st->frame / 256.0) * 256.0; + else + st->frame = (st->frame < 0.0) ? 0 : 255; + st->m_fSequenceFinished = TRUE; // just in case it wasn't caught in GetEvents + } + + return flInterval; +} + +/* +============================== +SetupClientAnimation + +Called to set up local player's animation values +============================== +*/ +void CGameStudioModelRenderer::SetupClientAnimation( entity_state_t *pplayer ) +{ + static double oldtime; + double curtime, dt; + + client_anim_state_t *st; + float fr, gs; + + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + curtime = gEngfuncs.GetClientTime(); + dt = curtime - oldtime; + dt = min( 1.0, max( 0.0, dt ) ); + + oldtime = curtime; + st = &g_clientstate; + + st->framerate = 1.0; + + int oldseq = st->sequence; + Game_GetSequence( &st->sequence, &st->gaitsequence ); //CVAR_GET_FLOAT( "sequence" ); + Game_GetOrientation( (float *)&st->origin, (float *)&st->angles ); + st->realangles = st->angles; + + if ( st->sequence != oldseq ) + { + st->frame = 0.0; + st->lv.prevsequence = oldseq; + st->lv.sequencetime = st->animtime; + + memcpy( st->lv.prevseqblending, st->blending, 2 ); + memcpy( st->lv.prevcontroller, st->controller, 4 ); + } + + void *pmodel = (studiohdr_t *)IEngineStudio.Mod_Extradata( ent->model ); + + GetSequenceInfo( pmodel, st, &fr, &gs ); + st->m_fSequenceLoops = ((GetSequenceFlags( pmodel, st ) & STUDIO_LOOPING) != 0); + StudioFrameAdvance( st, fr, dt ); + +// gEngfuncs.Con_Printf( "gs %i frame %f\n", st->gaitsequence, st->frame ); + + ent->angles = st->realangles; + ent->curstate.angles = st->angles; + ent->curstate.origin = st->origin; + + ent->curstate.sequence = st->sequence; + pplayer->gaitsequence = st->gaitsequence; + ent->curstate.animtime = st->animtime; + ent->curstate.frame = st->frame; + ent->curstate.framerate = st->framerate; + memcpy( ent->curstate.blending, st->blending, 2 ); + memcpy( ent->curstate.controller, st->controller, 4 ); + + ent->latched = st->lv; +} + +/* +============================== +RestorePlayerState + +Called to restore original player state information +============================== +*/ +void CGameStudioModelRenderer::RestorePlayerState( entity_state_t *pplayer ) +{ + client_anim_state_t *st; + cl_entity_t *ent = IEngineStudio.GetCurrentEntity(); + assert( ent ); + if ( !ent ) + return; + + st = &g_clientstate; + + st->angles = ent->curstate.angles; + st->origin = ent->curstate.origin; + st->realangles = ent->angles; + + st->sequence = ent->curstate.sequence; + st->gaitsequence = pplayer->gaitsequence; + st->animtime = ent->curstate.animtime; + st->frame = ent->curstate.frame; + st->framerate = ent->curstate.framerate; + memcpy( st->blending, ent->curstate.blending, 2 ); + memcpy( st->controller, ent->curstate.controller, 4 ); + + st->lv = ent->latched; + + st = &g_state; + + ent->curstate.angles = st->angles; + ent->curstate.origin = st->origin; + ent->angles = st->realangles; + + ent->curstate.sequence = st->sequence; + pplayer->gaitsequence = st->gaitsequence; + ent->curstate.animtime = st->animtime; + ent->curstate.frame = st->frame; + ent->curstate.framerate = st->framerate; + memcpy( ent->curstate.blending, st->blending, 2 ); + memcpy( ent->curstate.controller, st->controller, 4 ); + + ent->latched = st->lv; +} + +/* +============================== +StudioDrawPlayer + +============================== +*/ +int CGameStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + int iret = 0; + + bool isLocalPlayer = false; + + // Set up for client? + if ( m_bLocal && IEngineStudio.GetCurrentEntity() == gEngfuncs.GetLocalPlayer() ) + { + isLocalPlayer = true; + } + + if ( isLocalPlayer ) + { + // Store original data + SavePlayerState( pplayer ); + + // Copy in client side animation data + SetupClientAnimation( pplayer ); + } + + // Call real draw function + iret = _StudioDrawPlayer( flags, pplayer ); + + // Restore for client? + if ( isLocalPlayer ) + { + // Restore the original data for the player + RestorePlayerState( pplayer ); + } + + return iret; +} + +/* +==================== +_StudioDrawPlayer + +==================== +*/ +int CGameStudioModelRenderer::_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + m_nPlayerIndex = pplayer->number - 1; + + if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + return 0; + + m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); + if (m_pRenderModel == NULL) + return 0; + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + if (pplayer->gaitsequence) + { + vec3_t orig_angles; + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + + StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + StudioSetUpTransform( 0 ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->curstate.controller[0] = 127; + m_pCurrentEntity->curstate.controller[1] = 127; + m_pCurrentEntity->curstate.controller[2] = 127; + m_pCurrentEntity->curstate.controller[3] = 127; + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + StudioSetUpTransform( 0 ); + } + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + StudioSetupBones( ); + StudioSaveBones( ); + m_pPlayerInfo->renderframe = m_nFrameCount; + + m_pPlayerInfo = NULL; + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + /* + if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + { + // show highest resolution multiplayer model + m_pCurrentEntity->curstate.body = 255; + } + + if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) + { + m_pCurrentEntity->curstate.body = 1; // force helmet + } + */ + + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + // get remap colors + m_nTopColor = m_pPlayerInfo->topcolor; + if (m_nTopColor < 0) + m_nTopColor = 0; + if (m_nTopColor > 360) + m_nTopColor = 360; + m_nBottomColor = m_pPlayerInfo->bottomcolor; + if (m_nBottomColor < 0) + m_nBottomColor = 0; + if (m_nBottomColor > 360) + m_nBottomColor = 360; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if (pplayer->weaponmodel) + { + cl_entity_t saveent = *m_pCurrentEntity; + + model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + + StudioMergeBones( pweaponmodel); + + IEngineStudio.StudioSetupLighting (&lighting); + + StudioRenderModel( ); + + StudioCalcAttachments( ); + + *m_pCurrentEntity = saveent; + } + } + + return 1; +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void CGameStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + } + else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + float offset; + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + offset = gEngfuncs.pfnRandomFloat(-10,10); + transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + } + break; + case kRenderFxExplode: + { + if ( iRenderStateChanged ) + { + g_flStartScaleTime = m_clTime; + iRenderStateChanged = FALSE; + } + + // Make the Model continue to shrink + float flTimeDelta = m_clTime - g_flStartScaleTime; + if ( flTimeDelta > 0 ) + { + float flScale = 0.001; + // Goes almost all away + if ( flTimeDelta <= 2.0 ) + flScale = 1.0 - (flTimeDelta / 2.0); + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + transform[i][j] *= flScale; + } + } + } + break; + } +} + +//////////////////////////////////// +// Hooks to class implementation +//////////////////////////////////// + +/* +==================== +R_StudioDrawPlayer + +==================== +*/ +int R_StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + return g_StudioRenderer.StudioDrawPlayer( flags, pplayer ); +} + +/* +==================== +R_StudioDrawModel + +==================== +*/ +int R_StudioDrawModel( int flags ) +{ + return g_StudioRenderer.StudioDrawModel( flags ); +} + +/* +==================== +R_StudioInit + +==================== +*/ +void R_StudioInit( void ) +{ + g_StudioRenderer.Init(); +} + +// The simple drawing interface we'll pass back to the engine +r_studio_interface_t studio = +{ + STUDIO_INTERFACE_VERSION, + R_StudioDrawModel, + R_StudioDrawPlayer, +}; + +/* +==================== +HUD_GetStudioModelInterface + +Export this function for the engine to use the studio renderer class to render objects. +==================== +*/ +#define DLLEXPORT __declspec( dllexport ) +extern "C" int DLLEXPORT HUD_GetStudioModelInterface( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ) +{ + if ( version != STUDIO_INTERFACE_VERSION ) + return 0; + + // Point the engine to our callbacks + *ppinterface = &studio; + + // Copy in engine helper functions + memcpy( &IEngineStudio, pstudio, sizeof( IEngineStudio ) ); + + // Initialize local variables, etc. + R_StudioInit(); + + // Success + return 1; +} diff --git a/cl_dll/GameStudioModelRenderer_Sample.h b/cl_dll/GameStudioModelRenderer_Sample.h new file mode 100644 index 00000000..bf5cc73f --- /dev/null +++ b/cl_dll/GameStudioModelRenderer_Sample.h @@ -0,0 +1,55 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( GAMESTUDIOMODELRENDERER_H ) +#define GAMESTUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CGameStudioModelRenderer + +==================== +*/ +class CGameStudioModelRenderer : public CStudioModelRenderer +{ +public: + CGameStudioModelRenderer( void ); + + // Set up model bone positions + virtual void StudioSetupBones ( void ); + + // Estimate gait frame for player + virtual void StudioEstimateGait ( entity_state_t *pplayer ); + + // Process movement of player + virtual void StudioProcessGait ( entity_state_t *pplayer ); + + // Player drawing code + virtual int StudioDrawPlayer( int flags, entity_state_t *pplayer ); + virtual int _StudioDrawPlayer( int flags, entity_state_t *pplayer ); + + // Apply special effects to transform matrix + virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); + +private: + // For local player, in third person, we need to store real render data and then + // setup for with fake/client side animation data + void SavePlayerState( entity_state_t *pplayer ); + // Called to set up local player's animation values + void SetupClientAnimation( entity_state_t *pplayer ); + // Called to restore original player state information + void RestorePlayerState( entity_state_t *pplayer ); + +private: + // Private data + bool m_bLocal; +}; + +#endif // GAMESTUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/StudioModelRenderer.cpp b/cl_dll/StudioModelRenderer.cpp new file mode 100644 index 00000000..e051fa95 --- /dev/null +++ b/cl_dll/StudioModelRenderer.cpp @@ -0,0 +1,1677 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// studio_model.cpp +// routines for setting up to draw 3DStudio models + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "dlight.h" +#include "triangleapi.h" + +#include +#include +#include +#include + +#include "studio_util.h" +#include "r_studioint.h" + +#include "StudioModelRenderer.h" +#include "GameStudioModelRenderer.h" + +// Global engine <-> studio model rendering code interface +engine_studio_api_t IEngineStudio; + +///////////////////// +// Implementation of CStudioModelRenderer.h + +/* +==================== +Init + +==================== +*/ +void CStudioModelRenderer::Init( void ) +{ + // Set up some variables shared with engine + m_pCvarHiModels = IEngineStudio.GetCvar( "cl_himodels" ); + m_pCvarDeveloper = IEngineStudio.GetCvar( "developer" ); + m_pCvarDrawEntities = IEngineStudio.GetCvar( "r_drawentities" ); + + m_pChromeSprite = IEngineStudio.GetChromeSprite(); + + IEngineStudio.GetModelCounters( &m_pStudioModelCount, &m_pModelsDrawn ); + + // Get pointers to engine data structures + m_pbonetransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetBoneTransform(); + m_plighttransform = (float (*)[MAXSTUDIOBONES][3][4])IEngineStudio.StudioGetLightTransform(); + m_paliastransform = (float (*)[3][4])IEngineStudio.StudioGetAliasTransform(); + m_protationmatrix = (float (*)[3][4])IEngineStudio.StudioGetRotationMatrix(); +} + +/* +==================== +CStudioModelRenderer + +==================== +*/ +CStudioModelRenderer::CStudioModelRenderer( void ) +{ + m_fDoInterp = 1; + m_fGaitEstimation = 1; + m_pCurrentEntity = NULL; + m_pCvarHiModels = NULL; + m_pCvarDeveloper = NULL; + m_pCvarDrawEntities = NULL; + m_pChromeSprite = NULL; + m_pStudioModelCount = NULL; + m_pModelsDrawn = NULL; + m_protationmatrix = NULL; + m_paliastransform = NULL; + m_pbonetransform = NULL; + m_plighttransform = NULL; + m_pStudioHeader = NULL; + m_pBodyPart = NULL; + m_pSubModel = NULL; + m_pPlayerInfo = NULL; + m_pRenderModel = NULL; +} + +/* +==================== +~CStudioModelRenderer + +==================== +*/ +CStudioModelRenderer::~CStudioModelRenderer( void ) +{ +} + +/* +==================== +StudioCalcBoneAdj + +==================== +*/ +void CStudioModelRenderer::StudioCalcBoneAdj( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ) +{ + int i, j; + float value; + mstudiobonecontroller_t *pbonecontroller; + + pbonecontroller = (mstudiobonecontroller_t *)((byte *)m_pStudioHeader + m_pStudioHeader->bonecontrollerindex); + + for (j = 0; j < m_pStudioHeader->numbonecontrollers; j++) + { + i = pbonecontroller[j].index; + if (i <= 3) + { + // check for 360% wrapping + if (pbonecontroller[j].type & STUDIO_RLOOP) + { + if (abs(pcontroller1[i] - pcontroller2[i]) > 128) + { + int a, b; + a = (pcontroller1[j] + 128) % 256; + b = (pcontroller2[j] + 128) % 256; + value = ((a * dadt) + (b * (1 - dadt)) - 128) * (360.0/256.0) + pbonecontroller[j].start; + } + else + { + value = ((pcontroller1[i] * dadt + (pcontroller2[i]) * (1.0 - dadt))) * (360.0/256.0) + pbonecontroller[j].start; + } + } + else + { + value = (pcontroller1[i] * dadt + pcontroller2[i] * (1.0 - dadt)) / 255.0; + if (value < 0) value = 0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + } + // Con_DPrintf( "%d %d %f : %f\n", m_pCurrentEntity->curstate.controller[j], m_pCurrentEntity->latched.prevcontroller[j], value, dadt ); + } + else + { + value = mouthopen / 64.0; + if (value > 1.0) value = 1.0; + value = (1.0 - value) * pbonecontroller[j].start + value * pbonecontroller[j].end; + // Con_DPrintf("%d %f\n", mouthopen, value ); + } + switch(pbonecontroller[j].type & STUDIO_TYPES) + { + case STUDIO_XR: + case STUDIO_YR: + case STUDIO_ZR: + adj[j] = value * (M_PI / 180.0); + break; + case STUDIO_X: + case STUDIO_Y: + case STUDIO_Z: + adj[j] = value; + break; + } + } +} + + +/* +==================== +StudioCalcBoneQuaterion + +==================== +*/ +void CStudioModelRenderer::StudioCalcBoneQuaterion( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ) +{ + int j, k; + vec4_t q1, q2; + vec3_t angle1, angle2; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + if (panim->offset[j+3] == 0) + { + angle2[j] = angle1[j] = pbone->value[j+3]; // default; + } + else + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j+3]); + k = frame; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // Bah, missing blend! + if (panimvalue->num.valid > k) + { + angle1[j] = panimvalue[k+1].value; + + if (panimvalue->num.valid > k + 1) + { + angle2[j] = panimvalue[k+2].value; + } + else + { + if (panimvalue->num.total > k + 1) + angle2[j] = angle1[j]; + else + angle2[j] = panimvalue[panimvalue->num.valid+2].value; + } + } + else + { + angle1[j] = panimvalue[panimvalue->num.valid].value; + if (panimvalue->num.total > k + 1) + { + angle2[j] = angle1[j]; + } + else + { + angle2[j] = panimvalue[panimvalue->num.valid + 2].value; + } + } + angle1[j] = pbone->value[j+3] + angle1[j] * pbone->scale[j+3]; + angle2[j] = pbone->value[j+3] + angle2[j] * pbone->scale[j+3]; + } + + if (pbone->bonecontroller[j+3] != -1) + { + angle1[j] += adj[pbone->bonecontroller[j+3]]; + angle2[j] += adj[pbone->bonecontroller[j+3]]; + } + } + + if (!VectorCompare( angle1, angle2 )) + { + AngleQuaternion( angle1, q1 ); + AngleQuaternion( angle2, q2 ); + QuaternionSlerp( q1, q2, s, q ); + } + else + { + AngleQuaternion( angle1, q ); + } +} + +/* +==================== +StudioCalcBonePosition + +==================== +*/ +void CStudioModelRenderer::StudioCalcBonePosition( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ) +{ + int j, k; + mstudioanimvalue_t *panimvalue; + + for (j = 0; j < 3; j++) + { + pos[j] = pbone->value[j]; // default; + if (panim->offset[j] != 0) + { + panimvalue = (mstudioanimvalue_t *)((byte *)panim + panim->offset[j]); + /* + if (i == 0 && j == 0) + Con_DPrintf("%d %d:%d %f\n", frame, panimvalue->num.valid, panimvalue->num.total, s ); + */ + + k = frame; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + // find span of values that includes the frame we want + while (panimvalue->num.total <= k) + { + k -= panimvalue->num.total; + panimvalue += panimvalue->num.valid + 1; + // DEBUG + if (panimvalue->num.total < panimvalue->num.valid) + k = 0; + } + // if we're inside the span + if (panimvalue->num.valid > k) + { + // and there's more data in the span + if (panimvalue->num.valid > k + 1) + { + pos[j] += (panimvalue[k+1].value * (1.0 - s) + s * panimvalue[k+2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[k+1].value * pbone->scale[j]; + } + } + else + { + // are we at the end of the repeating values section and there's another section with data? + if (panimvalue->num.total <= k + 1) + { + pos[j] += (panimvalue[panimvalue->num.valid].value * (1.0 - s) + s * panimvalue[panimvalue->num.valid + 2].value) * pbone->scale[j]; + } + else + { + pos[j] += panimvalue[panimvalue->num.valid].value * pbone->scale[j]; + } + } + } + if ( pbone->bonecontroller[j] != -1 && adj ) + { + pos[j] += adj[pbone->bonecontroller[j]]; + } + } +} + +/* +==================== +StudioSlerpBones + +==================== +*/ +void CStudioModelRenderer::StudioSlerpBones( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ) +{ + int i; + vec4_t q3; + float s1; + + if (s < 0) s = 0; + else if (s > 1.0) s = 1.0; + + s1 = 1.0 - s; + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionSlerp( q1[i], q2[i], s, q3 ); + q1[i][0] = q3[0]; + q1[i][1] = q3[1]; + q1[i][2] = q3[2]; + q1[i][3] = q3[3]; + pos1[i][0] = pos1[i][0] * s1 + pos2[i][0] * s; + pos1[i][1] = pos1[i][1] * s1 + pos2[i][1] * s; + pos1[i][2] = pos1[i][2] * s1 + pos2[i][2] * s; + } +} + +/* +==================== +StudioGetAnim + +==================== +*/ +mstudioanim_t *CStudioModelRenderer::StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ) +{ + mstudioseqgroup_t *pseqgroup; + cache_user_t *paSequences; + + pseqgroup = (mstudioseqgroup_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqgroupindex) + pseqdesc->seqgroup; + + if (pseqdesc->seqgroup == 0) + { + return (mstudioanim_t *)((byte *)m_pStudioHeader + pseqgroup->data + pseqdesc->animindex); + } + + paSequences = (cache_user_t *)m_pSubModel->submodels; + + if (paSequences == NULL) + { + paSequences = (cache_user_t *)IEngineStudio.Mem_Calloc( 16, sizeof( cache_user_t ) ); // UNDONE: leak! + m_pSubModel->submodels = (dmodel_t *)paSequences; + } + + if (!IEngineStudio.Cache_Check( (struct cache_user_s *)&(paSequences[pseqdesc->seqgroup]))) + { + gEngfuncs.Con_DPrintf("loading %s\n", pseqgroup->name ); + IEngineStudio.LoadCacheFile( pseqgroup->name, (struct cache_user_s *)&paSequences[pseqdesc->seqgroup] ); + } + return (mstudioanim_t *)((byte *)paSequences[pseqdesc->seqgroup].data + pseqdesc->animindex); +} + +/* +==================== +StudioPlayerBlend + +==================== +*/ +void CStudioModelRenderer::StudioPlayerBlend( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ) +{ + // calc up/down pointing + *pBlend = (*pPitch * 3); + if (*pBlend < pseqdesc->blendstart[0]) + { + *pPitch -= pseqdesc->blendstart[0] / 3.0; + *pBlend = 0; + } + else if (*pBlend > pseqdesc->blendend[0]) + { + *pPitch -= pseqdesc->blendend[0] / 3.0; + *pBlend = 255; + } + else + { + if (pseqdesc->blendend[0] - pseqdesc->blendstart[0] < 0.1) // catch qc error + *pBlend = 127; + else + *pBlend = 255 * (*pBlend - pseqdesc->blendstart[0]) / (pseqdesc->blendend[0] - pseqdesc->blendstart[0]); + *pPitch = 0; + } +} + +/* +==================== +StudioSetUpTransform + +==================== +*/ +void CStudioModelRenderer::StudioSetUpTransform (int trivial_accept) +{ + int i; + vec3_t angles; + vec3_t modelpos; + +// tweek model origin + //for (i = 0; i < 3; i++) + // modelpos[i] = m_pCurrentEntity->origin[i]; + + VectorCopy( m_pCurrentEntity->origin, modelpos ); + +// TODO: should really be stored with the entity instead of being reconstructed +// TODO: should use a look-up table +// TODO: could cache lazily, stored in the entity + angles[ROLL] = m_pCurrentEntity->curstate.angles[ROLL]; + angles[PITCH] = m_pCurrentEntity->curstate.angles[PITCH]; + angles[YAW] = m_pCurrentEntity->curstate.angles[YAW]; + + //Con_DPrintf("Angles %4.2f prev %4.2f for %i\n", angles[PITCH], m_pCurrentEntity->index); + //Con_DPrintf("movetype %d %d\n", m_pCurrentEntity->movetype, m_pCurrentEntity->aiment ); + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_STEP) + { + float f = 0; + float d; + + // don't do it if the goalstarttime hasn't updated in a while. + + // NOTE: Because we need to interpolate multiplayer characters, the interpolation time limit + // was increased to 1.0 s., which is 2x the max lag we are accounting for. + + if ( ( m_clTime < m_pCurrentEntity->curstate.animtime + 1.0f ) && + ( m_pCurrentEntity->curstate.animtime != m_pCurrentEntity->latched.prevanimtime ) ) + { + f = (m_clTime - m_pCurrentEntity->curstate.animtime) / (m_pCurrentEntity->curstate.animtime - m_pCurrentEntity->latched.prevanimtime); + //Con_DPrintf("%4.2f %.2f %.2f\n", f, m_pCurrentEntity->curstate.animtime, m_clTime); + } + + if (m_fDoInterp) + { + // ugly hack to interpolate angle, position. current is reached 0.1 seconds after being set + f = f - 1.0; + } + else + { + f = 0; + } + + for (i = 0; i < 3; i++) + { + modelpos[i] += (m_pCurrentEntity->origin[i] - m_pCurrentEntity->latched.prevorigin[i]) * f; + } + + // NOTE: Because multiplayer lag can be relatively large, we don't want to cap + // f at 1.5 anymore. + //if (f > -1.0 && f < 1.5) {} + +// Con_DPrintf("%.0f %.0f\n",m_pCurrentEntity->msg_angles[0][YAW], m_pCurrentEntity->msg_angles[1][YAW] ); + for (i = 0; i < 3; i++) + { + float ang1, ang2; + + ang1 = m_pCurrentEntity->angles[i]; + ang2 = m_pCurrentEntity->latched.prevangles[i]; + + d = ang1 - ang2; + if (d > 180) + { + d -= 360; + } + else if (d < -180) + { + d += 360; + } + + angles[i] += d * f; + } + //Con_DPrintf("%.3f \n", f ); + } + else if ( m_pCurrentEntity->curstate.movetype != MOVETYPE_NONE ) + { + VectorCopy( m_pCurrentEntity->angles, angles ); + } + + //Con_DPrintf("%.0f %0.f %0.f\n", modelpos[0], modelpos[1], modelpos[2] ); + //Con_DPrintf("%.0f %0.f %0.f\n", angles[0], angles[1], angles[2] ); + + angles[PITCH] = -angles[PITCH]; + AngleMatrix (angles, (*m_protationmatrix)); + + if ( !IEngineStudio.IsHardware() ) + { + static float viewmatrix[3][4]; + + VectorCopy (m_vRight, viewmatrix[0]); + VectorCopy (m_vUp, viewmatrix[1]); + VectorInverse (viewmatrix[1]); + VectorCopy (m_vNormal, viewmatrix[2]); + + (*m_protationmatrix)[0][3] = modelpos[0] - m_vRenderOrigin[0]; + (*m_protationmatrix)[1][3] = modelpos[1] - m_vRenderOrigin[1]; + (*m_protationmatrix)[2][3] = modelpos[2] - m_vRenderOrigin[2]; + + ConcatTransforms (viewmatrix, (*m_protationmatrix), (*m_paliastransform)); + + // do the scaling up of x and y to screen coordinates as part of the transform + // for the unclipped case (it would mess up clipping in the clipped case). + // Also scale down z, so 1/z is scaled 31 bits for free, and scale down x and y + // correspondingly so the projected x and y come out right + // FIXME: make this work for clipped case too? + if (trivial_accept) + { + for (i=0 ; i<4 ; i++) + { + (*m_paliastransform)[0][i] *= m_fSoftwareXScale * + (1.0 / (ZISCALE * 0x10000)); + (*m_paliastransform)[1][i] *= m_fSoftwareYScale * + (1.0 / (ZISCALE * 0x10000)); + (*m_paliastransform)[2][i] *= 1.0 / (ZISCALE * 0x10000); + + } + } + } + + (*m_protationmatrix)[0][3] = modelpos[0]; + (*m_protationmatrix)[1][3] = modelpos[1]; + (*m_protationmatrix)[2][3] = modelpos[2]; +} + + +/* +==================== +StudioEstimateInterpolant + +==================== +*/ +float CStudioModelRenderer::StudioEstimateInterpolant( void ) +{ + float dadt = 1.0; + + if ( m_fDoInterp && ( m_pCurrentEntity->curstate.animtime >= m_pCurrentEntity->latched.prevanimtime + 0.01 ) ) + { + dadt = (m_clTime - m_pCurrentEntity->curstate.animtime) / 0.1; + if (dadt > 2.0) + { + dadt = 2.0; + } + } + return dadt; +} + +/* +==================== +StudioCalcRotations + +==================== +*/ +void CStudioModelRenderer::StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) +{ + int i; + int frame; + mstudiobone_t *pbone; + + float s; + float adj[MAXSTUDIOCONTROLLERS]; + float dadt; + + if (f > pseqdesc->numframes - 1) + { + f = 0; // bah, fix this bug with changing sequences too fast + } + // BUG ( somewhere else ) but this code should validate this data. + // This could cause a crash if the frame # is negative, so we'll go ahead + // and clamp it here + else if ( f < -0.01 ) + { + f = -0.01; + } + + frame = (int)f; + + // Con_DPrintf("%d %.4f %.4f %.4f %.4f %d\n", m_pCurrentEntity->curstate.sequence, m_clTime, m_pCurrentEntity->animtime, m_pCurrentEntity->frame, f, frame ); + + // Con_DPrintf( "%f %f %f\n", m_pCurrentEntity->angles[ROLL], m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->angles[YAW] ); + + // Con_DPrintf("frame %d %d\n", frame1, frame2 ); + + + dadt = StudioEstimateInterpolant( ); + s = (f - frame); + + // add in programtic controllers + pbone = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + StudioCalcBoneAdj( dadt, adj, m_pCurrentEntity->curstate.controller, m_pCurrentEntity->latched.prevcontroller, m_pCurrentEntity->mouth.mouthopen ); + + for (i = 0; i < m_pStudioHeader->numbones; i++, pbone++, panim++) + { + StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); + + StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); + // if (0 && i == 0) + // Con_DPrintf("%d %d %d %d\n", m_pCurrentEntity->curstate.sequence, frame, j, k ); + } + + if (pseqdesc->motiontype & STUDIO_X) + { + pos[pseqdesc->motionbone][0] = 0.0; + } + if (pseqdesc->motiontype & STUDIO_Y) + { + pos[pseqdesc->motionbone][1] = 0.0; + } + if (pseqdesc->motiontype & STUDIO_Z) + { + pos[pseqdesc->motionbone][2] = 0.0; + } + + s = 0 * ((1.0 - (f - (int)(f))) / (pseqdesc->numframes)) * m_pCurrentEntity->curstate.framerate; + + if (pseqdesc->motiontype & STUDIO_LX) + { + pos[pseqdesc->motionbone][0] += s * pseqdesc->linearmovement[0]; + } + if (pseqdesc->motiontype & STUDIO_LY) + { + pos[pseqdesc->motionbone][1] += s * pseqdesc->linearmovement[1]; + } + if (pseqdesc->motiontype & STUDIO_LZ) + { + pos[pseqdesc->motionbone][2] += s * pseqdesc->linearmovement[2]; + } +} + +/* +==================== +Studio_FxTransform + +==================== +*/ +void CStudioModelRenderer::StudioFxTransform( cl_entity_t *ent, float transform[3][4] ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + VectorScale( transform[axis], gEngfuncs.pfnRandomFloat(1,1.484), transform[axis] ); + } + else if ( gEngfuncs.pfnRandomLong(0,49) == 0 ) + { + float offset; + int axis = gEngfuncs.pfnRandomLong(0,1); + if ( axis == 1 ) // Choose between x & z + axis = 2; + offset = gEngfuncs.pfnRandomFloat(-10,10); + transform[gEngfuncs.pfnRandomLong(0,2)][3] += offset; + } + break; + case kRenderFxExplode: + { + float scale; + + scale = 1.0 + ( m_clTime - ent->curstate.animtime) * 10.0; + if ( scale > 2 ) // Don't blow up more than 200% + scale = 2; + transform[0][1] *= scale; + transform[1][1] *= scale; + transform[2][1] *= scale; + } + break; + + } +} + +/* +==================== +StudioEstimateFrame + +==================== +*/ +float CStudioModelRenderer::StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) +{ + double dfdt, f; + + if ( m_fDoInterp ) + { + if ( m_clTime < m_pCurrentEntity->curstate.animtime ) + { + dfdt = 0; + } + else + { + dfdt = (m_clTime - m_pCurrentEntity->curstate.animtime) * m_pCurrentEntity->curstate.framerate * pseqdesc->fps; + + } + } + else + { + dfdt = 0; + } + + if (pseqdesc->numframes <= 1) + { + f = 0; + } + else + { + f = (m_pCurrentEntity->curstate.frame * (pseqdesc->numframes - 1)) / 256.0; + } + + f += dfdt; + + if (pseqdesc->flags & STUDIO_LOOPING) + { + if (pseqdesc->numframes > 1) + { + f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1); + } + if (f < 0) + { + f += (pseqdesc->numframes - 1); + } + } + else + { + if (f >= pseqdesc->numframes - 1.001) + { + f = pseqdesc->numframes - 1.001; + } + if (f < 0.0) + { + f = 0.0; + } + } + return f; +} + +/* +==================== +StudioSetupBones + +==================== +*/ +void CStudioModelRenderer::StudioSetupBones ( void ) +{ + int i; + double f; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + static vec4_t q[MAXSTUDIOBONES]; + float bonematrix[3][4]; + + static float pos2[MAXSTUDIOBONES][3]; + static vec4_t q2[MAXSTUDIOBONES]; + static float pos3[MAXSTUDIOBONES][3]; + static vec4_t q3[MAXSTUDIOBONES]; + static float pos4[MAXSTUDIOBONES][3]; + static vec4_t q4[MAXSTUDIOBONES]; + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + f = StudioEstimateFrame( pseqdesc ); + + if (m_pCurrentEntity->latched.prevframe > f) + { + //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + } + + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + if (pseqdesc->numblends > 1) + { + float s; + float dadt; + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, f ); + + dadt = StudioEstimateInterpolant(); + s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + + StudioSlerpBones( q, pos, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos3, q3, pseqdesc, panim, f ); + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos4, q4, pseqdesc, panim, f ); + + s = (m_pCurrentEntity->curstate.blending[0] * dadt + m_pCurrentEntity->latched.prevblending[0] * (1.0 - dadt)) / 255.0; + StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->curstate.blending[1] * dadt + m_pCurrentEntity->latched.prevblending[1] * (1.0 - dadt)) / 255.0; + StudioSlerpBones( q, pos, q3, pos3, s ); + } + } + + if (m_fDoInterp && + m_pCurrentEntity->latched.sequencetime && + ( m_pCurrentEntity->latched.sequencetime + 0.2 > m_clTime ) && + ( m_pCurrentEntity->latched.prevsequence < m_pStudioHeader->numseq )) + { + // blend from last sequence + static float pos1b[MAXSTUDIOBONES][3]; + static vec4_t q1b[MAXSTUDIOBONES]; + float s; + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->latched.prevsequence; + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + // clip prevframe + StudioCalcRotations( pos1b, q1b, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + if (pseqdesc->numblends > 1) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + StudioSlerpBones( q1b, pos1b, q2, pos2, s ); + + if (pseqdesc->numblends == 4) + { + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos3, q3, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + panim += m_pStudioHeader->numbones; + StudioCalcRotations( pos4, q4, pseqdesc, panim, m_pCurrentEntity->latched.prevframe ); + + s = (m_pCurrentEntity->latched.prevseqblending[0]) / 255.0; + StudioSlerpBones( q3, pos3, q4, pos4, s ); + + s = (m_pCurrentEntity->latched.prevseqblending[1]) / 255.0; + StudioSlerpBones( q1b, pos1b, q3, pos3, s ); + } + } + + s = 1.0 - (m_clTime - m_pCurrentEntity->latched.sequencetime) / 0.2; + StudioSlerpBones( q, pos, q1b, pos1b, s ); + } + else + { + //Con_DPrintf("prevframe = %4.2f\n", f); + m_pCurrentEntity->latched.prevframe = f; + } + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + // calc gait animation + if (m_pPlayerInfo && m_pPlayerInfo->gaitsequence != 0) + { + if (m_pPlayerInfo->gaitsequence >= m_pStudioHeader->numseq) + { + m_pPlayerInfo->gaitsequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pPlayerInfo->gaitsequence; + + panim = StudioGetAnim( m_pRenderModel, pseqdesc ); + StudioCalcRotations( pos2, q2, pseqdesc, panim, m_pPlayerInfo->gaitframe ); + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + if (strcmp( pbones[i].name, "Bip01 Spine") == 0) + break; + memcpy( pos[i], pos2[i], sizeof( pos[i] )); + memcpy( q[i], q2[i], sizeof( q[i] )); + } + } + + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + + // MatrixCopy should be faster... + //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } +} + + +/* +==================== +StudioSaveBones + +==================== +*/ +void CStudioModelRenderer::StudioSaveBones( void ) +{ + int i; + + mstudiobone_t *pbones; + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + m_nCachedBones = m_pStudioHeader->numbones; + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + strcpy( m_nCachedBoneNames[i], pbones[i].name ); + MatrixCopy( (*m_pbonetransform)[i], m_rgCachedBoneTransform[i] ); + MatrixCopy( (*m_plighttransform)[i], m_rgCachedLightTransform[i] ); + } +} + + +/* +==================== +StudioMergeBones + +==================== +*/ +void CStudioModelRenderer::StudioMergeBones ( model_t *m_pSubModel ) +{ + int i, j; + double f; + int do_hunt = true; + + mstudiobone_t *pbones; + mstudioseqdesc_t *pseqdesc; + mstudioanim_t *panim; + + static float pos[MAXSTUDIOBONES][3]; + float bonematrix[3][4]; + static vec4_t q[MAXSTUDIOBONES]; + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + f = StudioEstimateFrame( pseqdesc ); + + if (m_pCurrentEntity->latched.prevframe > f) + { + //Con_DPrintf("%f %f\n", m_pCurrentEntity->prevframe, f ); + } + + panim = StudioGetAnim( m_pSubModel, pseqdesc ); + StudioCalcRotations( pos, q, pseqdesc, panim, f ); + + pbones = (mstudiobone_t *)((byte *)m_pStudioHeader + m_pStudioHeader->boneindex); + + + for (i = 0; i < m_pStudioHeader->numbones; i++) + { + for (j = 0; j < m_nCachedBones; j++) + { + if (stricmp(pbones[i].name, m_nCachedBoneNames[j]) == 0) + { + MatrixCopy( m_rgCachedBoneTransform[j], (*m_pbonetransform)[i] ); + MatrixCopy( m_rgCachedLightTransform[j], (*m_plighttransform)[i] ); + break; + } + } + if (j >= m_nCachedBones) + { + QuaternionMatrix( q[i], bonematrix ); + + bonematrix[0][3] = pos[i][0]; + bonematrix[1][3] = pos[i][1]; + bonematrix[2][3] = pos[i][2]; + + if (pbones[i].parent == -1) + { + if ( IEngineStudio.IsHardware() ) + { + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_pbonetransform)[i]); + + // MatrixCopy should be faster... + //ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + MatrixCopy( (*m_pbonetransform)[i], (*m_plighttransform)[i] ); + } + else + { + ConcatTransforms ((*m_paliastransform), bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_protationmatrix), bonematrix, (*m_plighttransform)[i]); + } + + // Apply client-side effects to the transformation matrix + StudioFxTransform( m_pCurrentEntity, (*m_pbonetransform)[i] ); + } + else + { + ConcatTransforms ((*m_pbonetransform)[pbones[i].parent], bonematrix, (*m_pbonetransform)[i]); + ConcatTransforms ((*m_plighttransform)[pbones[i].parent], bonematrix, (*m_plighttransform)[i]); + } + } + } +} + +/* +==================== +StudioDrawModel + +==================== +*/ +int CStudioModelRenderer::StudioDrawModel( int flags ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + if (m_pCurrentEntity->curstate.renderfx == kRenderFxDeadPlayer) + { + entity_state_t deadplayer; + + int result; + int save_interp; + + if (m_pCurrentEntity->curstate.renderamt <= 0 || m_pCurrentEntity->curstate.renderamt > gEngfuncs.GetMaxClients() ) + return 0; + + // get copy of player + deadplayer = *(IEngineStudio.GetPlayerState( m_pCurrentEntity->curstate.renderamt - 1 )); //cl.frames[cl.parsecount & CL_UPDATE_MASK].playerstate[m_pCurrentEntity->curstate.renderamt-1]; + + // clear weapon, movement state + deadplayer.number = m_pCurrentEntity->curstate.renderamt; + deadplayer.weaponmodel = 0; + deadplayer.gaitsequence = 0; + + deadplayer.movetype = MOVETYPE_NONE; + VectorCopy( m_pCurrentEntity->curstate.angles, deadplayer.angles ); + VectorCopy( m_pCurrentEntity->curstate.origin, deadplayer.origin ); + + save_interp = m_fDoInterp; + m_fDoInterp = 0; + + // draw as though it were a player + result = StudioDrawPlayer( flags, &deadplayer ); + + m_fDoInterp = save_interp; + return result; + } + + m_pRenderModel = m_pCurrentEntity->model; + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + StudioSetUpTransform( 0 ); + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + if (m_pCurrentEntity->curstate.movetype == MOVETYPE_FOLLOW) + { + StudioMergeBones( m_pRenderModel ); + } + else + { + StudioSetupBones( ); + } + StudioSaveBones( ); + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + // get remap colors + m_nTopColor = m_pCurrentEntity->curstate.colormap & 0xFF; + m_nBottomColor = (m_pCurrentEntity->curstate.colormap & 0xFF00) >> 8; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + } + + return 1; +} + +/* +==================== +StudioEstimateGait + +==================== +*/ +void CStudioModelRenderer::StudioEstimateGait( entity_state_t *pplayer ) +{ + float dt; + vec3_t est_velocity; + + dt = (m_clTime - m_clOldTime); + if (dt < 0) + dt = 0; + else if (dt > 1.0) + dt = 1; + + if (dt == 0 || m_pPlayerInfo->renderframe == m_nFrameCount) + { + m_flGaitMovement = 0; + return; + } + + // VectorAdd( pplayer->velocity, pplayer->prediction_error, est_velocity ); + if ( m_fGaitEstimation ) + { + VectorSubtract( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin, est_velocity ); + VectorCopy( m_pCurrentEntity->origin, m_pPlayerInfo->prevgaitorigin ); + m_flGaitMovement = Length( est_velocity ); + if (dt <= 0 || m_flGaitMovement / dt < 5) + { + m_flGaitMovement = 0; + est_velocity[0] = 0; + est_velocity[1] = 0; + } + } + else + { + VectorCopy( pplayer->velocity, est_velocity ); + m_flGaitMovement = Length( est_velocity ) * dt; + } + + if (est_velocity[1] == 0 && est_velocity[0] == 0) + { + float flYawDiff = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYawDiff = flYawDiff - (int)(flYawDiff / 360) * 360; + if (flYawDiff > 180) + flYawDiff -= 360; + if (flYawDiff < -180) + flYawDiff += 360; + + if (dt < 0.25) + flYawDiff *= dt * 4; + else + flYawDiff *= dt; + + m_pPlayerInfo->gaityaw += flYawDiff; + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - (int)(m_pPlayerInfo->gaityaw / 360) * 360; + + m_flGaitMovement = 0; + } + else + { + m_pPlayerInfo->gaityaw = (atan2(est_velocity[1], est_velocity[0]) * 180 / M_PI); + if (m_pPlayerInfo->gaityaw > 180) + m_pPlayerInfo->gaityaw = 180; + if (m_pPlayerInfo->gaityaw < -180) + m_pPlayerInfo->gaityaw = -180; + } + +} + +/* +==================== +StudioProcessGait + +==================== +*/ +void CStudioModelRenderer::StudioProcessGait( entity_state_t *pplayer ) +{ + mstudioseqdesc_t *pseqdesc; + float dt; + int iBlend; + float flYaw; // view direction relative to movement + + if (m_pCurrentEntity->curstate.sequence >= m_pStudioHeader->numseq) + { + m_pCurrentEntity->curstate.sequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + m_pCurrentEntity->curstate.sequence; + + StudioPlayerBlend( pseqdesc, &iBlend, &m_pCurrentEntity->angles[PITCH] ); + + m_pCurrentEntity->latched.prevangles[PITCH] = m_pCurrentEntity->angles[PITCH]; + m_pCurrentEntity->curstate.blending[0] = iBlend; + m_pCurrentEntity->latched.prevblending[0] = m_pCurrentEntity->curstate.blending[0]; + m_pCurrentEntity->latched.prevseqblending[0] = m_pCurrentEntity->curstate.blending[0]; + + // Con_DPrintf("%f %d\n", m_pCurrentEntity->angles[PITCH], m_pCurrentEntity->blending[0] ); + + dt = (m_clTime - m_clOldTime); + if (dt < 0) + dt = 0; + else if (dt > 1.0) + dt = 1; + + StudioEstimateGait( pplayer ); + + // Con_DPrintf("%f %f\n", m_pCurrentEntity->angles[YAW], m_pPlayerInfo->gaityaw ); + + // calc side to side turning + flYaw = m_pCurrentEntity->angles[YAW] - m_pPlayerInfo->gaityaw; + flYaw = flYaw - (int)(flYaw / 360) * 360; + if (flYaw < -180) + flYaw = flYaw + 360; + if (flYaw > 180) + flYaw = flYaw - 360; + + if (flYaw > 120) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw - 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw - 180; + } + else if (flYaw < -120) + { + m_pPlayerInfo->gaityaw = m_pPlayerInfo->gaityaw + 180; + m_flGaitMovement = -m_flGaitMovement; + flYaw = flYaw + 180; + } + + // adjust torso + m_pCurrentEntity->curstate.controller[0] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[1] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[2] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->curstate.controller[3] = ((flYaw / 4.0) + 30) / (60.0 / 255.0); + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pCurrentEntity->angles[YAW] = m_pPlayerInfo->gaityaw; + if (m_pCurrentEntity->angles[YAW] < -0) + m_pCurrentEntity->angles[YAW] += 360; + m_pCurrentEntity->latched.prevangles[YAW] = m_pCurrentEntity->angles[YAW]; + + if (pplayer->gaitsequence >= m_pStudioHeader->numseq) + { + pplayer->gaitsequence = 0; + } + + pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + pplayer->gaitsequence; + + // calc gait frame + if (pseqdesc->linearmovement[0] > 0) + { + m_pPlayerInfo->gaitframe += (m_flGaitMovement / pseqdesc->linearmovement[0]) * pseqdesc->numframes; + } + else + { + m_pPlayerInfo->gaitframe += pseqdesc->fps * dt; + } + + // do modulo + m_pPlayerInfo->gaitframe = m_pPlayerInfo->gaitframe - (int)(m_pPlayerInfo->gaitframe / pseqdesc->numframes) * pseqdesc->numframes; + if (m_pPlayerInfo->gaitframe < 0) + m_pPlayerInfo->gaitframe += pseqdesc->numframes; +} + +/* +==================== +StudioDrawPlayer + +==================== +*/ +int CStudioModelRenderer::StudioDrawPlayer( int flags, entity_state_t *pplayer ) +{ + alight_t lighting; + vec3_t dir; + + m_pCurrentEntity = IEngineStudio.GetCurrentEntity(); + IEngineStudio.GetTimes( &m_nFrameCount, &m_clTime, &m_clOldTime ); + IEngineStudio.GetViewInfo( m_vRenderOrigin, m_vUp, m_vRight, m_vNormal ); + IEngineStudio.GetAliasScale( &m_fSoftwareXScale, &m_fSoftwareYScale ); + + // Con_DPrintf("DrawPlayer %d\n", m_pCurrentEntity->blending[0] ); + + // Con_DPrintf("DrawPlayer %d %d (%d)\n", m_nFrameCount, pplayer->player_index, m_pCurrentEntity->curstate.sequence ); + + // Con_DPrintf("Player %.2f %.2f %.2f\n", pplayer->velocity[0], pplayer->velocity[1], pplayer->velocity[2] ); + + m_nPlayerIndex = pplayer->number - 1; + + if (m_nPlayerIndex < 0 || m_nPlayerIndex >= gEngfuncs.GetMaxClients()) + return 0; + + m_pRenderModel = IEngineStudio.SetupPlayerModel( m_nPlayerIndex ); + if (m_pRenderModel == NULL) + return 0; + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (m_pRenderModel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + IEngineStudio.SetRenderModel( m_pRenderModel ); + + if (pplayer->gaitsequence) + { + vec3_t orig_angles; + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + VectorCopy( m_pCurrentEntity->angles, orig_angles ); + + StudioProcessGait( pplayer ); + + m_pPlayerInfo->gaitsequence = pplayer->gaitsequence; + m_pPlayerInfo = NULL; + + StudioSetUpTransform( 0 ); + VectorCopy( orig_angles, m_pCurrentEntity->angles ); + } + else + { + m_pCurrentEntity->curstate.controller[0] = 127; + m_pCurrentEntity->curstate.controller[1] = 127; + m_pCurrentEntity->curstate.controller[2] = 127; + m_pCurrentEntity->curstate.controller[3] = 127; + m_pCurrentEntity->latched.prevcontroller[0] = m_pCurrentEntity->curstate.controller[0]; + m_pCurrentEntity->latched.prevcontroller[1] = m_pCurrentEntity->curstate.controller[1]; + m_pCurrentEntity->latched.prevcontroller[2] = m_pCurrentEntity->curstate.controller[2]; + m_pCurrentEntity->latched.prevcontroller[3] = m_pCurrentEntity->curstate.controller[3]; + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + m_pPlayerInfo->gaitsequence = 0; + + StudioSetUpTransform( 0 ); + } + + if (flags & STUDIO_RENDER) + { + // see if the bounding box lets us trivially reject, also sets + if (!IEngineStudio.StudioCheckBBox ()) + return 0; + + (*m_pModelsDrawn)++; + (*m_pStudioModelCount)++; // render data cache cookie + + if (m_pStudioHeader->numbodyparts == 0) + return 1; + } + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + StudioSetupBones( ); + StudioSaveBones( ); + m_pPlayerInfo->renderframe = m_nFrameCount; + + m_pPlayerInfo = NULL; + + if (flags & STUDIO_EVENTS) + { + StudioCalcAttachments( ); + IEngineStudio.StudioClientEvents( ); + // copy attachments into global entity array + if ( m_pCurrentEntity->index > 0 ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( m_pCurrentEntity->index ); + + memcpy( ent->attachment, m_pCurrentEntity->attachment, sizeof( vec3_t ) * 4 ); + } + } + + if (flags & STUDIO_RENDER) + { + if (m_pCvarHiModels->value && m_pRenderModel != m_pCurrentEntity->model ) + { + // show highest resolution multiplayer model + m_pCurrentEntity->curstate.body = 255; + } + + if (!(m_pCvarDeveloper->value == 0 && gEngfuncs.GetMaxClients() == 1 ) && ( m_pRenderModel == m_pCurrentEntity->model ) ) + { + m_pCurrentEntity->curstate.body = 1; // force helmet + } + + lighting.plightvec = dir; + IEngineStudio.StudioDynamicLight(m_pCurrentEntity, &lighting ); + + IEngineStudio.StudioEntityLight( &lighting ); + + // model and frame independant + IEngineStudio.StudioSetupLighting (&lighting); + + m_pPlayerInfo = IEngineStudio.PlayerInfo( m_nPlayerIndex ); + + // get remap colors + m_nTopColor = m_pPlayerInfo->topcolor; + m_nBottomColor = m_pPlayerInfo->bottomcolor; + if (m_nTopColor < 0) + m_nTopColor = 0; + if (m_nTopColor > 360) + m_nTopColor = 360; + if (m_nBottomColor < 0) + m_nBottomColor = 0; + if (m_nBottomColor > 360) + m_nBottomColor = 360; + + IEngineStudio.StudioSetRemapColors( m_nTopColor, m_nBottomColor ); + + StudioRenderModel( ); + m_pPlayerInfo = NULL; + + if (pplayer->weaponmodel) + { + cl_entity_t saveent = *m_pCurrentEntity; + + model_t *pweaponmodel = IEngineStudio.GetModelByIndex( pplayer->weaponmodel ); + + m_pStudioHeader = (studiohdr_t *)IEngineStudio.Mod_Extradata (pweaponmodel); + IEngineStudio.StudioSetHeader( m_pStudioHeader ); + + StudioMergeBones( pweaponmodel); + + IEngineStudio.StudioSetupLighting (&lighting); + + StudioRenderModel( ); + + StudioCalcAttachments( ); + + *m_pCurrentEntity = saveent; + } + } + + return 1; +} + +/* +==================== +StudioCalcAttachments + +==================== +*/ +void CStudioModelRenderer::StudioCalcAttachments( void ) +{ + int i; + mstudioattachment_t *pattachment; + + if ( m_pStudioHeader->numattachments > 4 ) + { + gEngfuncs.Con_DPrintf( "Too many attachments on %s\n", m_pCurrentEntity->model->name ); + exit( -1 ); + } + + // calculate attachment points + pattachment = (mstudioattachment_t *)((byte *)m_pStudioHeader + m_pStudioHeader->attachmentindex); + for (i = 0; i < m_pStudioHeader->numattachments; i++) + { + VectorTransform( pattachment[i].org, (*m_plighttransform)[pattachment[i].bone], m_pCurrentEntity->attachment[i] ); + } +} + +/* +==================== +StudioRenderModel + +==================== +*/ +void CStudioModelRenderer::StudioRenderModel( void ) +{ + IEngineStudio.SetChromeOrigin(); + IEngineStudio.SetForceFaceFlags( 0 ); + + if ( m_pCurrentEntity->curstate.renderfx == kRenderFxGlowShell ) + { + m_pCurrentEntity->curstate.renderfx = kRenderFxNone; + StudioRenderFinal( ); + + if ( !IEngineStudio.IsHardware() ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + } + + IEngineStudio.SetForceFaceFlags( STUDIO_NF_CHROME ); + + gEngfuncs.pTriAPI->SpriteTexture( m_pChromeSprite, 0 ); + m_pCurrentEntity->curstate.renderfx = kRenderFxGlowShell; + + StudioRenderFinal( ); + if ( !IEngineStudio.IsHardware() ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + } + else + { + StudioRenderFinal( ); + } +} + +/* +==================== +StudioRenderFinal_Software + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal_Software( void ) +{ + int i; + + // Note, rendermode set here has effect in SW + IEngineStudio.SetupRenderer( 0 ); + + if (m_pCvarDrawEntities->value == 2) + { + IEngineStudio.StudioDrawBones( ); + } + else if (m_pCvarDrawEntities->value == 3) + { + IEngineStudio.StudioDrawHulls( ); + } + else + { + for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + { + IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); + IEngineStudio.StudioDrawPoints( ); + } + } + + if (m_pCvarDrawEntities->value == 4) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + IEngineStudio.StudioDrawHulls( ); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + + if (m_pCvarDrawEntities->value == 5) + { + IEngineStudio.StudioDrawAbsBBox( ); + } + + IEngineStudio.RestoreRenderer(); +} + +/* +==================== +StudioRenderFinal_Hardware + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal_Hardware( void ) +{ + int i; + int rendermode; + + rendermode = IEngineStudio.GetForceFaceFlags() ? kRenderTransAdd : m_pCurrentEntity->curstate.rendermode; + IEngineStudio.SetupRenderer( rendermode ); + + if (m_pCvarDrawEntities->value == 2) + { + IEngineStudio.StudioDrawBones(); + } + else if (m_pCvarDrawEntities->value == 3) + { + IEngineStudio.StudioDrawHulls(); + } + else + { + for (i=0 ; i < m_pStudioHeader->numbodyparts ; i++) + { + IEngineStudio.StudioSetupModel( i, (void **)&m_pBodyPart, (void **)&m_pSubModel ); + + if (m_fDoInterp) + { + // interpolation messes up bounding boxes. + m_pCurrentEntity->trivial_accept = 0; + } + + IEngineStudio.GL_SetRenderMode( rendermode ); + IEngineStudio.StudioDrawPoints(); + IEngineStudio.GL_StudioDrawShadow(); + } + } + + if ( m_pCvarDrawEntities->value == 4 ) + { + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + IEngineStudio.StudioDrawHulls( ); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + } + + IEngineStudio.RestoreRenderer(); +} + +/* +==================== +StudioRenderFinal + +==================== +*/ +void CStudioModelRenderer::StudioRenderFinal(void) +{ + if ( IEngineStudio.IsHardware() ) + { + StudioRenderFinal_Hardware(); + } + else + { + StudioRenderFinal_Software(); + } +} + diff --git a/cl_dll/StudioModelRenderer.h b/cl_dll/StudioModelRenderer.h new file mode 100644 index 00000000..51eaaa60 --- /dev/null +++ b/cl_dll/StudioModelRenderer.h @@ -0,0 +1,189 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( STUDIOMODELRENDERER_H ) +#define STUDIOMODELRENDERER_H +#if defined( _WIN32 ) +#pragma once +#endif + +/* +==================== +CStudioModelRenderer + +==================== +*/ +class CStudioModelRenderer +{ +public: + // Construction/Destruction + CStudioModelRenderer( void ); + virtual ~CStudioModelRenderer( void ); + + // Initialization + virtual void Init( void ); + +public: + // Public Interfaces + virtual int StudioDrawModel ( int flags ); + virtual int StudioDrawPlayer ( int flags, struct entity_state_s *pplayer ); + +public: + // Local interfaces + // + + // Look up animation data for sequence + virtual mstudioanim_t *StudioGetAnim ( model_t *m_pSubModel, mstudioseqdesc_t *pseqdesc ); + + // Interpolate model position and angles and set up matrices + virtual void StudioSetUpTransform (int trivial_accept); + + // Set up model bone positions + virtual void StudioSetupBones ( void ); + + // Find final attachment points + virtual void StudioCalcAttachments ( void ); + + // Save bone matrices and names + virtual void StudioSaveBones( void ); + + // Merge cached bones with current bones for model + virtual void StudioMergeBones ( model_t *m_pSubModel ); + + // Determine interpolation fraction + virtual float StudioEstimateInterpolant( void ); + + // Determine current frame for rendering + virtual float StudioEstimateFrame ( mstudioseqdesc_t *pseqdesc ); + + // Apply special effects to transform matrix + virtual void StudioFxTransform( cl_entity_t *ent, float transform[3][4] ); + + // Spherical interpolation of bones + virtual void StudioSlerpBones ( vec4_t q1[], float pos1[][3], vec4_t q2[], float pos2[][3], float s ); + + // Compute bone adjustments ( bone controllers ) + virtual void StudioCalcBoneAdj ( float dadt, float *adj, const byte *pcontroller1, const byte *pcontroller2, byte mouthopen ); + + // Get bone quaternions + virtual void StudioCalcBoneQuaterion ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *q ); + + // Get bone positions + virtual void StudioCalcBonePosition ( int frame, float s, mstudiobone_t *pbone, mstudioanim_t *panim, float *adj, float *pos ); + + // Compute rotations + virtual void StudioCalcRotations ( float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ); + + // Send bones and verts to renderer + virtual void StudioRenderModel ( void ); + + // Finalize rendering + virtual void StudioRenderFinal (void); + + // GL&D3D vs. Software renderer finishing functions + virtual void StudioRenderFinal_Software ( void ); + virtual void StudioRenderFinal_Hardware ( void ); + + // Player specific data + // Determine pitch and blending amounts for players + virtual void StudioPlayerBlend ( mstudioseqdesc_t *pseqdesc, int *pBlend, float *pPitch ); + + // Estimate gait frame for player + virtual void StudioEstimateGait ( entity_state_t *pplayer ); + + // Process movement of player + virtual void StudioProcessGait ( entity_state_t *pplayer ); + +public: + + // Client clock + double m_clTime; + // Old Client clock + double m_clOldTime; + + // Do interpolation? + int m_fDoInterp; + // Do gait estimation? + int m_fGaitEstimation; + + // Current render frame # + int m_nFrameCount; + + // Cvars that studio model code needs to reference + // + // Use high quality models? + cvar_t *m_pCvarHiModels; + // Developer debug output desired? + cvar_t *m_pCvarDeveloper; + // Draw entities bone hit boxes, etc? + cvar_t *m_pCvarDrawEntities; + + // The entity which we are currently rendering. + cl_entity_t *m_pCurrentEntity; + + // The model for the entity being rendered + model_t *m_pRenderModel; + + // Player info for current player, if drawing a player + player_info_t *m_pPlayerInfo; + + // The index of the player being drawn + int m_nPlayerIndex; + + // The player's gait movement + float m_flGaitMovement; + + // Pointer to header block for studio model data + studiohdr_t *m_pStudioHeader; + + // Pointers to current body part and submodel + mstudiobodyparts_t *m_pBodyPart; + mstudiomodel_t *m_pSubModel; + + // Palette substition for top and bottom of model + int m_nTopColor; + int m_nBottomColor; + + // + // Sprite model used for drawing studio model chrome + model_t *m_pChromeSprite; + + // Caching + // Number of bones in bone cache + int m_nCachedBones; + // Names of cached bones + char m_nCachedBoneNames[ MAXSTUDIOBONES ][ 32 ]; + // Cached bone & light transformation matrices + float m_rgCachedBoneTransform [ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float m_rgCachedLightTransform[ MAXSTUDIOBONES ][ 3 ][ 4 ]; + + // Software renderer scale factors + float m_fSoftwareXScale, m_fSoftwareYScale; + + // Current view vectors and render origin + float m_vUp[ 3 ]; + float m_vRight[ 3 ]; + float m_vNormal[ 3 ]; + + float m_vRenderOrigin[ 3 ]; + + // Model render counters ( from engine ) + int *m_pStudioModelCount; + int *m_pModelsDrawn; + + // Matrices + // Model to world transformation + float (*m_protationmatrix)[ 3 ][ 4 ]; + // Model to view transformation + float (*m_paliastransform)[ 3 ][ 4 ]; + + // Concatenated bone and light transforms + float (*m_pbonetransform) [ MAXSTUDIOBONES ][ 3 ][ 4 ]; + float (*m_plighttransform)[ MAXSTUDIOBONES ][ 3 ][ 4 ]; +}; + +#endif // STUDIOMODELRENDERER_H \ No newline at end of file diff --git a/cl_dll/ammo.cpp b/cl_dll/ammo.cpp new file mode 100644 index 00000000..5084e084 --- /dev/null +++ b/cl_dll/ammo.cpp @@ -0,0 +1,1204 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// Ammo.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include "pm_shared.h" + +#include +#include + +#include "ammohistory.h" +#include "vgui_TeamFortressViewport.h" + +WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise + // this points to the active weapon menu item +WEAPON *gpLastSel; // Last weapon menu selection + +client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); + +WeaponsResource gWR; + +int g_weaponselect = 0; + +void WeaponsResource :: LoadAllWeaponSprites( void ) +{ + for (int i = 0; i < MAX_WEAPONS; i++) + { + if ( rgWeapons[i].iId ) + LoadWeaponSprites( &rgWeapons[i] ); + } +} + +int WeaponsResource :: CountAmmo( int iId ) +{ + if ( iId < 0 ) + return 0; + + return riAmmo[iId]; +} + +int WeaponsResource :: HasAmmo( WEAPON *p ) +{ + if ( !p ) + return FALSE; + + // weapons with no max ammo can always be selected + if ( p->iMax1 == -1 ) + return TRUE; + + return (p->iAmmoType == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType) + || CountAmmo(p->iAmmo2Type) || ( p->iFlags & WEAPON_FLAGS_SELECTONEMPTY ); +} + + +void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) +{ + int i, iRes; + + if (ScreenWidth < 640) + iRes = 320; + else + iRes = 640; + + char sz[128]; + + if ( !pWeapon ) + return; + + memset( &pWeapon->rcActive, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcInactive, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcAmmo, 0, sizeof(wrect_t) ); + memset( &pWeapon->rcAmmo2, 0, sizeof(wrect_t) ); + pWeapon->hInactive = 0; + pWeapon->hActive = 0; + pWeapon->hAmmo = 0; + pWeapon->hAmmo2 = 0; + + sprintf(sz, "sprites/%s.txt", pWeapon->szName); + client_sprite_t *pList = SPR_GetList(sz, &i); + + if (!pList) + return; + + client_sprite_t *p; + + p = GetSpriteList( pList, "crosshair", iRes, i ); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hCrosshair = SPR_Load(sz); + pWeapon->rcCrosshair = p->rc; + } + else + pWeapon->hCrosshair = NULL; + + p = GetSpriteList(pList, "autoaim", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAutoaim = SPR_Load(sz); + pWeapon->rcAutoaim = p->rc; + } + else + pWeapon->hAutoaim = 0; + + p = GetSpriteList( pList, "zoom", iRes, i ); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hZoomedCrosshair = SPR_Load(sz); + pWeapon->rcZoomedCrosshair = p->rc; + } + else + { + pWeapon->hZoomedCrosshair = pWeapon->hCrosshair; //default to non-zoomed crosshair + pWeapon->rcZoomedCrosshair = pWeapon->rcCrosshair; + } + + p = GetSpriteList(pList, "zoom_autoaim", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hZoomedAutoaim = SPR_Load(sz); + pWeapon->rcZoomedAutoaim = p->rc; + } + else + { + pWeapon->hZoomedAutoaim = pWeapon->hZoomedCrosshair; //default to zoomed crosshair + pWeapon->rcZoomedAutoaim = pWeapon->rcZoomedCrosshair; + } + + p = GetSpriteList(pList, "weapon", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hInactive = SPR_Load(sz); + pWeapon->rcInactive = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hInactive = 0; + + p = GetSpriteList(pList, "weapon_s", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hActive = SPR_Load(sz); + pWeapon->rcActive = p->rc; + } + else + pWeapon->hActive = 0; + + p = GetSpriteList(pList, "ammo", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAmmo = SPR_Load(sz); + pWeapon->rcAmmo = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hAmmo = 0; + + p = GetSpriteList(pList, "ammo2", iRes, i); + if (p) + { + sprintf(sz, "sprites/%s.spr", p->szSprite); + pWeapon->hAmmo2 = SPR_Load(sz); + pWeapon->rcAmmo2 = p->rc; + + gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); + } + else + pWeapon->hAmmo2 = 0; + +} + +// Returns the first weapon for a given slot. +WEAPON *WeaponsResource :: GetFirstPos( int iSlot ) +{ + WEAPON *pret = NULL; + + for (int i = 0; i < MAX_WEAPON_POSITIONS; i++) + { + if ( rgSlots[iSlot][i] && HasAmmo( rgSlots[iSlot][i] ) ) + { + pret = rgSlots[iSlot][i]; + break; + } + } + + return pret; +} + + +WEAPON* WeaponsResource :: GetNextActivePos( int iSlot, int iSlotPos ) +{ + if ( iSlotPos >= MAX_WEAPON_POSITIONS || iSlot >= MAX_WEAPON_SLOTS ) + return NULL; + + WEAPON *p = gWR.rgSlots[ iSlot ][ iSlotPos+1 ]; + + if ( !p || !gWR.HasAmmo(p) ) + return GetNextActivePos( iSlot, iSlotPos + 1 ); + + return p; +} + + +int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height + +HSPRITE ghsprBuckets; // Sprite for top row of weapons menu + +DECLARE_MESSAGE(m_Ammo, CurWeapon ); // Current weapon and clip +DECLARE_MESSAGE(m_Ammo, WeaponList); // new weapon type +DECLARE_MESSAGE(m_Ammo, AmmoX); // update known ammo type's count +DECLARE_MESSAGE(m_Ammo, AmmoPickup); // flashes an ammo pickup record +DECLARE_MESSAGE(m_Ammo, WeapPickup); // flashes a weapon pickup record +DECLARE_MESSAGE(m_Ammo, HideWeapon); // hides the weapon, ammo, and crosshair displays temporarily +DECLARE_MESSAGE(m_Ammo, ItemPickup); + +DECLARE_COMMAND(m_Ammo, Slot1); +DECLARE_COMMAND(m_Ammo, Slot2); +DECLARE_COMMAND(m_Ammo, Slot3); +DECLARE_COMMAND(m_Ammo, Slot4); +DECLARE_COMMAND(m_Ammo, Slot5); +DECLARE_COMMAND(m_Ammo, Slot6); +DECLARE_COMMAND(m_Ammo, Slot7); +DECLARE_COMMAND(m_Ammo, Slot8); +DECLARE_COMMAND(m_Ammo, Slot9); +DECLARE_COMMAND(m_Ammo, Slot10); +DECLARE_COMMAND(m_Ammo, Close); +DECLARE_COMMAND(m_Ammo, NextWeapon); +DECLARE_COMMAND(m_Ammo, PrevWeapon); + +// width of ammo fonts +#define AMMO_SMALL_WIDTH 10 +#define AMMO_LARGE_WIDTH 20 + +#define HISTORY_DRAW_TIME "5" + +int CHudAmmo::Init(void) +{ + gHUD.AddHudElem(this); + + HOOK_MESSAGE(CurWeapon); + HOOK_MESSAGE(WeaponList); + HOOK_MESSAGE(AmmoPickup); + HOOK_MESSAGE(WeapPickup); + HOOK_MESSAGE(ItemPickup); + HOOK_MESSAGE(HideWeapon); + HOOK_MESSAGE(AmmoX); + + HOOK_COMMAND("slot1", Slot1); + HOOK_COMMAND("slot2", Slot2); + HOOK_COMMAND("slot3", Slot3); + HOOK_COMMAND("slot4", Slot4); + HOOK_COMMAND("slot5", Slot5); + HOOK_COMMAND("slot6", Slot6); + HOOK_COMMAND("slot7", Slot7); + HOOK_COMMAND("slot8", Slot8); + HOOK_COMMAND("slot9", Slot9); + HOOK_COMMAND("slot10", Slot10); + HOOK_COMMAND("cancelselect", Close); + HOOK_COMMAND("invnext", NextWeapon); + HOOK_COMMAND("invprev", PrevWeapon); + + Reset(); + + CVAR_CREATE( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 ); + CVAR_CREATE( "hud_fastswitch", "0", FCVAR_ARCHIVE ); // controls whether or not weapons can be selected in one keypress + + m_iFlags |= HUD_ACTIVE; //!!! + + gWR.Init(); + gHR.Init(); + + return 1; +}; + +void CHudAmmo::Reset(void) +{ + m_fFade = 0; + m_iFlags |= HUD_ACTIVE; //!!! + + gpActiveSel = NULL; + gHUD.m_iHideHUDDisplay = 0; + + gWR.Reset(); + gHR.Reset(); + + // VidInit(); + +} + +int CHudAmmo::VidInit(void) +{ + // Load sprites for buckets (top row of weapon menu) + m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" ); + m_HUD_selection = gHUD.GetSpriteIndex( "selection" ); + + ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0); + giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left; + giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top; + + gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top); + + // If we've already loaded weapons, let's get new sprites + gWR.LoadAllWeaponSprites(); + + if (ScreenWidth >= 640) + { + giABWidth = 20; + giABHeight = 4; + } + else + { + giABWidth = 10; + giABHeight = 2; + } + + return 1; +} + +// +// Think: +// Used for selection of weapon menu item. +// +void CHudAmmo::Think(void) +{ + if ( gHUD.m_fPlayerDead ) + return; + + if ( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) + { + gWR.iOldWeaponBits = gHUD.m_iWeaponBits; + + for (int i = MAX_WEAPONS-1; i > 0; i-- ) + { + WEAPON *p = gWR.GetWeapon(i); + + if ( p ) + { + if ( gHUD.m_iWeaponBits & ( 1 << p->iId ) ) + gWR.PickupWeapon( p ); + else + gWR.DropWeapon( p ); + } + } + } + + if (!gpActiveSel) + return; + + // has the player selected one? + if (gHUD.m_iKeyBits & IN_ATTACK) + { + if (gpActiveSel != (WEAPON *)1) + { + ServerCmd(gpActiveSel->szName); + g_weaponselect = gpActiveSel->iId; + } + + gpLastSel = gpActiveSel; + gpActiveSel = NULL; + gHUD.m_iKeyBits &= ~IN_ATTACK; + + PlaySound("common/wpn_select.wav", 1); + } + +} + +// +// Helper function to return a Ammo pointer from id +// + +HSPRITE* WeaponsResource :: GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) +{ + for ( int i = 0; i < MAX_WEAPONS; i++ ) + { + if ( rgWeapons[i].iAmmoType == iAmmoId ) + { + rect = rgWeapons[i].rcAmmo; + return &rgWeapons[i].hAmmo; + } + else if ( rgWeapons[i].iAmmo2Type == iAmmoId ) + { + rect = rgWeapons[i].rcAmmo2; + return &rgWeapons[i].hAmmo2; + } + } + + return NULL; +} + + +// Menu Selection Code + +void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) +{ + if ( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) ) + { // menu is overriding slot use commands + gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers + return; + } + + if ( iSlot > MAX_WEAPON_SLOTS ) + return; + + if ( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + return; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return; + + if ( ! ( gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)) )) + return; + + WEAPON *p = NULL; + bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; + + if ( (gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot) ) + { + PlaySound( "common/wpn_hudon.wav", 1 ); + p = GetFirstPos( iSlot ); + + if ( p && fastSwitch ) // check for fast weapon switch mode + { + // if fast weapon switch is on, then weapons can be selected in a single keypress + // but only if there is only one item in the bucket + WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos ); + if ( !p2 ) + { // only one active item in bucket, so change directly to weapon + ServerCmd( p->szName ); + g_weaponselect = p->iId; + return; + } + } + } + else + { + PlaySound("common/wpn_moveselect.wav", 1); + if ( gpActiveSel ) + p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos ); + if ( !p ) + p = GetFirstPos( iSlot ); + } + + + if ( !p ) // no selection found + { + // just display the weapon list, unless fastswitch is on just ignore it + if ( !fastSwitch ) + gpActiveSel = (WEAPON *)1; + else + gpActiveSel = NULL; + } + else + gpActiveSel = p; +} + +//------------------------------------------------------------------------ +// Message Handlers +//------------------------------------------------------------------------ + +// +// AmmoX -- Update the count of a known type of ammo +// +int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + int iIndex = READ_BYTE(); + int iCount = READ_BYTE(); + + gWR.SetAmmo( iIndex, abs(iCount) ); + + return 1; +} + +int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + int iIndex = READ_BYTE(); + int iCount = READ_BYTE(); + + // Add ammo to the history + gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) ); + + return 1; +} + +int CHudAmmo::MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + int iIndex = READ_BYTE(); + + // Add the weapon to the history + gHR.AddToHistory( HISTSLOT_WEAP, iIndex ); + + return 1; +} + +int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + const char *szName = READ_STRING(); + + // Add the weapon to the history + gHR.AddToHistory( HISTSLOT_ITEM, szName ); + + return 1; +} + + +int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + gHUD.m_iHideHUDDisplay = READ_BYTE(); + + if (gEngfuncs.IsSpectateOnly()) + return 1; + + if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ) ) + { + static wrect_t nullrc; + gpActiveSel = NULL; + SetCrosshair( 0, nullrc, 0, 0, 0 ); + } + else + { + if ( m_pWeapon ) + SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); + } + + return 1; +} + +// +// CurWeapon: Update hud state with the current weapon and clip count. Ammo +// counts are updated with AmmoX. Server assures that the Weapon ammo type +// numbers match a real ammo type. +// +int CHudAmmo::MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf ) +{ + static wrect_t nullrc; + int fOnTarget = FALSE; + + BEGIN_READ( pbuf, iSize ); + + int iState = READ_BYTE(); + int iId = READ_CHAR(); + int iClip = READ_CHAR(); + + // detect if we're also on target + if ( iState > 1 ) + { + fOnTarget = TRUE; + } + + if ( iId < 1 ) + { + SetCrosshair(0, nullrc, 0, 0, 0); + return 0; + } + + if ( g_iUser1 != OBS_IN_EYE ) + { + // Is player dead??? + if ((iId == -1) && (iClip == -1)) + { + gHUD.m_fPlayerDead = TRUE; + gpActiveSel = NULL; + return 1; + } + gHUD.m_fPlayerDead = FALSE; + } + + WEAPON *pWeapon = gWR.GetWeapon( iId ); + + if ( !pWeapon ) + return 0; + + if ( iClip < -1 ) + pWeapon->iClip = abs(iClip); + else + pWeapon->iClip = iClip; + + + if ( iState == 0 ) // we're not the current weapon, so update no more + return 1; + + m_pWeapon = pWeapon; + + if ( gHUD.m_iFOV >= 90 ) + { // normal crosshairs + if (fOnTarget && m_pWeapon->hAutoaim) + SetCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255); + else + SetCrosshair(m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255); + } + else + { // zoomed crosshairs + if (fOnTarget && m_pWeapon->hZoomedAutoaim) + SetCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255); + else + SetCrosshair(m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255); + + } + + m_fFade = 200.0f; //!!! + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +// +// WeaponList -- Tells the hud about a new weapon type. +// +int CHudAmmo::MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + WEAPON Weapon; + + strcpy( Weapon.szName, READ_STRING() ); + Weapon.iAmmoType = (int)READ_CHAR(); + + Weapon.iMax1 = READ_BYTE(); + if (Weapon.iMax1 == 255) + Weapon.iMax1 = -1; + + Weapon.iAmmo2Type = READ_CHAR(); + Weapon.iMax2 = READ_BYTE(); + if (Weapon.iMax2 == 255) + Weapon.iMax2 = -1; + + Weapon.iSlot = READ_CHAR(); + Weapon.iSlotPos = READ_CHAR(); + Weapon.iId = READ_CHAR(); + Weapon.iFlags = READ_BYTE(); + Weapon.iClip = 0; + + gWR.AddWeapon( &Weapon ); + + return 1; + +} + +//------------------------------------------------------------------------ +// Command Handlers +//------------------------------------------------------------------------ +// Slot button pressed +void CHudAmmo::SlotInput( int iSlot ) +{ + // Let the Viewport use it first, for menus + if ( gViewPort && gViewPort->SlotInput( iSlot ) ) + return; + + gWR.SelectSlot(iSlot, FALSE, 1); +} + +void CHudAmmo::UserCmd_Slot1(void) +{ + SlotInput( 0 ); +} + +void CHudAmmo::UserCmd_Slot2(void) +{ + SlotInput( 1 ); +} + +void CHudAmmo::UserCmd_Slot3(void) +{ + SlotInput( 2 ); +} + +void CHudAmmo::UserCmd_Slot4(void) +{ + SlotInput( 3 ); +} + +void CHudAmmo::UserCmd_Slot5(void) +{ + SlotInput( 4 ); +} + +void CHudAmmo::UserCmd_Slot6(void) +{ + SlotInput( 5 ); +} + +void CHudAmmo::UserCmd_Slot7(void) +{ + SlotInput( 6 ); +} + +void CHudAmmo::UserCmd_Slot8(void) +{ + SlotInput( 7 ); +} + +void CHudAmmo::UserCmd_Slot9(void) +{ + SlotInput( 8 ); +} + +void CHudAmmo::UserCmd_Slot10(void) +{ + SlotInput( 9 ); +} + +void CHudAmmo::UserCmd_Close(void) +{ + if (gpActiveSel) + { + gpLastSel = gpActiveSel; + gpActiveSel = NULL; + PlaySound("common/wpn_hudoff.wav", 1); + } + else + ClientCmd("escape"); +} + + +// Selects the next item in the weapon menu +void CHudAmmo::UserCmd_NextWeapon(void) +{ + if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + return; + + if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + gpActiveSel = m_pWeapon; + + int pos = 0; + int slot = 0; + if ( gpActiveSel ) + { + pos = gpActiveSel->iSlotPos + 1; + slot = gpActiveSel->iSlot; + } + + for ( int loop = 0; loop <= 1; loop++ ) + { + for ( ; slot < MAX_WEAPON_SLOTS; slot++ ) + { + for ( ; pos < MAX_WEAPON_POSITIONS; pos++ ) + { + WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); + + if ( wsp && gWR.HasAmmo(wsp) ) + { + gpActiveSel = wsp; + return; + } + } + + pos = 0; + } + + slot = 0; // start looking from the first slot again + } + + gpActiveSel = NULL; +} + +// Selects the previous item in the menu +void CHudAmmo::UserCmd_PrevWeapon(void) +{ + if ( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS | HIDEHUD_ALL)) ) + return; + + if ( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) + gpActiveSel = m_pWeapon; + + int pos = MAX_WEAPON_POSITIONS-1; + int slot = MAX_WEAPON_SLOTS-1; + if ( gpActiveSel ) + { + pos = gpActiveSel->iSlotPos - 1; + slot = gpActiveSel->iSlot; + } + + for ( int loop = 0; loop <= 1; loop++ ) + { + for ( ; slot >= 0; slot-- ) + { + for ( ; pos >= 0; pos-- ) + { + WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); + + if ( wsp && gWR.HasAmmo(wsp) ) + { + gpActiveSel = wsp; + return; + } + } + + pos = MAX_WEAPON_POSITIONS-1; + } + + slot = MAX_WEAPON_SLOTS-1; + } + + gpActiveSel = NULL; +} + + + +//------------------------------------------------------------------------- +// Drawing code +//------------------------------------------------------------------------- + +int CHudAmmo::Draw(float flTime) +{ + int a, x, y, r, g, b; + int AmmoWidth; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + return 1; + + // Draw Weapon Menu + DrawWList(flTime); + + // Draw ammo pickup history + gHR.DrawAmmoHistory( flTime ); + + if (!(m_iFlags & HUD_ACTIVE)) + return 0; + + if (!m_pWeapon) + return 0; + + WEAPON *pw = m_pWeapon; // shorthand + + // SPR_Draw Ammo + if ((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0)) + return 0; + + + int iFlags = DHN_DRAWZERO; // draw 0 values + + AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + + a = (int) max( MIN_ALPHA, m_fFade ); + + if (m_fFade > 0) + m_fFade -= (gHUD.m_flTimeDelta * 20); + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + ScaleColors(r, g, b, a ); + + // Does this weapon have a clip? + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight/2; + + // Does weapon have any ammo at all? + if (m_pWeapon->iAmmoType > 0) + { + int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left; + + if (pw->iClip >= 0) + { + // room for the number and the '|' and the current ammo + + x = ScreenWidth - (8 * AmmoWidth) - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, pw->iClip, r, g, b); + + wrect_t rc; + rc.top = 0; + rc.left = 0; + rc.right = AmmoWidth; + rc.bottom = 100; + + int iBarWidth = AmmoWidth/10; + + x += AmmoWidth/2; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + // draw the | bar + FillRGBA(x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a); + + x += iBarWidth + AmmoWidth/2;; + + // GL Seems to need this + ScaleColors(r, g, b, a ); + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + + + } + else + { + // SPR_Draw a bullets only line + x = ScreenWidth - 4 * AmmoWidth - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); + } + + // Draw the ammo Icon + int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top)/8; + SPR_Set(m_pWeapon->hAmmo, r, g, b); + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo); + } + + // Does weapon have seconday ammo? + if (pw->iAmmo2Type > 0) + { + int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left; + + // Do we have secondary ammo? + if ((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0)) + { + y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4; + x = ScreenWidth - 4 * AmmoWidth - iIconWidth; + x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b); + + // Draw the ammo Icon + SPR_Set(m_pWeapon->hAmmo2, r, g, b); + int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8; + SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2); + } + } + return 1; +} + + +// +// Draws the ammo bar on the hud +// +int DrawBar(int x, int y, int width, int height, float f) +{ + int r, g, b; + + if (f < 0) + f = 0; + if (f > 1) + f = 1; + + if (f) + { + int w = f * width; + + // Always show at least one pixel if we have ammo. + if (w <= 0) + w = 1; + UnpackRGB(r, g, b, RGB_GREENISH); + FillRGBA(x, y, w, height, r, g, b, 255); + x += w; + width -= w; + } + + UnpackRGB(r, g, b, RGB_YELLOWISH); + + FillRGBA(x, y, width, height, r, g, b, 128); + + return (x + width); +} + + + +void DrawAmmoBar(WEAPON *p, int x, int y, int width, int height) +{ + if ( !p ) + return; + + if (p->iAmmoType != -1) + { + if (!gWR.CountAmmo(p->iAmmoType)) + return; + + float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1; + + x = DrawBar(x, y, width, height, f); + + + // Do we have secondary ammo too? + + if (p->iAmmo2Type != -1) + { + f = (float)gWR.CountAmmo(p->iAmmo2Type)/(float)p->iMax2; + + x += 5; //!!! + + DrawBar(x, y, width, height, f); + } + } +} + + + + +// +// Draw Weapon Menu +// +int CHudAmmo::DrawWList(float flTime) +{ + int r,g,b,x,y,a,i; + + if ( !gpActiveSel ) + return 0; + + int iActiveSlot; + + if ( gpActiveSel == (WEAPON *)1 ) + iActiveSlot = -1; // current slot has no weapons + else + iActiveSlot = gpActiveSel->iSlot; + + x = 10; //!!! + y = 10; //!!! + + + // Ensure that there are available choices in the active slot + if ( iActiveSlot > 0 ) + { + if ( !gWR.GetFirstPos( iActiveSlot ) ) + { + gpActiveSel = (WEAPON *)1; + iActiveSlot = -1; + } + } + + // Draw top line + for ( i = 0; i < MAX_WEAPON_SLOTS; i++ ) + { + int iWidth; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + if ( iActiveSlot == i ) + a = 255; + else + a = 192; + + ScaleColors(r, g, b, 255); + SPR_Set(gHUD.GetSprite(m_HUD_bucket0 + i), r, g, b ); + + // make active slot wide enough to accomodate gun pictures + if ( i == iActiveSlot ) + { + WEAPON *p = gWR.GetFirstPos(iActiveSlot); + if ( p ) + iWidth = p->rcActive.right - p->rcActive.left; + else + iWidth = giBucketWidth; + } + else + iWidth = giBucketWidth; + + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i)); + + x += iWidth + 5; + } + + + a = 128; //!!! + x = 10; + + // Draw all of the buckets + for (i = 0; i < MAX_WEAPON_SLOTS; i++) + { + y = giBucketHeight + 10; + + // If this is the active slot, draw the bigger pictures, + // otherwise just draw boxes + if ( i == iActiveSlot ) + { + WEAPON *p = gWR.GetFirstPos( i ); + int iWidth = giBucketWidth; + if ( p ) + iWidth = p->rcActive.right - p->rcActive.left; + + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + p = gWR.GetWeaponSlot( i, iPos ); + + if ( !p || !p->iId ) + continue; + + UnpackRGB( r,g,b, RGB_YELLOWISH ); + + // if active, then we must have ammo. + + if ( gpActiveSel == p ) + { + SPR_Set(p->hActive, r, g, b ); + SPR_DrawAdditive(0, x, y, &p->rcActive); + + SPR_Set(gHUD.GetSprite(m_HUD_selection), r, g, b ); + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_selection)); + } + else + { + // Draw Weapon if Red if no ammo + + if ( gWR.HasAmmo(p) ) + ScaleColors(r, g, b, 192); + else + { + UnpackRGB(r,g,b, RGB_REDISH); + ScaleColors(r, g, b, 128); + } + + SPR_Set( p->hInactive, r, g, b ); + SPR_DrawAdditive( 0, x, y, &p->rcInactive ); + } + + // Draw Ammo Bar + + DrawAmmoBar(p, x + giABWidth/2, y, giABWidth, giABHeight); + + y += p->rcActive.bottom - p->rcActive.top + 5; + } + + x += iWidth + 5; + + } + else + { + // Draw Row of weapons. + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) + { + WEAPON *p = gWR.GetWeaponSlot( i, iPos ); + + if ( !p || !p->iId ) + continue; + + if ( gWR.HasAmmo(p) ) + { + UnpackRGB(r,g,b, RGB_YELLOWISH); + a = 128; + } + else + { + UnpackRGB(r,g,b, RGB_REDISH); + a = 96; + } + + FillRGBA( x, y, giBucketWidth, giBucketHeight, r, g, b, a ); + + y += giBucketHeight + 5; + } + + x += giBucketWidth + 5; + } + } + + return 1; + +} + + +/* ================================= + GetSpriteList + +Finds and returns the matching +sprite name 'psz' and resolution 'iRes' +in the given sprite list 'pList' +iCount is the number of items in the pList +================================= */ +client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount) +{ + if (!pList) + return NULL; + + int i = iCount; + client_sprite_t *p = pList; + + while(i--) + { + if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) + return p; + p++; + } + + return NULL; +} diff --git a/client/hud/hud_ammo.h b/cl_dll/ammo.h similarity index 57% rename from client/hud/hud_ammo.h rename to cl_dll/ammo.h index 98a43a2b..ad730cc8 100644 --- a/client/hud/hud_ammo.h +++ b/cl_dll/ammo.h @@ -16,14 +16,16 @@ #ifndef __AMMO_H__ #define __AMMO_H__ -#define MAX_WEAPON_NAME 128 -#define MAX_WEAPON_SLOTS 5 // hud item selection slots +#define MAX_WEAPON_NAME 128 + + #define WEAPON_FLAGS_SELECTONEMPTY 1 -#define WEAPON_IS_ONTARGET 0x40 + +#define WEAPON_IS_ONTARGET 0x40 struct WEAPON { - char szName[MAX_WEAPON_NAME]; + char szName[MAX_WEAPON_NAME]; int iAmmoType; int iAmmo2Type; int iMax1; @@ -33,25 +35,25 @@ struct WEAPON int iFlags; int iId; int iClip; - int iCount; // # of itesm in plist - int iOnTarget; // weapon is onTarget - HSPRITE hActive; - wrect_t rcActive; - HSPRITE hInactive; - wrect_t rcInactive; - HSPRITE hAmmo; - wrect_t rcAmmo; - HSPRITE hAmmo2; - wrect_t rcAmmo2; - HSPRITE hCrosshair; - wrect_t rcCrosshair; - HSPRITE hAutoaim; - wrect_t rcAutoaim; - HSPRITE hZoomedCrosshair; - wrect_t rcZoomedCrosshair; - HSPRITE hZoomedAutoaim; - wrect_t rcZoomedAutoaim; + int iCount; // # of itesm in plist + + HSPRITE hActive; + wrect_t rcActive; + HSPRITE hInactive; + wrect_t rcInactive; + HSPRITE hAmmo; + wrect_t rcAmmo; + HSPRITE hAmmo2; + wrect_t rcAmmo2; + HSPRITE hCrosshair; + wrect_t rcCrosshair; + HSPRITE hAutoaim; + wrect_t rcAutoaim; + HSPRITE hZoomedCrosshair; + wrect_t rcZoomedCrosshair; + HSPRITE hZoomedAutoaim; + wrect_t rcZoomedAutoaim; }; typedef int AMMO; diff --git a/cl_dll/ammo_secondary.cpp b/cl_dll/ammo_secondary.cpp new file mode 100644 index 00000000..2ca07d2d --- /dev/null +++ b/cl_dll/ammo_secondary.cpp @@ -0,0 +1,159 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// ammo_secondary.cpp +// +// implementation of CHudAmmoSecondary class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + +DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal ); +DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon ); + +int CHudAmmoSecondary :: Init( void ) +{ + HOOK_MESSAGE( SecAmmoVal ); + HOOK_MESSAGE( SecAmmoIcon ); + + gHUD.AddHudElem(this); + m_HUD_ammoicon = 0; + + for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + m_iAmmoAmounts[i] = -1; // -1 means don't draw this value + + Reset(); + + return 1; +} + +void CHudAmmoSecondary :: Reset( void ) +{ + m_fFade = 0; +} + +int CHudAmmoSecondary :: VidInit( void ) +{ + return 1; +} + +int CHudAmmoSecondary :: Draw(float flTime) +{ + if ( (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL )) ) + return 1; + + // draw secondary ammo icons above normal ammo readout + int a, x, y, r, g, b, AmmoWidth; + UnpackRGB( r, g, b, RGB_YELLOWISH ); + a = (int) max( MIN_ALPHA, m_fFade ); + if (m_fFade > 0) + m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons + ScaleColors( r, g, b, a ); + + AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + + y = ScreenHeight - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values + x = ScreenWidth - AmmoWidth; + + if ( m_HUD_ammoicon ) + { + // Draw the ammo icon + x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left); + y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom); + + SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) ); + } + else + { // move the cursor by the '0' char instead, since we don't have an icon to work with + x -= AmmoWidth; + y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom); + } + + // draw the ammo counts, in reverse order, from right to left + for ( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) + { + if ( m_iAmmoAmounts[i] < 0 ) + continue; // negative ammo amounts imply that they shouldn't be drawn + + // half a char gap between the ammo number and the previous pic + x -= (AmmoWidth / 2); + + // draw the number, right-aligned + x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth); + gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b ); + + if ( i != 0 ) + { + // draw the divider bar + x -= (AmmoWidth / 2); + FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a); + } + } + + return 1; +} + +// Message handler for Secondary Ammo Value +// accepts one value: +// string: sprite name +int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_HUD_ammoicon = gHUD.GetSpriteIndex( READ_STRING() ); + + return 1; +} + +// Message handler for Secondary Ammo Icon +// Sets an ammo value +// takes two values: +// byte: ammo index +// byte: ammo value +int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int index = READ_BYTE(); + if ( index < 0 || index >= MAX_SEC_AMMO_VALUES ) + return 1; + + m_iAmmoAmounts[index] = READ_BYTE(); + m_iFlags |= HUD_ACTIVE; + + // check to see if there is anything left to draw + int count = 0; + for ( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) + { + count += max( 0, m_iAmmoAmounts[i] ); + } + + if ( count == 0 ) + { // the ammo fields are all empty, so turn off this hud area + m_iFlags &= ~HUD_ACTIVE; + return 1; + } + + // make the icons light up + m_fFade = 200.0f; + + return 1; +} + + diff --git a/client/hud/hud_ammohistory.cpp b/cl_dll/ammohistory.cpp similarity index 87% rename from client/hud/hud_ammohistory.cpp rename to cl_dll/ammohistory.cpp index 67b8f674..bfe70058 100644 --- a/client/hud/hud_ammohistory.cpp +++ b/cl_dll/ammohistory.cpp @@ -17,18 +17,22 @@ // -#include "extdll.h" -#include "utils.h" #include "hud.h" -#include "hud_ammohistory.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +#include "ammohistory.h" HistoryResource gHR; -#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5) -#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2)) -#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight - 100) +#define AMMO_PICKUP_GAP (gHR.iHistoryGap+5) +#define AMMO_PICKUP_PICK_HEIGHT (32 + (gHR.iHistoryGap * 2)) +#define AMMO_PICKUP_HEIGHT_MAX (ScreenHeight - 100) -#define MAX_ITEM_NAME 32 +#define MAX_ITEM_NAME 32 int HISTORY_DRAW_TIME = 5; // keep a list of items @@ -65,8 +69,7 @@ void HistoryResource :: AddToHistory( int iType, const char *szName, int iCount return; if ( (((AMMO_PICKUP_GAP * iCurrentHistorySlot) + AMMO_PICKUP_PICK_HEIGHT) > AMMO_PICKUP_HEIGHT_MAX) || (iCurrentHistorySlot >= MAX_HISTORY) ) - { - // the pic would have to be drawn too high + { // the pic would have to be drawn too high // so start from the bottom iCurrentHistorySlot = 0; } @@ -111,8 +114,7 @@ int HistoryResource :: DrawAmmoHistory( float flTime ) rgAmmoHistory[i].DisplayTime = min( rgAmmoHistory[i].DisplayTime, gHUD.m_flTime + HISTORY_DRAW_TIME ); if ( rgAmmoHistory[i].DisplayTime <= flTime ) - { - // pic drawing time has expired + { // pic drawing time has expired memset( &rgAmmoHistory[i], 0, sizeof(HIST_ITEM) ); CheckClearHistory(); } @@ -122,7 +124,7 @@ int HistoryResource :: DrawAmmoHistory( float flTime ) HSPRITE *spr = gWR.GetAmmoPicFromWeapon( rgAmmoHistory[i].iId, rcPic ); int r, g, b; - UnpackRGB(r,g,b, gHUD.m_iHUDColor); + UnpackRGB(r,g,b, RGB_YELLOWISH); float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; ScaleColors(r, g, b, min(scale, 255) ); @@ -146,7 +148,7 @@ int HistoryResource :: DrawAmmoHistory( float flTime ) return 1; // we don't know about the weapon yet, so don't draw anything int r, g, b; - UnpackRGB(r,g,b, gHUD.m_iHUDColor); + UnpackRGB(r,g,b, RGB_YELLOWISH); if ( !gWR.HasAmmo( weap ) ) UnpackRGB(r,g,b, RGB_REDISH); // if the weapon doesn't have ammo, display it as red @@ -168,7 +170,7 @@ int HistoryResource :: DrawAmmoHistory( float flTime ) wrect_t rect = gHUD.GetSpriteRect( rgAmmoHistory[i].iId ); - UnpackRGB(r,g,b, gHUD.m_iHUDColor); + UnpackRGB(r,g,b, RGB_YELLOWISH); float scale = (rgAmmoHistory[i].DisplayTime - flTime) * 80; ScaleColors(r, g, b, min(scale, 255) ); diff --git a/client/hud/hud_ammohistory.h b/cl_dll/ammohistory.h similarity index 80% rename from client/hud/hud_ammohistory.h rename to cl_dll/ammohistory.h index c64a5d0e..74bf43f5 100644 --- a/client/hud/hud_ammohistory.h +++ b/cl_dll/ammohistory.h @@ -26,10 +26,8 @@ private: WEAPON rgWeapons[MAX_WEAPONS]; // Weapons Array // counts of weapons * ammo - // The slots currently in use by weapons. The value is a pointer to the weapon; - // if it's NULL, no weapon is there - WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1]; - int riAmmo[MAX_AMMO_SLOTS]; // count of each ammo type + WEAPON* rgSlots[MAX_WEAPON_SLOTS+1][MAX_WEAPON_POSITIONS+1]; // The slots currently in use by weapons. The value is a pointer to the weapon; if it's NULL, no weapon is there + int riAmmo[MAX_AMMO_TYPES]; // count of each ammo type public: void Init( void ) @@ -40,14 +38,13 @@ public: void Reset( void ) { - iOldWeaponBits = iOldFOV = 0; + iOldWeaponBits = 0; memset( rgSlots, 0, sizeof rgSlots ); memset( riAmmo, 0, sizeof riAmmo ); } ///// WEAPON ///// - int iOldWeaponBits; - int iOldFOV; + int iOldWeaponBits; WEAPON *GetWeapon( int iId ) { return &rgWeapons[iId]; } void AddWeapon( WEAPON *wp ) @@ -85,7 +82,7 @@ public: int HasAmmo( WEAPON *p ); - ///// AMMO ///// +///// AMMO ///// AMMO GetAmmo( int iId ) { return iId; } void SetAmmo( int iId, int iCount ) { riAmmo[ iId ] = iCount; } @@ -95,9 +92,11 @@ public: HSPRITE* GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ); }; -#define MAX_HISTORY 12 -enum -{ +extern WeaponsResource gWR; + + +#define MAX_HISTORY 12 +enum { HISTSLOT_EMPTY, HISTSLOT_AMMO, HISTSLOT_WEAP, @@ -107,8 +106,7 @@ enum class HistoryResource { private: - struct HIST_ITEM - { + struct HIST_ITEM { int type; float DisplayTime; // the time at which this item should be removed from the history int iCount; @@ -116,9 +114,18 @@ private: }; HIST_ITEM rgAmmoHistory[MAX_HISTORY]; + public: - void Init( void ) { Reset(); } - void Reset( void ) { memset( rgAmmoHistory, 0, sizeof rgAmmoHistory ); } + + void Init( void ) + { + Reset(); + } + + void Reset( void ) + { + memset( rgAmmoHistory, 0, sizeof rgAmmoHistory ); + } int iHistoryGap; int iCurrentHistorySlot; @@ -130,5 +137,7 @@ public: int DrawAmmoHistory( float flTime ); }; -extern WeaponsResource gWR; -extern HistoryResource gHR; \ No newline at end of file +extern HistoryResource gHR; + + + diff --git a/client/hud/hud_battery.cpp b/cl_dll/battery.cpp similarity index 63% rename from client/hud/hud_battery.cpp rename to cl_dll/battery.cpp index 4bd12161..0ec45542 100644 --- a/client/hud/hud_battery.cpp +++ b/cl_dll/battery.cpp @@ -18,26 +18,30 @@ // implementation of CHudBattery class // -#include "extdll.h" -#include "utils.h" #include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" -DECLARE_MESSAGE( m_Battery, Battery ) +#include +#include -int CHudBattery :: Init( void ) +DECLARE_MESSAGE(m_Battery, Battery) + +int CHudBattery::Init(void) { m_iBat = 0; m_fFade = 0; m_iFlags = 0; - HOOK_MESSAGE( Battery ); + HOOK_MESSAGE(Battery); - gHUD.AddHudElem( this ); + gHUD.AddHudElem(this); return 1; -} +}; -int CHudBattery :: VidInit( void ) + +int CHudBattery::VidInit(void) { int HUD_suit_empty = gHUD.GetSpriteIndex( "suit_empty" ); int HUD_suit_full = gHUD.GetSpriteIndex( "suit_full" ); @@ -50,86 +54,85 @@ int CHudBattery :: VidInit( void ) return 1; }; -int CHudBattery:: MsgFunc_Battery( const char *pszName, int iSize, void *pbuf ) +int CHudBattery:: MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ) { m_iFlags |= HUD_ACTIVE; - BEGIN_READ( pszName, iSize, pbuf ); + BEGIN_READ( pbuf, iSize ); int x = READ_SHORT(); - if( x != m_iBat ) + if (x != m_iBat) { m_fFade = FADE_TIME; m_iBat = x; } - END_READ(); - return 1; } -int CHudBattery :: Draw( float flTime ) + +int CHudBattery::Draw(float flTime) { - if( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) + if ( gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH ) return 1; int r, g, b, x, y, a; wrect_t rc; rc = *m_prc2; + rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01); // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 - // battery can go from 0 to 100 so * 0.01 goes from 0 to 1 - rc.top += m_iHeight * ((float)(100-(min(100,m_iBat))) * 0.01); + UnpackRGB(r,g,b, RGB_YELLOWISH); - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - - if(!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)))) + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) return 1; // Has health changed? Flash the health # - if( m_fFade ) + if (m_fFade) { - if( m_fFade > FADE_TIME ) + if (m_fFade > FADE_TIME) m_fFade = FADE_TIME; m_fFade -= (gHUD.m_flTimeDelta * 20); - if( m_fFade <= 0 ) + if (m_fFade <= 0) { a = 128; m_fFade = 0; } // Fade the health number back to dim + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; } - else a = MIN_ALPHA; + else + a = MIN_ALPHA; - ScaleColors( r, g, b, a ); + ScaleColors(r, g, b, a ); - int iOffset = (m_prc1->bottom - m_prc1->top) / 6; + int iOffset = (m_prc1->bottom - m_prc1->top)/6; y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - x = ScreenWidth / 5; + x = ScreenWidth/5; // make sure we have the right sprite handles - if( !m_hSprite1 ) - m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" )); - if( !m_hSprite2 ) - m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" )); + if ( !m_hSprite1 ) + m_hSprite1 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_empty" ) ); + if ( !m_hSprite2 ) + m_hSprite2 = gHUD.GetSprite( gHUD.GetSpriteIndex( "suit_full" ) ); - SPR_Set( m_hSprite1, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset, m_prc1 ); + SPR_Set(m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset, m_prc1); - if( rc.bottom > rc.top ) + if (rc.bottom > rc.top) { - SPR_Set( m_hSprite2, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc ); + SPR_Set(m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x, y - iOffset + (rc.top - m_prc2->top), &rc); } x += (m_prc1->right - m_prc1->left); - x = gHUD.DrawHudNumber( x, y, DHN_3DIGITS|DHN_DRAWZERO, m_iBat, r, g, b ); + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iBat, r, g, b); return 1; -} +} \ No newline at end of file diff --git a/cl_dll/camera.h b/cl_dll/camera.h new file mode 100644 index 00000000..af1591d7 --- /dev/null +++ b/cl_dll/camera.h @@ -0,0 +1,24 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Camera.h -- defines and such for a 3rd person camera +// NOTE: must include quakedef.h first + +#ifndef _CAMERA_H_ +#define _CAMEA_H_ + +// pitch, yaw, dist +extern vec3_t cam_ofs; +// Using third person camera +extern int cam_thirdperson; + +void CAM_Init( void ); +void CAM_ClearStates( void ); +void CAM_StartMouseMove(void); +void CAM_EndMouseMove(void); + +#endif // _CAMERA_H_ diff --git a/cl_dll/cdll_int.cpp b/cl_dll/cdll_int.cpp new file mode 100644 index 00000000..41e1c28f --- /dev/null +++ b/cl_dll/cdll_int.cpp @@ -0,0 +1,288 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cdll_int.c +// +// this implementation handles the linking of the engine to the DLL +// + +#include "hud.h" +#include "cl_util.h" +#include "netadr.h" +#include "vgui_schememanager.h" + +extern "C" +{ +#include "pm_shared.h" +} + +#include +#include "hud_servers.h" +#include "vgui_int.h" + +#define DLLEXPORT __declspec( dllexport ) + + +cl_enginefunc_t gEngfuncs; +CHud gHUD; +TeamFortressViewport *gViewPort = NULL; + +void InitInput (void); +void EV_HookEvents( void ); +void IN_Commands( void ); + +/* +========================== + Initialize + +Called when the DLL is first loaded. +========================== +*/ +extern "C" +{ +int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ); +int DLLEXPORT HUD_VidInit( void ); +void DLLEXPORT HUD_Init( void ); +int DLLEXPORT HUD_Redraw( float flTime, int intermission ); +int DLLEXPORT HUD_UpdateClientData( client_data_t *cdata, float flTime ); +void DLLEXPORT HUD_Reset ( void ); +void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ); +void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ); +char DLLEXPORT HUD_PlayerMoveTexture( char *name ); +int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); +int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ); +void DLLEXPORT HUD_Frame( double time ); +void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking); +void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ); +} + +/* +================================ +HUD_GetHullBounds + + Engine calls this to enumerate player collision hulls, for prediction. Return 0 if the hullnumber doesn't exist. +================================ +*/ +int DLLEXPORT HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) +{ + int iret = 0; + + switch ( hullnumber ) + { + case 0: // Normal player + mins = Vector(-16, -16, -36); + maxs = Vector(16, 16, 36); + iret = 1; + break; + case 1: // Crouched player + mins = Vector(-16, -16, -18 ); + maxs = Vector(16, 16, 18 ); + iret = 1; + break; + case 2: // Point based hull + mins = Vector( 0, 0, 0 ); + maxs = Vector( 0, 0, 0 ); + iret = 1; + break; + } + + return iret; +} + +/* +================================ +HUD_ConnectionlessPacket + + Return 1 if the packet is valid. Set response_buffer_size if you want to send a response packet. Incoming, it holds the max + size of the response_buffer, so you must zero it out if you choose not to respond. +================================ +*/ +int DLLEXPORT HUD_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ) +{ + // Parse stuff from args + int max_buffer_size = *response_buffer_size; + + // Zero it out since we aren't going to respond. + // If we wanted to response, we'd write data into response_buffer + *response_buffer_size = 0; + + // Since we don't listen for anything here, just respond that it's a bogus message + // If we didn't reject the message, we'd return 1 for success instead. + return 0; +} + +void DLLEXPORT HUD_PlayerMoveInit( struct playermove_s *ppmove ) +{ + PM_Init( ppmove ); +} + +char DLLEXPORT HUD_PlayerMoveTexture( char *name ) +{ + return PM_FindTextureType( name ); +} + +void DLLEXPORT HUD_PlayerMove( struct playermove_s *ppmove, int server ) +{ + PM_Move( ppmove, server ); +} + +int DLLEXPORT Initialize( cl_enginefunc_t *pEnginefuncs, int iVersion ) +{ + gEngfuncs = *pEnginefuncs; + + if (iVersion != CLDLL_INTERFACE_VERSION) + return 0; + + memcpy(&gEngfuncs, pEnginefuncs, sizeof(cl_enginefunc_t)); + + EV_HookEvents(); + + return 1; +} + + +/* +========================== + HUD_VidInit + +Called when the game initializes +and whenever the vid_mode is changed +so the HUD can reinitialize itself. +========================== +*/ + +int DLLEXPORT HUD_VidInit( void ) +{ + gHUD.VidInit(); + +// FIXME: implement Vgui +// VGui_Startup(); + + return 1; +} + +/* +========================== + HUD_Init + +Called whenever the client connects +to a server. Reinitializes all +the hud variables. +========================== +*/ + +void DLLEXPORT HUD_Init( void ) +{ + InitInput(); + gHUD.Init(); + Scheme_Init(); +} + + +/* +========================== + HUD_Redraw + +called every screen frame to +redraw the HUD. +=========================== +*/ + +int DLLEXPORT HUD_Redraw( float time, int intermission ) +{ + gHUD.Redraw( time, intermission ); + + return 1; +} + + +/* +========================== + HUD_UpdateClientData + +called every time shared client +dll/engine data gets changed, +and gives the cdll a chance +to modify the data. + +returns 1 if anything has been changed, 0 otherwise. +========================== +*/ + +int DLLEXPORT HUD_UpdateClientData(client_data_t *pcldata, float flTime ) +{ + IN_Commands(); + + return gHUD.UpdateClientData(pcldata, flTime ); +} + +/* +========================== + HUD_Reset + +Called at start and end of demos to restore to "non"HUD state. +========================== +*/ + +void DLLEXPORT HUD_Reset( void ) +{ + gHUD.VidInit(); +} + +/* +========================== +HUD_Frame + +Called by engine every frame that client .dll is loaded +========================== +*/ + +void DLLEXPORT HUD_Frame( double time ) +{ + ServersThink( time ); + + if( gViewPort ) + GetClientVoiceMgr()->Frame(time); +} + + +/* +========================== +HUD_VoiceStatus + +Called when a player starts or stops talking. +========================== +*/ + +void DLLEXPORT HUD_VoiceStatus(int entindex, qboolean bTalking) +{ + if( gViewPort ) + GetClientVoiceMgr()->UpdateSpeakerStatus(entindex, bTalking); +} + +/* +========================== +HUD_DirectorEvent + +Called when a director event message was received +========================== +*/ + +void DLLEXPORT HUD_DirectorMessage( int iSize, void *pbuf ) +{ + gHUD.m_Spectator.DirectorMessage( iSize, pbuf ); +} + + diff --git a/dlls/bshift.dsp b/cl_dll/cl_dll.dsp similarity index 53% rename from dlls/bshift.dsp rename to cl_dll/cl_dll.dsp index e4efaa0f..fe9820a0 100644 --- a/dlls/bshift.dsp +++ b/cl_dll/cl_dll.dsp @@ -1,24 +1,24 @@ -# Microsoft Developer Studio Project File - Name="bshift" - Package Owner=<4> +# Microsoft Developer Studio Project File - Name="cl_dll" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=bshift - Win32 Release +CFG=cl_dll - Win32 Release !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "bshift.mak". +!MESSAGE NMAKE /f "cl_dll.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "bshift.mak" CFG="bshift - Win32 Release" +!MESSAGE NMAKE /f "cl_dll.mak" CFG="cl_dll - Win32 Release" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "bshift - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "bshift - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cl_dll - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cl_dll - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -29,7 +29,7 @@ CPP=cl.exe MTL=midl.exe RSC=rc.exe -!IF "$(CFG)" == "bshift - Win32 Release" +!IF "$(CFG)" == "cl_dll - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 @@ -38,13 +38,13 @@ RSC=rc.exe # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\bshift\!release" -# PROP Intermediate_Dir "..\temp\bshift\!release" +# PROP Output_Dir "..\temp\cl_dll\!release" +# PROP Intermediate_Dir "..\temp\cl_dll\!release" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\dlls" /I "..\common" /I "..\game_shared" /I "..\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "BSHIFT_DLL" /FD /c -# SUBTRACT CPP /Fr /YX +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\utils\vgui\include" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\dlls" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /YX /FD /c +# SUBTRACT CPP /Z # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -54,34 +54,33 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 -# ADD LINK32 msvcrt.lib /nologo /subsystem:windows /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /def:".\hl.def" /out:"..\temp\bshift\!release/hl.dll" -# SUBTRACT LINK32 /profile /map /debug +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /machine:I386 /out:"..\temp\cl_dll\!release/client.dll" +# SUBTRACT LINK32 /map # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\bshift\!release -InputPath=\Xash3D\src_main\temp\bshift\!release\hl.dll +TargetDir=\Xash3D\src_main\temp\cl_dll\!release +InputPath=\Xash3D\src_main\temp\cl_dll\!release\client.dll SOURCE="$(InputPath)" -"D:\Xash3D\bshift\bin\server.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\hl.dll "D:\Xash3D\bshift\bin\server.dll" +"D:\Xash3D\valve\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\client.dll "D:\Xash3D\valve\cl_dlls\client.dll" # End Custom Build -!ELSEIF "$(CFG)" == "bshift - Win32 Debug" +!ELSEIF "$(CFG)" == "cl_dll - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 -# PROP BASE Output_Dir ".\hl___Win" -# PROP BASE Intermediate_Dir ".\hl___Win" +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\temp\bshift\!debug" -# PROP Intermediate_Dir "..\temp\bshift\!debug" -# PROP Ignore_Export_Lib 1 +# PROP Output_Dir "..\temp\cl_dll\!debug" +# PROP Intermediate_Dir "..\temp\cl_dll\!debug" +# PROP Ignore_Export_Lib 0 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\dlls" /I "..\common" /I "..\game_shared" /I "..\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "BSHIFT_DLL" /FR /FD /c -# SUBTRACT CPP /YX +# ADD CPP /nologo /G5 /MTd /W3 /Gm /GR /GX /ZI /Od /I "..\dlls" /I "..\common" /I "..\pm_shared" /I "..\engine" /I "..\utils\vgui\include" /I "..\game_shared" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "CLIENT_DLL" /D "CLIENT_WEAPONS" /FR /YX /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" @@ -91,15 +90,14 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 -# ADD LINK32 msvcrtd.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"libc.lib" /def:".\hl.def" /out:"..\temp\bshift\!debug/hl.dll" /pdbtype:sept -# SUBTRACT LINK32 /profile +# ADD LINK32 oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib ../utils/vgui/lib/win32_vc6/vgui.lib wsock32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /out:"..\temp\cl_dll\!debug/client.dll" # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\bshift\!debug -InputPath=\Xash3D\src_main\temp\bshift\!debug\hl.dll +TargetDir=\Xash3D\src_main\temp\cl_dll\!debug +InputPath=\Xash3D\src_main\temp\cl_dll\!debug\client.dll SOURCE="$(InputPath)" -"D:\Xash3D\bshift\bin\server.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\hl.dll "D:\Xash3D\bshift\bin\server.dll" +"D:\Xash3D\valve\cl_dlls\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\client.dll "D:\Xash3D\valve\cl_dlls\client.dll" # End Custom Build @@ -107,390 +105,267 @@ SOURCE="$(InputPath)" # Begin Target -# Name "bshift - Win32 Release" -# Name "bshift - Win32 Debug" +# Name "cl_dll - Win32 Release" +# Name "cl_dll - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" -# Begin Source File - -SOURCE=.\aflock.cpp -# End Source File -# Begin Source File - -SOURCE=.\agrunt.cpp -# End Source File -# Begin Source File - -SOURCE=.\airtank.cpp -# End Source File -# Begin Source File - -SOURCE=.\animating.cpp -# End Source File -# Begin Source File - -SOURCE=.\animation.cpp -# End Source File -# Begin Source File - -SOURCE=.\apache.cpp -# End Source File -# Begin Source File - -SOURCE=.\barnacle.cpp -# End Source File -# Begin Source File - -SOURCE=.\barney.cpp -# End Source File -# Begin Source File - -SOURCE=.\bigmomma.cpp -# End Source File -# Begin Source File - -SOURCE=.\bloater.cpp -# End Source File -# Begin Source File - -SOURCE=.\bmodels.cpp -# End Source File -# Begin Source File - -SOURCE=.\bullsquid.cpp -# End Source File -# Begin Source File - -SOURCE=.\buttons.cpp -# End Source File -# Begin Source File - -SOURCE=.\cbase.cpp -# End Source File -# Begin Source File - -SOURCE=.\client.cpp -# End Source File -# Begin Source File +# Begin Group "hl" -SOURCE=.\combat.cpp -# End Source File -# Begin Source File - -SOURCE=.\controller.cpp -# End Source File -# Begin Source File - -SOURCE=.\crossbow.cpp -# End Source File -# Begin Source File - -SOURCE=.\crowbar.cpp -# End Source File -# Begin Source File - -SOURCE=.\defaultai.cpp -# End Source File -# Begin Source File - -SOURCE=.\doors.cpp -# End Source File -# Begin Source File - -SOURCE=.\effects.cpp -# End Source File -# Begin Source File - -SOURCE=.\egon.cpp -# End Source File -# Begin Source File - -SOURCE=.\explode.cpp -# End Source File -# Begin Source File - -SOURCE=.\flyingmonster.cpp -# End Source File -# Begin Source File - -SOURCE=.\func_break.cpp -# End Source File -# Begin Source File - -SOURCE=.\func_tank.cpp -# End Source File -# Begin Source File - -SOURCE=.\game.cpp -# End Source File -# Begin Source File - -SOURCE=.\gamerules.cpp -# End Source File -# Begin Source File - -SOURCE=.\gargantua.cpp -# End Source File -# Begin Source File - -SOURCE=.\gauss.cpp -# End Source File -# Begin Source File - -SOURCE=.\genericmonster.cpp -# End Source File +# PROP Default_Filter "*.CPP" # Begin Source File -SOURCE=.\ggrenade.cpp +SOURCE=..\dlls\crossbow.cpp # End Source File # Begin Source File -SOURCE=.\globals.cpp +SOURCE=..\dlls\crowbar.cpp # End Source File # Begin Source File -SOURCE=.\glock.cpp +SOURCE=..\dlls\egon.cpp # End Source File # Begin Source File -SOURCE=.\gman.cpp +SOURCE=.\ev_hldm.cpp # End Source File # Begin Source File -SOURCE=.\h_ai.cpp +SOURCE=..\dlls\gauss.cpp # End Source File # Begin Source File -SOURCE=.\h_battery.cpp +SOURCE=..\dlls\handgrenade.cpp # End Source File # Begin Source File -SOURCE=.\h_cine.cpp +SOURCE=.\hl\hl_baseentity.cpp # End Source File # Begin Source File -SOURCE=.\h_cycler.cpp +SOURCE=.\hl\hl_events.cpp # End Source File # Begin Source File -SOURCE=.\h_export.cpp +SOURCE=.\hl\hl_objects.cpp # End Source File # Begin Source File -SOURCE=.\handgrenade.cpp +SOURCE=.\hl\hl_weapons.cpp # End Source File # Begin Source File -SOURCE=.\hassassin.cpp +SOURCE=..\dlls\wpn_shared\hl_wpn_glock.cpp # End Source File # Begin Source File -SOURCE=.\headcrab.cpp +SOURCE=..\dlls\hornetgun.cpp # End Source File # Begin Source File -SOURCE=.\healthkit.cpp +SOURCE=..\dlls\mp5.cpp # End Source File # Begin Source File -SOURCE=.\hgrunt.cpp +SOURCE=..\dlls\python.cpp # End Source File # Begin Source File -SOURCE=.\hornet.cpp +SOURCE=..\dlls\rpg.cpp # End Source File # Begin Source File -SOURCE=.\hornetgun.cpp +SOURCE=..\dlls\satchel.cpp # End Source File # Begin Source File -SOURCE=.\houndeye.cpp +SOURCE=..\dlls\shotgun.cpp # End Source File # Begin Source File -SOURCE=.\ichthyosaur.cpp +SOURCE=..\dlls\squeakgrenade.cpp # End Source File # Begin Source File -SOURCE=.\islave.cpp +SOURCE=..\dlls\tripmine.cpp # End Source File # Begin Source File -SOURCE=.\items.cpp +SOURCE=..\game_shared\vgui_scrollbar2.cpp # End Source File # Begin Source File -SOURCE=.\leech.cpp +SOURCE=..\game_shared\vgui_slider2.cpp # End Source File # Begin Source File -SOURCE=.\lights.cpp +SOURCE=..\game_shared\voice_banmgr.cpp # End Source File # Begin Source File -SOURCE=.\maprules.cpp +SOURCE=..\game_shared\voice_status.cpp # End Source File +# End Group # Begin Source File -SOURCE=.\monstermaker.cpp +SOURCE=.\ammo.cpp # End Source File # Begin Source File -SOURCE=.\monsters.cpp +SOURCE=.\ammo_secondary.cpp # End Source File # Begin Source File -SOURCE=.\monsterstate.cpp +SOURCE=.\ammohistory.cpp # End Source File # Begin Source File -SOURCE=.\mortar.cpp +SOURCE=.\battery.cpp # End Source File # Begin Source File -SOURCE=.\mp5.cpp +SOURCE=.\cdll_int.cpp # End Source File # Begin Source File -SOURCE=.\multiplay_gamerules.cpp +SOURCE=.\com_weapons.cpp # End Source File # Begin Source File -SOURCE=.\nihilanth.cpp +SOURCE=.\death.cpp # End Source File # Begin Source File -SOURCE=.\nodes.cpp +SOURCE=.\demo.cpp # End Source File # Begin Source File -SOURCE=.\osprey.cpp +SOURCE=.\entity.cpp # End Source File # Begin Source File -SOURCE=.\pathcorner.cpp +SOURCE=.\ev_common.cpp # End Source File # Begin Source File -SOURCE=.\plane.cpp +SOURCE=.\events.cpp # End Source File # Begin Source File -SOURCE=.\plats.cpp +SOURCE=.\flashlight.cpp # End Source File # Begin Source File -SOURCE=.\player.cpp +SOURCE=.\GameStudioModelRenderer.cpp # End Source File # Begin Source File -SOURCE=..\game_shared\pm_debug.cpp +SOURCE=.\geiger.cpp # End Source File # Begin Source File -SOURCE=..\game_shared\pm_math.cpp +SOURCE=.\health.cpp # End Source File # Begin Source File -SOURCE=..\game_shared\pm_shared.cpp +SOURCE=.\hud.cpp # End Source File # Begin Source File -SOURCE=.\python.cpp +SOURCE=.\hud_msg.cpp # End Source File # Begin Source File -SOURCE=.\rat.cpp +SOURCE=.\hud_redraw.cpp # End Source File # Begin Source File -SOURCE=.\roach.cpp +SOURCE=.\hud_servers.cpp # End Source File # Begin Source File -SOURCE=.\rpg.cpp +SOURCE=.\hud_spectator.cpp # End Source File # Begin Source File -SOURCE=.\satchel.cpp +SOURCE=.\hud_update.cpp # End Source File # Begin Source File -SOURCE=.\schedule.cpp +SOURCE=.\in_camera.cpp # End Source File # Begin Source File -SOURCE=.\scientist.cpp +SOURCE=.\input.cpp # End Source File # Begin Source File -SOURCE=.\scripted.cpp +SOURCE=.\inputw32.cpp # End Source File # Begin Source File -SOURCE=.\shotgun.cpp +SOURCE=.\menu.cpp # End Source File # Begin Source File -SOURCE=.\singleplay_gamerules.cpp +SOURCE=.\message.cpp # End Source File # Begin Source File -SOURCE=.\skill.cpp +SOURCE=.\overview.cpp +# PROP Exclude_From_Build 1 # End Source File # Begin Source File -SOURCE=.\sound.cpp +SOURCE=.\parsemsg.cpp # End Source File # Begin Source File -SOURCE=.\soundent.cpp +SOURCE=.\parsemsg.h # End Source File # Begin Source File -SOURCE=.\spectator.cpp +SOURCE=..\pm_shared\pm_debug.c # End Source File # Begin Source File -SOURCE=.\squadmonster.cpp +SOURCE=..\pm_shared\pm_math.c # End Source File # Begin Source File -SOURCE=.\squeakgrenade.cpp +SOURCE=..\pm_shared\pm_shared.c # End Source File # Begin Source File -SOURCE=.\subs.cpp +SOURCE=.\saytext.cpp # End Source File # Begin Source File -SOURCE=.\talkmonster.cpp +SOURCE=.\status_icons.cpp # End Source File # Begin Source File -SOURCE=.\teamplay_gamerules.cpp +SOURCE=.\statusbar.cpp # End Source File # Begin Source File -SOURCE=.\tempmonster.cpp +SOURCE=.\studio_util.cpp # End Source File # Begin Source File -SOURCE=.\tentacle.cpp +SOURCE=.\StudioModelRenderer.cpp # End Source File # Begin Source File -SOURCE=.\triggers.cpp +SOURCE=.\text_message.cpp # End Source File # Begin Source File -SOURCE=.\tripmine.cpp +SOURCE=.\train.cpp # End Source File # Begin Source File -SOURCE=.\turret.cpp +SOURCE=.\tri.cpp # End Source File # Begin Source File @@ -498,19 +373,75 @@ SOURCE=.\util.cpp # End Source File # Begin Source File -SOURCE=.\weapons.cpp +SOURCE=..\game_shared\vgui_checkbutton2.cpp # End Source File # Begin Source File -SOURCE=.\world.cpp +SOURCE=.\vgui_ClassMenu.cpp # End Source File # Begin Source File -SOURCE=.\xen.cpp +SOURCE=.\vgui_ConsolePanel.cpp # End Source File # Begin Source File -SOURCE=.\zombie.cpp +SOURCE=.\vgui_ControlConfigPanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_CustomObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_grid.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_helpers.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_int.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_listbox.cpp +# End Source File +# Begin Source File + +SOURCE=..\game_shared\vgui_loadtga.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_MOTDWindow.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_SchemeManager.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ScorePanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_ServerBrowser.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_SpectatorPanel.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_TeamFortressViewport.cpp +# End Source File +# Begin Source File + +SOURCE=.\vgui_teammenu.cpp +# End Source File +# Begin Source File + +SOURCE=.\view.cpp # End Source File # End Group # Begin Group "Header Files" @@ -518,171 +449,111 @@ SOURCE=.\zombie.cpp # PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" # Begin Source File -SOURCE=.\activity.h +SOURCE=.\ammo.h # End Source File # Begin Source File -SOURCE=.\activitymap.h +SOURCE=.\ammohistory.h # End Source File # Begin Source File -SOURCE=.\animation.h +SOURCE=.\camera.h # End Source File # Begin Source File -SOURCE=.\basemonster.h +SOURCE=.\cl_dll.h # End Source File # Begin Source File -SOURCE=.\cbase.h +SOURCE=.\com_weapons.h # End Source File # Begin Source File -SOURCE=.\cdll_dll.h +SOURCE=.\demo.h # End Source File # Begin Source File -SOURCE=.\client.h +SOURCE=.\ev_hldm.h # End Source File # Begin Source File -SOURCE=.\decals.h +SOURCE=.\eventscripts.h # End Source File # Begin Source File -SOURCE=.\defaultai.h +SOURCE=.\GameStudioModelRenderer.h # End Source File # Begin Source File -SOURCE=.\doors.h +SOURCE=.\health.h # End Source File # Begin Source File -SOURCE=.\effects.h +SOURCE=.\hud.h # End Source File # Begin Source File -SOURCE=..\engine\eiface.h +SOURCE=.\hud_iface.h # End Source File # Begin Source File -SOURCE=.\enginecallback.h +SOURCE=.\hud_servers.h # End Source File # Begin Source File -SOURCE=.\explode.h +SOURCE=.\hud_servers_priv.h # End Source File # Begin Source File -SOURCE=.\extdll.h +SOURCE=.\hud_spectator.h # End Source File # Begin Source File -SOURCE=.\flyingmonster.h +SOURCE=.\in_defs.h # End Source File # Begin Source File -SOURCE=.\func_break.h +SOURCE=..\common\itrackeruser.h # End Source File # Begin Source File -SOURCE=.\gamerules.h +SOURCE=.\kbutton.h # End Source File # Begin Source File -SOURCE=.\hornet.h +SOURCE=.\overview.h # End Source File # Begin Source File -SOURCE=.\items.h +SOURCE=..\pm_shared\pm_debug.h # End Source File # Begin Source File -SOURCE=.\monsterevent.h +SOURCE=..\pm_shared\pm_defs.h # End Source File # Begin Source File -SOURCE=.\monsters.h +SOURCE=..\pm_shared\pm_info.h # End Source File # Begin Source File -SOURCE=.\nodes.h +SOURCE=..\pm_shared\pm_materials.h # End Source File # Begin Source File -SOURCE=.\plane.h +SOURCE=..\pm_shared\pm_movevars.h # End Source File # Begin Source File -SOURCE=.\player.h +SOURCE=..\pm_shared\pm_shared.h # End Source File # Begin Source File -SOURCE=..\game_shared\pm_debug.h +SOURCE=.\studio_util.h # End Source File # Begin Source File -SOURCE=..\game_shared\pm_defs.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_info.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_materials.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_movevars.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_shared.h -# End Source File -# Begin Source File - -SOURCE=.\saverestore.h -# End Source File -# Begin Source File - -SOURCE=.\schedule.h -# End Source File -# Begin Source File - -SOURCE=.\scripted.h -# End Source File -# Begin Source File - -SOURCE=.\scriptevent.h -# End Source File -# Begin Source File - -SOURCE=.\skill.h -# End Source File -# Begin Source File - -SOURCE=.\soundent.h -# End Source File -# Begin Source File - -SOURCE=.\spectator.h -# End Source File -# Begin Source File - -SOURCE=.\squadmonster.h -# End Source File -# Begin Source File - -SOURCE=.\talkmonster.h -# End Source File -# Begin Source File - -SOURCE=.\teamplay_gamerules.h -# End Source File -# Begin Source File - -SOURCE=.\trains.h +SOURCE=.\StudioModelRenderer.h # End Source File # Begin Source File @@ -690,11 +561,59 @@ SOURCE=.\util.h # End Source File # Begin Source File -SOURCE=.\vector.h +SOURCE=.\util_vector.h # End Source File # Begin Source File -SOURCE=.\weapons.h +SOURCE=.\vgui_ConsolePanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ControlConfigPanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_int.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_SchemeManager.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ScorePanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_ServerBrowser.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_SpectatorPanel.h +# End Source File +# Begin Source File + +SOURCE=.\vgui_TeamFortressViewport.h +# End Source File +# Begin Source File + +SOURCE=.\view.h +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_banmgr.h +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_status.h +# End Source File +# Begin Source File + +SOURCE=..\game_shared\voice_vgui_tweakdlg.h +# End Source File +# Begin Source File + +SOURCE=.\wrect.h # End Source File # End Group # Begin Group "Resource Files" diff --git a/cl_dll/cl_dll.h b/cl_dll/cl_dll.h new file mode 100644 index 00000000..e2b594d1 --- /dev/null +++ b/cl_dll/cl_dll.h @@ -0,0 +1,40 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cl_dll.h +// + +// 4-23-98 JOHN + +// +// This DLL is linked by the client when they first initialize. +// This DLL is responsible for the following tasks: +// - Loading the HUD graphics upon initialization +// - Drawing the HUD graphics every frame +// - Handling the custum HUD-update packets +// +typedef unsigned char byte; +typedef unsigned short word; +typedef float vec_t; +typedef vec_t vec4_t[4]; +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); + +#include "util_vector.h" +#define EXPORT _declspec( dllexport ) + +#include "../engine/cdll_int.h" +#include "../dlls/cdll_dll.h" + +extern cl_enginefunc_t gEngfuncs; diff --git a/cl_dll/cl_util.h b/cl_dll/cl_util.h new file mode 100644 index 00000000..f72d5892 --- /dev/null +++ b/cl_dll/cl_util.h @@ -0,0 +1,160 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// cl_util.h +// + +#include "cvardef.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +// Macros to hook function calls into the HUD object +#define HOOK_MESSAGE(x) gEngfuncs.pfnHookUserMsg(#x, __MsgFunc_##x ); + +#define DECLARE_MESSAGE(y, x) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ + { \ + return gHUD.##y.MsgFunc_##x(pszName, iSize, pbuf ); \ + } + + +#define HOOK_COMMAND(x, y) gEngfuncs.pfnAddCommand( x, __CmdFunc_##y ); +#define DECLARE_COMMAND(y, x) void __CmdFunc_##x( void ) \ + { \ + gHUD.##y.UserCmd_##x( ); \ + } + +inline float CVAR_GET_FLOAT( const char *x ) { return gEngfuncs.pfnGetCvarFloat( (char*)x ); } +inline char* CVAR_GET_STRING( const char *x ) { return gEngfuncs.pfnGetCvarString( (char*)x ); } +inline struct cvar_s *CVAR_CREATE( const char *cv, const char *val, const int flags ) { return gEngfuncs.pfnRegisterVariable( (char*)cv, (char*)val, flags ); } + +#define SPR_Load (*gEngfuncs.pfnSPR_Load) +#define SPR_Set (*gEngfuncs.pfnSPR_Set) +#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) +#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) + +// SPR_Draw draws a the current sprite as solid +#define SPR_Draw (*gEngfuncs.pfnSPR_Draw) +// SPR_DrawHoles draws the current sprites, with color index255 not drawn (transparent) +#define SPR_DrawHoles (*gEngfuncs.pfnSPR_DrawHoles) +// SPR_DrawAdditive adds the sprites RGB values to the background (additive transulency) +#define SPR_DrawAdditive (*gEngfuncs.pfnSPR_DrawAdditive) + +// SPR_EnableScissor sets a clipping rect for HUD sprites. (0,0) is the top-left hand corner of the screen. +#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) +// SPR_DisableScissor disables the clipping rect +#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) +// +#define FillRGBA (*gEngfuncs.pfnFillRGBA) + + +// ScreenHeight returns the height of the screen, in pixels +#define ScreenHeight (gHUD.m_scrinfo.iHeight) +// ScreenWidth returns the width of the screen, in pixels +#define ScreenWidth (gHUD.m_scrinfo.iWidth) + +// Use this to set any co-ords in 640x480 space +#define XRES(x) ((int)(float(x) * ((float)ScreenWidth / 640.0f) + 0.5f)) +#define YRES(y) ((int)(float(y) * ((float)ScreenHeight / 480.0f) + 0.5f)) + +// use this to project world coordinates to screen coordinates +#define XPROJECT(x) ( (1.0f+(x))*ScreenWidth*0.5f ) +#define YPROJECT(y) ( (1.0f-(y))*ScreenHeight*0.5f ) + +#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) +#define ServerCmd (*gEngfuncs.pfnServerCmd) +#define ClientCmd (*gEngfuncs.pfnClientCmd) +#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) +#define AngleVectors (*gEngfuncs.pfnAngleVectors) + + +// Gets the height & width of a sprite, at the specified frame +inline int SPR_Height( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Height(x, f); } +inline int SPR_Width( HSPRITE x, int f ) { return gEngfuncs.pfnSPR_Width(x, f); } + +inline client_textmessage_t *TextMessageGet( const char *pName ) { return gEngfuncs.pfnTextMessageGet( pName ); } +inline int TextMessageDrawChar( int x, int y, int number, int r, int g, int b ) +{ + return gEngfuncs.pfnDrawCharacter( x, y, number, r, g, b ); +} + +inline int DrawConsoleString( int x, int y, const char *string ) +{ + return gEngfuncs.pfnDrawConsoleString( x, y, (char*) string ); +} + +inline void GetConsoleStringSize( const char *string, int *width, int *height ) +{ + gEngfuncs.pfnDrawConsoleStringLen( string, width, height ); +} + +inline int ConsoleStringLen( const char *string ) +{ + int _width, _height; + GetConsoleStringSize( string, &_width, &_height ); + return _width; +} + +inline void ConsolePrint( const char *string ) +{ + gEngfuncs.pfnConsolePrint( string ); +} + +inline void CenterPrint( const char *string ) +{ + gEngfuncs.pfnCenterPrint( string ); +} + +// returns the players name of entity no. +#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) + +// sound functions +inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } +inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } + +#define max(a, b) (((a) > (b)) ? (a) : (b)) +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#define fabs(x) ((x) > 0 ? (x) : 0 - (x)) + +void ScaleColors( int &r, int &g, int &b, int a ); + +#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#define VectorSubtract(a,b,c) {(c)[0]=(a)[0]-(b)[0];(c)[1]=(a)[1]-(b)[1];(c)[2]=(a)[2]-(b)[2];} +#define VectorAdd(a,b,c) {(c)[0]=(a)[0]+(b)[0];(c)[1]=(a)[1]+(b)[1];(c)[2]=(a)[2]+(b)[2];} +#define VectorCopy(a,b) {(b)[0]=(a)[0];(b)[1]=(a)[1];(b)[2]=(a)[2];} +inline void VectorClear(float *a) { a[0]=0.0;a[1]=0.0;a[2]=0.0;} +float Length(const float *v); +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc); +void VectorScale (const float *in, float scale, float *out); +float VectorNormalize (float *v); +void VectorInverse ( float *v ); + +extern vec3_t vec3_origin; + +// disable 'possible loss of data converting float to int' warning message +#pragma warning( disable: 4244 ) +// disable 'truncation from 'const double' to 'float' warning message +#pragma warning( disable: 4305 ) + +inline void UnpackRGB(int &r, int &g, int &b, unsigned long ulRGB)\ +{\ + r = (ulRGB & 0xFF0000) >>16;\ + g = (ulRGB & 0xFF00) >> 8;\ + b = ulRGB & 0xFF;\ +} + +HSPRITE LoadSprite(const char *pszName); diff --git a/cl_dll/com_weapons.cpp b/cl_dll/com_weapons.cpp new file mode 100644 index 00000000..66b1c82d --- /dev/null +++ b/cl_dll/com_weapons.cpp @@ -0,0 +1,277 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +// Com_Weapons.cpp +// Shared weapons common/shared functions +#include +#include "hud.h" +#include "cl_util.h" +#include "com_weapons.h" + +#include "const.h" +#include "entity_state.h" +#include "r_efx.h" + +// g_runfuncs is true if this is the first time we've "predicated" a particular movement/firing +// command. If it is 1, then we should play events/sounds etc., otherwise, we just will be +// updating state info, but not firing events +int g_runfuncs = 0; + +// During our weapon prediction processing, we'll need to reference some data that is part of +// the final state passed into the postthink functionality. We'll set this pointer and then +// reset it to NULL as appropriate +struct local_state_s *g_finalstate = NULL; + +/* +==================== +COM_Log + +Log debug messages to file ( appends ) +==================== +*/ +void COM_Log( char *pszFile, char *fmt, ...) +{ + va_list argptr; + char string[1024]; + FILE *fp; + char *pfilename; + + if ( !pszFile ) + { + pfilename = "c:\\hllog.txt"; + } + else + { + pfilename = pszFile; + } + + va_start (argptr,fmt); + vsprintf (string, fmt,argptr); + va_end (argptr); + + fp = fopen( pfilename, "a+t"); + if (fp) + { + fprintf(fp, "%s", string); + fclose(fp); + } +} + +// remember the current animation for the view model, in case we get out of sync with +// server. +static int g_currentanim; + +/* +===================== +HUD_SendWeaponAnim + +Change weapon model animation +===================== +*/ +void HUD_SendWeaponAnim( int iAnim, int body, int force ) +{ + // Don't actually change it. + if ( !g_runfuncs && !force ) + return; + + g_currentanim = iAnim; + + // Tell animation system new info + gEngfuncs.pfnWeaponAnim( iAnim, body ); +} + +/* +===================== +HUD_GetWeaponAnim + +Retrieve current predicted weapon animation +===================== +*/ +int HUD_GetWeaponAnim( void ) +{ + return g_currentanim; +} + +/* +===================== +HUD_PlaySound + +Play a sound, if we are seeing this command for the first time +===================== +*/ +void HUD_PlaySound( char *sound, float volume ) +{ + if ( !g_runfuncs || !g_finalstate ) + return; + + gEngfuncs.pfnPlaySoundByNameAtLocation( sound, volume, (float *)&g_finalstate->playerstate.origin ); +} + +/* +===================== +HUD_PlaybackEvent + +Directly queue up an event on the client +===================== +*/ +void HUD_PlaybackEvent( int flags, const edict_t *pInvoker, unsigned short eventindex, float delay, + float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ) +{ + vec3_t org; + vec3_t ang; + + if ( !g_runfuncs || !g_finalstate ) + return; + + // Weapon prediction events are assumed to occur at the player's origin + org = g_finalstate->playerstate.origin; + ang = v_angles; + gEngfuncs.pfnPlaybackEvent( flags, pInvoker, eventindex, delay, (float *)&org, (float *)&ang, fparam1, fparam2, iparam1, iparam2, bparam1, bparam2 ); +} + +/* +===================== +HUD_SetMaxSpeed + +===================== +*/ +void HUD_SetMaxSpeed( const edict_t *ed, float speed ) +{ +} + + +/* +===================== +UTIL_WeaponTimeBase + +Always 0.0 on client, even if not predicting weapons ( won't get called + in that case ) +===================== +*/ +float UTIL_WeaponTimeBase( void ) +{ + return 0.0; +} + +static unsigned int glSeed = 0; + +unsigned int seed_table[ 256 ] = +{ + 28985, 27138, 26457, 9451, 17764, 10909, 28790, 8716, 6361, 4853, 17798, 21977, 19643, 20662, 10834, 20103, + 27067, 28634, 18623, 25849, 8576, 26234, 23887, 18228, 32587, 4836, 3306, 1811, 3035, 24559, 18399, 315, + 26766, 907, 24102, 12370, 9674, 2972, 10472, 16492, 22683, 11529, 27968, 30406, 13213, 2319, 23620, 16823, + 10013, 23772, 21567, 1251, 19579, 20313, 18241, 30130, 8402, 20807, 27354, 7169, 21211, 17293, 5410, 19223, + 10255, 22480, 27388, 9946, 15628, 24389, 17308, 2370, 9530, 31683, 25927, 23567, 11694, 26397, 32602, 15031, + 18255, 17582, 1422, 28835, 23607, 12597, 20602, 10138, 5212, 1252, 10074, 23166, 19823, 31667, 5902, 24630, + 18948, 14330, 14950, 8939, 23540, 21311, 22428, 22391, 3583, 29004, 30498, 18714, 4278, 2437, 22430, 3439, + 28313, 23161, 25396, 13471, 19324, 15287, 2563, 18901, 13103, 16867, 9714, 14322, 15197, 26889, 19372, 26241, + 31925, 14640, 11497, 8941, 10056, 6451, 28656, 10737, 13874, 17356, 8281, 25937, 1661, 4850, 7448, 12744, + 21826, 5477, 10167, 16705, 26897, 8839, 30947, 27978, 27283, 24685, 32298, 3525, 12398, 28726, 9475, 10208, + 617, 13467, 22287, 2376, 6097, 26312, 2974, 9114, 21787, 28010, 4725, 15387, 3274, 10762, 31695, 17320, + 18324, 12441, 16801, 27376, 22464, 7500, 5666, 18144, 15314, 31914, 31627, 6495, 5226, 31203, 2331, 4668, + 12650, 18275, 351, 7268, 31319, 30119, 7600, 2905, 13826, 11343, 13053, 15583, 30055, 31093, 5067, 761, + 9685, 11070, 21369, 27155, 3663, 26542, 20169, 12161, 15411, 30401, 7580, 31784, 8985, 29367, 20989, 14203, + 29694, 21167, 10337, 1706, 28578, 887, 3373, 19477, 14382, 675, 7033, 15111, 26138, 12252, 30996, 21409, + 25678, 18555, 13256, 23316, 22407, 16727, 991, 9236, 5373, 29402, 6117, 15241, 27715, 19291, 19888, 19847 +}; + +unsigned int U_Random( void ) +{ + glSeed *= 69069; + glSeed += seed_table[ glSeed & 0xff ]; + + return ( ++glSeed & 0x0fffffff ); +} + +void U_Srand( unsigned int seed ) +{ + glSeed = seed_table[ seed & 0xff ]; +} + +/* +===================== +UTIL_SharedRandomLong +===================== +*/ +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ) +{ + unsigned int range; + + U_Srand( (int)seed + low + high ); + + range = high - low + 1; + if ( !(range - 1) ) + { + return low; + } + else + { + int offset; + int rnum; + + rnum = U_Random(); + + offset = rnum % range; + + return (low + offset); + } +} + +/* +===================== +UTIL_SharedRandomFloat +===================== +*/ +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ) +{ + // + unsigned int range; + + U_Srand( (int)seed + *(int *)&low + *(int *)&high ); + + U_Random(); + U_Random(); + + range = high - low; + if ( !range ) + { + return low; + } + else + { + int tensixrand; + float offset; + + tensixrand = U_Random() & 65535; + + offset = (float)tensixrand / 65536.0; + + return (low + offset * range ); + } +} + +/* +====================== +stub_* + +stub functions for such things as precaching. So we don't have to modify weapons code that + is compiled into both game and client .dlls. +====================== +*/ +int stub_PrecacheModel ( char* s ) { return 0; } +int stub_PrecacheSound ( char* s ) { return 0; } +unsigned short stub_PrecacheEvent ( int type, const char *s ) { return 0; } +const char *stub_NameForFunction ( unsigned long function ) { return "func"; } +void stub_SetModel ( edict_t *e, const char *m ) {} diff --git a/cl_dll/com_weapons.h b/cl_dll/com_weapons.h new file mode 100644 index 00000000..e2fd2749 --- /dev/null +++ b/cl_dll/com_weapons.h @@ -0,0 +1,48 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// com_weapons.h +// Shared weapons common function prototypes +#if !defined( COM_WEAPONSH ) +#define COM_WEAPONSH +#ifdef _WIN32 +#pragma once +#endif + +#include "hud_iface.h" + +extern "C" +{ + void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); +} + +void COM_Log( char *pszFile, char *fmt, ...); +int CL_IsDead( void ); + +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); +int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); + +int HUD_GetWeaponAnim( void ); +void HUD_SendWeaponAnim( int iAnim, int body, int force ); +void HUD_PlaySound( char *sound, float volume ); +void HUD_PlaybackEvent( int flags, const struct edict_s *pInvoker, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); +void HUD_SetMaxSpeed( const struct edict_s *ed, float speed ); +int stub_PrecacheModel( char* s ); +int stub_PrecacheSound( char* s ); +unsigned short stub_PrecacheEvent( int type, const char *s ); +const char *stub_NameForFunction ( unsigned long function ); +void stub_SetModel ( struct edict_s *e, const char *m ); + + +extern cvar_t *cl_lw; + +extern int g_runfuncs; +extern vec3_t v_angles; +extern float g_lastFOV; +extern struct local_state_s *g_finalstate; + +#endif \ No newline at end of file diff --git a/cl_dll/death.cpp b/cl_dll/death.cpp new file mode 100644 index 00000000..208f587a --- /dev/null +++ b/cl_dll/death.cpp @@ -0,0 +1,304 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// death notice +// +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +#include "vgui_TeamFortressViewport.h" + +DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); + +struct DeathNoticeItem { + char szKiller[MAX_PLAYER_NAME_LENGTH*2]; + char szVictim[MAX_PLAYER_NAME_LENGTH*2]; + int iId; // the index number of the associated sprite + int iSuicide; + int iTeamKill; + int iNonPlayerKill; + float flDisplayTime; + float *KillerColor; + float *VictimColor; +}; + +#define MAX_DEATHNOTICES 4 +static int DEATHNOTICE_DISPLAY_TIME = 6; + +#define DEATHNOTICE_TOP 32 + +DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; + +float g_ColorBlue[3] = { 0.6, 0.8, 1.0 }; +float g_ColorRed[3] = { 1.0, 0.25, 0.25 }; +float g_ColorGreen[3] = { 0.6, 1.0, 0.6 }; +float g_ColorYellow[3] = { 1.0, 0.7, 0.0 }; +float g_ColorGrey[3] = { 0.8, 0.8, 0.8 }; + +float *GetClientColor( int clientIndex ) +{ + switch ( g_PlayerExtraInfo[clientIndex].teamnumber ) + { + case 1: return g_ColorBlue; + case 2: return g_ColorRed; + case 3: return g_ColorYellow; + case 4: return g_ColorGreen; + case 0: return g_ColorYellow; + + default : return g_ColorGrey; + } + + return NULL; +} + +int CHudDeathNotice :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( DeathMsg ); + + CVAR_CREATE( "hud_deathnotice_time", "6", 0 ); + + return 1; +} + + +void CHudDeathNotice :: InitHUDData( void ) +{ + memset( rgDeathNoticeList, 0, sizeof(rgDeathNoticeList) ); +} + + +int CHudDeathNotice :: VidInit( void ) +{ + m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); + + return 1; +} + +int CHudDeathNotice :: Draw( float flTime ) +{ + int x, y, r, g, b; + + for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) + { + if ( rgDeathNoticeList[i].iId == 0 ) + break; // we've gone through them all + + if ( rgDeathNoticeList[i].flDisplayTime < flTime ) + { // display time has expired + // remove the current item from the list + memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i) ); + i--; // continue on the next item; stop the counter getting incremented + continue; + } + + rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); + + // Only draw if the viewport will let me + if ( gViewPort && gViewPort->AllowedToPrintText() ) + { + // Draw the death notice + y = YRES(DEATHNOTICE_TOP) + 2 + (20 * i); //!!! + + int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; + x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + if ( !rgDeathNoticeList[i].iSuicide ) + { + x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); + + // Draw killers name + if ( rgDeathNoticeList[i].KillerColor ) + gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].KillerColor[0], rgDeathNoticeList[i].KillerColor[1], rgDeathNoticeList[i].KillerColor[2] ); + x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); + } + + r = 255; g = 80; b = 0; + if ( rgDeathNoticeList[i].iTeamKill ) + { + r = 10; g = 240; b = 10; // display it in sickly green + } + + // Draw death weapon + SPR_Set( gHUD.GetSprite(id), r, g, b ); + SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(id) ); + + x += (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); + + // Draw victims name (if it was a player that was killed) + if (rgDeathNoticeList[i].iNonPlayerKill == FALSE) + { + if ( rgDeathNoticeList[i].VictimColor ) + gEngfuncs.pfnDrawSetTextColor( rgDeathNoticeList[i].VictimColor[0], rgDeathNoticeList[i].VictimColor[1], rgDeathNoticeList[i].VictimColor[2] ); + x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); + } + } + } + + return 1; +} + +// This message handler may be better off elsewhere +int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) +{ + m_iFlags |= HUD_ACTIVE; + + BEGIN_READ( pbuf, iSize ); + + int killer = READ_BYTE(); + int victim = READ_BYTE(); + + char killedwith[32]; + strcpy( killedwith, "d_" ); + strncat( killedwith, READ_STRING(), 32 ); + + if (gViewPort) + gViewPort->DeathMsg( killer, victim ); + + gHUD.m_Spectator.DeathMessage(victim); + + for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) + { + if ( rgDeathNoticeList[i].iId == 0 ) + break; + } + if ( i == MAX_DEATHNOTICES ) + { // move the rest of the list forward to make room for this item + memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof(DeathNoticeItem) * MAX_DEATHNOTICES ); + i = MAX_DEATHNOTICES - 1; + } + + if (gViewPort) + gViewPort->GetAllPlayersInfo(); + + // Get the Killer's name + char *killer_name = g_PlayerInfoList[ killer ].name; + if ( !killer_name ) + { + killer_name = ""; + rgDeathNoticeList[i].szKiller[0] = 0; + } + else + { + rgDeathNoticeList[i].KillerColor = GetClientColor( killer ); + strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szKiller[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Get the Victim's name + char *victim_name = NULL; + // If victim is -1, the killer killed a specific, non-player object (like a sentrygun) + if ( ((char)victim) != -1 ) + victim_name = g_PlayerInfoList[ victim ].name; + if ( !victim_name ) + { + victim_name = ""; + rgDeathNoticeList[i].szVictim[0] = 0; + } + else + { + rgDeathNoticeList[i].VictimColor = GetClientColor( victim ); + strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); + rgDeathNoticeList[i].szVictim[MAX_PLAYER_NAME_LENGTH-1] = 0; + } + + // Is it a non-player object kill? + if ( ((char)victim) == -1 ) + { + rgDeathNoticeList[i].iNonPlayerKill = TRUE; + + // Store the object's name in the Victim slot (skip the d_ bit) + strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 ); + } + else + { + if ( killer == victim || killer == 0 ) + rgDeathNoticeList[i].iSuicide = TRUE; + + if ( !strcmp( killedwith, "d_teammate" ) ) + rgDeathNoticeList[i].iTeamKill = TRUE; + } + + // Find the sprite in the list + int spr = gHUD.GetSpriteIndex( killedwith ); + + rgDeathNoticeList[i].iId = spr; + + DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); + rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; + + if (rgDeathNoticeList[i].iNonPlayerKill) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed a " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + ConsolePrint( "\n" ); + } + else + { + // record the death notice in the console + if ( rgDeathNoticeList[i].iSuicide ) + { + ConsolePrint( rgDeathNoticeList[i].szVictim ); + + if ( !strcmp( killedwith, "d_world" ) ) + { + ConsolePrint( " died" ); + } + else + { + ConsolePrint( " killed self" ); + } + } + else if ( rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed his teammate " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + else + { + ConsolePrint( rgDeathNoticeList[i].szKiller ); + ConsolePrint( " killed " ); + ConsolePrint( rgDeathNoticeList[i].szVictim ); + } + + if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) + { + ConsolePrint( " with " ); + + // replace the code names with the 'real' names + if ( !strcmp( killedwith+2, "egon" ) ) + strcpy( killedwith, "d_gluon gun" ); + if ( !strcmp( killedwith+2, "gauss" ) ) + strcpy( killedwith, "d_tau cannon" ); + + ConsolePrint( killedwith+2 ); // skip over the "d_" part + } + + ConsolePrint( "\n" ); + } + + return 1; +} + + + + diff --git a/cl_dll/demo.cpp b/cl_dll/demo.cpp new file mode 100644 index 00000000..6968b387 --- /dev/null +++ b/cl_dll/demo.cpp @@ -0,0 +1,103 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "hud.h" +#include "cl_util.h" +#include "demo.h" +#include "demo_api.h" +#include + +#define DLLEXPORT __declspec( dllexport ) + +int g_demosniper = 0; +int g_demosniperdamage = 0; +float g_demosniperorg[3]; +float g_demosniperangles[3]; +float g_demozoom; + +// FIXME: There should be buffer helper functions to avoid all of the *(int *)& crap. + +extern "C" +{ + void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ); +} + +/* +===================== +Demo_WriteBuffer + +Write some data to the demo stream +===================== +*/ +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ) +{ + int pos = 0; + unsigned char buf[ 32 * 1024 ]; + *( int * )&buf[pos] = type; + pos+=sizeof( int ); + + memcpy( &buf[pos], buffer, size ); + + // Write full buffer out + gEngfuncs.pDemoAPI->WriteBuffer( size + sizeof( int ), buf ); +} + +/* +===================== +Demo_ReadBuffer + +Engine wants us to parse some data from the demo stream +===================== +*/ +void DLLEXPORT Demo_ReadBuffer( int size, unsigned char *buffer ) +{ + int type; + int i = 0; + + type = *( int * )buffer; + i += sizeof( int ); + switch ( type ) + { + case TYPE_SNIPERDOT: + g_demosniper = *(int * )&buffer[ i ]; + i += sizeof( int ); + + if ( g_demosniper ) + { + g_demosniperdamage = *( int * )&buffer[ i ]; + i += sizeof( int ); + + g_demosniperangles[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperangles[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 0 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 1 ] = *(float *)&buffer[i]; + i += sizeof( float ); + g_demosniperorg[ 2 ] = *(float *)&buffer[i]; + i += sizeof( float ); + } + break; + case TYPE_ZOOM: + g_demozoom = *(float * )&buffer[ i ]; + i += sizeof( float ); + break; + default: + gEngfuncs.Con_DPrintf( "Unknown demo buffer type, skipping.\n" ); + break; + } +} \ No newline at end of file diff --git a/cl_dll/demo.h b/cl_dll/demo.h new file mode 100644 index 00000000..c5a5057b --- /dev/null +++ b/cl_dll/demo.h @@ -0,0 +1,27 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( DEMOH ) +#define DEMOH +#pragma once + +// Types of demo messages we can write/parse +enum +{ + TYPE_SNIPERDOT = 0, + TYPE_ZOOM +}; + +void Demo_WriteBuffer( int type, int size, unsigned char *buffer ); + +extern int g_demosniper; +extern int g_demosniperdamage; +extern float g_demosniperorg[3]; +extern float g_demosniperangles[3]; +extern float g_demozoom; + +#endif \ No newline at end of file diff --git a/cl_dll/entity.cpp b/cl_dll/entity.cpp new file mode 100644 index 00000000..cac9e9c2 --- /dev/null +++ b/cl_dll/entity.cpp @@ -0,0 +1,978 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Client side entity management functions + +#include + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_types.h" +#include "studio_event.h" // def. of mstudioevent_t +#include "r_efx.h" +#include "event_api.h" +#include "pm_defs.h" +#include "pmtrace.h" +#include "pm_shared.h" + +#define DLLEXPORT __declspec( dllexport ) + +void Game_AddObjects( void ); + +extern vec3_t v_origin; + +int g_iAlive = 1; + +extern "C" +{ + int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ); + void DLLEXPORT HUD_CreateEntities( void ); + void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); + void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); + void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); + void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ); + void DLLEXPORT HUD_TempEntUpdate( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( struct cl_entity_s *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp ) ); + struct cl_entity_s DLLEXPORT *HUD_GetUserEntity( int index ); +} + +/* +======================== +HUD_AddEntity + Return 0 to filter entity from visible list for rendering +======================== +*/ +int DLLEXPORT HUD_AddEntity( int type, struct cl_entity_s *ent, const char *modelname ) +{ + switch ( type ) + { + case ET_NORMAL: + case ET_PLAYER: + case ET_BEAM: + case ET_TEMPENTITY: + case ET_FRAGMENTED: + default: + break; + } + // each frame every entity passes this function, so the overview hooks it to filter the overview entities + // in spectator mode: + // each frame every entity passes this function, so the overview hooks + // it to filter the overview entities + + if ( g_iUser1 ) + { + gHUD.m_Spectator.AddOverviewEntity( type, ent, modelname ); + + if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && + ent->index == g_iUser2 ) + return 0; // don't draw the player we are following in eye + + } + + return 1; +} + +/* +========================= +HUD_TxferLocalOverrides + +The server sends us our origin with extra precision as part of the clientdata structure, not during the normal +playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate +structure, we need to copy them into the state structure at this point. +========================= +*/ +void DLLEXPORT HUD_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ) +{ + VectorCopy( client->origin, state->origin ); + + // Spectator + state->iuser1 = client->iuser1; + state->iuser2 = client->iuser2; + + // Duck prevention + state->iuser3 = client->iuser3; + + // Fire prevention + state->iuser4 = client->iuser4; +} + +/* +========================= +HUD_ProcessPlayerState + +We have received entity_state_t for this player over the network. We need to copy appropriate fields to the +playerstate structure +========================= +*/ +void DLLEXPORT HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ) +{ + // Copy in network data + VectorCopy( src->origin, dst->origin ); + VectorCopy( src->angles, dst->angles ); + + VectorCopy( src->velocity, dst->velocity ); + + dst->frame = src->frame; + dst->modelindex = src->modelindex; + dst->skin = src->skin; + dst->effects = src->effects; + dst->weaponmodel = src->weaponmodel; + dst->movetype = src->movetype; + dst->sequence = src->sequence; + dst->animtime = src->animtime; + + dst->solid = src->solid; + + dst->rendermode = src->rendermode; + dst->renderamt = src->renderamt; + dst->rendercolor.r = src->rendercolor.r; + dst->rendercolor.g = src->rendercolor.g; + dst->rendercolor.b = src->rendercolor.b; + dst->renderfx = src->renderfx; + + dst->framerate = src->framerate; + dst->body = src->body; + + memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); + memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); + + VectorCopy( src->basevelocity, dst->basevelocity ); + + dst->friction = src->friction; + dst->gravity = src->gravity; + dst->gaitsequence = src->gaitsequence; + dst->spectator = src->spectator; + dst->usehull = src->usehull; + dst->playerclass = src->playerclass; + dst->team = src->team; + dst->colormap = src->colormap; + + // Save off some data so other areas of the Client DLL can get to it + cl_entity_t *player = gEngfuncs.GetLocalPlayer(); // Get the local player's index + if ( dst->number == player->index ) + { + g_iPlayerClass = dst->playerclass; + g_iTeamNumber = dst->team; + + g_iUser1 = src->iuser1; + g_iUser2 = src->iuser2; + g_iUser3 = src->iuser3; + } +} + +/* +========================= +HUD_TxferPredictionData + +Because we can predict an arbitrary number of frames before the server responds with an update, we need to be able to copy client side prediction data in + from the state that the server ack'd receiving, which can be anywhere along the predicted frame path ( i.e., we could predict 20 frames into the future and the server ack's + up through 10 of those frames, so we need to copy persistent client-side only state from the 10th predicted frame to the slot the server + update is occupying. +========================= +*/ +void DLLEXPORT HUD_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ) +{ + ps->oldbuttons = pps->oldbuttons; + ps->flFallVelocity = pps->flFallVelocity; + ps->iStepLeft = pps->iStepLeft; + ps->playerclass = pps->playerclass; + + pcd->viewmodel = ppcd->viewmodel; + pcd->m_iId = ppcd->m_iId; + pcd->ammo_shells = ppcd->ammo_shells; + pcd->ammo_nails = ppcd->ammo_nails; + pcd->ammo_cells = ppcd->ammo_cells; + pcd->ammo_rockets = ppcd->ammo_rockets; + pcd->m_flNextAttack = ppcd->m_flNextAttack; + pcd->fov = ppcd->fov; + pcd->weaponanim = ppcd->weaponanim; + pcd->tfstate = ppcd->tfstate; + pcd->maxspeed = ppcd->maxspeed; + + pcd->deadflag = ppcd->deadflag; + + // Spectating or not dead == get control over view angles. + g_iAlive = ( ppcd->iuser1 || ( pcd->deadflag == DEAD_NO ) ) ? 1 : 0; + + // Spectator + pcd->iuser1 = ppcd->iuser1; + pcd->iuser2 = ppcd->iuser2; + + // Duck prevention + pcd->iuser3 = ppcd->iuser3; + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in specator mode we tell the engine who we want to spectate and how + // iuser3 is not used for duck prevention (since the spectator can't duck at all) + pcd->iuser1 = g_iUser1; // observer mode + pcd->iuser2 = g_iUser2; // first target + pcd->iuser3 = g_iUser3; // second target + + } + + // Fire prevention + pcd->iuser4 = ppcd->iuser4; + + pcd->fuser2 = ppcd->fuser2; + pcd->fuser3 = ppcd->fuser3; + + VectorCopy( ppcd->vuser1, pcd->vuser1 ); + VectorCopy( ppcd->vuser2, pcd->vuser2 ); + VectorCopy( ppcd->vuser3, pcd->vuser3 ); + VectorCopy( ppcd->vuser4, pcd->vuser4 ); + + memcpy( wd, pwd, 32 * sizeof( weapon_data_t ) ); +} + +/* +//#define TEST_IT +#if defined( TEST_IT ) + +cl_entity_t mymodel[9]; + +void MoveModel( void ) +{ + cl_entity_t *player; + int i, j; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + for ( i = 0; i < 3; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + // Don't draw over ourself... + if ( ( i == 1 ) && ( j == 1 ) ) + continue; + + mymodel[ i * 3 + j ] = *player; + + mymodel[ i * 3 + j ].player = 0; + + mymodel[ i * 3 + j ].model = mod; + mymodel[ i * 3 + j ].curstate.modelindex = modelindex; + + // Move it out a bit + mymodel[ i * 3 + j ].origin[0] = player->origin[0] + 50 * ( 1 - i ); + mymodel[ i * 3 + j ].origin[1] = player->origin[1] + 50 * ( 1 - j ); + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &mymodel[i*3+j] ); + } + } + +} + +#endif + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern int hitent; + +cl_entity_t hit; + +void TraceModel( void ) +{ + cl_entity_t *ent; + + if ( hitent <= 0 ) + return; + + // Load it up with some bogus data + ent = gEngfuncs.GetEntityByIndex( hitent ); + if ( !ent ) + return; + + hit = *ent; + //hit.curstate.rendermode = kRenderTransTexture; + //hit.curstate.renderfx = kRenderFxGlowShell; + //hit.curstate.renderamt = 100; + + hit.origin[2] += 40; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, &hit ); +} + +#endif +*/ + +/* +void ParticleCallback( struct particle_s *particle, float frametime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + particle->org[ i ] += particle->vel[ i ] * frametime; + } +} + +cvar_t *color = NULL; +void Particles( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 2.0 ) + return; + + if ( !color ) + { + color = gEngfuncs.pfnRegisterVariable ( "color","255 0 0", 0 ); + } + + lasttime = curtime; + + // Create a few particles + particle_t *p; + int i, j; + + for ( i = 0; i < 1000; i++ ) + { + int r, g, b; + p = gEngfuncs.pEfxAPI->R_AllocParticle( ParticleCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->org[ j ] = v_origin[ j ] + gEngfuncs.pfnRandomFloat( -32.0, 32.0 );; + p->vel[ j ] = gEngfuncs.pfnRandomFloat( -100.0, 100.0 ); + } + + if ( color ) + { + sscanf( color->string, "%i %i %i", &r, &g, &b ); + } + else + { + r = 192; + g = 0; + b = 0; + } + + p->color = gEngfuncs.pEfxAPI->R_LookupColor( r, g, b ); + gEngfuncs.pEfxAPI->R_GetPackedColor( &p->packedColor, p->color ); + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 3.0; + } +} +*/ + +/* +void TempEntCallback ( struct tempent_s *ent, float frametime, float currenttime ) +{ + int i; + + for ( i = 0; i < 3; i++ ) + { + ent->entity.curstate.origin[ i ] += ent->entity.baseline.origin[ i ] * frametime; + } +} + +void TempEnts( void ) +{ + static float lasttime; + float curtime; + + curtime = gEngfuncs.GetClientTime(); + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + lasttime = curtime; + + TEMPENTITY *p; + int i, j; + struct model_s *mod; + vec3_t origin; + int index; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserdot.spr", &index ); + + for ( i = 0; i < 100; i++ ) + { + for ( j = 0; j < 3; j++ ) + { + origin[ j ] = v_origin[ j ]; + if ( j != 2 ) + { + origin[ j ] += 75; + } + } + + p = gEngfuncs.pEfxAPI->CL_TentEntAllocCustom( (float *)&origin, mod, 0, TempEntCallback ); + if ( !p ) + break; + + for ( j = 0; j < 3; j++ ) + { + p->entity.curstate.origin[ j ] = origin[ j ]; + + // Store velocity in baseline origin + p->entity.baseline.origin[ j ] = gEngfuncs.pfnRandomFloat( -100, 100 ); + } + + // p->die is set to current time so all you have to do is add an additional time to it + p->die += 10.0; + } +} +*/ + +#if defined( BEAM_TEST ) +// Note can't index beam[ 0 ] in Beam callback, so don't use that index +// Room for 1 beam ( 0 can't be used ) +static cl_entity_t beams[ 2 ]; + +void BeamEndModel( void ) +{ + cl_entity_t *player, *model; + int modelindex; + struct model_s *mod; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + mod = gEngfuncs.CL_LoadModel( "models/sentry3.mdl", &modelindex ); + if ( !mod ) + return; + + // Slot 1 + model = &beams[ 1 ]; + + *model = *player; + model->player = 0; + model->model = mod; + model->curstate.modelindex = modelindex; + + // Move it out a bit + model->origin[0] = player->origin[0] - 100; + model->origin[1] = player->origin[1]; + + model->attachment[0] = model->origin; + model->attachment[1] = model->origin; + model->attachment[2] = model->origin; + model->attachment[3] = model->origin; + + gEngfuncs.CL_CreateVisibleEntity( ET_NORMAL, model ); +} + +void Beams( void ) +{ + static float lasttime; + float curtime; + struct model_s *mod; + int index; + + BeamEndModel(); + + curtime = gEngfuncs.GetClientTime(); + float end[ 3 ]; + + if ( ( curtime - lasttime ) < 10.0 ) + return; + + mod = gEngfuncs.CL_LoadModel( "sprites/laserbeam.spr", &index ); + if ( !mod ) + return; + + lasttime = curtime; + + end [ 0 ] = v_origin.x + 100; + end [ 1 ] = v_origin.y + 100; + end [ 2 ] = v_origin.z; + + BEAM *p1; + p1 = gEngfuncs.pEfxAPI->R_BeamEntPoint( -1, end, index, + 10.0, 2.0, 0.3, 1.0, 5.0, 0.0, 1.0, 1.0, 1.0, 1.0 ); +} +#endif + +/* +========================= +HUD_CreateEntities + +Gives us a chance to add additional entities to the render this frame +========================= +*/ +void DLLEXPORT HUD_CreateEntities( void ) +{ + // e.g., create a persistent cl_entity_t somewhere. + // Load an appropriate model into it ( gEngfuncs.CL_LoadModel ) + // Call gEngfuncs.CL_CreateVisibleEntity to add it to the visedicts list +/* +#if defined( TEST_IT ) + MoveModel(); +#endif + +#if defined( TRACE_TEST ) + TraceModel(); +#endif +*/ +/* + Particles(); +*/ +/* + TempEnts(); +*/ + +#if defined( BEAM_TEST ) + Beams(); +#endif + + // Add in any game specific objects + Game_AddObjects(); + + if( gViewPort ) + GetClientVoiceMgr()->CreateEntities(); +} + +/* +========================= +HUD_StudioEvent + +The entity's studio model description indicated an event was +fired during this frame, handle the event by it's tag ( e.g., muzzleflash, sound ) +========================= +*/ +void DLLEXPORT HUD_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ) +{ + switch( event->event ) + { + case 5001: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[0], atoi( event->options) ); + break; + case 5011: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[1], atoi( event->options) ); + break; + case 5021: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[2], atoi( event->options) ); + break; + case 5031: + gEngfuncs.pEfxAPI->R_MuzzleFlash( (float *)&entity->attachment[3], atoi( event->options) ); + break; + case 5002: + gEngfuncs.pEfxAPI->R_SparkEffect( (float *)&entity->attachment[0], atoi( event->options), -100, 100 ); + break; + // Client side sound + case 5004: + gEngfuncs.pfnPlaySoundByNameAtLocation( (char *)event->options, 1.0, (float *)&entity->attachment[0] ); + break; + default: + break; + } +} + +/* +================= +CL_UpdateTEnts + +Simulation and cleanup of temporary entities +================= +*/ +void DLLEXPORT HUD_TempEntUpdate ( + double frametime, // Simulation time + double client_time, // Absolute time on client + double cl_gravity, // True gravity on client + TEMPENTITY **ppTempEntFree, // List of freed temporary ents + TEMPENTITY **ppTempEntActive, // List + int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), + void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ) +{ + static int gTempEntFrame = 0; + int i; + TEMPENTITY *pTemp, *pnext, *pprev; + float freq, gravity, gravitySlow, life, fastFreq; + + // Nothing to simulate + if ( !*ppTempEntActive ) + return; + + // in order to have tents collide with players, we have to run the player prediction code so + // that the client has the player list. We run this code once when we detect any COLLIDEALL + // tent, then set this BOOL to true so the code doesn't get run again if there's more than + // one COLLIDEALL ent for this update. (often are). + 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 ( -1 ); + + // !!!BUGBUG -- This needs to be time based + gTempEntFrame = (gTempEntFrame+1) & 31; + + pTemp = *ppTempEntActive; + + // !!! Don't simulate while paused.... This is sort of a hack, revisit. + if ( frametime <= 0 ) + { + while ( pTemp ) + { + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + Callback_AddVisibleEntity( &pTemp->entity ); + } + pTemp = pTemp->next; + } + goto finish; + } + + pprev = NULL; + freq = client_time * 0.01; + fastFreq = client_time * 5.5; + gravity = -frametime * cl_gravity; + gravitySlow = gravity * 0.5; + + while ( pTemp ) + { + int active; + + active = 1; + + life = pTemp->die - client_time; + pnext = pTemp->next; + if ( life < 0 ) + { + if ( pTemp->flags & FTENT_FADEOUT ) + { + if (pTemp->entity.curstate.rendermode == kRenderNormal) + pTemp->entity.curstate.rendermode = kRenderTransTexture; + pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); + if ( pTemp->entity.curstate.renderamt <= 0 ) + active = 0; + + } + else + active = 0; + } + if ( !active ) // Kill it + { + pTemp->next = *ppTempEntFree; + *ppTempEntFree = pTemp; + if ( !pprev ) // Deleting at head of list + *ppTempEntActive = pnext; + else + pprev->next = pnext; + } + else + { + pprev = pTemp; + + VectorCopy( pTemp->entity.origin, pTemp->entity.prevstate.origin ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Adjust speed if it's time + // Scale is next think time + if ( client_time > pTemp->entity.baseline.scale ) + { + // Show Sparks + gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); + + // Reduce life + pTemp->entity.baseline.framerate -= 0.1; + + if ( pTemp->entity.baseline.framerate <= 0.0 ) + { + pTemp->die = client_time; + } + else + { + // So it will die no matter what + pTemp->die = client_time + 0.5; + + // Next think + pTemp->entity.baseline.scale = client_time + 0.1; + } + } + } + else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) + { + cl_entity_t *pClient; + + pClient = gEngfuncs.GetEntityByIndex( pTemp->clientIndex ); + + VectorAdd( pClient->origin, pTemp->tentOffset, pTemp->entity.origin ); + } + else if ( pTemp->flags & FTENT_SINEWAVE ) + { + pTemp->x += pTemp->entity.baseline.origin[0] * frametime; + pTemp->y += pTemp->entity.baseline.origin[1] * frametime; + + pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); + pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + else if ( pTemp->flags & FTENT_SPIRAL ) + { + float s, c; + s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); + c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); + + pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)pTemp ); + pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)pTemp ); + pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; + } + + else + { + for ( i = 0; i < 3; i++ ) + pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; + } + + if ( pTemp->flags & FTENT_SPRANIMATE ) + { + pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + + if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) + { + // this animating sprite isn't set to loop, so destroy it. + pTemp->die = client_time; + pTemp = pnext; + continue; + } + } + } + else if ( pTemp->flags & FTENT_SPRCYCLE ) + { + pTemp->entity.curstate.frame += frametime * 10; + if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) + { + pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); + } + } +// Experiment +#if 0 + if ( pTemp->flags & FTENT_SCALE ) + pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); +#endif + + if ( pTemp->flags & FTENT_ROTATE ) + { + pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; + pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; + pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime; + + VectorCopy( pTemp->entity.angles, pTemp->entity.latched.prevangles ); + } + + if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) + { + vec3_t traceNormal; + float traceFraction = 1; + + if ( pTemp->flags & FTENT_COLLIDEALL ) + { + pmtrace_t pmtrace; + physent_t *pe; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); + + + if ( pmtrace.fraction != 1 ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); + + if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + } + else if ( pTemp->flags & FTENT_COLLIDEWORLD ) + { + pmtrace_t pmtrace; + + gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); + + gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); + + if ( pmtrace.fraction != 1 ) + { + traceFraction = pmtrace.fraction; + VectorCopy( pmtrace.plane.normal, traceNormal ); + + if ( pTemp->flags & FTENT_SPARKSHOWER ) + { + // Chop spark speeds a bit more + // + VectorScale( pTemp->entity.baseline.origin, 0.6, pTemp->entity.baseline.origin ); + + if ( Length( pTemp->entity.baseline.origin ) < 10 ) + { + pTemp->entity.baseline.framerate = 0.0; + } + } + + if ( pTemp->hitcallback ) + { + (*pTemp->hitcallback)( pTemp, &pmtrace ); + } + } + } + + if ( traceFraction != 1 ) // Decent collision now, and damping works + { + float proj, damp; + + // Place at contact point + VectorMA( pTemp->entity.prevstate.origin, traceFraction*frametime, pTemp->entity.baseline.origin, pTemp->entity.origin ); + // Damp velocity + damp = pTemp->bounceFactor; + if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) + { + damp *= 0.5; + if ( traceNormal[2] > 0.9 ) // Hit floor? + { + if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) + { + damp = 0; // Stop + pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); + pTemp->entity.angles[0] = 0; + pTemp->entity.angles[2] = 0; + } + } + } + + if (pTemp->hitSound) + { + Callback_TempEntPlaySound(pTemp, damp); + } + + if (pTemp->flags & FTENT_COLLIDEKILL) + { + // die on impact + pTemp->flags &= ~FTENT_FADEOUT; + pTemp->die = client_time; + } + else + { + // Reflect velocity + if ( damp != 0 ) + { + proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); + VectorMA( pTemp->entity.baseline.origin, -proj*2, traceNormal, pTemp->entity.baseline.origin ); + // Reflect rotation (fake) + + pTemp->entity.angles[1] = -pTemp->entity.angles[1]; + } + + if ( damp != 1 ) + { + + VectorScale( pTemp->entity.baseline.origin, damp, pTemp->entity.baseline.origin ); + VectorScale( pTemp->entity.angles, 0.9, pTemp->entity.angles ); + } + } + } + } + + + if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) + { + dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); + VectorCopy (pTemp->entity.origin, dl->origin); + dl->radius = 60; + dl->color.r = 255; + dl->color.g = 120; + dl->color.b = 0; + dl->die = client_time + 0.01; + } + + if ( pTemp->flags & FTENT_SMOKETRAIL ) + { + gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); + } + + if ( pTemp->flags & FTENT_GRAVITY ) + pTemp->entity.baseline.origin[2] += gravity; + else if ( pTemp->flags & FTENT_SLOWGRAVITY ) + pTemp->entity.baseline.origin[2] += gravitySlow; + + if ( pTemp->flags & FTENT_CLIENTCUSTOM ) + { + if ( pTemp->callback ) + { + ( *pTemp->callback )( pTemp, frametime, client_time ); + } + } + + // Cull to PVS (not frustum cull, just PVS) + if ( !(pTemp->flags & FTENT_NOMODEL ) ) + { + if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) + { + if ( !(pTemp->flags & FTENT_PERSIST) ) + { + pTemp->die = client_time; // If we can't draw it this frame, just dump it. + pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die + } + } + } + } + pTemp = pnext; + } + +finish: + // Restore state info + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +================= +HUD_GetUserEntity + +If you specify negative numbers for beam start and end point entities, then + the engine will call back into this function requesting a pointer to a cl_entity_t + object that describes the entity to attach the beam onto. + +Indices must start at 1, not zero. +================= +*/ +cl_entity_t DLLEXPORT *HUD_GetUserEntity( int index ) +{ +#if defined( BEAM_TEST ) + // None by default, you would return a valic pointer if you create a client side + // beam and attach it to a client side entity. + if ( index > 0 && index <= 1 ) + { + return &beams[ index ]; + } + else + { + return NULL; + } +#else + return NULL; +#endif +} + diff --git a/cl_dll/ev_common.cpp b/cl_dll/ev_common.cpp new file mode 100644 index 00000000..224633dd --- /dev/null +++ b/cl_dll/ev_common.cpp @@ -0,0 +1,205 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// shared event functions +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" + +#include "r_efx.h" + +#include "eventscripts.h" +#include "event_api.h" +#include "pm_shared.h" + +#define IS_FIRSTPERSON_SPEC ( g_iUser1 == OBS_IN_EYE || (g_iUser1 && (gHUD.m_Spectator.m_pip->value == INSET_IN_EYE)) ) +/* +================= +GetEntity + +Return's the requested cl_entity_t +================= +*/ +struct cl_entity_s *GetEntity( int idx ) +{ + return gEngfuncs.GetEntityByIndex( idx ); +} + +/* +================= +GetViewEntity + +Return's the current weapon/view model +================= +*/ +struct cl_entity_s *GetViewEntity( void ) +{ + return gEngfuncs.GetViewModel(); +} + +/* +================= +EV_CreateTracer + +Creates a tracer effect +================= +*/ +void EV_CreateTracer( float *start, float *end ) +{ + gEngfuncs.pEfxAPI->R_TracerEffect( start, end ); +} + +/* +================= +EV_IsPlayer + +Is the entity's index in the player range? +================= +*/ +qboolean EV_IsPlayer( int idx ) +{ + if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) + return true; + + return false; +} + +/* +================= +EV_IsLocal + +Is the entity == the local player +================= +*/ +qboolean EV_IsLocal( int idx ) +{ + // check if we are in some way in first person spec mode + if ( IS_FIRSTPERSON_SPEC ) + return (g_iUser2 == idx); + else + return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; +} + +/* +================= +EV_GetGunPosition + +Figure out the height of the gun +================= +*/ +void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) +{ + int idx; + vec3_t view_ofs; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + // in spec mode use entity viewheigh, not own + if ( EV_IsLocal( idx ) && !IS_FIRSTPERSON_SPEC ) + { + // Grab predicted result for local player + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + VectorAdd( origin, view_ofs, pos ); +} + +/* +================= +EV_EjectBrass + +Bullet shell casings +================= +*/ +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ) +{ + vec3_t endpos; + VectorClear( endpos ); + endpos[1] = rotation; + gEngfuncs.pEfxAPI->R_TempModel( origin, velocity, endpos, 2.5, model, soundtype ); +} + +/* +================= +EV_GetDefaultShellInfo + +Determine where to eject shells from +================= +*/ +void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ) +{ + int i; + vec3_t view_ofs; + float fR, fU; + + int idx; + + idx = args->entindex; + + VectorClear( view_ofs ); + view_ofs[2] = DEFAULT_VIEWHEIGHT; + + if ( EV_IsPlayer( idx ) ) + { + if ( EV_IsLocal( idx ) ) + { + gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); + } + else if ( args->ducking == 1 ) + { + view_ofs[2] = VEC_DUCK_VIEW; + } + } + + fR = gEngfuncs.pfnRandomFloat( 50, 70 ); + fU = gEngfuncs.pfnRandomFloat( 100, 150 ); + + for ( i = 0; i < 3; i++ ) + { + ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; + ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; + } +} + +/* +================= +EV_MuzzleFlash + +Flag weapon/view model for muzzle flash +================= +*/ +void EV_MuzzleFlash( void ) +{ + // Add muzzle flash to current weapon model + cl_entity_t *ent = GetViewEntity(); + if ( !ent ) + { + return; + } + + // Or in the muzzle flash + ent->curstate.effects |= EF_MUZZLEFLASH; +} \ No newline at end of file diff --git a/client/global/ev_hldm.cpp b/cl_dll/ev_hldm.cpp similarity index 63% rename from client/global/ev_hldm.cpp rename to cl_dll/ev_hldm.cpp index 835f76c4..ad9ba305 100644 --- a/client/global/ev_hldm.cpp +++ b/cl_dll/ev_hldm.cpp @@ -1,29 +1,55 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// ev_common.cpp - events common code -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "r_beams.h" -#include "r_efx.h" -#include "r_particle.h" -#include "r_tempents.h" -#include "pm_materials.h" -#include "pm_movevars.h" -#include "pm_shared.h" -#include "pm_defs.h" -#include "ev_hldm.h" -#include "event_args.h" +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ #include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "entity_types.h" +#include "usercmd.h" +#include "pm_defs.h" +#include "pm_materials.h" +#include "eventscripts.h" +#include "ev_hldm.h" + +#include "r_efx.h" +#include "event_api.h" +#include "event_args.h" +#include "in_defs.h" + +#include + +#include "r_studioint.h" +#include "com_model.h" + +extern engine_studio_api_t IEngineStudio; + +static int tracerCount[ 32 ]; + +extern "C" char PM_FindTextureType( char *name ); -Vector previousorigin; // egon use this -float g_flApplyVel = 0.0f; // for gauss-jumping -static int tracerCount[32]; void V_PunchAxis( int axis, float punch ); void VectorAngles( const float *forward, float *angles ); +extern cvar_t *cl_lw; + +extern "C" +{ + +// HLDM void EV_FireGlock1( struct event_args_s *args ); void EV_FireGlock2( struct event_args_s *args ); void EV_FireShotGunSingle( struct event_args_s *args ); @@ -43,18 +69,22 @@ void EV_HornetGunFire( struct event_args_s *args ); void EV_TripmineFire( struct event_args_s *args ); void EV_SnarkFire( struct event_args_s *args ); -#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) -#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) -#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) -#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) -#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) -#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) -#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) -#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) -#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) -#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) -#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) -#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) + +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +#define VECTOR_CONE_1DEGREES Vector( 0.00873, 0.00873, 0.00873 ) +#define VECTOR_CONE_2DEGREES Vector( 0.01745, 0.01745, 0.01745 ) +#define VECTOR_CONE_3DEGREES Vector( 0.02618, 0.02618, 0.02618 ) +#define VECTOR_CONE_4DEGREES Vector( 0.03490, 0.03490, 0.03490 ) +#define VECTOR_CONE_5DEGREES Vector( 0.04362, 0.04362, 0.04362 ) +#define VECTOR_CONE_6DEGREES Vector( 0.05234, 0.05234, 0.05234 ) +#define VECTOR_CONE_7DEGREES Vector( 0.06105, 0.06105, 0.06105 ) +#define VECTOR_CONE_8DEGREES Vector( 0.06976, 0.06976, 0.06976 ) +#define VECTOR_CONE_9DEGREES Vector( 0.07846, 0.07846, 0.07846 ) +#define VECTOR_CONE_10DEGREES Vector( 0.08716, 0.08716, 0.08716 ) +#define VECTOR_CONE_15DEGREES Vector( 0.13053, 0.13053, 0.13053 ) +#define VECTOR_CONE_20DEGREES Vector( 0.17365, 0.17365, 0.17365 ) // play a strike sound based on the texture that was hit by the attack traceline. VecSrc/VecEnd are the // original traceline endpoints used by the attacker, iBulletType is the type of bullet that hit the texture. @@ -68,10 +98,10 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v char *rgsz[4]; int cnt; float fattn = ATTN_NORM; - int entity = 0; + int entity; char *pTextureName; - char texname[64]; - char szbuffer[64]; + char texname[ 64 ]; + char szbuffer[ 64 ]; entity = gEngfuncs.pEventAPI->EV_IndexFromTrace( ptr ); @@ -91,35 +121,35 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v // get texture from entity or world (world is ent(0)) pTextureName = (char *)gEngfuncs.pEventAPI->EV_TraceTexture( ptr->ent, vecSrc, vecEnd ); - if( pTextureName ) + if ( pTextureName ) { strcpy( texname, pTextureName ); pTextureName = texname; // strip leading '-0' or '+0~' or '{' or '!' - if ( *pTextureName == '-' || *pTextureName == '+' ) + if (*pTextureName == '-' || *pTextureName == '+') { pTextureName += 2; } - if ( *pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ' ) + if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') { pTextureName++; } // '}}' strcpy( szbuffer, pTextureName ); - szbuffer[CBTEXTURENAMEMAX - 1] = 0; + szbuffer[ CBTEXTURENAMEMAX - 1 ] = 0; // get texture type chTextureType = PM_FindTextureType( szbuffer ); } } - switch ( chTextureType ) + switch (chTextureType) { - case CHAR_TEX_CONCRETE: - default: fvol = 0.9; fvolbar = 0.6; + default: + case CHAR_TEX_CONCRETE: fvol = 0.9; fvolbar = 0.6; rgsz[0] = "player/pl_step1.wav"; rgsz[1] = "player/pl_step2.wav"; cnt = 2; @@ -174,8 +204,8 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v cnt = 3; break; case CHAR_TEX_FLESH: - if ( iBulletType == BULLET_PLAYER_CROWBAR ) - return 0.0f; // crowbar already makes this sound + if (iBulletType == BULLET_PLAYER_CROWBAR) + return 0.0; // crowbar already makes this sound fvol = 1.0; fvolbar = 0.2; rgsz[0] = "weapons/bullet_hit1.wav"; rgsz[1] = "weapons/bullet_hit2.wav"; @@ -185,18 +215,18 @@ float EV_HLDM_PlayTextureSound( int idx, pmtrace_t *ptr, float *vecSrc, float *v } // play material hit sound - gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[RANDOM_LONG(0, cnt-1)], fvol, fattn, 0, 96 + RANDOM_LONG( 0, 0xf )); + gEngfuncs.pEventAPI->EV_PlaySound( 0, ptr->endpos, CHAN_STATIC, rgsz[gEngfuncs.pfnRandomLong(0,cnt-1)], fvol, fattn, 0, 96 + gEngfuncs.pfnRandomLong(0,0xf) ); return fvolbar; } char *EV_HLDM_DamageDecal( physent_t *pe ) { - static char decalname[32]; + static char decalname[ 32 ]; int idx; if ( pe->classnumber == 1 ) { - idx = RANDOM_LONG( 0, 2 ); + idx = gEngfuncs.pfnRandomLong( 0, 2 ); sprintf( decalname, "{break%i", idx + 1 ); } else if ( pe->rendermode != kRenderNormal ) @@ -205,7 +235,7 @@ char *EV_HLDM_DamageDecal( physent_t *pe ) } else { - idx = RANDOM_LONG( 0, 4 ); + idx = gEngfuncs.pfnRandomLong( 0, 4 ); sprintf( decalname, "{shot%i", idx + 1 ); } return decalname; @@ -213,44 +243,34 @@ char *EV_HLDM_DamageDecal( physent_t *pe ) void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ) { - int iRand; + int iRand; physent_t *pe; - g_pParticles->BulletImpactParticles( pTrace->endpos ); + gEngfuncs.pEfxAPI->R_BulletImpactParticles( pTrace->endpos ); - iRand = RANDOM_LONG( 0, 0x7FFF ); - if ( iRand < ( 0x7fff / 2 )) // not every bullet makes a sound. + iRand = gEngfuncs.pfnRandomLong(0,0x7FFF); + if ( iRand < (0x7fff/2) )// not every bullet makes a sound. { - switch( iRand % 5 ) + switch( iRand % 5) { - case 0: - gEngfuncs.pEventAPI->EV_PlaySound( NULL, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); - break; - case 1: - gEngfuncs.pEventAPI->EV_PlaySound( NULL, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); - break; - case 2: - gEngfuncs.pEventAPI->EV_PlaySound( NULL, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); - break; - case 3: - gEngfuncs.pEventAPI->EV_PlaySound( NULL, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); - break; - case 4: - gEngfuncs.pEventAPI->EV_PlaySound( NULL, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); - break; + case 0: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric1.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 1: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric2.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 2: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric3.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 3: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric4.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; + case 4: gEngfuncs.pEventAPI->EV_PlaySound( -1, pTrace->endpos, 0, "weapons/ric5.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); break; } } pe = gEngfuncs.pEventAPI->EV_GetPhysent( pTrace->ent ); - struct model_s *mdl = pe->model; - // Only decal brush models such as the world etc. - if( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP )) + if ( decalName && decalName[0] && pe && ( pe->solid == SOLID_BSP || pe->movetype == MOVETYPE_PUSHSTEP ) ) { if ( CVAR_GET_FLOAT( "r_decals" ) ) { - g_pTempEnts->PlaceDecal( pTrace->endpos, gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), decalName ); + gEngfuncs.pEfxAPI->R_DecalShoot( + gEngfuncs.pEfxAPI->Draw_DecalIndex( gEngfuncs.pEfxAPI->Draw_DecalIndexFromName( decalName ) ), + gEngfuncs.pEventAPI->EV_IndexFromTrace( pTrace ), 0, pTrace->endpos, 0 ); } } } @@ -273,34 +293,38 @@ void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ) case BULLET_PLAYER_357: default: // smoke and decal - EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe )); + EV_HLDM_GunshotDecalTrace( pTrace, EV_HLDM_DamageDecal( pe ) ); break; } } } -int EV_HLDM_CheckTracer( int idx, Vector vecSrc, Vector end, Vector forward, Vector right, int iBulletType, int iTracerFreq, int *tracerCount ) +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ) { int tracer = 0; - BOOL player = (idx >= 1 && idx <= gEngfuncs.GetMaxClients()) ? true : false; + int i; + qboolean player = idx >= 1 && idx <= gEngfuncs.GetMaxClients() ? true : false; - if ( iTracerFreq != 0 && ( ( *tracerCount )++ % iTracerFreq ) == 0 ) + if ( iTracerFreq != 0 && ( (*tracerCount)++ % iTracerFreq) == 0 ) { - Vector vecTracerSrc; + vec3_t vecTracerSrc; if ( player ) { - Vector offset( 0, 0, -4 ); + vec3_t offset( 0, 0, -4 ); // adjust tracer position for player - vecTracerSrc = vecSrc + offset + right * 2 + forward * 16; + for ( i = 0; i < 3; i++ ) + { + vecTracerSrc[ i ] = vecSrc[ i ] + offset[ i ] + right[ i ] * 2 + forward[ i ] * 16; + } } else { - vecTracerSrc = vecSrc; + VectorCopy( vecSrc, vecTracerSrc ); } - if ( iTracerFreq != 1 ) // guns that always trace also always decal + if ( iTracerFreq != 1 ) // guns that always trace also always decal tracer = 1; switch( iBulletType ) @@ -314,9 +338,11 @@ int EV_HLDM_CheckTracer( int idx, Vector vecSrc, Vector end, Vector forward, Vec break; } } + return tracer; } + /* ================ FireBullets @@ -324,34 +350,41 @@ FireBullets Go to the trouble of combining multiple pellets into a single damage call. ================ */ -void EV_HLDM_FireBullets( int idx, Vector forward, Vector right, Vector up, int cShots, Vector vecSrc, Vector vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ) +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ) { + int i; pmtrace_t tr; int iShot; int tracer; for ( iShot = 1; iShot <= cShots; iShot++ ) { - Vector vecDir, vecEnd; + vec3_t vecDir, vecEnd; float x, y, z; - // we randomize for the Shotgun. + //We randomize for the Shotgun. if ( iBulletType == BULLET_PLAYER_BUCKSHOT ) { do { - x = RANDOM_FLOAT( -0.5f, 0.5f ) + RANDOM_FLOAT( -0.5f, 0.5f ); - y = RANDOM_FLOAT( -0.5f, 0.5f ) + RANDOM_FLOAT( -0.5f, 0.5f ); - z = x * x + y * y; - } while ( z > 1 ); + x = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); + y = gEngfuncs.pfnRandomFloat(-0.5,0.5) + gEngfuncs.pfnRandomFloat(-0.5,0.5); + z = x*x+y*y; + } while (z > 1); - vecDir = vecDirShooting + x * flSpreadX * right + y * flSpreadY * up; - vecEnd = vecSrc + flDistance * vecDir; - } + for ( i = 0 ; i < 3; i++ ) + { + vecDir[i] = vecDirShooting[i] + x * flSpreadX * right[ i ] + y * flSpreadY * up [ i ]; + vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + } + }//But other guns already have their spread randomized in the synched spread. else { - // But other guns already have their spread randomized in the synched spread. - vecDir = vecDirShooting + flSpreadX * right + flSpreadY * up; - vecEnd = vecSrc + flDistance * vecDir; + + for ( i = 0 ; i < 3; i++ ) + { + vecDir[i] = vecDirShooting[i] + flSpreadX * right[ i ] + flSpreadY * up [ i ]; + vecEnd[i] = vecSrc[ i ] + flDistance * vecDir[ i ]; + } } gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); @@ -368,16 +401,19 @@ void EV_HLDM_FireBullets( int idx, Vector forward, Vector right, Vector up, int tracer = EV_HLDM_CheckTracer( idx, vecSrc, tr.endpos, forward, right, iBulletType, iTracerFreq, tracerCount ); // do damage, paint decals - if ( tr.fraction != 1.0f ) + if ( tr.fraction != 1.0 ) { - switch( iBulletType ) + switch(iBulletType) { default: case BULLET_PLAYER_9MM: + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); EV_HLDM_DecalGunshot( &tr, iBulletType ); - break; + + break; case BULLET_PLAYER_MP5: + if ( !tracer ) { EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); @@ -385,14 +421,20 @@ void EV_HLDM_FireBullets( int idx, Vector forward, Vector right, Vector up, int } break; case BULLET_PLAYER_BUCKSHOT: + EV_HLDM_DecalGunshot( &tr, iBulletType ); + break; case BULLET_PLAYER_357: + EV_HLDM_PlayTextureSound( idx, &tr, vecSrc, vecEnd, iBulletType ); EV_HLDM_DecalGunshot( &tr, iBulletType ); + break; + } } + gEngfuncs.pEventAPI->EV_PopPMStates(); } } @@ -415,9 +457,9 @@ void EV_FireGlock1( event_args_t *args ) vec3_t up, right, forward; idx = args->entindex; - origin = args->origin; - angles = args->angles; - velocity = args->velocity; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); empty = args->bparam1; AngleVectors( angles, forward, right, up ); @@ -440,7 +482,7 @@ void EV_FireGlock1( event_args_t *args ) EV_GetGunPosition( args, vecSrc, origin ); - vecAiming = forward; + VectorCopy( forward, vecAiming ); EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, 0, args->fparam1, args->fparam2 ); } @@ -460,9 +502,9 @@ void EV_FireGlock2( event_args_t *args ) vec3_t up, right, forward; idx = args->entindex; - origin = args->origin; - angles = args->angles; - velocity = args->velocity; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); AngleVectors( angles, forward, right, up ); @@ -485,7 +527,7 @@ void EV_FireGlock2( event_args_t *args ) EV_GetGunPosition( args, vecSrc, origin ); - vecAiming = forward; + VectorCopy( forward, vecAiming ); EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_9MM, 0, &tracerCount[idx-1], args->fparam1, args->fparam2 ); @@ -514,9 +556,9 @@ void EV_FireShotGunDouble( event_args_t *args ) float flSpread = 0.01; idx = args->entindex; - origin = args->origin; - angles = args->angles; - velocity = args->velocity; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); AngleVectors( angles, forward, right, up ); @@ -540,7 +582,7 @@ void EV_FireShotGunDouble( event_args_t *args ) gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/dbarrel1.wav", gEngfuncs.pfnRandomFloat(0.98, 1.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); EV_GetGunPosition( args, vecSrc, origin ); - vecAiming = forward; + VectorCopy( forward, vecAiming ); if ( gEngfuncs.GetMaxClients() > 1 ) { @@ -568,9 +610,9 @@ void EV_FireShotGunSingle( event_args_t *args ) float flSpread = 0.01; idx = args->entindex; - origin = args->origin; - angles = args->angles; - velocity = args->velocity; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); AngleVectors( angles, forward, right, up ); @@ -592,7 +634,7 @@ void EV_FireShotGunSingle( event_args_t *args ) gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/sbarrel1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); EV_GetGunPosition( args, vecSrc, origin ); - vecAiming = forward; + VectorCopy( forward, vecAiming ); if ( gEngfuncs.GetMaxClients() > 1 ) { @@ -625,9 +667,9 @@ void EV_FireMP5( event_args_t *args ) float flSpread = 0.01; idx = args->entindex; - origin = args->origin; - angles = args->angles; - velocity = args->velocity; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); AngleVectors( angles, forward, right, up ); @@ -657,7 +699,7 @@ void EV_FireMP5( event_args_t *args ) } EV_GetGunPosition( args, vecSrc, origin ); - vecAiming = forward; + VectorCopy( forward, vecAiming ); if ( gEngfuncs.GetMaxClients() > 1 ) { @@ -677,7 +719,7 @@ void EV_FireMP52( event_args_t *args ) vec3_t origin; idx = args->entindex; - origin = args->origin; + VectorCopy( args->origin, origin ); if ( EV_IsLocal( idx ) ) { @@ -715,9 +757,9 @@ void EV_FirePython( event_args_t *args ) float flSpread = 0.01; idx = args->entindex; - origin = args->origin; - angles = args->angles; - velocity = args->velocity; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); AngleVectors( angles, forward, right, up ); @@ -745,7 +787,7 @@ void EV_FirePython( event_args_t *args ) EV_GetGunPosition( args, vecSrc, origin ); - vecAiming = forward; + VectorCopy( forward, vecAiming ); EV_HLDM_FireBullets( idx, forward, right, up, 1, vecSrc, vecAiming, 8192, BULLET_PLAYER_357, 0, 0, args->fparam1, args->fparam2 ); } @@ -757,9 +799,7 @@ void EV_FirePython( event_args_t *args ) //====================== // GAUSS START //====================== -#define GAUSS_PRIMARY_CHARGE_VOLUME 256 // how loud gauss is while charging -#define GAUSS_PRIMARY_FIRE_VOLUME 450 // how loud gauss is when discharged -#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch +#define SND_CHANGE_PITCH (1<<7) // duplicated in protocol.h change sound pitch void EV_SpinGauss( event_args_t *args ) { @@ -772,23 +812,15 @@ void EV_SpinGauss( event_args_t *args ) int pitch; idx = args->entindex; - origin = args->origin; - angles = args->angles; - velocity = args->velocity; + 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, "ambience/pulsemachine.wav", 1.0, ATTN_NORM, iSoundState, pitch ); - - if( EV_IsLocal( idx )) - { - cl_entity_t *view = GetViewModel(); - - // change framerate up from 1.0 to 2.5x - view->curstate.framerate = (float)pitch / PITCH_NORM; - } } /* @@ -804,6 +836,8 @@ void EV_StopPreviousGauss( int idx ) gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_WEAPON, "ambience/pulsemachine.wav" ); } +extern float g_flApplyVel; + void EV_FireGauss( event_args_t *args ) { int idx; @@ -815,23 +849,23 @@ void EV_FireGauss( event_args_t *args ) int m_fPrimaryFire = args->bparam1; int m_iWeaponVolume = GAUSS_PRIMARY_FIRE_VOLUME; - Vector vecSrc, vecDest; - - cl_entity_t *pentIgnore; + vec3_t vecSrc; + vec3_t vecDest; + edict_t *pentIgnore; pmtrace_t tr, beam_tr; float flMaxFrac = 1.0; - int nTotal = 0; + int nTotal = 0; int fHasPunched = 0; int fFirstBeam = 1; - int nMaxHits = 10; + int nMaxHits = 10; physent_t *pEntity; int m_iBeam, m_iGlow, m_iBalls; - Vector forward; + vec3_t up, right, forward; idx = args->entindex; - origin = args->origin; - angles = args->angles; - velocity = args->velocity; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); + VectorCopy( args->velocity, velocity ); if ( args->bparam2 ) { @@ -839,29 +873,29 @@ void EV_FireGauss( event_args_t *args ) return; } -// gEngfuncs.Con_Printf( "firing gauss with %f\n", flDamage ); +// Con_Printf( "Firing gauss with %f\n", flDamage ); EV_GetGunPosition( args, vecSrc, origin ); m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/smoke.spr" ); m_iBalls = m_iGlow = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hotglow.spr" ); - AngleVectors( angles, forward, NULL, NULL ); - - vecDest = vecSrc + forward * 8192; - + AngleVectors( angles, forward, right, up ); + + VectorMA( vecSrc, 8192, forward, vecDest ); + if ( EV_IsLocal( idx ) ) { V_PunchAxis( 0, -2.0 ); gEngfuncs.pEventAPI->EV_WeaponAnimation( GAUSS_FIRE2, 2 ); if ( m_fPrimaryFire == false ) - g_flApplyVel = flDamage; - + g_flApplyVel = flDamage; + } - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + RANDOM_LONG( 0, 0x1f ) ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/gauss2.wav", 0.5 + flDamage * (1.0 / 400.0), ATTN_NORM, 0, 85 + gEngfuncs.pfnRandomLong( 0, 0x1f ) ); - while (flDamage > 10 && nMaxHits > 0 ) + while (flDamage > 10 && nMaxHits > 0) { nMaxHits--; @@ -877,7 +911,7 @@ void EV_FireGauss( event_args_t *args ) gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecDest, PM_STUDIO_BOX, -1, &tr ); gEngfuncs.pEventAPI->EV_PopPMStates(); - + if ( tr.allsolid ) break; @@ -890,9 +924,10 @@ void EV_FireGauss( event_args_t *args ) } fFirstBeam = 0; - g_pViewRenderBeams->CreateBeamEntPoint( + gEngfuncs.pEfxAPI->R_BeamEntPoint( idx | 0x1000, - tr.endpos, m_iBeam, + tr.endpos, + m_iBeam, 0.1, m_fPrimaryFire ? 1.0 : 2.5, 0.0, @@ -900,25 +935,24 @@ void EV_FireGauss( event_args_t *args ) 0, 0, 0, - m_fPrimaryFire ? 255 : 255, // g-cont. ??? + m_fPrimaryFire ? 255 : 255, m_fPrimaryFire ? 128 : 255, m_fPrimaryFire ? 0 : 255 ); } else { - g_pViewRenderBeams->CreateBeamPoints( - vecSrc, + gEngfuncs.pEfxAPI->R_BeamPoints( vecSrc, tr.endpos, m_iBeam, 0.1, m_fPrimaryFire ? 1.0 : 2.5, - 0.0f, + 0.0, m_fPrimaryFire ? 128.0 : flDamage, 0, 0, 0, - m_fPrimaryFire ? 255 : 255, // g-cont. ??? + m_fPrimaryFire ? 255 : 255, m_fPrimaryFire ? 128 : 255, m_fPrimaryFire ? 0 : 255 ); @@ -927,7 +961,7 @@ void EV_FireGauss( event_args_t *args ) pEntity = gEngfuncs.pEventAPI->EV_GetPhysent( tr.ent ); if ( pEntity == NULL ) break; - + if ( pEntity->solid == SOLID_BSP ) { float n; @@ -936,33 +970,33 @@ void EV_FireGauss( event_args_t *args ) n = -DotProduct( tr.plane.normal, forward ); - if ( n < 0.5f ) // 60 degrees + if (n < 0.5) // 60 degrees { - // gEngfuncs.Con_Printf( "reflect %f\n", n ); + // ALERT( at_console, "reflect %f\n", n ); // reflect - Vector r; + vec3_t r; - r = forward + ( tr.plane.normal * (2.0f * n )); + VectorMA( forward, 2.0 * n, tr.plane.normal, r ); flMaxFrac = flMaxFrac - tr.fraction; - forward = r; + VectorCopy( r, forward ); - vecSrc = tr.endpos + forward * 8.0f; - vecDest = vecSrc + forward * 8192.0f; + VectorMA( tr.endpos, 8.0, forward, vecSrc ); + VectorMA( vecSrc, 8192.0, forward, vecDest ); - g_pTempEnts->TempSprite( tr.endpos, g_vecZero, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT ); - - Vector fwd; - fwd = tr.endpos + tr.plane.normal; + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage * n / 255.0, flDamage * n * 0.5 * 0.1, FTENT_FADEOUT ); + + vec3_t fwd; + VectorAdd( tr.endpos, tr.plane.normal, fwd ); + + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, + 255, 100 ); - g_pTempEnts->Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, RANDOM_FLOAT( 10, 20 ) / 100.0, 100, - 255, 100 ); - // lose energy if ( n == 0 ) { - n = 0.1f; + n = 0.1; } flDamage = flDamage * (1 - n); @@ -973,7 +1007,7 @@ void EV_FireGauss( event_args_t *args ) // tunnel EV_HLDM_DecalGunshot( &tr, BULLET_MONSTER_12MM ); - g_pTempEnts->TempSprite( tr.endpos, g_vecZero, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 1.0, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); // limit it to one hole punch if (fHasPunched) @@ -985,9 +1019,9 @@ void EV_FireGauss( event_args_t *args ) // try punching through wall if secondary attack (primary is incapable of breaking through) if ( !m_fPrimaryFire ) { - Vector start; - - start = tr.endpos + forward * 8.0f; + vec3_t start; + + VectorMA( tr.endpos, 8.0, forward, start ); // Store off the old count gEngfuncs.pEventAPI->EV_PushPMStates(); @@ -996,22 +1030,22 @@ void EV_FireGauss( event_args_t *args ) gEngfuncs.pEventAPI->EV_SetSolidPlayers ( idx - 1 ); gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); + gEngfuncs.pEventAPI->EV_PlayerTrace( start, vecDest, PM_STUDIO_BOX, -1, &beam_tr ); if ( !beam_tr.allsolid ) { - Vector delta; + vec3_t delta; float n; // trace backwards to find exit point gEngfuncs.pEventAPI->EV_PlayerTrace( beam_tr.endpos, tr.endpos, PM_STUDIO_BOX, -1, &beam_tr ); - delta = beam_tr.endpos - tr.endpos; + VectorSubtract( beam_tr.endpos, tr.endpos, delta ); - n = delta.Length(); + n = Length( delta ); - if ( n < flDamage ) + if (n < flDamage) { if (n == 0) n = 1; @@ -1019,28 +1053,35 @@ void EV_FireGauss( event_args_t *args ) // absorption balls { - Vector fwd = tr.endpos - forward; - g_pTempEnts->Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, RANDOM_FLOAT( 10, 20 ) / 100.0, 100, + vec3_t fwd; + VectorSubtract( tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 3, 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 100, 255, 100 ); } + //////////////////////////////////// WHAT TO DO HERE + // CSoundEnt::InsertSound ( bits_SOUND_COMBAT, pev->origin, NORMAL_EXPLOSION_VOLUME, 3.0 ); + EV_HLDM_DecalGunshot( &beam_tr, BULLET_MONSTER_12MM ); - g_pTempEnts->TempSprite( beam_tr.endpos, g_vecZero, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); + gEngfuncs.pEfxAPI->R_TempSprite( beam_tr.endpos, vec3_origin, 0.1, m_iGlow, kRenderGlow, kRenderFxNoDissipation, flDamage / 255.0, 6.0, FTENT_FADEOUT ); // balls { - Vector fwd = beam_tr.endpos - forward; - g_pTempEnts->Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, RANDOM_FLOAT( 10, 20 ) / 100.0, 200, 255, 40 ); + vec3_t fwd; + VectorSubtract( beam_tr.endpos, forward, fwd ); + gEngfuncs.pEfxAPI->R_Sprite_Trail( TE_SPRITETRAIL, beam_tr.endpos, fwd, m_iBalls, (int)(flDamage * 0.3), 0.1, gEngfuncs.pfnRandomFloat( 10, 20 ) / 100.0, 200, + 255, 40 ); } - vecSrc = beam_tr.endpos + forward; + VectorAdd( beam_tr.endpos, forward, vecSrc ); } } else { flDamage = 0; } + gEngfuncs.pEventAPI->EV_PopPMStates(); } else @@ -1049,12 +1090,12 @@ void EV_FireGauss( event_args_t *args ) { // slug doesn't punch through ever with primary // fire, so leave a little glowy bit and make some balls - g_pTempEnts->TempSprite( tr.endpos, g_vecZero, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); - + gEngfuncs.pEfxAPI->R_TempSprite( tr.endpos, vec3_origin, 0.2, m_iGlow, kRenderGlow, kRenderFxNoDissipation, 200.0 / 255.0, 0.3, FTENT_FADEOUT ); + { - Vector fwd; - fwd = tr.endpos + tr.plane.normal; - g_pTempEnts->Sprite_Trail( TE_SPRITETRAIL, tr.endpos, fwd, m_iBalls, 8, 0.6, RANDOM_FLOAT( 10, 20 ) / 100.0, 100, + 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 ); } } @@ -1065,7 +1106,7 @@ void EV_FireGauss( event_args_t *args ) } else { - vecSrc = tr.endpos + forward; + VectorAdd( tr.endpos, forward, vecSrc ); } } } @@ -1076,6 +1117,19 @@ void EV_FireGauss( event_args_t *args ) //====================== // CROWBAR START //====================== + +enum crowbar_e { + CROWBAR_IDLE = 0, + CROWBAR_DRAW, + CROWBAR_HOLSTER, + CROWBAR_ATTACK1HIT, + CROWBAR_ATTACK1MISS, + CROWBAR_ATTACK2MISS, + CROWBAR_ATTACK2HIT, + CROWBAR_ATTACK3MISS, + CROWBAR_ATTACK3HIT +}; + int g_iSwing; //Only predict the miss sounds, hit sounds are still played @@ -1088,7 +1142,7 @@ void EV_Crowbar( event_args_t *args ) vec3_t velocity; idx = args->entindex; - origin = args->origin; + VectorCopy( args->origin, origin ); //Play Swing sound gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/cbar_miss1.wav", 1, ATTN_NORM, 0, PITCH_NORM); @@ -1115,12 +1169,27 @@ void EV_Crowbar( event_args_t *args ) //====================== // CROSSBOW START //====================== +enum crossbow_e { + CROSSBOW_IDLE1 = 0, // full + CROSSBOW_IDLE2, // empty + CROSSBOW_FIDGET1, // full + CROSSBOW_FIDGET2, // empty + CROSSBOW_FIRE1, // full + CROSSBOW_FIRE2, // reload + CROSSBOW_FIRE3, // empty + CROSSBOW_RELOAD, // from empty + CROSSBOW_DRAW1, // full + CROSSBOW_DRAW2, // empty + CROSSBOW_HOLSTER1, // full + CROSSBOW_HOLSTER2, // empty +}; + //===================== // EV_BoltCallback // This function is used to correct the origin and angles // of the bolt, so it looks like it's stuck on the wall. //===================== -void EV_BoltCallback ( struct tent_s *ent, float frametime, float currenttime ) +void EV_BoltCallback ( struct tempent_s *ent, float frametime, float currenttime ) { ent->entity.origin = ent->entity.baseline.vuser1; ent->entity.angles = ent->entity.baseline.vuser2; @@ -1138,16 +1207,16 @@ void EV_FireCrossbow2( event_args_t *args ) vec3_t velocity; idx = args->entindex; - origin = args->origin; - angles = args->angles; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); - velocity = args->velocity; + VectorCopy( args->velocity, velocity ); AngleVectors( angles, forward, right, up ); EV_GetGunPosition( args, vecSrc, origin ); - vecEnd = vecSrc + forward * 8192.0f; + VectorMA( vecSrc, 8192, forward, vecEnd ); gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); @@ -1191,14 +1260,14 @@ void EV_FireCrossbow2( event_args_t *args ) //Not underwater, do some sparks... if ( gEngfuncs.PM_PointContents( tr.endpos, NULL ) != CONTENTS_WATER) - g_pTempEnts->SparkShower( tr.endpos ); + gEngfuncs.pEfxAPI->R_SparkShower( tr.endpos ); vec3_t vBoltAngles; int iModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "models/crossbow_bolt.mdl" ); VectorAngles( forward, vBoltAngles ); - TENT *bolt = g_pTempEnts->TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); + TEMPENTITY *bolt = gEngfuncs.pEfxAPI->R_TempModel( tr.endpos - forward * 10, Vector( 0, 0, 0), vBoltAngles , 5, iModelIndex, TE_BOUNCE_NULL ); if ( bolt ) { @@ -1213,14 +1282,14 @@ void EV_FireCrossbow2( event_args_t *args ) gEngfuncs.pEventAPI->EV_PopPMStates(); } -// TODO: Fully predict the fliying bolt. +//TODO: Fully predict the fliying bolt. void EV_FireCrossbow( event_args_t *args ) { int idx; vec3_t origin; idx = args->entindex; - origin = args->origin; + VectorCopy( args->origin, origin ); gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/xbow_fire1.wav", 1, ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/xbow_reload1.wav", gEngfuncs.pfnRandomFloat(0.95, 1.0), ATTN_NORM, 0, 93 + gEngfuncs.pfnRandomLong(0,0xF) ); @@ -1243,13 +1312,26 @@ void EV_FireCrossbow( event_args_t *args ) //====================== // RPG START //====================== +enum rpg_e { + RPG_IDLE = 0, + RPG_FIDGET, + RPG_RELOAD, // to reload + RPG_FIRE2, // to empty + RPG_HOLSTER1, // loaded + RPG_DRAW1, // loaded + RPG_HOLSTER2, // unloaded + RPG_DRAW_UL, // unloaded + RPG_IDLE_UL, // unloaded idle + RPG_FIDGET_UL, // unloaded fidget +}; + void EV_FireRpg( event_args_t *args ) { int idx; vec3_t origin; idx = args->entindex; - origin = args->origin; + VectorCopy( args->origin, origin ); gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, "weapons/rocketfire1.wav", 0.9, ATTN_NORM, 0, PITCH_NORM ); gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_ITEM, "weapons/glauncher.wav", 0.7, ATTN_NORM, 0, PITCH_NORM ); @@ -1267,27 +1349,39 @@ void EV_FireRpg( event_args_t *args ) //====================== //====================== -// EGON START +// EGON END //====================== +enum egon_e { + EGON_IDLE1 = 0, + EGON_FIDGET1, + EGON_ALTFIREON, + EGON_ALTFIRECYCLE, + EGON_ALTFIREOFF, + EGON_FIRE1, + EGON_FIRE2, + EGON_FIRE3, + EGON_FIRE4, + EGON_DRAW, + EGON_HOLSTER +}; + int g_fireAnims1[] = { EGON_FIRE1, EGON_FIRE2, EGON_FIRE3, EGON_FIRE4 }; int g_fireAnims2[] = { EGON_ALTFIRECYCLE }; -enum EGON_FIRESTATE { FIRE_OFF = 0, FIRE_CHARGE }; -enum EGON_FIREMODE { FIRE_NARROW = 0, FIRE_WIDE }; +enum EGON_FIRESTATE { FIRE_OFF, FIRE_CHARGE }; +enum EGON_FIREMODE { FIRE_NARROW, FIRE_WIDE}; -#define EGON_PULSE_INTERVAL 0.1 -#define EGON_DISCHARGE_INTERVAL 0.1 -#define EGON_PRIMARY_VOLUME 450 +#define EGON_PRIMARY_VOLUME 450 #define EGON_BEAM_SPRITE "sprites/xbeam1.spr" #define EGON_FLARE_SPRITE "sprites/XSpark1.spr" -#define EGON_SOUND_OFF "weapons/egon_off1.wav" -#define EGON_SOUND_RUN "weapons/egon_run3.wav" +#define EGON_SOUND_OFF "weapons/egon_off1.wav" +#define EGON_SOUND_RUN "weapons/egon_run3.wav" #define EGON_SOUND_STARTUP "weapons/egon_windup2.wav" -Beam_t *m_pBeam = NULL; -Beam_t *m_pNoise = NULL; +#define ARRAYSIZE(p) (sizeof(p)/sizeof(p[0])) -TENT *m_pEndFlare = NULL; +BEAM *pBeam; +BEAM *pBeam2; void EV_EgonFire( event_args_t *args ) { @@ -1295,51 +1389,53 @@ void EV_EgonFire( event_args_t *args ) vec3_t origin; idx = args->entindex; - origin = args->origin; + VectorCopy( args->origin, origin ); iFireState = args->iparam1; iFireMode = args->iparam2; int iStartup = args->bparam1; - int m_iFlare = gEngfuncs.pEventAPI->EV_FindModelIndex( EGON_FLARE_SPRITE ); + if ( iStartup ) { if ( iFireMode == FIRE_WIDE ) - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98f, ATTN_NORM, 0, 125 ); - else gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9f, ATTN_NORM, 0, 100 ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.98, ATTN_NORM, 0, 125 ); + else + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_WEAPON, EGON_SOUND_STARTUP, 0.9, ATTN_NORM, 0, 100 ); } else { if ( iFireMode == FIRE_WIDE ) - gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98f, ATTN_NORM, 0, 125 ); - else gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9f, ATTN_NORM, 0, 100 ); + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.98, ATTN_NORM, 0, 125 ); + else + gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, EGON_SOUND_RUN, 0.9, ATTN_NORM, 0, 100 ); } - // Only play the weapon anims if I shot it. + //Only play the weapon anims if I shot it. if ( EV_IsLocal( idx ) ) gEngfuncs.pEventAPI->EV_WeaponAnimation ( g_fireAnims1[ gEngfuncs.pfnRandomLong( 0, 3 ) ], 1 ); - if ( iStartup == 1 && EV_IsLocal( idx ) && !m_pBeam && !m_pNoise && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. + if ( iStartup == 1 && EV_IsLocal( idx ) && !pBeam && !pBeam2 && cl_lw->value ) //Adrian: Added the cl_lw check for those lital people that hate weapon prediction. { - Vector vecSrc, vecEnd, origin, angles, forward; + vec3_t vecSrc, vecEnd, origin, angles, forward, right, up; pmtrace_t tr; - cl_entity_t *pl = GetEntityByIndex( idx ); + cl_entity_t *pl = gEngfuncs.GetEntityByIndex( idx ); if ( pl ) { - angles = gHUD.m_vecAngles; - - AngleVectors( angles, forward, NULL, NULL ); + VectorCopy( gHUD.m_vecAngles, angles ); + + AngleVectors( angles, forward, right, up ); EV_GetGunPosition( args, vecSrc, pl->origin ); - - vecEnd = vecSrc + forward * 2048; - + + VectorMA( vecSrc, 2048, forward, vecEnd ); + 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 ); @@ -1350,72 +1446,23 @@ void EV_EgonFire( event_args_t *args ) int iBeamModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( EGON_BEAM_SPRITE ); - float r = 0.5f; // g-cont. skip check for IEngineStudio.isHardware() - float g = 0.5f; + float r = 50.0f; + float g = 50.0f; float b = 125.0f; - - if ( iFireMode == FIRE_WIDE ) + + if ( IEngineStudio.IsHardware() ) { - m_pBeam = g_pViewRenderBeams->CreateBeamEntPoint( - idx | 0x1000, // end entity & attachment - tr.endpos, // start pos (sic!) - iBeamModelIndex, // beamSprite - 99999, // life - 4.0, // width - 2.0, // amplitude (noise) - 100, // brightness - 55, // scrollSpeed - 0, // startframe - 0, // framerate - r, g, b ); // color - - if ( m_pBeam ) m_pBeam->SetFlags( FBEAM_SINENOISE ); - - m_pNoise = g_pViewRenderBeams->CreateBeamEntPoint( - idx | 0x1000, // end entity & attachment - tr.endpos, // start pos (sic!) - iBeamModelIndex, // beamSprite - 99999, // life - 5.5, // width - 0.08, // amplitude (noise) - 100, // brightness - 2.5, // scrollSpeed - 0, // startframe - 0, // framerate - 50, 50, 255 ); // color + r /= 100.0f; + g /= 100.0f; } - else - { - m_pBeam = g_pViewRenderBeams->CreateBeamEntPoint( - idx | 0x1000, // end entity & attachment - tr.endpos, // start pos (sic!) - iBeamModelIndex, // beamSprite - 99999, // life - 1.5, // width - 0.5, // amplitude (noise) - 100, // brightness - 5.5, // scrollSpeed - 0, // startframe - 0, // framerate - r, g, b ); // color + + + pBeam = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 3.5, 0.2, 0.7, 55, 0, 0, r, g, b ); - if ( m_pBeam ) m_pBeam->SetFlags( FBEAM_SINENOISE ); - - m_pNoise = g_pViewRenderBeams->CreateBeamEntPoint( - idx | 0x1000, // end entity & attachment - tr.endpos, // start pos (sic!) - iBeamModelIndex, // beamSprite - 99999, // life - 5.5, // width - 0.2, // amplitude (noise) - 100, // brightness - 2.5, // scrollSpeed - 0, // startframe - 0, // framerate - 80, 120, 255 ); // color - } - - m_pEndFlare = g_pTempEnts->TempSprite( tr.endpos, g_vecZero, 1.0, m_iFlare, kRenderGlow, kRenderFxNoDissipation, 1.0, 9999, FTENT_SPRCYCLE ); + if ( pBeam ) + pBeam->flags |= ( FBEAM_SINENOISE ); + + pBeam2 = gEngfuncs.pEfxAPI->R_BeamEntPoint ( idx | 0x1000, tr.endpos, iBeamModelIndex, 99999, 5.0, 0.08, 0.7, 25, 0, 0, r, g, b ); } } } @@ -1426,7 +1473,7 @@ void EV_EgonStop( event_args_t *args ) vec3_t origin; idx = args->entindex; - origin = args->origin; + VectorCopy ( args->origin, origin ); gEngfuncs.pEventAPI->EV_StopSound( idx, CHAN_STATIC, EGON_SOUND_RUN ); @@ -1435,119 +1482,18 @@ void EV_EgonStop( event_args_t *args ) if ( EV_IsLocal( idx ) ) { - int iFireMode = args->iparam2; - - if ( m_pBeam ) + if ( pBeam ) { - m_pBeam->die = 0.0f; - m_pBeam = NULL; + pBeam->die = 0.0; + pBeam = NULL; } - - if ( m_pNoise ) + + + if ( pBeam2 ) { - m_pNoise->die = 0.0f; - m_pNoise = NULL; + pBeam2->die = 0.0; + pBeam2 = NULL; } - - if ( m_pEndFlare ) - { - if ( iFireMode == FIRE_WIDE ) - { - // m_pSprite->Expand( 10, 500 ); - m_pEndFlare->flags = FTENT_SCALE|FTENT_FADEOUT; - m_pEndFlare->fadeSpeed = 3.0f; - } - else - { - // UTIL_Remove( m_pSprite ); - m_pEndFlare->die = 0.0f; - } - m_pEndFlare = NULL; - } - - // g-cont. to prevent cyclyc playing fire anims - gEngfuncs.pEventAPI->EV_WeaponAnimation( EGON_IDLE1, 1 ); - } -} - -void EV_UpdateBeams ( void ) -{ - if ( !m_pBeam && !m_pNoise ) return; - - Vector forward, vecSrc, vecEnd, origin, angles; - pmtrace_t tr; - float timedist; - - cl_entity_t *pthisplayer = GetLocalPlayer(); - int idx = pthisplayer->index; - - // Get our exact viewangles from engine - GetViewAngles( angles ); - - origin = previousorigin; // HUD_GetLastOrg - - AngleVectors( angles, forward, NULL, NULL ); - - vecSrc = origin; - - vecEnd = vecSrc + forward * 2048; - - 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, vecEnd, PM_STUDIO_BOX, -1, &tr ); - - gEngfuncs.pEventAPI->EV_PopPMStates(); - - // HACKHACK: extract firemode from beamWidth - int iFireMode = ( m_pBeam->width == 4.0 ) ? FIRE_WIDE : FIRE_NARROW; - - // calc timedelta for beam effects - switch( iFireMode ) - { - case FIRE_NARROW: - if ( m_pBeam->m_flDmgTime < GetClientTime() ) - { - m_pBeam->m_flDmgTime = GetClientTime() + EGON_PULSE_INTERVAL; - } - timedist = ( m_pBeam->m_flDmgTime - GetClientTime() ) / EGON_DISCHARGE_INTERVAL; - break; - case FIRE_WIDE: - if ( m_pBeam->m_flDmgTime < GetClientTime() ) - { - m_pBeam->m_flDmgTime = GetClientTime() + EGON_PULSE_INTERVAL; - } - timedist = ( m_pBeam->m_flDmgTime - GetClientTime() ) / EGON_DISCHARGE_INTERVAL; - break; - } - - // clamp and inverse - timedist = bound( 0.0f, timedist, 1.0f ); - timedist = 1.0f - timedist; - - m_pBeam->SetEndPos( tr.endpos ); - m_pBeam->SetBrightness( 255 - ( timedist * 180 )); - m_pBeam->SetWidth( 40 - ( timedist * 20 )); - m_pBeam->die = GetClientTime() + 0.1f; // We keep it alive just a little bit forward in the future, just in case. - - if ( iFireMode == FIRE_WIDE ) - m_pBeam->SetColor( 30 + (25 * timedist), 30 + (30 * timedist), 64 + 80 * fabs( sin( GetClientTime() * 10 ))); - else - m_pBeam->SetColor( 60 + (25 * timedist), 120 + (30 * timedist), 64 + 80 * fabs( sin( GetClientTime() * 10 ))); - - m_pNoise->SetEndPos( tr.endpos ); - m_pNoise->die = GetClientTime() + 0.1f; // We keep it alive just a little bit forward in the future, just in case. - - if( m_pEndFlare ) - { - m_pEndFlare->entity.origin = tr.endpos; - m_pEndFlare->die = GetClientTime() + 0.1f; } } //====================== @@ -1557,14 +1503,23 @@ void EV_UpdateBeams ( void ) //====================== // HORNET START //====================== +enum hgun_e { + HGUN_IDLE1 = 0, + HGUN_FIDGETSWAY, + HGUN_FIDGETSHAKE, + HGUN_DOWN, + HGUN_UP, + HGUN_SHOOT +}; + void EV_HornetGunFire( event_args_t *args ) { int idx, iFireMode; vec3_t origin, angles, vecSrc, forward, right, up; idx = args->entindex; - origin = args->origin; - angles = args->angles; + VectorCopy( args->origin, origin ); + VectorCopy( args->angles, angles ); iFireMode = args->iparam1; //Only play the weapon anims if I shot it. @@ -1588,6 +1543,18 @@ void EV_HornetGunFire( event_args_t *args ) //====================== // TRIPMINE START //====================== +enum tripmine_e { + TRIPMINE_IDLE1 = 0, + TRIPMINE_IDLE2, + TRIPMINE_ARM1, + TRIPMINE_ARM2, + TRIPMINE_FIDGET, + TRIPMINE_HOLSTER, + TRIPMINE_DRAW, + TRIPMINE_WORLD, + TRIPMINE_GROUND, +}; + //We only check if it's possible to put a trip mine //and if it is, then we play the animation. Server still places it. void EV_TripmineFire( event_args_t *args ) @@ -1597,8 +1564,8 @@ void EV_TripmineFire( event_args_t *args ) pmtrace_t tr; idx = args->entindex; - vecSrc = args->origin; - angles = args->angles; + VectorCopy( args->origin, vecSrc ); + VectorCopy( args->angles, angles ); AngleVectors ( angles, forward, NULL, NULL ); @@ -1618,7 +1585,7 @@ void EV_TripmineFire( event_args_t *args ) gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecSrc + forward * 128, PM_NORMAL, -1, &tr ); - // Hit something solid + //Hit something solid if ( tr.fraction < 1.0 ) gEngfuncs.pEventAPI->EV_WeaponAnimation ( TRIPMINE_DRAW, 0 ); @@ -1631,6 +1598,18 @@ void EV_TripmineFire( event_args_t *args ) //====================== // SQUEAK START //====================== +enum squeak_e { + SQUEAK_IDLE1 = 0, + SQUEAK_FIDGETFIT, + SQUEAK_FIDGETNIP, + SQUEAK_DOWN, + SQUEAK_UP, + SQUEAK_THROW +}; + +#define VEC_HULL_MIN Vector(-16, -16, -36) +#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) + void EV_SnarkFire( event_args_t *args ) { int idx; @@ -1638,8 +1617,8 @@ void EV_SnarkFire( event_args_t *args ) pmtrace_t tr; idx = args->entindex; - vecSrc = args->origin; - angles = args->angles; + VectorCopy( args->origin, vecSrc ); + VectorCopy( args->angles, angles ); AngleVectors ( angles, forward, NULL, NULL ); @@ -1667,81 +1646,6 @@ void EV_SnarkFire( event_args_t *args ) // SQUEAK END //====================== - -//====================== -// LASERSPOT START -//====================== -TENT *m_pLaserSpot = NULL; - -void EV_UpdateLaserSpot( void ) -{ - cl_entity_t *m_pPlayer = GetLocalPlayer(); - cl_entity_t *m_pWeapon = GetViewModel(); - - if( !m_pPlayer ) return; - - if( m_pPlayer->curstate.effects & EF_LASERSPOT && !m_pLaserSpot && cl_lw->value ) - { - // create laserspot - int m_iSpotModel = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/laserdot.spr" ); - - m_pLaserSpot = g_pTempEnts->TempSprite( g_vecZero, g_vecZero, 1.0, m_iSpotModel, kRenderGlow, kRenderFxNoDissipation, 1.0, 9999, FTENT_SPRCYCLE ); - if( !m_pLaserSpot ) return; - - m_pLaserSpot->entity.baseline.rendercolor.r = 200; - m_pLaserSpot->entity.baseline.rendercolor.g = 12; - m_pLaserSpot->entity.baseline.rendercolor.b = 12; -// gEngfuncs.Con_Printf( "CLaserSpot::Create()\n" ); - } - else if( !( m_pPlayer->curstate.effects & EF_LASERSPOT ) && m_pLaserSpot ) - { - // destroy laserspot -// gEngfuncs.Con_Printf( "CLaserSpot::Killed()\n" ); - m_pLaserSpot->die = 0.0f; - m_pLaserSpot = NULL; - return; - } - else if( !m_pLaserSpot ) - { - // inactive - return; - } - - ASSERT( m_pLaserSpot != NULL ); - - Vector forward, vecSrc, vecEnd, origin, angles; - pmtrace_t tr; - -#if 1 - GetViewAngles( angles ); // viewmodel doesn't have attachment - origin = m_pWeapon->origin; -#else - // TEST: give viewmodel first attachment - origin = m_pWeapon->origin + pEnt->attachment_origin[0]; - angles = pEnt->attachment_angles[0]; // already include viewmodel angles -#endif - AngleVectors( angles, forward, NULL, NULL ); - - vecSrc = origin; - vecEnd = vecSrc + forward * 8192; - - gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); - gEngfuncs.pEventAPI->EV_PushPMStates(); - gEngfuncs.pEventAPI->EV_SetSolidPlayers ( m_pPlayer->index - 1 ); - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecSrc, vecEnd, PM_STUDIO_BOX, -1, &tr ); - gEngfuncs.pEventAPI->EV_PopPMStates(); - - // update laserspot endpos - m_pLaserSpot->entity.origin = tr.endpos; - m_pLaserSpot->die = GetClientTime() + 0.1f; -} -//====================== -// LASERSPOT END -//====================== - - void EV_TrainPitchAdjust( event_args_t *args ) { int idx; @@ -1757,7 +1661,7 @@ void EV_TrainPitchAdjust( event_args_t *args ) idx = args->entindex; - origin = args->origin; + VectorCopy( args->origin, origin ); us_params = (unsigned short)args->iparam1; stop = args->bparam1; @@ -1788,4 +1692,9 @@ void EV_TrainPitchAdjust( event_args_t *args ) { gEngfuncs.pEventAPI->EV_PlaySound( idx, origin, CHAN_STATIC, sz, m_flVolume, ATTN_NORM, SND_CHANGE_PITCH, pitch ); } +} + +int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ) +{ + return 0; } \ No newline at end of file diff --git a/cl_dll/ev_hldm.h b/cl_dll/ev_hldm.h new file mode 100644 index 00000000..567e6877 --- /dev/null +++ b/cl_dll/ev_hldm.h @@ -0,0 +1,95 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( EV_HLDMH ) +#define EV_HLDMH + +// bullet types +typedef enum +{ + BULLET_NONE = 0, + BULLET_PLAYER_9MM, // glock + BULLET_PLAYER_MP5, // mp5 + BULLET_PLAYER_357, // python + BULLET_PLAYER_BUCKSHOT, // shotgun + BULLET_PLAYER_CROWBAR, // crowbar swipe + + BULLET_MONSTER_9MM, + BULLET_MONSTER_MP5, + BULLET_MONSTER_12MM, +} Bullet; + +enum glock_e { + GLOCK_IDLE1 = 0, + GLOCK_IDLE2, + GLOCK_IDLE3, + GLOCK_SHOOT, + GLOCK_SHOOT_EMPTY, + GLOCK_RELOAD, + GLOCK_RELOAD_NOT_EMPTY, + GLOCK_DRAW, + GLOCK_HOLSTER, + GLOCK_ADD_SILENCER +}; + +enum shotgun_e { + SHOTGUN_IDLE = 0, + SHOTGUN_FIRE, + SHOTGUN_FIRE2, + SHOTGUN_RELOAD, + SHOTGUN_PUMP, + SHOTGUN_START_RELOAD, + SHOTGUN_DRAW, + SHOTGUN_HOLSTER, + SHOTGUN_IDLE4, + SHOTGUN_IDLE_DEEP +}; + +enum mp5_e +{ + MP5_LONGIDLE = 0, + MP5_IDLE1, + MP5_LAUNCH, + MP5_RELOAD, + MP5_DEPLOY, + MP5_FIRE1, + MP5_FIRE2, + MP5_FIRE3, +}; + +enum python_e { + PYTHON_IDLE1 = 0, + PYTHON_FIDGET, + PYTHON_FIRE1, + PYTHON_RELOAD, + PYTHON_HOLSTER, + PYTHON_DRAW, + PYTHON_IDLE2, + PYTHON_IDLE3 +}; + +#define GAUSS_PRIMARY_CHARGE_VOLUME 256// how loud gauss is while charging +#define GAUSS_PRIMARY_FIRE_VOLUME 450// how loud gauss is when discharged + +enum gauss_e { + GAUSS_IDLE = 0, + GAUSS_IDLE2, + GAUSS_FIDGET, + GAUSS_SPINUP, + GAUSS_SPIN, + GAUSS_FIRE, + GAUSS_FIRE2, + GAUSS_HOLSTER, + GAUSS_DRAW +}; + +void EV_HLDM_GunshotDecalTrace( pmtrace_t *pTrace, char *decalName ); +void EV_HLDM_DecalGunshot( pmtrace_t *pTrace, int iBulletType ); +int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); +void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); + +#endif // EV_HLDMH \ No newline at end of file diff --git a/cl_dll/events.cpp b/cl_dll/events.cpp new file mode 100644 index 00000000..65c842bc --- /dev/null +++ b/cl_dll/events.cpp @@ -0,0 +1,23 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" + +void Game_HookEvents( void ); + +/* +=================== +EV_HookEvents + +See if game specific code wants to hook any events. +=================== +*/ +void EV_HookEvents( void ) +{ + Game_HookEvents(); +} \ No newline at end of file diff --git a/cl_dll/eventscripts.h b/cl_dll/eventscripts.h new file mode 100644 index 00000000..e8b145be --- /dev/null +++ b/cl_dll/eventscripts.h @@ -0,0 +1,73 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// eventscripts.h +#if !defined ( EVENTSCRIPTSH ) +#define EVENTSCRIPTSH + +// defaults for clientinfo messages +#define DEFAULT_VIEWHEIGHT 28 +#define VEC_DUCK_VIEW 12 + +#define FTENT_FADEOUT 0x00000080 + +#define DMG_GENERIC 0 // generic damage was done +#define DMG_CRUSH (1 << 0) // crushed by falling or moving object +#define DMG_BULLET (1 << 1) // shot +#define DMG_SLASH (1 << 2) // cut, clawed, stabbed +#define DMG_BURN (1 << 3) // heat burned +#define DMG_FREEZE (1 << 4) // frozen +#define DMG_FALL (1 << 5) // fell too far +#define DMG_BLAST (1 << 6) // explosive blast damage +#define DMG_CLUB (1 << 7) // crowbar, punch, headbutt +#define DMG_SHOCK (1 << 8) // electric shock +#define DMG_SONIC (1 << 9) // sound pulse shockwave +#define DMG_ENERGYBEAM (1 << 10) // laser or other high energy beam +#define DMG_NEVERGIB (1 << 12) // with this bit OR'd in, no damage type will be able to gib victims upon death +#define DMG_ALWAYSGIB (1 << 13) // with this bit OR'd in, any damage type can be made to gib victims upon death. + +// time-based damage +//mask off TF-specific stuff too +#define DMG_TIMEBASED (~(0xff003fff)) // mask for time-based damage + +#define DMG_DROWN (1 << 14) // Drowning +#define DMG_FIRSTTIMEBASED DMG_DROWN + +#define DMG_PARALYZE (1 << 15) // slows affected creature down +#define DMG_NERVEGAS (1 << 16) // nerve toxins, very bad +#define DMG_POISON (1 << 17) // blood poisioning +#define DMG_RADIATION (1 << 18) // radiation exposure +#define DMG_DROWNRECOVER (1 << 19) // drowning recovery +#define DMG_ACID (1 << 20) // toxic chemicals or acid burns +#define DMG_SLOWBURN (1 << 21) // in an oven +#define DMG_SLOWFREEZE (1 << 22) // in a subzero freezer +#define DMG_MORTAR (1 << 23) // Hit by air raid (done to distinguish grenade from mortar) + +//TF ADDITIONS +#define DMG_IGNITE (1 << 24) // Players hit by this begin to burn +#define DMG_RADIUS_MAX (1 << 25) // Radius damage with this flag doesn't decrease over distance +#define DMG_RADIUS_QUAKE (1 << 26) // Radius damage is done like Quake. 1/2 damage at 1/2 radius. +#define DMG_IGNOREARMOR (1 << 27) // Damage ignores target's armor +#define DMG_AIMED (1 << 28) // Does Hit location damage +#define DMG_WALLPIERCING (1 << 29) // Blast Damages ents through walls + +#define DMG_CALTROP (1<<30) +#define DMG_HALLUC (1<<31) + +// Some of these are HL/TFC specific? +void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); +void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); +void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ); +qboolean EV_IsLocal( int idx ); +qboolean EV_IsPlayer( int idx ); +void EV_CreateTracer( float *start, float *end ); + +struct cl_entity_s *GetEntity( int idx ); +struct cl_entity_s *GetViewEntity( void ); +void EV_MuzzleFlash( void ); + +#endif // EVENTSCRIPTSH diff --git a/cl_dll/flashlight.cpp b/cl_dll/flashlight.cpp new file mode 100644 index 00000000..dab2421b --- /dev/null +++ b/cl_dll/flashlight.cpp @@ -0,0 +1,149 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// flashlight.cpp +// +// implementation of CHudFlashlight class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + + + +DECLARE_MESSAGE(m_Flash, FlashBat) +DECLARE_MESSAGE(m_Flash, Flashlight) + +#define BAT_NAME "sprites/%d_Flashlight.spr" + +int CHudFlashlight::Init(void) +{ + m_fFade = 0; + m_fOn = 0; + + HOOK_MESSAGE(Flashlight); + HOOK_MESSAGE(FlashBat); + + m_iFlags |= HUD_ACTIVE; + + gHUD.AddHudElem(this); + + return 1; +}; + +void CHudFlashlight::Reset(void) +{ + m_fFade = 0; + m_fOn = 0; +} + +int CHudFlashlight::VidInit(void) +{ + int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" ); + int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" ); + int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" ); + + m_hSprite1 = gHUD.GetSprite(HUD_flash_empty); + m_hSprite2 = gHUD.GetSprite(HUD_flash_full); + m_hBeam = gHUD.GetSprite(HUD_flash_beam); + m_prc1 = &gHUD.GetSpriteRect(HUD_flash_empty); + m_prc2 = &gHUD.GetSpriteRect(HUD_flash_full); + m_prcBeam = &gHUD.GetSpriteRect(HUD_flash_beam); + m_iWidth = m_prc2->right - m_prc2->left; + + return 1; +}; + +int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) +{ + + + BEGIN_READ( pbuf, iSize ); + int x = READ_BYTE(); + m_iBat = x; + m_flBat = ((float)x)/100.0; + + return 1; +} + +int CHudFlashlight:: MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ) +{ + + BEGIN_READ( pbuf, iSize ); + m_fOn = READ_BYTE(); + int x = READ_BYTE(); + m_iBat = x; + m_flBat = ((float)x)/100.0; + + return 1; +} + +int CHudFlashlight::Draw(float flTime) +{ + if ( gHUD.m_iHideHUDDisplay & ( HIDEHUD_FLASHLIGHT | HIDEHUD_ALL ) ) + return 1; + + int r, g, b, x, y, a; + wrect_t rc; + + if (!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) )) + return 1; + + if (m_fOn) + a = 225; + else + a = MIN_ALPHA; + + if (m_flBat < 0.20) + UnpackRGB(r,g,b, RGB_REDISH); + else + UnpackRGB(r,g,b, RGB_YELLOWISH); + + ScaleColors(r, g, b, a); + + y = (m_prc1->bottom - m_prc2->top)/2; + x = ScreenWidth - m_iWidth - m_iWidth/2 ; + + // Draw the flashlight casing + SPR_Set(m_hSprite1, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prc1); + + if ( m_fOn ) + { // draw the flashlight beam + x = ScreenWidth - m_iWidth/2; + + SPR_Set( m_hBeam, r, g, b ); + SPR_DrawAdditive( 0, x, y, m_prcBeam ); + } + + // draw the flashlight energy level + x = ScreenWidth - m_iWidth - m_iWidth/2 ; + int iOffset = m_iWidth * (1.0 - m_flBat); + if (iOffset < m_iWidth) + { + rc = *m_prc2; + rc.left += iOffset; + + SPR_Set(m_hSprite2, r, g, b ); + SPR_DrawAdditive( 0, x + iOffset, y, &rc); + } + + + return 1; +} \ No newline at end of file diff --git a/cl_dll/geiger.cpp b/cl_dll/geiger.cpp new file mode 100644 index 00000000..6f5f984f --- /dev/null +++ b/cl_dll/geiger.cpp @@ -0,0 +1,184 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// Geiger.cpp +// +// implementation of CHudAmmo class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include + +#include "parsemsg.h" + +DECLARE_MESSAGE(m_Geiger, Geiger ) + +int CHudGeiger::Init(void) +{ + HOOK_MESSAGE( Geiger ); + + m_iGeigerRange = 0; + m_iFlags = 0; + + gHUD.AddHudElem(this); + + srand( (unsigned)time( NULL ) ); + + return 1; +}; + +int CHudGeiger::VidInit(void) +{ + return 1; +}; + +int CHudGeiger::MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf) +{ + + BEGIN_READ( pbuf, iSize ); + + // update geiger data + m_iGeigerRange = READ_BYTE(); + m_iGeigerRange = m_iGeigerRange << 2; + + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +int CHudGeiger::Draw (float flTime) +{ + int pct; + float flvol; + int rg[3]; + int i; + + if (m_iGeigerRange < 1000 && m_iGeigerRange > 0) + { + // peicewise linear is better than continuous formula for this + if (m_iGeigerRange > 800) + { + pct = 0; //Con_Printf ( "range > 800\n"); + } + else if (m_iGeigerRange > 600) + { + pct = 2; + flvol = 0.4; //Con_Printf ( "range > 600\n"); + rg[0] = 1; + rg[1] = 1; + i = 2; + } + else if (m_iGeigerRange > 500) + { + pct = 4; + flvol = 0.5; //Con_Printf ( "range > 500\n"); + rg[0] = 1; + rg[1] = 2; + i = 2; + } + else if (m_iGeigerRange > 400) + { + pct = 8; + flvol = 0.6; //Con_Printf ( "range > 400\n"); + rg[0] = 1; + rg[1] = 2; + rg[2] = 3; + i = 3; + } + else if (m_iGeigerRange > 300) + { + pct = 8; + flvol = 0.7; //Con_Printf ( "range > 300\n"); + rg[0] = 2; + rg[1] = 3; + rg[2] = 4; + i = 3; + } + else if (m_iGeigerRange > 200) + { + pct = 28; + flvol = 0.78; //Con_Printf ( "range > 200\n"); + rg[0] = 2; + rg[1] = 3; + rg[2] = 4; + i = 3; + } + else if (m_iGeigerRange > 150) + { + pct = 40; + flvol = 0.80; //Con_Printf ( "range > 150\n"); + rg[0] = 3; + rg[1] = 4; + rg[2] = 5; + i = 3; + } + else if (m_iGeigerRange > 100) + { + pct = 60; + flvol = 0.85; //Con_Printf ( "range > 100\n"); + rg[0] = 3; + rg[1] = 4; + rg[2] = 5; + i = 3; + } + else if (m_iGeigerRange > 75) + { + pct = 80; + flvol = 0.9; //Con_Printf ( "range > 75\n"); + //gflGeigerDelay = cl.time + GEIGERDELAY * 0.75; + rg[0] = 4; + rg[1] = 5; + rg[2] = 6; + i = 3; + } + else if (m_iGeigerRange > 50) + { + pct = 90; + flvol = 0.95; //Con_Printf ( "range > 50\n"); + rg[0] = 5; + rg[1] = 6; + i = 2; + } + else + { + pct = 95; + flvol = 1.0; //Con_Printf ( "range < 50\n"); + rg[0] = 5; + rg[1] = 6; + i = 2; + } + + flvol = (flvol * ((rand() & 127)) / 255) + 0.25; // UTIL_RandomFloat(0.25, 0.5); + + if ((rand() & 127) < pct || (rand() & 127) < pct) + { + //S_StartDynamicSound (-1, 0, rgsfx[rand() % i], r_origin, flvol, 1.0, 0, 100); + char sz[256]; + + int j = rand() & 1; + if (i > 2) + j += rand() & 1; + + sprintf(sz, "player/geiger%d.wav", j + 1); + PlaySound(sz, flvol); + + } + } + + return 1; +} diff --git a/cl_dll/health.cpp b/cl_dll/health.cpp new file mode 100644 index 00000000..f5835e4e --- /dev/null +++ b/cl_dll/health.cpp @@ -0,0 +1,472 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// Health.cpp +// +// implementation of CHudHealth class +// + +#include "STDIO.H" +#include "STDLIB.H" +#include "MATH.H" + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include + + +DECLARE_MESSAGE(m_Health, Health ) +DECLARE_MESSAGE(m_Health, Damage ) + +#define PAIN_NAME "sprites/%d_pain.spr" +#define DAMAGE_NAME "sprites/%d_dmg.spr" + +int giDmgHeight, giDmgWidth; + +int giDmgFlags[NUM_DMG_TYPES] = +{ + DMG_POISON, + DMG_ACID, + DMG_FREEZE|DMG_SLOWFREEZE, + DMG_DROWN, + DMG_BURN|DMG_SLOWBURN, + DMG_NERVEGAS, + DMG_RADIATION, + DMG_SHOCK, + DMG_CALTROP, + DMG_TRANQ, + DMG_CONCUSS, + DMG_HALLUC +}; + +int CHudHealth::Init(void) +{ + HOOK_MESSAGE(Health); + HOOK_MESSAGE(Damage); + m_iHealth = 100; + m_fFade = 0; + m_iFlags = 0; + m_bitsDamage = 0; + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + giDmgHeight = 0; + giDmgWidth = 0; + + memset(m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES); + + + gHUD.AddHudElem(this); + return 1; +} + +void CHudHealth::Reset( void ) +{ + // make sure the pain compass is cleared when the player respawns + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + + + // force all the flashing damage icons to expire + m_bitsDamage = 0; + for ( int i = 0; i < NUM_DMG_TYPES; i++ ) + { + m_dmg[i].fExpire = 0; + } +} + +int CHudHealth::VidInit(void) +{ + m_hSprite = 0; + + m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; + m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); + + 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; + return 1; +} + +int CHudHealth:: MsgFunc_Health(const char *pszName, int iSize, void *pbuf ) +{ + // TODO: update local health data + BEGIN_READ( pbuf, iSize ); + int x = READ_BYTE(); + + m_iFlags |= HUD_ACTIVE; + + // Only update the fade if we've changed health + if (x != m_iHealth) + { + m_fFade = FADE_TIME; + m_iHealth = x; + } + + return 1; +} + + +int CHudHealth:: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int armor = READ_BYTE(); // armor + int damageTaken = READ_BYTE(); // health + long bitsDamage = READ_LONG(); // damage bits + + vec3_t vecFrom; + + for ( int i = 0 ; i < 3 ; i++) + vecFrom[i] = READ_COORD(); + + UpdateTiles(gHUD.m_flTime, bitsDamage); + + // Actually took damage? + if ( damageTaken > 0 || armor > 0 ) + CalcDamageDirection(vecFrom); + + return 1; +} + + +// Returns back a color from the +// Green <-> Yellow <-> Red ramp +void CHudHealth::GetPainColor( int &r, int &g, int &b ) +{ + int iHealth = m_iHealth; + + if (iHealth > 25) + iHealth -= 25; + else if ( iHealth < 0 ) + iHealth = 0; +#if 0 + g = iHealth * 255 / 100; + r = 255 - g; + b = 0; +#else + if (m_iHealth > 25) + { + UnpackRGB(r,g,b, RGB_YELLOWISH); + } + else + { + r = 250; + g = 0; + b = 0; + } +#endif +} + +int CHudHealth::Draw(float flTime) +{ + int r, g, b; + int a = 0, x, y; + int HealthWidth; + + if ( (gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || gEngfuncs.IsSpectateOnly() ) + return 1; + + if ( !m_hSprite ) + m_hSprite = LoadSprite(PAIN_NAME); + + // Has health changed? Flash the health # + if (m_fFade) + { + m_fFade -= (gHUD.m_flTimeDelta * 20); + if (m_fFade <= 0) + { + a = MIN_ALPHA; + m_fFade = 0; + } + + // Fade the health number back to dim + + a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; + + } + else + a = MIN_ALPHA; + + // If health is getting low, make it bright red + if (m_iHealth <= 15) + a = 255; + + GetPainColor( r, g, b ); + ScaleColors(r, g, b, a ); + + // Only draw health if we have the suit. + if (gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT))) + { + HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; + + y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; + x = CrossWidth /2; + + SPR_Set(gHUD.GetSprite(m_HUD_cross), r, g, b); + SPR_DrawAdditive(0, x, y, &gHUD.GetSpriteRect(m_HUD_cross)); + + x = CrossWidth + HealthWidth / 2; + + x = gHUD.DrawHudNumber(x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b); + + x += HealthWidth/2; + + int iHeight = gHUD.m_iFontHeight; + int iWidth = HealthWidth/10; + FillRGBA(x, y, iWidth, iHeight, 255, 160, 0, a); + } + + DrawDamage(flTime); + return DrawPain(flTime); +} + +void CHudHealth::CalcDamageDirection(vec3_t vecFrom) +{ + vec3_t forward, right, up; + float side, front; + vec3_t vecOrigin, vecAngles; + + if (!vecFrom[0] && !vecFrom[1] && !vecFrom[2]) + { + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; + return; + } + + + memcpy(vecOrigin, gHUD.m_vecOrigin, sizeof(vec3_t)); + memcpy(vecAngles, gHUD.m_vecAngles, sizeof(vec3_t)); + + + VectorSubtract (vecFrom, vecOrigin, vecFrom); + + float flDistToTarget = vecFrom.Length(); + + vecFrom = vecFrom.Normalize(); + AngleVectors (vecAngles, forward, right, up); + + front = DotProduct (vecFrom, right); + side = DotProduct (vecFrom, forward); + + if (flDistToTarget <= 50) + { + m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; + } + else + { + if (side > 0) + { + if (side > 0.3) + m_fAttackFront = max(m_fAttackFront, side); + } + else + { + float f = fabs(side); + if (f > 0.3) + m_fAttackRear = max(m_fAttackRear, f); + } + + if (front > 0) + { + if (front > 0.3) + m_fAttackRight = max(m_fAttackRight, front); + } + else + { + float f = fabs(front); + if (f > 0.3) + m_fAttackLeft = max(m_fAttackLeft, f); + } + } +} + +int CHudHealth::DrawPain(float flTime) +{ + if (!(m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight)) + return 1; + + int r, g, b; + int x, y, a, shade; + + // TODO: get the shift value of the health + a = 255; // max brightness until then + + float fFade = gHUD.m_flTimeDelta * 2; + + // SPR_Draw top + if (m_fAttackFront > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackFront, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 0)/2; + y = ScreenHeight/2 - SPR_Height(m_hSprite,0) * 3; + SPR_DrawAdditive(0, x, y, NULL); + m_fAttackFront = max( 0, m_fAttackFront - fFade ); + } else + m_fAttackFront = 0; + + if (m_fAttackRight > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackRight, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 + SPR_Width(m_hSprite, 1) * 2; + y = ScreenHeight/2 - SPR_Height(m_hSprite,1)/2; + SPR_DrawAdditive(1, x, y, NULL); + m_fAttackRight = max( 0, m_fAttackRight - fFade ); + } else + m_fAttackRight = 0; + + if (m_fAttackRear > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackRear, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 2)/2; + y = ScreenHeight/2 + SPR_Height(m_hSprite,2) * 2; + SPR_DrawAdditive(2, x, y, NULL); + m_fAttackRear = max( 0, m_fAttackRear - fFade ); + } else + m_fAttackRear = 0; + + if (m_fAttackLeft > 0.4) + { + GetPainColor(r,g,b); + shade = a * max( m_fAttackLeft, 0.5 ); + ScaleColors(r, g, b, shade); + SPR_Set(m_hSprite, r, g, b ); + + x = ScreenWidth/2 - SPR_Width(m_hSprite, 3) * 3; + y = ScreenHeight/2 - SPR_Height(m_hSprite,3)/2; + SPR_DrawAdditive(3, x, y, NULL); + + m_fAttackLeft = max( 0, m_fAttackLeft - fFade ); + } else + m_fAttackLeft = 0; + + return 1; +} + +int CHudHealth::DrawDamage(float flTime) +{ + int r, g, b, a; + DAMAGE_IMAGE *pdmg; + + if (!m_bitsDamage) + return 1; + + UnpackRGB(r,g,b, RGB_YELLOWISH); + + a = (int)( fabs(sin(flTime*2)) * 256.0); + + ScaleColors(r, g, b, a); + + // Draw all the items + for (int i = 0; i < NUM_DMG_TYPES; i++) + { + if (m_bitsDamage & giDmgFlags[i]) + { + pdmg = &m_dmg[i]; + SPR_Set(gHUD.GetSprite(m_HUD_dmg_bio + i), r, g, b ); + SPR_DrawAdditive(0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect(m_HUD_dmg_bio + i)); + } + } + + + // check for bits that should be expired + for ( i = 0; i < NUM_DMG_TYPES; i++ ) + { + DAMAGE_IMAGE *pdmg = &m_dmg[i]; + + if ( m_bitsDamage & giDmgFlags[i] ) + { + pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); + + if ( pdmg->fExpire <= flTime // when the time has expired + && a < 40 ) // and the flash is at the low point of the cycle + { + pdmg->fExpire = 0; + + int y = pdmg->y; + pdmg->x = pdmg->y = 0; + + // move everyone above down + for (int j = 0; j < NUM_DMG_TYPES; j++) + { + pdmg = &m_dmg[j]; + if ((pdmg->y) && (pdmg->y < y)) + pdmg->y += giDmgHeight; + + } + + m_bitsDamage &= ~giDmgFlags[i]; // clear the bits + } + } + } + + return 1; +} + + +void CHudHealth::UpdateTiles(float flTime, long bitsDamage) +{ + DAMAGE_IMAGE *pdmg; + + // Which types are new? + long bitsOn = ~m_bitsDamage & bitsDamage; + + for (int i = 0; i < NUM_DMG_TYPES; i++) + { + pdmg = &m_dmg[i]; + + // Is this one already on? + if (m_bitsDamage & giDmgFlags[i]) + { + pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration + if (!pdmg->fBaseline) + pdmg->fBaseline = flTime; + } + + // Are we just turning it on? + if (bitsOn & giDmgFlags[i]) + { + // put this one at the bottom + pdmg->x = giDmgWidth/8; + pdmg->y = ScreenHeight - giDmgHeight * 2; + pdmg->fExpire=flTime + DMG_IMAGE_LIFE; + + // move everyone else up + for (int j = 0; j < NUM_DMG_TYPES; j++) + { + if (j == i) + continue; + + pdmg = &m_dmg[j]; + if (pdmg->y) + pdmg->y -= giDmgHeight; + + } + pdmg = &m_dmg[i]; + } + } + + // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) + m_bitsDamage |= bitsDamage; +} diff --git a/client/hud/hud_health.h b/cl_dll/health.h similarity index 88% rename from client/hud/hud_health.h rename to cl_dll/health.h index dcdc8d13..41717e78 100644 --- a/client/hud/hud_health.h +++ b/cl_dll/health.h @@ -86,10 +86,12 @@ #define DMG_TRANQ DMG_MORTAR #define DMG_CONCUSS DMG_SONIC + + typedef struct { - float fExpire; - float fBaseline; + float fExpire; + float fBaseline; int x, y; } DAMAGE_IMAGE; @@ -101,10 +103,10 @@ class CHudHealth: public CHudBase public: virtual int Init( void ); virtual int VidInit( void ); - virtual int Draw( float fTime ); + virtual int Draw(float fTime); virtual void Reset( void ); - int MsgFunc_Health( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Health(const char *pszName, int iSize, void *pbuf); + int MsgFunc_Damage(const char *pszName, int iSize, void *pbuf); int m_iHealth; int m_HUD_dmg_bio; int m_HUD_cross; @@ -117,9 +119,9 @@ private: HSPRITE m_hDamage; DAMAGE_IMAGE m_dmg[NUM_DMG_TYPES]; - int m_bitsDamage; - int DrawPain( float fTime ); - int DrawDamage( float fTime ); - void CalcDamageDirection( vec3_t vecFrom ); - void UpdateTiles( float fTime, long bits ); + int m_bitsDamage; + int DrawPain(float fTime); + int DrawDamage(float fTime); + void CalcDamageDirection(vec3_t vecFrom); + void UpdateTiles(float fTime, long bits); }; diff --git a/cl_dll/hl/hl_baseentity.cpp b/cl_dll/hl/hl_baseentity.cpp new file mode 100644 index 00000000..547d5532 --- /dev/null +++ b/cl_dll/hl/hl_baseentity.cpp @@ -0,0 +1,347 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +/* +========================== +This file contains "stubs" of class member implementations so that we can predict certain + weapons client side. From time to time you might find that you need to implement part of the + these functions. If so, cut it from here, paste it in hl_weapons.cpp or somewhere else and + add in the functionality you need. +========================== +*/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" +#include "weapons.h" +#include "nodes.h" +#include "soundent.h" +#include "skill.h" + +// Globals used by game logic +const Vector g_vecZero = Vector( 0, 0, 0 ); +int gmsgWeapPickup = 0; +enginefuncs_t g_engfuncs; +globalvars_t *gpGlobals; + +ItemInfo CBasePlayerItem::ItemInfoArray[MAX_WEAPONS]; + +void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch) { } + +// CBaseEntity Stubs +int CBaseEntity :: TakeHealth( float flHealth, int bitsDamageType ) { return 1; } +int CBaseEntity :: TakeDamage( entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int bitsDamageType ) { return 1; } +CBaseEntity *CBaseEntity::GetNextTarget( void ) { return NULL; } +int CBaseEntity::Save( CSave &save ) { return 1; } +int CBaseEntity::Restore( CRestore &restore ) { return 1; } +void CBaseEntity::SetObjectCollisionBox( void ) { } +int CBaseEntity :: Intersects( CBaseEntity *pOther ) { return 0; } +void CBaseEntity :: MakeDormant( void ) { } +int CBaseEntity :: IsDormant( void ) { return 0; } +BOOL CBaseEntity :: IsInWorld( void ) { return TRUE; } +int CBaseEntity::ShouldToggle( USE_TYPE useType, BOOL currentState ) { return 0; } +int CBaseEntity :: DamageDecal( int bitsDamageType ) { return -1; } +CBaseEntity * CBaseEntity::Create( char *szName, const Vector &vecOrigin, const Vector &vecAngles, edict_t *pentOwner ) { return NULL; } +void CBaseEntity::SUB_Remove( void ) { } + +// CBaseDelay Stubs +void CBaseDelay :: KeyValue( struct KeyValueData_s * ) { } +int CBaseDelay::Restore( class CRestore & ) { return 1; } +int CBaseDelay::Save( class CSave & ) { return 1; } + +// CBaseAnimating Stubs +int CBaseAnimating::Restore( class CRestore & ) { return 1; } +int CBaseAnimating::Save( class CSave & ) { return 1; } + +// DEBUG Stubs +edict_t *DBG_EntOfVars( const entvars_t *pev ) { return NULL; } +void DBG_AssertFunction(BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage) { } + +// UTIL_* Stubs +void UTIL_PrecacheOther( const char *szClassname ) { } +void UTIL_BloodDrips( const Vector &origin, const Vector &direction, int color, int amount ) { } +void UTIL_DecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_GunshotDecalTrace( TraceResult *pTrace, int decalNumber ) { } +void UTIL_MakeVectors( const Vector &vecAngles ) { } +BOOL UTIL_IsValidEntity( edict_t *pent ) { return TRUE; } +void UTIL_SetOrigin( entvars_t *, const Vector &org ) { } +BOOL UTIL_GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerItem *pCurrentWeapon ) { return TRUE; } +void UTIL_LogPrintf(char *,...) { } +void UTIL_ClientPrintAll( int,char const *,char const *,char const *,char const *,char const *) { } +void ClientPrint( entvars_t *client, int msg_dest, const char *msg_name, const char *param1, const char *param2, const char *param3, const char *param4 ) { } + +// CBaseToggle Stubs +int CBaseToggle::Restore( class CRestore & ) { return 1; } +int CBaseToggle::Save( class CSave & ) { return 1; } +void CBaseToggle :: KeyValue( struct KeyValueData_s * ) { } + +// CGrenade Stubs +void CGrenade::BounceSound( void ) { } +void CGrenade::Explode( Vector, Vector ) { } +void CGrenade::Explode( TraceResult *, int ) { } +void CGrenade::Killed( entvars_t *, int ) { } +void CGrenade::Spawn( void ) { } +CGrenade * CGrenade:: ShootTimed( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity, float time ){ return 0; } +CGrenade *CGrenade::ShootContact( entvars_t *pevOwner, Vector vecStart, Vector vecVelocity ){ return 0; } +void CGrenade::DetonateUse( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ){ } + +void UTIL_Remove( CBaseEntity *pEntity ){ } +struct skilldata_t gSkillData; +void UTIL_SetSize( entvars_t *pev, const Vector &vecMin, const Vector &vecMax ){ } +CBaseEntity *UTIL_FindEntityInSphere( CBaseEntity *pStartEntity, const Vector &vecCenter, float flRadius ){ return 0;} + +Vector UTIL_VecToAngles( const Vector &vec ){ return 0; } +CSprite *CSprite::SpriteCreate( const char *pSpriteName, const Vector &origin, BOOL animate ) { return 0; } +void CBeam::PointEntInit( const Vector &start, int endIndex ) { } +CBeam *CBeam::BeamCreate( const char *pSpriteName, int width ) { return NULL; } +void CSprite::Expand( float scaleSpeed, float fadeSpeed ) { } + + +CBaseEntity* CBaseMonster :: CheckTraceHullAttack( float flDist, int iDamage, int iDmgType ) { return NULL; } +void CBaseMonster :: Eat ( float flFullDuration ) { } +BOOL CBaseMonster :: FShouldEat ( void ) { return TRUE; } +void CBaseMonster :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } +void CBaseMonster :: BarnacleVictimReleased ( void ) { } +void CBaseMonster :: Listen ( void ) { } +float CBaseMonster :: FLSoundVolume ( CSound *pSound ) { return 0.0; } +BOOL CBaseMonster :: FValidateHintType ( short sHint ) { return FALSE; } +void CBaseMonster :: Look ( int iDistance ) { } +int CBaseMonster :: ISoundMask ( void ) { return 0; } +CSound* CBaseMonster :: PBestSound ( void ) { return NULL; } +CSound* CBaseMonster :: PBestScent ( void ) { return NULL; } +float CBaseAnimating :: StudioFrameAdvance ( float flInterval ) { return 0.0; } +void CBaseMonster :: MonsterThink ( void ) { } +void CBaseMonster :: MonsterUse ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) { } +int CBaseMonster :: IgnoreConditions ( void ) { return 0; } +void CBaseMonster :: RouteClear ( void ) { } +void CBaseMonster :: RouteNew ( void ) { } +BOOL CBaseMonster :: FRouteClear ( void ) { return FALSE; } +BOOL CBaseMonster :: FRefreshRoute ( void ) { return 0; } +BOOL CBaseMonster::MoveToEnemy( Activity movementAct, float waitTime ) { return FALSE; } +BOOL CBaseMonster::MoveToLocation( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } +BOOL CBaseMonster::MoveToTarget( Activity movementAct, float waitTime ) { return FALSE; } +BOOL CBaseMonster::MoveToNode( Activity movementAct, float waitTime, const Vector &goal ) { return FALSE; } +int ShouldSimplify( int routeType ) { return TRUE; } +void CBaseMonster :: RouteSimplify( CBaseEntity *pTargetEnt ) { } +BOOL CBaseMonster :: FBecomeProne ( void ) { return TRUE; } +BOOL CBaseMonster :: CheckRangeAttack1 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckRangeAttack2 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckMeleeAttack1 ( float flDot, float flDist ) { return FALSE; } +BOOL CBaseMonster :: CheckMeleeAttack2 ( float flDot, float flDist ) { return FALSE; } +void CBaseMonster :: CheckAttacks ( CBaseEntity *pTarget, float flDist ) { } +BOOL CBaseMonster :: FCanCheckAttacks ( void ) { return FALSE; } +int CBaseMonster :: CheckEnemy ( CBaseEntity *pEnemy ) { return 0; } +void CBaseMonster :: PushEnemy( CBaseEntity *pEnemy, Vector &vecLastKnownPos ) { } +BOOL CBaseMonster :: PopEnemy( ) { return FALSE; } +void CBaseMonster :: SetActivity ( Activity NewActivity ) { } +void CBaseMonster :: SetSequenceByName ( char *szSequence ) { } +int CBaseMonster :: CheckLocalMove ( const Vector &vecStart, const Vector &vecEnd, CBaseEntity *pTarget, float *pflDist ) { return 0; } +float CBaseMonster :: OpenDoorAndWait( entvars_t *pevDoor ) { return 0.0; } +void CBaseMonster :: AdvanceRoute ( float distance ) { } +int CBaseMonster :: RouteClassify( int iMoveFlag ) { return 0; } +BOOL CBaseMonster :: BuildRoute ( const Vector &vecGoal, int iMoveFlag, CBaseEntity *pTarget ) { return FALSE; } +void CBaseMonster :: InsertWaypoint ( Vector vecLocation, int afMoveFlags ) { } +BOOL CBaseMonster :: FTriangulate ( const Vector &vecStart , const Vector &vecEnd, float flDist, CBaseEntity *pTargetEnt, Vector *pApex ) { return FALSE; } +void CBaseMonster :: Move ( float flInterval ) { } +BOOL CBaseMonster:: ShouldAdvanceRoute( float flWaypointDist ) { return FALSE; } +void CBaseMonster::MoveExecute( CBaseEntity *pTargetEnt, const Vector &vecDir, float flInterval ) { } +void CBaseMonster :: MonsterInit ( void ) { } +void CBaseMonster :: MonsterInitThink ( void ) { } +void CBaseMonster :: StartMonster ( void ) { } +void CBaseMonster :: MovementComplete( void ) { } +int CBaseMonster::TaskIsRunning( void ) { return 0; } +int CBaseMonster::IRelationship ( CBaseEntity *pTarget ) { return 0; } +BOOL CBaseMonster :: FindCover ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } +BOOL CBaseMonster :: BuildNearestRoute ( Vector vecThreat, Vector vecViewOffset, float flMinDist, float flMaxDist ) { return FALSE; } +CBaseEntity *CBaseMonster :: BestVisibleEnemy ( void ) { return NULL; } +BOOL CBaseMonster :: FInViewCone ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseMonster :: FInViewCone ( Vector *pOrigin ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( CBaseEntity *pEntity ) { return FALSE; } +BOOL CBaseEntity :: FVisible ( const Vector &vecOrigin ) { return FALSE; } +void CBaseMonster :: MakeIdealYaw( Vector vecTarget ) { } +float CBaseMonster::FlYawDiff ( void ) { return 0.0; } +float CBaseMonster::ChangeYaw ( int yawSpeed ) { return 0; } +float CBaseMonster::VecToYaw ( Vector vecDir ) { return 0.0; } +int CBaseAnimating :: LookupActivity ( int activity ) { return 0; } +int CBaseAnimating :: LookupActivityHeaviest ( int activity ) { return 0; } +void CBaseMonster :: SetEyePosition ( void ) { } +int CBaseAnimating :: LookupSequence ( const char *label ) { return 0; } +void CBaseAnimating :: ResetSequenceInfo ( ) { } +BOOL CBaseAnimating :: GetSequenceFlags( ) { return FALSE; } +void CBaseAnimating :: DispatchAnimEvents ( float flInterval ) { } +void CBaseMonster :: HandleAnimEvent( MonsterEvent_t *pEvent ) { } +float CBaseAnimating :: SetBoneController ( int iController, float flValue ) { return 0.0; } +void CBaseAnimating :: InitBoneControllers ( void ) { } +float CBaseAnimating :: SetBlending ( int iBlender, float flValue ) { return 0; } +void CBaseAnimating :: GetBonePosition ( int iBone, Vector &origin, Vector &angles ) { } +void CBaseAnimating :: GetAttachment ( int iAttachment, Vector &origin, Vector &angles ) { } +int CBaseAnimating :: FindTransition( int iEndingSequence, int iGoalSequence, int *piDir ) { return -1; } +void CBaseAnimating :: GetAutomovement( Vector &origin, Vector &angles, float flInterval ) { } +void CBaseAnimating :: SetBodygroup( int iGroup, int iValue ) { } +int CBaseAnimating :: GetBodygroup( int iGroup ) { return 0; } +Vector CBaseMonster :: GetGunPosition( void ) { return g_vecZero; } +void CBaseEntity::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +void CBaseEntity::FireBullets(ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker ) { } +void CBaseEntity :: TraceBleed( float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType ) { } +void CBaseMonster :: MakeDamageBloodDecal ( int cCount, float flNoise, TraceResult *ptr, const Vector &vecDir ) { } +BOOL CBaseMonster :: FGetNodeRoute ( Vector vecDest ) { return TRUE; } +int CBaseMonster :: FindHintNode ( void ) { return NO_NODE; } +void CBaseMonster::ReportAIState( void ) { } +void CBaseMonster :: KeyValue( KeyValueData *pkvd ) { } +BOOL CBaseMonster :: FCheckAITrigger ( void ) { return FALSE; } +int CBaseMonster :: CanPlaySequence( BOOL fDisregardMonsterState, int interruptLevel ) { return FALSE; } +BOOL CBaseMonster :: FindLateralCover ( const Vector &vecThreat, const Vector &vecViewOffset ) { return FALSE; } +Vector CBaseMonster :: ShootAtEnemy( const Vector &shootOrigin ) { return g_vecZero; } +BOOL CBaseMonster :: FacingIdeal( void ) { return FALSE; } +BOOL CBaseMonster :: FCanActiveIdle ( void ) { return FALSE; } +void CBaseMonster::PlaySentence( const char *pszSentence, float duration, float volume, float attenuation ) { } +void CBaseMonster::PlayScriptedSentence( const char *pszSentence, float duration, float volume, float attenuation, BOOL bConcurrent, CBaseEntity *pListener ) { } +void CBaseMonster::SentenceStop( void ) { } +void CBaseMonster::CorpseFallThink( void ) { } +void CBaseMonster :: MonsterInitDead( void ) { } +BOOL CBaseMonster :: BBoxFlat ( void ) { return TRUE; } +BOOL CBaseMonster :: GetEnemy ( void ) { return FALSE; } +void CBaseMonster :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +CBaseEntity* CBaseMonster :: DropItem ( char *pszItemName, const Vector &vecPos, const Vector &vecAng ) { return NULL; } +BOOL CBaseMonster :: ShouldFadeOnDeath( void ) { return FALSE; } +void CBaseMonster :: RadiusDamage(entvars_t* pevInflictor, entvars_t* pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster :: RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int iClassIgnore, int bitsDamageType ) { } +void CBaseMonster::FadeMonster( void ) { } +void CBaseMonster :: GibMonster( void ) { } +BOOL CBaseMonster :: HasHumanGibs( void ) { return FALSE; } +BOOL CBaseMonster :: HasAlienGibs( void ) { return FALSE; } +Activity CBaseMonster :: GetDeathActivity ( void ) { return ACT_DIE_HEADSHOT; } +MONSTERSTATE CBaseMonster :: GetIdealState ( void ) { return MONSTERSTATE_ALERT; } +Schedule_t* CBaseMonster :: GetScheduleOfType ( int Type ) { return NULL; } +Schedule_t *CBaseMonster :: GetSchedule ( void ) { return NULL; } +void CBaseMonster :: RunTask ( Task_t *pTask ) { } +void CBaseMonster :: StartTask ( Task_t *pTask ) { } +Schedule_t *CBaseMonster::ScheduleFromName( const char *pName ) { return NULL;} +void CBaseMonster::BecomeDead( void ) {} +void CBaseMonster :: RunAI ( void ) {} +void CBaseMonster :: Killed( entvars_t *pevAttacker, int iGib ) {} +int CBaseMonster :: TakeHealth (float flHealth, int bitsDamageType) { return 0; } +int CBaseMonster :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +int CBaseMonster::Restore( class CRestore & ) { return 1; } +int CBaseMonster::Save( class CSave & ) { return 1; } + +int TrainSpeed(int iSpeed, int iMax) { return 0; } +void CBasePlayer :: DeathSound( void ) { } +int CBasePlayer :: TakeHealth( float flHealth, int bitsDamageType ) { return 0; } +void CBasePlayer :: TraceAttack( entvars_t *pevAttacker, float flDamage, Vector vecDir, TraceResult *ptr, int bitsDamageType) { } +int CBasePlayer :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType ) { return 0; } +void CBasePlayer::PackDeadPlayerItems( void ) { } +void CBasePlayer::RemoveAllItems( BOOL removeSuit ) { } +void CBasePlayer::SetAnimation( PLAYER_ANIM playerAnim ) { } +void CBasePlayer::WaterMove() { } +BOOL CBasePlayer::IsOnLadder( void ) { return FALSE; } +void CBasePlayer::PlayerDeathThink(void) { } +void CBasePlayer::StartDeathCam( void ) { } +void CBasePlayer::StartObserver( Vector vecPosition, Vector vecViewAngle ) { } +void CBasePlayer::PlayerUse ( void ) { } +void CBasePlayer::Jump() { } +void CBasePlayer::Duck( ) { } +int CBasePlayer::Classify ( void ) { return 0; } +void CBasePlayer::PreThink(void) { } +void CBasePlayer::CheckTimeBasedDamage() { } +void CBasePlayer :: UpdateGeigerCounter( void ) { } +void CBasePlayer::CheckSuitUpdate() { } +void CBasePlayer::SetSuitUpdate(char *name, int fgroup, int iNoRepeatTime) { } +void CBasePlayer :: UpdatePlayerSound ( void ) { } +void CBasePlayer::PostThink() { } +void CBasePlayer :: Precache( void ) { } +int CBasePlayer::Save( CSave &save ) { return 0; } +void CBasePlayer::RenewItems(void) { } +int CBasePlayer::Restore( CRestore &restore ) { return 0; } +void CBasePlayer::SelectNextItem( int iItem ) { } +BOOL CBasePlayer::HasWeapons( void ) { return FALSE; } +void CBasePlayer::SelectPrevItem( int iItem ) { } +CBaseEntity *FindEntityForward( CBaseEntity *pMe ) { return NULL; } +BOOL CBasePlayer :: FlashlightIsOn( void ) { return FALSE; } +void CBasePlayer :: FlashlightTurnOn( void ) { } +void CBasePlayer :: FlashlightTurnOff( void ) { } +void CBasePlayer :: ForceClientDllUpdate( void ) { } +void CBasePlayer::ImpulseCommands( ) { } +void CBasePlayer::CheatImpulseCommands( int iImpulse ) { } +int CBasePlayer::AddPlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +int CBasePlayer::RemovePlayerItem( CBasePlayerItem *pItem ) { return FALSE; } +void CBasePlayer::ItemPreFrame() { } +void CBasePlayer::ItemPostFrame() { } +int CBasePlayer::AmmoInventory( int iAmmoIndex ) { return -1; } +int CBasePlayer::GetAmmoIndex(const char *psz) { return -1; } +void CBasePlayer::SendAmmoUpdate(void) { } +void CBasePlayer :: UpdateClientData( void ) { } +BOOL CBasePlayer :: FBecomeProne ( void ) { return TRUE; } +void CBasePlayer :: BarnacleVictimBitten ( entvars_t *pevBarnacle ) { } +void CBasePlayer :: BarnacleVictimReleased ( void ) { } +int CBasePlayer :: Illumination( void ) { return 0; } +void CBasePlayer :: EnableControl(BOOL fControl) { } +Vector CBasePlayer :: GetAutoaimVector( float flDelta ) { return g_vecZero; } +Vector CBasePlayer :: AutoaimDeflection( Vector &vecSrc, float flDist, float flDelta ) { return g_vecZero; } +void CBasePlayer :: ResetAutoaim( ) { } +void CBasePlayer :: SetCustomDecalFrames( int nFrames ) { } +int CBasePlayer :: GetCustomDecalFrames( void ) { return -1; } +void CBasePlayer::DropPlayerItem ( char *pszItemName ) { } +BOOL CBasePlayer::HasPlayerItem( CBasePlayerItem *pCheckItem ) { return FALSE; } +BOOL CBasePlayer :: SwitchWeapon( CBasePlayerItem *pWeapon ) { return FALSE; } +Vector CBasePlayer :: GetGunPosition( void ) { return g_vecZero; } +const char *CBasePlayer::TeamID( void ) { return ""; } +int CBasePlayer :: GiveAmmo( int iCount, char *szName, int iMax ) { return 0; } +void CBasePlayer::AddPoints( int score, BOOL bAllowNegativeScore ) { } +void CBasePlayer::AddPointsToTeam( int score, BOOL bAllowNegativeScore ) { } + +void ClearMultiDamage(void) { } +void ApplyMultiDamage(entvars_t *pevInflictor, entvars_t *pevAttacker ) { } +void AddMultiDamage( entvars_t *pevInflictor, CBaseEntity *pEntity, float flDamage, int bitsDamageType) { } +void SpawnBlood(Vector vecSpot, int bloodColor, float flDamage) { } +int DamageDecal( CBaseEntity *pEntity, int bitsDamageType ) { return 0; } +void DecalGunshot( TraceResult *pTrace, int iBulletType ) { } +void EjectBrass ( const Vector &vecOrigin, const Vector &vecVelocity, float rotation, int model, int soundtype ) { } +void AddAmmoNameToAmmoRegistry( const char *szAmmoname ) { } +int CBasePlayerItem::Restore( class CRestore & ) { return 1; } +int CBasePlayerItem::Save( class CSave & ) { return 1; } +int CBasePlayerWeapon::Restore( class CRestore & ) { return 1; } +int CBasePlayerWeapon::Save( class CSave & ) { return 1; } +void CBasePlayerItem :: SetObjectCollisionBox( void ) { } +void CBasePlayerItem :: FallInit( void ) { } +void CBasePlayerItem::FallThink ( void ) { } +void CBasePlayerItem::Materialize( void ) { } +void CBasePlayerItem::AttemptToMaterialize( void ) { } +void CBasePlayerItem :: CheckRespawn ( void ) { } +CBaseEntity* CBasePlayerItem::Respawn( void ) { return NULL; } +void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) { } +void CBasePlayerItem::DestroyItem( void ) { } +int CBasePlayerItem::AddToPlayer( CBasePlayer *pPlayer ) { return TRUE; } +void CBasePlayerItem::Drop( void ) { } +void CBasePlayerItem::Kill( void ) { } +void CBasePlayerItem::Holster( int skiplocal ) { } +void CBasePlayerItem::AttachToPlayer ( CBasePlayer *pPlayer ) { } +int CBasePlayerWeapon::AddDuplicate( CBasePlayerItem *pOriginal ) { return 0; } +int CBasePlayerWeapon::AddToPlayer( CBasePlayer *pPlayer ) { return FALSE; } +int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) { return 0; } +BOOL CBasePlayerWeapon :: AddPrimaryAmmo( int iCount, char *szName, int iMaxClip, int iMaxCarry ) { return TRUE; } +BOOL CBasePlayerWeapon :: AddSecondaryAmmo( int iCount, char *szName, int iMax ) { return TRUE; } +BOOL CBasePlayerWeapon :: IsUseable( void ) { return TRUE; } +int CBasePlayerWeapon::PrimaryAmmoIndex( void ) { return -1; } +int CBasePlayerWeapon::SecondaryAmmoIndex( void ) { return -1; } +void CBasePlayerAmmo::Spawn( void ) { } +CBaseEntity* CBasePlayerAmmo::Respawn( void ) { return this; } +void CBasePlayerAmmo::Materialize( void ) { } +void CBasePlayerAmmo :: DefaultTouch( CBaseEntity *pOther ) { } +int CBasePlayerWeapon::ExtractAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +int CBasePlayerWeapon::ExtractClipAmmo( CBasePlayerWeapon *pWeapon ) { return 0; } +void CBasePlayerWeapon::RetireWeapon( void ) { } +void CSoundEnt::InsertSound ( int iType, const Vector &vecOrigin, int iVolume, float flDuration ) {} +void RadiusDamage( Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, float flRadius, int iClassIgnore, int bitsDamageType ){} \ No newline at end of file diff --git a/cl_dll/hl/hl_events.cpp b/cl_dll/hl/hl_events.cpp new file mode 100644 index 00000000..5ad4459e --- /dev/null +++ b/cl_dll/hl/hl_events.cpp @@ -0,0 +1,80 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "../hud.h" +#include "../cl_util.h" +#include "event_api.h" + +extern "C" +{ +// HLDM +void EV_FireGlock1( struct event_args_s *args ); +void EV_FireGlock2( struct event_args_s *args ); +void EV_FireShotGunSingle( struct event_args_s *args ); +void EV_FireShotGunDouble( struct event_args_s *args ); +void EV_FireMP5( struct event_args_s *args ); +void EV_FireMP52( struct event_args_s *args ); +void EV_FirePython( struct event_args_s *args ); +void EV_FireGauss( struct event_args_s *args ); +void EV_SpinGauss( struct event_args_s *args ); +void EV_Crowbar( struct event_args_s *args ); +void EV_FireCrossbow( struct event_args_s *args ); +void EV_FireCrossbow2( struct event_args_s *args ); +void EV_FireRpg( struct event_args_s *args ); +void EV_EgonFire( struct event_args_s *args ); +void EV_EgonStop( struct event_args_s *args ); +void EV_HornetGunFire( struct event_args_s *args ); +void EV_TripmineFire( struct event_args_s *args ); +void EV_SnarkFire( struct event_args_s *args ); + + + +void EV_TrainPitchAdjust( struct event_args_s *args ); +} + +/* +====================== +Game_HookEvents + +Associate script file name with callback functions. Callback's must be extern "C" so + the engine doesn't get confused about name mangling stuff. Note that the format is + always the same. Of course, a clever mod team could actually embed parameters, behavior + into the actual .sc files and create a .sc file parser and hook their functionality through + that.. i.e., a scripting system. + +That was what we were going to do, but we ran out of time...oh well. +====================== +*/ +void Game_HookEvents( void ) +{ + gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); + gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); + gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); + gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); + gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); + gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); + gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); + gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); + gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); + gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); + gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); + gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); + gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); + gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); + gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); + gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); + gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); + gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); + gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); +} diff --git a/cl_dll/hl/hl_objects.cpp b/cl_dll/hl/hl_objects.cpp new file mode 100644 index 00000000..e95dfae7 --- /dev/null +++ b/cl_dll/hl/hl_objects.cpp @@ -0,0 +1,90 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "../hud.h" +#include "../cl_util.h" +#include "../demo.h" + +#include "demo_api.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" + +#include "pm_defs.h" +#include "event_api.h" +#include "entity_types.h" +#include "r_efx.h" + +extern BEAM *pBeam; +extern BEAM *pBeam2; +void HUD_GetLastOrg( float *org ); + +void UpdateBeams ( void ) +{ + vec3_t forward, vecSrc, vecEnd, origin, angles, right, up; + vec3_t view_ofs; + pmtrace_t tr; + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + int idx = pthisplayer->index; + + // Get our exact viewangles from engine + gEngfuncs.GetViewAngles( (float *)angles ); + + // Determine our last predicted origin + HUD_GetLastOrg( (float *)&origin ); + + AngleVectors( angles, forward, right, up ); + + VectorCopy( origin, vecSrc ); + + VectorMA( vecSrc, 2048, forward, vecEnd ); + + 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, vecEnd, PM_STUDIO_BOX, -1, &tr ); + + gEngfuncs.pEventAPI->EV_PopPMStates(); + + if ( pBeam ) + { + pBeam->target = tr.endpos; + pBeam->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + } + + if ( pBeam2 ) + { + pBeam2->target = tr.endpos; + pBeam2->die = gEngfuncs.GetClientTime() + 0.1; // We keep it alive just a little bit forward in the future, just in case. + } +} + +/* +===================== +Game_AddObjects + +Add game specific, client-side objects here +===================== +*/ +void Game_AddObjects( void ) +{ + if ( pBeam && pBeam2 ) + UpdateBeams(); +} diff --git a/cl_dll/hl/hl_weapons.cpp b/cl_dll/hl/hl_weapons.cpp new file mode 100644 index 00000000..820e49ff --- /dev/null +++ b/cl_dll/hl/hl_weapons.cpp @@ -0,0 +1,1095 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "monsters.h" +#include "weapons.h" +#include "nodes.h" +#include "player.h" + +#include "usercmd.h" +#include "entity_state.h" +#include "demo_api.h" +#include "pm_defs.h" +#include "event_api.h" +#include "r_efx.h" + +#include "../hud_iface.h" +#include "../com_weapons.h" +#include "../demo.h" + +extern globalvars_t *gpGlobals; +extern int g_iUser1; + +// Pool of client side entities/entvars_t +static entvars_t ev[ 32 ]; +static int num_ents = 0; + +// The entity we'll use to represent the local client +static CBasePlayer player; + +// Local version of game .dll global variables ( time, etc. ) +static globalvars_t Globals; + +static CBasePlayerWeapon *g_pWpns[ 32 ]; + +float g_flApplyVel = 0.0; +int g_irunninggausspred = 0; + +vec3_t previousorigin; + +// HLDM Weapon placeholder entities. +CGlock g_Glock; +CCrowbar g_Crowbar; +CPython g_Python; +CMP5 g_Mp5; +CCrossbow g_Crossbow; +CShotgun g_Shotgun; +CRpg g_Rpg; +CGauss g_Gauss; +CEgon g_Egon; +CHgun g_HGun; +CHandGrenade g_HandGren; +CSatchel g_Satchel; +CTripmine g_Tripmine; +CSqueak g_Snark; + + +/* +====================== +AlertMessage + +Print debug messages to console +====================== +*/ +void AlertMessage( ALERT_TYPE atype, char *szFmt, ... ) +{ + va_list argptr; + static char string[1024]; + + va_start (argptr, szFmt); + vsprintf (string, szFmt,argptr); + va_end (argptr); + + gEngfuncs.Con_Printf( "cl: " ); + gEngfuncs.Con_Printf( string ); +} + +//Returns if it's multiplayer. +//Mostly used by the client side weapons. +bool bIsMultiplayer ( void ) +{ + return gEngfuncs.GetMaxClients() == 1 ? 0 : 1; +} +//Just loads a v_ model. +void LoadVModel ( char *szViewModel, CBasePlayer *m_pPlayer ) +{ + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); +} + +/* +===================== +HUD_PrepEntity + +Links the raw entity to an entvars_s holder. If a player is passed in as the owner, then +we set up the m_pPlayer field. +===================== +*/ +void HUD_PrepEntity( CBaseEntity *pEntity, CBasePlayer *pWeaponOwner ) +{ + memset( &ev[ num_ents ], 0, sizeof( entvars_t ) ); + pEntity->pev = &ev[ num_ents++ ]; + + pEntity->Precache(); + pEntity->Spawn(); + + if ( pWeaponOwner ) + { + ItemInfo info; + + ((CBasePlayerWeapon *)pEntity)->m_pPlayer = pWeaponOwner; + + ((CBasePlayerWeapon *)pEntity)->GetItemInfo( &info ); + + g_pWpns[ info.iId ] = (CBasePlayerWeapon *)pEntity; + } +} + +/* +===================== +CBaseEntity :: Killed + +If weapons code "kills" an entity, just set its effects to EF_NODRAW +===================== +*/ +void CBaseEntity :: Killed( entvars_t *pevAttacker, int iGib ) +{ + pev->effects |= EF_NODRAW; +} + +/* +===================== +CBasePlayerWeapon :: DefaultReload +===================== +*/ +BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, int body ) +{ + + if (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + return FALSE; + + int j = min(iClipSize - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + + if (j == 0) + return FALSE; + + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; + + //!!UNDONE -- reload sound goes here !!! + SendWeaponAnim( iAnim, UseDecrement(), body ); + + m_fInReload = TRUE; + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: CanDeploy +===================== +*/ +BOOL CBasePlayerWeapon :: CanDeploy( void ) +{ + BOOL bHasAmmo = 0; + + if ( !pszAmmo1() ) + { + // this weapon doesn't use ammo, can always deploy. + return TRUE; + } + + if ( pszAmmo1() ) + { + bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] != 0); + } + if ( pszAmmo2() ) + { + bHasAmmo |= (m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType] != 0); + } + if (m_iClip > 0) + { + bHasAmmo |= 1; + } + if (!bHasAmmo) + { + return FALSE; + } + + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: DefaultDeploy + +===================== +*/ +BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal, int body ) +{ + if ( !CanDeploy() ) + return FALSE; + + gEngfuncs.CL_LoadModel( szViewModel, &m_pPlayer->pev->viewmodel ); + + SendWeaponAnim( iAnim, skiplocal, body ); + + g_irunninggausspred = false; + m_pPlayer->m_flNextAttack = 0.5; + m_flTimeWeaponIdle = 1.0; + return TRUE; +} + +/* +===================== +CBasePlayerWeapon :: PlayEmptySound + +===================== +*/ +BOOL CBasePlayerWeapon :: PlayEmptySound( void ) +{ + if (m_iPlayEmptySound) + { + HUD_PlaySound( "weapons/357_cock1.wav", 0.8 ); + m_iPlayEmptySound = 0; + return 0; + } + return 0; +} + +/* +===================== +CBasePlayerWeapon :: ResetEmptySound + +===================== +*/ +void CBasePlayerWeapon :: ResetEmptySound( void ) +{ + m_iPlayEmptySound = 1; +} + +/* +===================== +CBasePlayerWeapon::Holster + +Put away weapon +===================== +*/ +void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) +{ + m_fInReload = FALSE; // cancel any reload in progress. + g_irunninggausspred = false; + m_pPlayer->pev->viewmodel = 0; +} + +/* +===================== +CBasePlayerWeapon::SendWeaponAnim + +Animate weapon model +===================== +*/ +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) +{ + m_pPlayer->pev->weaponanim = iAnim; + + HUD_SendWeaponAnim( iAnim, body, 0 ); +} + +/* +===================== +CBaseEntity::FireBulletsPlayer + +Only produces random numbers to match the server ones. +===================== +*/ +Vector CBaseEntity::FireBulletsPlayer ( ULONG cShots, Vector vecSrc, Vector vecDirShooting, Vector vecSpread, float flDistance, int iBulletType, int iTracerFreq, int iDamage, entvars_t *pevAttacker, int shared_rand ) +{ + float x, y, z; + + for ( ULONG iShot = 1; iShot <= cShots; iShot++ ) + { + if ( pevAttacker == NULL ) + { + // get circular gaussian spread + do { + x = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5); + y = RANDOM_FLOAT(-0.5, 0.5) + RANDOM_FLOAT(-0.5, 0.5); + z = x*x+y*y; + } while (z > 1); + } + else + { + //Use player's random seed. + // get circular gaussian spread + x = UTIL_SharedRandomFloat( shared_rand + iShot, -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 1 + iShot ) , -0.5, 0.5 ); + y = UTIL_SharedRandomFloat( shared_rand + ( 2 + iShot ), -0.5, 0.5 ) + UTIL_SharedRandomFloat( shared_rand + ( 3 + iShot ), -0.5, 0.5 ); + z = x * x + y * y; + } + + } + + return Vector ( x * vecSpread.x, y * vecSpread.y, 0.0 ); +} + +/* +===================== +CBasePlayerWeapon::ItemPostFrame + +Handles weapon firing, reloading, etc. +===================== +*/ +void CBasePlayerWeapon::ItemPostFrame( void ) +{ + if ((m_fInReload) && (m_pPlayer->m_flNextAttack <= 0.0)) + { +#if 0 // FIXME, need ammo on client to make this work right + // complete the reload. + int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); + + // Add them to the clip + m_iClip += j; + m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; +#else + m_iClip += 10; +#endif + m_fInReload = FALSE; + } + + if ((m_pPlayer->pev->button & IN_ATTACK2) && (m_flNextSecondaryAttack <= 0.0)) + { + if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) + { + m_fFireOnEmpty = TRUE; + } + + SecondaryAttack(); + m_pPlayer->pev->button &= ~IN_ATTACK2; + } + else if ((m_pPlayer->pev->button & IN_ATTACK) && (m_flNextPrimaryAttack <= 0.0)) + { + if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) + { + m_fFireOnEmpty = TRUE; + } + + PrimaryAttack(); + } + else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) + { + // reload when reload is pressed, or if no buttons are down and weapon is empty. + Reload(); + } + else if ( !(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2) ) ) + { + // no fire buttons down + + m_fFireOnEmpty = FALSE; + + // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing + if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < 0.0 ) + { + Reload(); + return; + } + + WeaponIdle( ); + return; + } + + // catch all + if ( ShouldWeaponIdle() ) + { + WeaponIdle(); + } +} + +/* +===================== +CBasePlayer::SelectItem + + Switch weapons +===================== +*/ +void CBasePlayer::SelectItem(const char *pstr) +{ + if (!pstr) + return; + + CBasePlayerItem *pItem = NULL; + + if (!pItem) + return; + + + if (pItem == m_pActiveItem) + return; + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + m_pLastItem = m_pActiveItem; + m_pActiveItem = pItem; + + if (m_pActiveItem) + { + m_pActiveItem->Deploy( ); + } +} + +/* +===================== +CBasePlayer::SelectLastItem + +===================== +*/ +void CBasePlayer::SelectLastItem(void) +{ + if (!m_pLastItem) + { + return; + } + + if ( m_pActiveItem && !m_pActiveItem->CanHolster() ) + { + return; + } + + if (m_pActiveItem) + m_pActiveItem->Holster( ); + + CBasePlayerItem *pTemp = m_pActiveItem; + m_pActiveItem = m_pLastItem; + m_pLastItem = pTemp; + m_pActiveItem->Deploy( ); +} + +/* +===================== +CBasePlayer::Killed + +===================== +*/ +void CBasePlayer::Killed( entvars_t *pevAttacker, int iGib ) +{ + // Holster weapon immediately, to allow it to cleanup + if ( m_pActiveItem ) + m_pActiveItem->Holster( ); + + g_irunninggausspred = false; +} + +/* +===================== +CBasePlayer::Spawn + +===================== +*/ +void CBasePlayer::Spawn( void ) +{ + if (m_pActiveItem) + m_pActiveItem->Deploy( ); + + g_irunninggausspred = false; +} + +/* +===================== +UTIL_TraceLine + +Don't actually trace, but act like the trace didn't hit anything. +===================== +*/ +void UTIL_TraceLine( const Vector &vecStart, const Vector &vecEnd, IGNORE_MONSTERS igmon, edict_t *pentIgnore, TraceResult *ptr ) +{ + memset( ptr, 0, sizeof( *ptr ) ); + ptr->flFraction = 1.0; +} + +/* +===================== +UTIL_ParticleBox + +For debugging, draw a box around a player made out of particles +===================== +*/ +void UTIL_ParticleBox( CBasePlayer *player, float *mins, float *maxs, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + int i; + vec3_t mmin, mmax; + + for ( i = 0; i < 3; i++ ) + { + mmin[ i ] = player->pev->origin[ i ] + mins[ i ]; + mmax[ i ] = player->pev->origin[ i ] + maxs[ i ]; + } + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mmin, (float *)&mmax, 5.0, 0, 255, 0 ); +} + +/* +===================== +UTIL_ParticleBoxes + +For debugging, draw boxes for other collidable players +===================== +*/ +void UTIL_ParticleBoxes( void ) +{ + int idx; + physent_t *pe; + cl_entity_t *player; + vec3_t mins, maxs; + + gEngfuncs.pEventAPI->EV_SetUpPlayerPrediction( false, true ); + + // Store off the old count + gEngfuncs.pEventAPI->EV_PushPMStates(); + + player = gEngfuncs.GetLocalPlayer(); + // Now add in all of the players. + gEngfuncs.pEventAPI->EV_SetSolidPlayers ( player->index - 1 ); + + for ( idx = 1; idx < 100; idx++ ) + { + pe = gEngfuncs.pEventAPI->EV_GetPhysent( idx ); + if ( !pe ) + break; + + if ( pe->info >= 1 && pe->info <= gEngfuncs.GetMaxClients() ) + { + mins = pe->origin + pe->mins; + maxs = pe->origin + pe->maxs; + + gEngfuncs.pEfxAPI->R_ParticleBox( (float *)&mins, (float *)&maxs, 0, 0, 255, 2.0 ); + } + } + + gEngfuncs.pEventAPI->EV_PopPMStates(); +} + +/* +===================== +UTIL_ParticleLine + +For debugging, draw a line made out of particles +===================== +*/ +void UTIL_ParticleLine( CBasePlayer *player, float *start, float *end, float life, unsigned char r, unsigned char g, unsigned char b ) +{ + gEngfuncs.pEfxAPI->R_ParticleLine( start, end, r, g, b, life ); +} + +/* +===================== +CBasePlayerWeapon::PrintState + +For debugging, print out state variables to log file +===================== +*/ +void CBasePlayerWeapon::PrintState( void ) +{ + COM_Log( "c:\\hl.log", "%.4f ", gpGlobals->time ); + COM_Log( "c:\\hl.log", "%.4f ", m_pPlayer->m_flNextAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flNextPrimaryAttack ); + COM_Log( "c:\\hl.log", "%.4f ", m_flTimeWeaponIdle - gpGlobals->time); + COM_Log( "c:\\hl.log", "%i ", m_iClip ); +} + +/* +===================== +HUD_InitClientWeapons + +Set up weapons, player and functions needed to run weapons code client-side. +===================== +*/ +void HUD_InitClientWeapons( void ) +{ + static int initialized = 0; + if ( initialized ) + return; + + initialized = 1; + + // Set up pointer ( dummy object ) + gpGlobals = &Globals; + + // Fill in current time ( probably not needed ) + gpGlobals->time = gEngfuncs.GetClientTime(); + + // Fake functions + g_engfuncs.pfnPrecacheModel = stub_PrecacheModel; + g_engfuncs.pfnPrecacheSound = stub_PrecacheSound; + g_engfuncs.pfnPrecacheEvent = stub_PrecacheEvent; + g_engfuncs.pfnNameForFunction = stub_NameForFunction; + g_engfuncs.pfnSetModel = stub_SetModel; + g_engfuncs.pfnSetClientMaxspeed = HUD_SetMaxSpeed; + + // Handled locally + g_engfuncs.pfnPlaybackEvent = HUD_PlaybackEvent; + g_engfuncs.pfnAlertMessage = AlertMessage; + + // Pass through to engine + g_engfuncs.pfnPrecacheEvent = gEngfuncs.pfnPrecacheEvent; + g_engfuncs.pfnRandomFloat = gEngfuncs.pfnRandomFloat; + g_engfuncs.pfnRandomLong = gEngfuncs.pfnRandomLong; + + // Allocate a slot for the local player + HUD_PrepEntity( &player , NULL ); + + // Allocate slot(s) for each weapon that we are going to be predicting + HUD_PrepEntity( &g_Glock , &player ); + HUD_PrepEntity( &g_Crowbar , &player ); + HUD_PrepEntity( &g_Python , &player ); + HUD_PrepEntity( &g_Mp5 , &player ); + HUD_PrepEntity( &g_Crossbow , &player ); + HUD_PrepEntity( &g_Shotgun , &player ); + HUD_PrepEntity( &g_Rpg , &player ); + HUD_PrepEntity( &g_Gauss , &player ); + HUD_PrepEntity( &g_Egon , &player ); + HUD_PrepEntity( &g_HGun , &player ); + HUD_PrepEntity( &g_HandGren , &player ); + HUD_PrepEntity( &g_Satchel , &player ); + HUD_PrepEntity( &g_Tripmine , &player ); + HUD_PrepEntity( &g_Snark , &player ); +} + +/* +===================== +HUD_GetLastOrg + +Retruns the last position that we stored for egon beam endpoint. +===================== +*/ +void HUD_GetLastOrg( float *org ) +{ + int i; + + // Return last origin + for ( i = 0; i < 3; i++ ) + { + org[i] = previousorigin[i]; + } +} + +/* +===================== +HUD_SetLastOrg + +Remember our exact predicted origin so we can draw the egon to the right position. +===================== +*/ +void HUD_SetLastOrg( void ) +{ + int i; + + // Offset final origin by view_offset + for ( i = 0; i < 3; i++ ) + { + previousorigin[i] = g_finalstate->playerstate.origin[i] + g_finalstate->client.view_ofs[ i ]; + } +} + +/* +===================== +HUD_WeaponsPostThink + +Run Weapon firing code on client +===================== +*/ +void HUD_WeaponsPostThink( local_state_s *from, local_state_s *to, usercmd_t *cmd, double time, unsigned int random_seed ) +{ + int i; + int buttonsChanged; + CBasePlayerWeapon *pWeapon = NULL; + CBasePlayerWeapon *pCurrent; + weapon_data_t nulldata, *pfrom, *pto; + static int lasthealth; + + memset( &nulldata, 0, sizeof( nulldata ) ); + + HUD_InitClientWeapons(); + + // Get current clock + gpGlobals->time = time; + + // Fill in data based on selected weapon + // FIXME, make this a method in each weapon? where you pass in an entity_state_t *? + switch ( from->client.m_iId ) + { + case WEAPON_CROWBAR: + pWeapon = &g_Crowbar; + break; + + case WEAPON_GLOCK: + pWeapon = &g_Glock; + break; + + case WEAPON_PYTHON: + pWeapon = &g_Python; + break; + + case WEAPON_MP5: + pWeapon = &g_Mp5; + break; + + case WEAPON_CROSSBOW: + pWeapon = &g_Crossbow; + break; + + case WEAPON_SHOTGUN: + pWeapon = &g_Shotgun; + break; + + case WEAPON_RPG: + pWeapon = &g_Rpg; + break; + + case WEAPON_GAUSS: + pWeapon = &g_Gauss; + break; + + case WEAPON_EGON: + pWeapon = &g_Egon; + break; + + case WEAPON_HORNETGUN: + pWeapon = &g_HGun; + break; + + case WEAPON_HANDGRENADE: + pWeapon = &g_HandGren; + break; + + case WEAPON_SATCHEL: + pWeapon = &g_Satchel; + break; + + case WEAPON_TRIPMINE: + pWeapon = &g_Tripmine; + break; + + case WEAPON_SNARK: + pWeapon = &g_Snark; + break; + } + + // Store pointer to our destination entity_state_t so we can get our origin, etc. from it + // for setting up events on the client + g_finalstate = to; + + // If we are running events/etc. go ahead and see if we + // managed to die between last frame and this one + // If so, run the appropriate player killed or spawn function + if ( g_runfuncs ) + { + if ( to->client.health <= 0 && lasthealth > 0 ) + { + player.Killed( NULL, 0 ); + + } + else if ( to->client.health > 0 && lasthealth <= 0 ) + { + player.Spawn(); + } + + lasthealth = to->client.health; + } + + // We are not predicting the current weapon, just bow out here. + if ( !pWeapon ) + return; + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + if ( !pCurrent ) + { + continue; + } + + pfrom = &from->weapondata[ i ]; + + pCurrent->m_fInReload = pfrom->m_fInReload; + pCurrent->m_fInSpecialReload = pfrom->m_fInSpecialReload; +// pCurrent->m_flPumpTime = pfrom->m_flPumpTime; + pCurrent->m_iClip = pfrom->m_iClip; + pCurrent->m_flNextPrimaryAttack = pfrom->m_flNextPrimaryAttack; + pCurrent->m_flNextSecondaryAttack = pfrom->m_flNextSecondaryAttack; + pCurrent->m_flTimeWeaponIdle = pfrom->m_flTimeWeaponIdle; + pCurrent->pev->fuser1 = pfrom->fuser1; + pCurrent->m_flStartThrow = pfrom->fuser2; + pCurrent->m_flReleaseThrow = pfrom->fuser3; + pCurrent->m_chargeReady = pfrom->iuser1; + pCurrent->m_fInAttack = pfrom->iuser2; + pCurrent->m_fireState = pfrom->iuser3; + + pCurrent->m_iSecondaryAmmoType = (int)from->client.vuser3[ 2 ]; + pCurrent->m_iPrimaryAmmoType = (int)from->client.vuser4[ 0 ]; + player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ] = (int)from->client.vuser4[ 1 ]; + player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ] = (int)from->client.vuser4[ 2 ]; + } + + // For random weapon events, use this seed to seed random # generator + player.random_seed = random_seed; + + // Get old buttons from previous state. + player.m_afButtonLast = from->playerstate.oldbuttons; + + // Which buttsons chave changed + buttonsChanged = (player.m_afButtonLast ^ cmd->buttons); // These buttons have changed this frame + + // Debounced button codes for pressed/released + // The changed ones still down are "pressed" + player.m_afButtonPressed = buttonsChanged & cmd->buttons; + // The ones not down are "released" + player.m_afButtonReleased = buttonsChanged & (~cmd->buttons); + + // Set player variables that weapons code might check/alter + player.pev->button = cmd->buttons; + + player.pev->velocity = from->client.velocity; + player.pev->flags = from->client.flags; + + player.pev->deadflag = from->client.deadflag; + player.pev->waterlevel = from->client.waterlevel; + player.pev->maxspeed = from->client.maxspeed; + player.pev->fov = from->client.fov; + player.pev->weaponanim = from->client.weaponanim; + player.pev->viewmodel = from->client.viewmodel; + player.m_flNextAttack = from->client.m_flNextAttack; + player.m_flNextAmmoBurn = from->client.fuser2; + player.m_flAmmoStartCharge = from->client.fuser3; + + //Stores all our ammo info, so the client side weapons can use them. + player.ammo_9mm = (int)from->client.vuser1[0]; + player.ammo_357 = (int)from->client.vuser1[1]; + player.ammo_argrens = (int)from->client.vuser1[2]; + player.ammo_bolts = (int)from->client.ammo_nails; //is an int anyways... + player.ammo_buckshot = (int)from->client.ammo_shells; + player.ammo_uranium = (int)from->client.ammo_cells; + player.ammo_hornets = (int)from->client.vuser2[0]; + player.ammo_rockets = (int)from->client.ammo_rockets; + + + // Point to current weapon object + if ( from->client.m_iId ) + { + player.m_pActiveItem = g_pWpns[ from->client.m_iId ]; + } + + if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + { + ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive = (int)from->client.vuser2[ 1 ]; + ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets = (int)from->client.vuser2[ 2 ]; + } + + // Don't go firing anything if we have died. + // Or if we don't have a weapon model deployed + if ( ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) && + !CL_IsDead() && player.pev->viewmodel && !g_iUser1 ) + { + if ( player.m_flNextAttack <= 0 ) + { + pWeapon->ItemPostFrame(); + } + } + + // Assume that we are not going to switch weapons + to->client.m_iId = from->client.m_iId; + + // Now see if we issued a changeweapon command ( and we're not dead ) + if ( cmd->weaponselect && ( player.pev->deadflag != ( DEAD_DISCARDBODY + 1 ) ) ) + { + // Switched to a different weapon? + if ( from->weapondata[ cmd->weaponselect ].m_iId == cmd->weaponselect ) + { + CBasePlayerWeapon *pNew = g_pWpns[ cmd->weaponselect ]; + if ( pNew && ( pNew != pWeapon ) ) + { + // Put away old weapon + if (player.m_pActiveItem) + player.m_pActiveItem->Holster( ); + + player.m_pLastItem = player.m_pActiveItem; + player.m_pActiveItem = pNew; + + // Deploy new weapon + if (player.m_pActiveItem) + { + player.m_pActiveItem->Deploy( ); + } + + // Update weapon id so we can predict things correctly. + to->client.m_iId = cmd->weaponselect; + } + } + } + + // Copy in results of prediction code + to->client.viewmodel = player.pev->viewmodel; + to->client.fov = player.pev->fov; + to->client.weaponanim = player.pev->weaponanim; + to->client.m_flNextAttack = player.m_flNextAttack; + to->client.fuser2 = player.m_flNextAmmoBurn; + to->client.fuser3 = player.m_flAmmoStartCharge; + to->client.maxspeed = player.pev->maxspeed; + + //HL Weapons + to->client.vuser1[0] = player.ammo_9mm; + to->client.vuser1[1] = player.ammo_357; + to->client.vuser1[2] = player.ammo_argrens; + + to->client.ammo_nails = player.ammo_bolts; + to->client.ammo_shells = player.ammo_buckshot; + to->client.ammo_cells = player.ammo_uranium; + to->client.vuser2[0] = player.ammo_hornets; + to->client.ammo_rockets = player.ammo_rockets; + + if ( player.m_pActiveItem->m_iId == WEAPON_RPG ) + { + from->client.vuser2[ 1 ] = ( ( CRpg * )player.m_pActiveItem)->m_fSpotActive; + from->client.vuser2[ 2 ] = ( ( CRpg * )player.m_pActiveItem)->m_cActiveRockets; + } + + // Make sure that weapon animation matches what the game .dll is telling us + // over the wire ( fixes some animation glitches ) + if ( g_runfuncs && ( HUD_GetWeaponAnim() != to->client.weaponanim ) ) + { + int body = 2; + + //Pop the model to body 0. + if ( pWeapon == &g_Tripmine ) + body = 0; + + //Show laser sight/scope combo + if ( pWeapon == &g_Python && bIsMultiplayer() ) + body = 1; + + // Force a fixed anim down to viewmodel + HUD_SendWeaponAnim( to->client.weaponanim, body, 1 ); + } + + for ( i = 0; i < 32; i++ ) + { + pCurrent = g_pWpns[ i ]; + + pto = &to->weapondata[ i ]; + + if ( !pCurrent ) + { + memset( pto, 0, sizeof( weapon_data_t ) ); + continue; + } + + pto->m_fInReload = pCurrent->m_fInReload; + pto->m_fInSpecialReload = pCurrent->m_fInSpecialReload; +// pto->m_flPumpTime = pCurrent->m_flPumpTime; + pto->m_iClip = pCurrent->m_iClip; + pto->m_flNextPrimaryAttack = pCurrent->m_flNextPrimaryAttack; + pto->m_flNextSecondaryAttack = pCurrent->m_flNextSecondaryAttack; + pto->m_flTimeWeaponIdle = pCurrent->m_flTimeWeaponIdle; + pto->fuser1 = pCurrent->pev->fuser1; + pto->fuser2 = pCurrent->m_flStartThrow; + pto->fuser3 = pCurrent->m_flReleaseThrow; + pto->iuser1 = pCurrent->m_chargeReady; + pto->iuser2 = pCurrent->m_fInAttack; + pto->iuser3 = pCurrent->m_fireState; + + // Decrement weapon counters, server does this at same time ( during post think, after doing everything else ) + pto->m_flNextReload -= cmd->msec / 1000.0; + pto->m_fNextAimBonus -= cmd->msec / 1000.0; + pto->m_flNextPrimaryAttack -= cmd->msec / 1000.0; + pto->m_flNextSecondaryAttack -= cmd->msec / 1000.0; + pto->m_flTimeWeaponIdle -= cmd->msec / 1000.0; + pto->fuser1 -= cmd->msec / 1000.0; + + to->client.vuser3[2] = pCurrent->m_iSecondaryAmmoType; + to->client.vuser4[0] = pCurrent->m_iPrimaryAmmoType; + to->client.vuser4[1] = player.m_rgAmmo[ pCurrent->m_iPrimaryAmmoType ]; + to->client.vuser4[2] = player.m_rgAmmo[ pCurrent->m_iSecondaryAmmoType ]; + +/* if ( pto->m_flPumpTime != -9999 ) + { + pto->m_flPumpTime -= cmd->msec / 1000.0; + if ( pto->m_flPumpTime < -0.001 ) + pto->m_flPumpTime = -0.001; + }*/ + + if ( pto->m_fNextAimBonus < -1.0 ) + { + pto->m_fNextAimBonus = -1.0; + } + + if ( pto->m_flNextPrimaryAttack < -1.0 ) + { + pto->m_flNextPrimaryAttack = -1.0; + } + + if ( pto->m_flNextSecondaryAttack < -0.001 ) + { + pto->m_flNextSecondaryAttack = -0.001; + } + + if ( pto->m_flTimeWeaponIdle < -0.001 ) + { + pto->m_flTimeWeaponIdle = -0.001; + } + + if ( pto->m_flNextReload < -0.001 ) + { + pto->m_flNextReload = -0.001; + } + + if ( pto->fuser1 < -0.001 ) + { + pto->fuser1 = -0.001; + } + } + + // m_flNextAttack is now part of the weapons, but is part of the player instead + to->client.m_flNextAttack -= cmd->msec / 1000.0; + if ( to->client.m_flNextAttack < -0.001 ) + { + to->client.m_flNextAttack = -0.001; + } + + to->client.fuser2 -= cmd->msec / 1000.0; + if ( to->client.fuser2 < -0.001 ) + { + to->client.fuser2 = -0.001; + } + + to->client.fuser3 -= cmd->msec / 1000.0; + if ( to->client.fuser3 < -0.001 ) + { + to->client.fuser3 = -0.001; + } + + // Store off the last position from the predicted state. + HUD_SetLastOrg(); + + // Wipe it so we can't use it after this frame + g_finalstate = NULL; +} + +/* +===================== +HUD_PostRunCmd + +Client calls this during prediction, after it has moved the player and updated any info changed into to-> +time is the current client clock based on prediction +cmd is the command that caused the movement, etc +runfuncs is 1 if this is the first time we've predicted this command. If so, sounds and effects should play, otherwise, they should +be ignored +===================== +*/ +void _DLLEXPORT HUD_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ) +{ + g_runfuncs = runfuncs; + +#if defined( CLIENT_WEAPONS ) + if ( cl_lw && cl_lw->value ) + { + HUD_WeaponsPostThink( from, to, cmd, time, random_seed ); + } + else +#endif + { + to->client.fov = g_lastFOV; + } + + if ( g_irunninggausspred == 1 ) + { + Vector forward; + gEngfuncs.pfnAngleVectors( v_angles, forward, NULL, NULL ); + to->client.velocity = to->client.velocity - forward * g_flApplyVel * 5; + g_irunninggausspred = false; + } + + // All games can use FOV state + g_lastFOV = to->client.fov; +} diff --git a/cl_dll/hud.cpp b/cl_dll/hud.cpp new file mode 100644 index 00000000..f614e95a --- /dev/null +++ b/cl_dll/hud.cpp @@ -0,0 +1,683 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud.cpp +// +// implementation of CHud class +// + +#include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" +#include "hud_servers.h" +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" + +#include "demo.h" +#include "demo_api.h" +#include "vgui_scorepanel.h" + + + +class CHLVoiceStatusHelper : public IVoiceStatusHelper +{ +public: + virtual void GetPlayerTextColor(int entindex, int color[3]) + { + color[0] = color[1] = color[2] = 255; + + if( entindex >= 0 && entindex < sizeof(g_PlayerExtraInfo)/sizeof(g_PlayerExtraInfo[0]) ) + { + int iTeam = g_PlayerExtraInfo[entindex].teamnumber; + + if ( iTeam < 0 ) + { + iTeam = 0; + } + + iTeam = iTeam % iNumberOfTeamColors; + + color[0] = iTeamColors[iTeam][0]; + color[1] = iTeamColors[iTeam][1]; + color[2] = iTeamColors[iTeam][2]; + } + } + + virtual void UpdateCursorState() + { + gViewPort->UpdateCursorState(); + } + + virtual int GetAckIconHeight() + { + return ScreenHeight - gHUD.m_iFontHeight*3 - 6; + } + + virtual bool CanShowSpeakerLabels() + { + if( gViewPort && gViewPort->m_pScoreBoard ) + return !gViewPort->m_pScoreBoard->isVisible(); + else + return false; + } +}; +static CHLVoiceStatusHelper g_VoiceStatusHelper; + + +extern client_sprite_t *GetSpriteList(client_sprite_t *pList, const char *psz, int iRes, int iCount); + +extern cvar_t *sensitivity; +cvar_t *cl_lw = NULL; + +void ShutdownInput (void); + +//DECLARE_MESSAGE(m_Logo, Logo) +int __MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_Logo(pszName, iSize, pbuf ); +} + +//DECLARE_MESSAGE(m_Logo, Logo) +int __MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_ResetHUD(pszName, iSize, pbuf ); +} + +int __MsgFunc_InitHUD(const char *pszName, int iSize, void *pbuf) +{ + gHUD.MsgFunc_InitHUD( pszName, iSize, pbuf ); + return 1; +} + +int __MsgFunc_ViewMode(const char *pszName, int iSize, void *pbuf) +{ + gHUD.MsgFunc_ViewMode( pszName, iSize, pbuf ); + return 1; +} + +int __MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_SetFOV( pszName, iSize, pbuf ); +} + +int __MsgFunc_Concuss(const char *pszName, int iSize, void *pbuf) +{ + return gHUD.MsgFunc_Concuss( pszName, iSize, pbuf ); +} + +int __MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) +{ + return gHUD.MsgFunc_GameMode( pszName, iSize, pbuf ); +} + +// TFFree Command Menu +void __CmdFunc_OpenCommandMenu(void) +{ + if ( gViewPort ) + { + gViewPort->ShowCommandMenu( gViewPort->m_StandardMenu ); + } +} + +// TFC "special" command +void __CmdFunc_InputPlayerSpecial(void) +{ + if ( gViewPort ) + { + gViewPort->InputPlayerSpecial(); + } +} + +void __CmdFunc_CloseCommandMenu(void) +{ + if ( gViewPort ) + { + gViewPort->InputSignalHideCommandMenu(); + } +} + +void __CmdFunc_ForceCloseCommandMenu( void ) +{ + if ( gViewPort ) + { + gViewPort->HideCommandMenu(); + } +} + +void __CmdFunc_ToggleServerBrowser( void ) +{ + if ( gViewPort ) + { + gViewPort->ToggleServerBrowser(); + } +} + +// TFFree Command Menu Message Handlers +int __MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_ValClass( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamNames( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_Feign(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_Feign( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_Detpack( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_VGUIMenu( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_MOTD(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_MOTD( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_BuildSt(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_BuildSt( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_RandomPC(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_RandomPC( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_ServerName(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_ServerName( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_ScoreInfo(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_ScoreInfo( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_TeamScore(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamScore( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_TeamInfo(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_TeamInfo( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_Spectator(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_Spectator( pszName, iSize, pbuf ); + return 0; +} + +int __MsgFunc_AllowSpec(const char *pszName, int iSize, void *pbuf) +{ + if (gViewPort) + return gViewPort->MsgFunc_AllowSpec( pszName, iSize, pbuf ); + return 0; +} + +// This is called every time the DLL is loaded +void CHud :: Init( void ) +{ + HOOK_MESSAGE( Logo ); + HOOK_MESSAGE( ResetHUD ); + HOOK_MESSAGE( GameMode ); + HOOK_MESSAGE( InitHUD ); + HOOK_MESSAGE( ViewMode ); + HOOK_MESSAGE( SetFOV ); + HOOK_MESSAGE( Concuss ); + + // TFFree CommandMenu + HOOK_COMMAND( "+commandmenu", OpenCommandMenu ); + HOOK_COMMAND( "-commandmenu", CloseCommandMenu ); + HOOK_COMMAND( "ForceCloseCommandMenu", ForceCloseCommandMenu ); + HOOK_COMMAND( "special", InputPlayerSpecial ); + HOOK_COMMAND( "togglebrowser", ToggleServerBrowser ); + + HOOK_MESSAGE( ValClass ); + HOOK_MESSAGE( TeamNames ); + HOOK_MESSAGE( Feign ); + HOOK_MESSAGE( Detpack ); + HOOK_MESSAGE( MOTD ); + HOOK_MESSAGE( BuildSt ); + HOOK_MESSAGE( RandomPC ); + HOOK_MESSAGE( ServerName ); + HOOK_MESSAGE( ScoreInfo ); + HOOK_MESSAGE( TeamScore ); + HOOK_MESSAGE( TeamInfo ); + + HOOK_MESSAGE( Spectator ); + HOOK_MESSAGE( AllowSpec ); + + // VGUI Menus + HOOK_MESSAGE( VGUIMenu ); + + 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 + + + m_iLogo = 0; + m_iFOV = 0; + + CVAR_CREATE( "zoom_sensitivity_ratio", "1.2", 0 ); + default_fov = CVAR_CREATE( "default_fov", "90", 0 ); + m_pCvarStealMouse = CVAR_CREATE( "hud_capturemouse", "1", FCVAR_ARCHIVE ); + m_pCvarDraw = CVAR_CREATE( "hud_draw", "1", FCVAR_ARCHIVE ); + cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); + + m_pSpriteList = NULL; + + // Clear any old HUD list + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + // In case we get messages before the first update -- time will be valid + m_flTime = 1.0; + + m_Ammo.Init(); + m_Health.Init(); + m_SayText.Init(); + m_Spectator.Init(); + m_Geiger.Init(); + m_Train.Init(); + m_Battery.Init(); + m_Flash.Init(); + m_Message.Init(); + m_StatusBar.Init(); + m_DeathNotice.Init(); + m_AmmoSecondary.Init(); + m_TextMessage.Init(); + m_StatusIcons.Init(); + + if( gViewPort ) + GetClientVoiceMgr()->Init(&g_VoiceStatusHelper, (vgui::Panel**)&gViewPort); + + m_Menu.Init(); + + ServersInit(); + + MsgFunc_ResetHUD(0, 0, NULL ); +} + +// CHud destructor +// cleans up memory allocated for m_rg* arrays +CHud :: ~CHud() +{ + delete [] m_rghSprites; + delete [] m_rgrcRects; + delete [] m_rgszSpriteNames; + + if ( m_pHudList ) + { + HUDLIST *pList; + while ( m_pHudList ) + { + pList = m_pHudList; + m_pHudList = m_pHudList->pNext; + free( pList ); + } + m_pHudList = NULL; + } + + ServersShutdown(); +} + +// GetSpriteIndex() +// searches through the sprite list loaded from hud.txt for a name matching SpriteName +// returns an index into the gHUD.m_rghSprites[] array +// returns 0 if sprite not found +int CHud :: GetSpriteIndex( const char *SpriteName ) +{ + // look through the loaded sprite name list for SpriteName + for ( int i = 0; i < m_iSpriteCount; i++ ) + { + if ( strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH ) == 0 ) + return i; + } + + return -1; // invalid sprite +} + +void CHud :: VidInit( void ) +{ + m_scrinfo.iSize = sizeof(m_scrinfo); + GetScreenInfo(&m_scrinfo); + + // ---------- + // Load Sprites + // --------- +// m_hsprFont = LoadSprite("sprites/%d_font.spr"); + + m_hsprLogo = 0; + m_hsprCursor = 0; + + if (ScreenWidth < 640) + m_iRes = 320; + else + m_iRes = 640; + + // Only load this once + if ( !m_pSpriteList ) + { + // we need to load the hud.txt, and all sprites within + m_pSpriteList = SPR_GetList("sprites/hud.txt", &m_iSpriteCountAllRes); + + if (m_pSpriteList) + { + // count the number of sprites of the appropriate res + m_iSpriteCount = 0; + client_sprite_t *p = m_pSpriteList; + for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + m_iSpriteCount++; + p++; + } + + // allocated memory for sprite handle arrays + m_rghSprites = new HSPRITE[m_iSpriteCount]; + m_rgrcRects = new wrect_t[m_iSpriteCount]; + m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; + + p = m_pSpriteList; + int index = 0; + for ( j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf(sz, "sprites/%s.spr", p->szSprite); + m_rghSprites[index] = SPR_Load(sz); + m_rgrcRects[index] = p->rc; + strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); + + index++; + } + + p++; + } + } + } + else + { + // we have already have loaded the sprite reference from hud.txt, but + // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) + client_sprite_t *p = m_pSpriteList; + int index = 0; + for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) + { + if ( p->iRes == m_iRes ) + { + char sz[256]; + sprintf( sz, "sprites/%s.spr", p->szSprite ); + m_rghSprites[index] = SPR_Load(sz); + index++; + } + + p++; + } + } + + // assumption: number_1, number_2, etc, are all listed and loaded sequentially + m_HUD_number_0 = GetSpriteIndex( "number_0" ); + + m_iFontHeight = m_rgrcRects[m_HUD_number_0].bottom - m_rgrcRects[m_HUD_number_0].top; + + m_Ammo.VidInit(); + m_Health.VidInit(); + m_Spectator.VidInit(); + m_Geiger.VidInit(); + m_Train.VidInit(); + m_Battery.VidInit(); + m_Flash.VidInit(); + m_Message.VidInit(); + m_StatusBar.VidInit(); + m_DeathNotice.VidInit(); + m_SayText.VidInit(); + m_Menu.VidInit(); + m_AmmoSecondary.VidInit(); + m_TextMessage.VidInit(); + m_StatusIcons.VidInit(); + + if( gViewPort ) + GetClientVoiceMgr()->VidInit(); +} + +int CHud::MsgFunc_Logo(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + // update Train data + m_iLogo = READ_BYTE(); + + return 1; +} + +float g_lastFOV = 0.0; + +/* +============ +COM_FileBase +============ +*/ +// Extracts the base name of a file (no path, no extension, assumes '/' as path separator) +void COM_FileBase ( const char *in, char *out) +{ + int len, start, end; + + len = strlen( in ); + + // scan backward for '.' + end = len - 1; + while ( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) + end--; + + if ( in[end] != '.' ) // no '.', copy to end + end = len-1; + else + end--; // Found ',', copy to left of '.' + + + // Scan backward for '/' + start = len-1; + while ( start >= 0 && in[start] != '/' && in[start] != '\\' ) + start--; + + if ( in[start] != '/' && in[start] != '\\' ) + start = 0; + else + start++; + + // Length of new sting + len = end - start + 1; + + // Copy partial string + strncpy( out, &in[start], len ); + // Terminate it + out[len] = 0; +} + +/* +================= +HUD_IsGame + +================= +*/ +int HUD_IsGame( const char *game ) +{ + const char *gamedir; + char gd[ 1024 ]; + + gamedir = gEngfuncs.pfnGetGameDirectory(); + if ( gamedir && gamedir[0] ) + { + COM_FileBase( gamedir, gd ); + if ( !stricmp( gd, game ) ) + return 1; + } + return 0; +} + +/* +===================== +HUD_GetFOV + +Returns last FOV +===================== +*/ +float HUD_GetFOV( void ) +{ + if ( gEngfuncs.pDemoAPI->IsRecording() ) + { + // Write it + int i = 0; + unsigned char buf[ 100 ]; + + // Active + *( float * )&buf[ i ] = g_lastFOV; + i += sizeof( float ); + + Demo_WriteBuffer( TYPE_ZOOM, i, buf ); + } + + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + { + g_lastFOV = g_demozoom; + } + return g_lastFOV; +} + +int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + int newfov = READ_BYTE(); + int def_fov = CVAR_GET_FLOAT( "default_fov" ); + + //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). + if ( cl_lw && cl_lw->value ) + return 1; + + g_lastFOV = newfov; + + if ( newfov == 0 ) + { + m_iFOV = def_fov; + } + else + { + m_iFOV = newfov; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == def_fov ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)def_fov) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + + return 1; +} + + +void CHud::AddHudElem(CHudBase *phudelem) +{ + HUDLIST *pdl, *ptemp; + +//phudelem->Think(); + + if (!phudelem) + return; + + pdl = (HUDLIST *)malloc(sizeof(HUDLIST)); + if (!pdl) + return; + + memset(pdl, 0, sizeof(HUDLIST)); + pdl->p = phudelem; + + if (!m_pHudList) + { + m_pHudList = pdl; + return; + } + + ptemp = m_pHudList; + + while (ptemp->pNext) + ptemp = ptemp->pNext; + + ptemp->pNext = pdl; +} + +float CHud::GetSensitivity( void ) +{ + return m_flMouseSensitivity; +} + + diff --git a/client/hud/hud.h b/cl_dll/hud.h similarity index 50% rename from client/hud/hud.h rename to cl_dll/hud.h index 5d6ca599..7d49e537 100644 --- a/client/hud/hud.h +++ b/cl_dll/hud.h @@ -1,50 +1,65 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// hud.h - hud primary header -//======================================================================= +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud.h +// +// class CHud declaration +// +// CHud handles the message, calculation, and drawing the HUD +// -#define RGB_YELLOWISH 0x00FFA000 // 255, 160, 0 -#define RGB_REDISH 0x00FF1010 // 255, 160, 0 -#define RGB_GREENISH 0x0000A000 // 0, 160, 0 -#include "hud_ammo.h" +#define RGB_YELLOWISH 0x00FFA000 //255,160,0 +#define RGB_REDISH 0x00FF1010 //255,160,0 +#define RGB_GREENISH 0x0000A000 //0,160,0 -#define DHN_DRAWZERO 1 -#define DHN_2DIGITS 2 -#define DHN_3DIGITS 4 -#define MIN_ALPHA 100 +#include "wrect.h" +#include "cl_dll.h" +#include "ammo.h" -#define HUDELEM_ACTIVE 1 -#define HUD_MAX_FADES 8 // can be blindly increased +#define DHN_DRAWZERO 1 +#define DHN_2DIGITS 2 +#define DHN_3DIGITS 4 +#define MIN_ALPHA 100 -typedef struct -{ - int x, y; +#define HUDELEM_ACTIVE 1 + +typedef struct { + int x, y; } POSITION; -typedef struct -{ - int dripsPerSecond; - float distFromPlayer; - float windX, windY; - float randX, randY; - int weatherMode; // 0 - snow, 1 - rain - float globalHeight; -} RainData; +enum +{ + MAX_PLAYERS = 64, + MAX_TEAMS = 64, + MAX_TEAM_NAME = 16, +}; -typedef struct -{ - byte r, g, b, a; +typedef struct { + unsigned char r,g,b,a; } RGBA; -#define HUD_ACTIVE 1 -#define HUD_INTERMISSION 2 -#define MAX_SEC_AMMO_VALUES 4 -#define MAX_PLAYER_NAME_LENGTH 32 -#define MAX_MOTD_LENGTH 1536 -#define FADE_TIME 100 -#define maxHUDMessages 16 -#define MAX_SPRITE_NAME_LENGTH 24 +typedef struct cvar_s cvar_t; + + +#define HUD_ACTIVE 1 +#define HUD_INTERMISSION 2 + +#define MAX_PLAYER_NAME_LENGTH 32 + +#define MAX_MOTD_LENGTH 1536 // //----------------------------------------------------- @@ -52,25 +67,33 @@ typedef struct class CHudBase { public: - POSITION m_pos; - int m_type; - int m_iFlags; // active, moving, + POSITION m_pos; + int m_type; + int m_iFlags; // active, moving, + virtual ~CHudBase() {} + virtual int Init( void ) {return 0;} + virtual int VidInit( void ) {return 0;} + virtual int Draw(float flTime) {return 0;} + virtual void Think(void) {return;} + virtual void Reset(void) {return;} + virtual void InitHUDData( void ) {} // called every time a server is connected to - virtual ~CHudBase(){ } - virtual int Init( void ){ return 0; } - virtual int VidInit( void ){ return 0; } - virtual int Draw( float flTime ){ return 0; } - virtual void Think( void ){ return; } - virtual void Reset( void ){ return; } - virtual void InitHUDData( void ){ } // called every time a server is connected to }; -struct HUDLIST -{ +struct HUDLIST { CHudBase *p; - HUDLIST *pNext; + HUDLIST *pNext; }; + + +// +//----------------------------------------------------- +// +#include "..\game_shared\voice_status.h" +#include "hud_spectator.h" + + // //----------------------------------------------------- // @@ -83,9 +106,9 @@ public: void Think(void); void Reset(void); int DrawWList(float flTime); - int MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_WeaponList( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_CurWeapon(const char *pszName, int iSize, void *pbuf); + int MsgFunc_WeaponList(const char *pszName, int iSize, void *pbuf); + int MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf); int MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ); int MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ); int MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ); @@ -107,17 +130,18 @@ public: void _cdecl UserCmd_PrevWeapon( void ); private: - float m_fFade; - RGBA m_rgba; - WEAPON *m_pWeapon; + float m_fFade; + RGBA m_rgba; + WEAPON *m_pWeapon; int m_HUD_bucket0; - int m_HUD_selection; + int m_HUD_selection; }; // //----------------------------------------------------- // + class CHudAmmoSecondary: public CHudBase { public: @@ -130,13 +154,21 @@ public: int MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ); private: + enum { + MAX_SEC_AMMO_VALUES = 4 + }; + int m_HUD_ammoicon; // sprite indices int m_iAmmoAmounts[MAX_SEC_AMMO_VALUES]; float m_fFade; }; -#include "hud_health.h" +#include "health.h" + + +#define FADE_TIME 100 + // //----------------------------------------------------- @@ -146,11 +178,12 @@ class CHudGeiger: public CHudBase public: int Init( void ); int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_Geiger( const char *pszName, int iSize, void *pbuf ); - + int Draw(float flTime); + int MsgFunc_Geiger(const char *pszName, int iSize, void *pbuf); + private: int m_iGeigerRange; + }; // @@ -161,8 +194,8 @@ class CHudTrain: public CHudBase public: int Init( void ); int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_Train( const char *pszName, int iSize, void *pbuf ); + int Draw(float flTime); + int MsgFunc_Train(const char *pszName, int iSize, void *pbuf); private: HSPRITE m_hSprite; @@ -170,6 +203,12 @@ private: }; +// +//----------------------------------------------------- +// +// REMOVED: Vgui has replaced this. +// +/* class CHudMOTD : public CHudBase { public: @@ -182,68 +221,11 @@ public: protected: static int MOTD_DISPLAY_TIME; - char m_szMOTD[MAX_MOTD_LENGTH]; - float m_flActiveTill; + char m_szMOTD[ MAX_MOTD_LENGTH ]; + float m_flActiveRemaining; int m_iLines; }; - -// -//----------------------------------------------------- -// -class CHudScoreboard: public CHudBase -{ -public: - int Init( void ); - void InitHUDData( void ); - int VidInit( void ); - int Draw( float flTime ); - int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing - void UserCmd_ShowScores( void ); - void UserCmd_HideScores( void ); - int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); - void DeathMsg( int killer, int victim ); - - enum - { - MAX_PLAYERS = 64, - MAX_TEAMS = 64, - MAX_TEAM_NAME = 16, - }; - - struct extra_player_info_t - { - short frags; - short deaths; - char teamname[MAX_TEAM_NAME]; - }; - - struct team_info_t - { - char name[MAX_TEAM_NAME]; - short frags; - short deaths; - short ping; - short packetloss; - short ownteam; - short players; - int already_drawn; - int scores_overriden; - }; - - hud_player_info_t m_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine - extra_player_info_t m_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client.dll - team_info_t m_TeamInfo[MAX_TEAMS+1]; - - int m_iNumTeams; - int m_iLastKilledBy; - int m_fLastKillTime; - int m_iPlayerNum; - int m_iShowscoresHeld; - - void GetAllPlayersInfo( void ); -}; +*/ // //----------------------------------------------------- @@ -261,16 +243,15 @@ public: int MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ); protected: - enum - { + enum { MAX_STATUSTEXT_LENGTH = 128, MAX_STATUSBAR_VALUES = 8, MAX_STATUSBAR_LINES = 2, }; - char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn - char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn - int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar + char m_szStatusText[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // a text string describing how the status bar is to be drawn + char m_szStatusBar[MAX_STATUSBAR_LINES][MAX_STATUSTEXT_LENGTH]; // the constructed bar that is drawn + int m_iStatusValues[MAX_STATUSBAR_VALUES]; // an array of values for use in the status bar int m_bReparseString; // set to TRUE whenever the m_szStatusBar needs to be recalculated @@ -278,6 +259,70 @@ protected: float *m_pflNameColors[MAX_STATUSBAR_LINES]; }; +// +//----------------------------------------------------- +// +// REMOVED: Vgui has replaced this. +// +/* +class CHudScoreboard: public CHudBase +{ +public: + int Init( void ); + void InitHUDData( void ); + int VidInit( void ); + int Draw( float flTime ); + int DrawPlayers( int xoffset, float listslot, int nameoffset = 0, char *team = NULL ); // returns the ypos where it finishes drawing + void UserCmd_ShowScores( void ); + void UserCmd_HideScores( void ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + void DeathMsg( int killer, int victim ); + + int m_iNumTeams; + + int m_iLastKilledBy; + int m_fLastKillTime; + int m_iPlayerNum; + int m_iShowscoresHeld; + + void GetAllPlayersInfo( void ); +private: + struct cvar_s *cl_showpacketloss; + +}; +*/ + +struct extra_player_info_t +{ + short frags; + short deaths; + short playerclass; + short teamnumber; + char teamname[MAX_TEAM_NAME]; +}; + +struct team_info_t +{ + char name[MAX_TEAM_NAME]; + short frags; + short deaths; + short ping; + short packetloss; + short ownteam; + short players; + int already_drawn; + int scores_overriden; + int teamnumber; +}; + +extern hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extern extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +extern team_info_t g_TeamInfo[MAX_TEAMS+1]; +extern int g_IsSpectator[MAX_PLAYERS+1]; + + // //----------------------------------------------------- // @@ -328,10 +373,12 @@ public: int MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ); void SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex = -1 ); void EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ); +friend class CHudSpectator; + private: - float m_HUD_saytext; - float m_HUD_saytext_time; + struct cvar_s * m_HUD_saytext; + struct cvar_s * m_HUD_saytext_time; }; // @@ -342,17 +389,17 @@ class CHudBattery: public CHudBase public: int Init( void ); int VidInit( void ); - int Draw( float flTime ); + int Draw(float flTime); int MsgFunc_Battery(const char *pszName, int iSize, void *pbuf ); - + private: HSPRITE m_hSprite1; HSPRITE m_hSprite2; wrect_t *m_prc1; wrect_t *m_prc2; - int m_iBat; + int m_iBat; float m_fFade; - int m_iHeight; // width of the battery innards + int m_iHeight; // width of the battery innards }; @@ -366,9 +413,9 @@ public: int VidInit( void ); int Draw(float flTime); void Reset( void ); - int MsgFunc_Flashlight( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_FlashBat( const char *pszName, int iSize, void *pbuf ); - + int MsgFunc_Flashlight(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ); + private: HSPRITE m_hSprite1; HSPRITE m_hSprite2; @@ -376,22 +423,23 @@ private: wrect_t *m_prc1; wrect_t *m_prc2; wrect_t *m_prcBeam; - float m_flBat; - int m_iBat; - int m_fOn; + float m_flBat; + int m_iBat; + int m_fOn; float m_fFade; - int m_iWidth; // width of the battery innards + int m_iWidth; // width of the battery innards }; // //----------------------------------------------------- // +const int maxHUDMessages = 16; struct message_parms_t { - client_textmessage_t *pMessage; - float time; + client_textmessage_t *pMessage; + float time; int x, y; - int totalWidth, totalHeight; + int totalWidth, totalHeight; int width; int lines; int lineLength; @@ -406,6 +454,7 @@ struct message_parms_t // //----------------------------------------------------- // + class CHudTextMessage: public CHudBase { public: @@ -413,7 +462,7 @@ public: static char *LocaliseTextString( const char *msg, char *dst_buffer, int buffer_size ); static char *BufferedLocaliseTextString( const char *msg ); char *LookupString( const char *msg_name, int *msg_dest = NULL ); - int MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TextMsg(const char *pszName, int iSize, void *pbuf); }; // @@ -425,27 +474,28 @@ class CHudMessage: public CHudBase public: int Init( void ); int VidInit( void ); - int Draw( float flTime ); - int MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ); - int MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ); + int Draw(float flTime); + int MsgFunc_HudText(const char *pszName, int iSize, void *pbuf); + int MsgFunc_GameTitle(const char *pszName, int iSize, void *pbuf); float FadeBlend( float fadein, float fadeout, float hold, float localTime ); - int XPosition( float x, int width, int lineWidth ); + int XPosition( float x, int width, int lineWidth ); int YPosition( float y, int height ); void MessageAdd( const char *pName, float time ); - void MessageAdd( client_textmessage_t * newMessage ); + void MessageAdd(client_textmessage_t * newMessage ); void MessageDrawScan( client_textmessage_t *pMessage, float time ); void MessageScanStart( void ); void MessageScanNextChar( void ); void Reset( void ); private: - client_textmessage_t *m_pMessages[maxHUDMessages]; - float m_startTime[maxHUDMessages]; - message_parms_t m_parms; - float m_gameTitleTime; - client_textmessage_t *m_pGameTitle; + client_textmessage_t *m_pMessages[maxHUDMessages]; + float m_startTime[maxHUDMessages]; + message_parms_t m_parms; + float m_gameTitleTime; + client_textmessage_t *m_pGameTitle; + int m_HUD_title_life; int m_HUD_title_half; }; @@ -453,24 +503,26 @@ private: // //----------------------------------------------------- // +#define MAX_SPRITE_NAME_LENGTH 24 + class CHudStatusIcons: public CHudBase { public: int Init( void ); int VidInit( void ); void Reset( void ); - int Draw( float flTime ); - int MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf ); + int Draw(float flTime); + int MsgFunc_StatusIcon(const char *pszName, int iSize, void *pbuf); - enum - { + enum { MAX_ICONSPRITENAME_LENGTH = MAX_SPRITE_NAME_LENGTH, MAX_ICONSPRITES = 4, }; - // had to make these public so CHud could access them (to enable concussion icon) - // could use a friend declaration instead... - void EnableIcon( char *pszIconName, byte red, byte green, byte blue ); + + //had to make these public so CHud could access them (to enable concussion icon) + //could use a friend declaration instead... + void EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ); void DisableIcon( char *pszIconName ); private: @@ -480,144 +532,136 @@ private: char szSpriteName[MAX_ICONSPRITENAME_LENGTH]; HSPRITE spr; wrect_t rc; - byte r, g, b; + unsigned char r, g, b; } icon_sprite_t; icon_sprite_t m_IconList[MAX_ICONSPRITES]; + }; // //----------------------------------------------------- // + + + class CHud { private: - HUDLIST *m_pHudList; - HSPRITE m_hsprLogo; - int m_iLogo; - client_sprite_t *m_pSpriteList; - int m_iSpriteCount; - int m_iSpriteCountAllRes; - float m_flMouseSensitivity; - int m_iConcussionEffect; - int m_iNoClip; + HUDLIST *m_pHudList; + HSPRITE m_hsprLogo; + int m_iLogo; + client_sprite_t *m_pSpriteList; + int m_iSpriteCount; + int m_iSpriteCountAllRes; + float m_flMouseSensitivity; + int m_iConcussionEffect; + public: - HSPRITE m_hsprCursor; - float m_flTime; // the current client time - float m_fOldTime; // the time at which the HUD was last redrawn - double m_flTimeDelta;// the difference between flTime and fOldTime - float m_vecOrigin[3]; - float m_vecAngles[3]; - int m_iKeyBits; - int m_iHideHUDDisplay; - float m_iFOV; - int m_Teamplay; - int m_iRes; - int m_iCameraMode; + + HSPRITE m_hsprCursor; + float m_flTime; // the current client time + float m_fOldTime; // the time at which the HUD was last redrawn + double m_flTimeDelta; // the difference between flTime and fOldTime + Vector m_vecOrigin; + Vector m_vecAngles; + int m_iKeyBits; + int m_iHideHUDDisplay; + int m_iFOV; + int m_Teamplay; + int m_iRes; + cvar_t *m_pCvarStealMouse; + cvar_t *m_pCvarDraw; + int m_iFontHeight; - int DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b ); - int DrawHudString( int x, int y, int iMaxX, char *szString, int r, int g, int b ); + int DrawHudNumber(int x, int y, int iFlags, int iNumber, int r, int g, int b ); + int DrawHudString(int x, int y, int iMaxX, char *szString, int r, int g, int b ); int DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ); int DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ); - int GetNumWidth( int iNumber, int iFlags ); - int m_iHUDColor; + int GetNumWidth(int iNumber, int iFlags); + private: - // the memory for these arrays are allocated in the first call to CHud::VidInit() - // when the hud.txt and associated sprites are loaded. freed in ~CHud() - HSPRITE *m_rghSprites; // the sprites loaded from hud.txt - wrect_t *m_rgrcRects; - wrect_t nullRect; - char *m_rgszSpriteNames; - cvar_t *default_fov; + // the memory for these arrays are allocated in the first call to CHud::VidInit(), when the hud.txt and associated sprites are loaded. + // freed in ~CHud() + HSPRITE *m_rghSprites; /*[HUD_SPRITE_COUNT]*/ // the sprites loaded from hud.txt + wrect_t *m_rgrcRects; /*[HUD_SPRITE_COUNT]*/ + char *m_rgszSpriteNames; /*[HUD_SPRITE_COUNT][MAX_SPRITE_NAME_LENGTH]*/ + + struct cvar_s *default_fov; public: - HSPRITE GetSprite( int index ) { return (index < 0) ? 0 : m_rghSprites[index]; } - wrect_t& GetSpriteRect( int index ) { return (index < 0) ? nullRect : m_rgrcRects[index]; } - int InitMessages( void ); // init hud messages - int GetSpriteIndex( const char *SpriteName ); + HSPRITE GetSprite( int index ) + { + return (index < 0) ? 0 : m_rghSprites[index]; + } + + wrect_t& GetSpriteRect( int index ) + { + return m_rgrcRects[index]; + } + + + int GetSpriteIndex( const char *SpriteName ); // gets a sprite index, for use in the m_rghSprites[] array CHudAmmo m_Ammo; - CHudHealth m_Health; - CHudGeiger m_Geiger; - CHudBattery m_Battery; + CHudHealth m_Health; + CHudSpectator m_Spectator; + CHudGeiger m_Geiger; + CHudBattery m_Battery; CHudTrain m_Train; CHudFlashlight m_Flash; - CHudMessage m_Message; - CHudScoreboard m_Scoreboard; - CHudStatusBar m_StatusBar; - CHudDeathNotice m_DeathNotice; - CHudSayText m_SayText; + CHudMessage m_Message; + CHudStatusBar m_StatusBar; + CHudDeathNotice m_DeathNotice; + CHudSayText m_SayText; CHudMenu m_Menu; CHudAmmoSecondary m_AmmoSecondary; - CHudTextMessage m_TextMessage; - CHudStatusIcons m_StatusIcons; - CHudMOTD m_MOTD; - + CHudTextMessage m_TextMessage; + CHudStatusIcons m_StatusIcons; + void Init( void ); void VidInit( void ); - void Think( void ); - int Redraw( float flTime ); + void Think(void); + int Redraw( float flTime, int intermission ); int UpdateClientData( client_data_t *cdata, float time ); - CHud() : m_pHudList(NULL) { } - ~CHud(); // destructor, frees allocated memory + CHud() : m_iSpriteCount(0), m_pHudList(NULL) {} + ~CHud(); // destructor, frees allocated memory // user messages - int _cdecl MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_ResetHUD( const char *pszName, int iSize, void *pbuf); - int _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_SetFOV( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_RainData( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_HUDColor( const char *pszName, int iSize, void *pbuf); - int _cdecl MsgFunc_SetFog( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_SetBody( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_SetSkin( const char *pszName, int iSize, void *pbuf ); - int _cdecl MsgFunc_Particle( const char *pszName, int iSize, void *pbuf ); - - // user commands - void _cdecl UserCmd_ChangeLevel( void ); + int _cdecl MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_Logo(const char *pszName, int iSize, void *pbuf); + int _cdecl MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf); + void _cdecl MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ); + void _cdecl MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ); + int _cdecl MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf); + int _cdecl MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ); // Screen information SCREENINFO m_scrinfo; - + int m_iWeaponBits; int m_fPlayerDead; - int m_iIntermission; - - RainData Rain; // buz rain - - // fog stuff - Vector m_vecFogColor; - float m_flStartDist; - float m_flEndDist; - int m_iFinalEndDist; - float m_fFadeDuration; - - // wind stuff - Vector m_vecWindVelocity; + int m_iIntermission; // sprite indexes - int m_HUD_number_0; + int m_HUD_number_0; + + + void AddHudElem(CHudBase *p); + + float GetSensitivity(); - // error sprite - int m_HUD_error; - HSPRITE m_hHudError; - - void AddHudElem( CHudBase *p ); - float GetSensitivity() { return m_flMouseSensitivity; } - int IsNoClipping() { return m_iNoClip; } }; -extern CHud gHUD; +class TeamFortressViewport; -float HUD_GetFOV( void ); +extern CHud gHUD; +extern TeamFortressViewport *gViewPort; extern int g_iPlayerClass; extern int g_iTeamNumber; extern int g_iUser1; extern int g_iUser2; -extern int g_iUser3; \ No newline at end of file +extern int g_iUser3; + diff --git a/cl_dll/hud_iface.h b/cl_dll/hud_iface.h new file mode 100644 index 00000000..d08763c0 --- /dev/null +++ b/cl_dll/hud_iface.h @@ -0,0 +1,20 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_IFACEH ) +#define HUD_IFACEH +#pragma once + +#define EXPORT _declspec( dllexport ) +#define _DLLEXPORT __declspec( dllexport ) + +typedef int (*pfnUserMsgHook)(const char *pszName, int iSize, void *pbuf); +#include "wrect.h" +#include "../engine/cdll_int.h" +extern cl_enginefunc_t gEngfuncs; + +#endif \ No newline at end of file diff --git a/cl_dll/hud_msg.cpp b/cl_dll/hud_msg.cpp new file mode 100644 index 00000000..0505d172 --- /dev/null +++ b/cl_dll/hud_msg.cpp @@ -0,0 +1,120 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud_msg.cpp +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" +#include "r_efx.h" + +#define MAX_CLIENTS 32 + +extern BEAM *pBeam; +extern BEAM *pBeam2; + +/// USER-DEFINED SERVER MESSAGE HANDLERS + +int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) +{ + ASSERT( iSize == 0 ); + + // clear all hud data + HUDLIST *pList = m_pHudList; + + while ( pList ) + { + if ( pList->p ) + pList->p->Reset(); + pList = pList->pNext; + } + + // reset sensitivity + m_flMouseSensitivity = 0; + + // reset concussion effect + m_iConcussionEffect = 0; + + return 1; +} + +void CAM_ToFirstPerson(void); + +void CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) +{ + CAM_ToFirstPerson(); +} + +void CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) +{ + // prepare all hud data + HUDLIST *pList = m_pHudList; + + while (pList) + { + if ( pList->p ) + pList->p->InitHUDData(); + pList = pList->pNext; + } + + //Probably not a good place to put this. + pBeam = pBeam2 = NULL; +} + + +int CHud :: MsgFunc_GameMode(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_Teamplay = READ_BYTE(); + + return 1; +} + + +int CHud :: MsgFunc_Damage(const char *pszName, int iSize, void *pbuf ) +{ + int armor, blood; + Vector from; + int i; + float count; + + BEGIN_READ( pbuf, iSize ); + armor = READ_BYTE(); + blood = READ_BYTE(); + + for (i=0 ; i<3 ; i++) + from[i] = READ_COORD(); + + count = (blood * 0.5) + (armor * 0.5); + + if (count < 10) + count = 10; + + // TODO: kick viewangles, show damage visually + + return 1; +} + +int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + m_iConcussionEffect = READ_BYTE(); + if (m_iConcussionEffect) + this->m_StatusIcons.EnableIcon("dmg_concuss",255,160,0); + else + this->m_StatusIcons.DisableIcon("dmg_concuss"); + return 1; +} diff --git a/cl_dll/hud_redraw.cpp b/cl_dll/hud_redraw.cpp new file mode 100644 index 00000000..903fbdd4 --- /dev/null +++ b/cl_dll/hud_redraw.cpp @@ -0,0 +1,349 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud_redraw.cpp +// +#include +#include "hud.h" +#include "cl_util.h" + +#include "vgui_TeamFortressViewport.h" + +#define MAX_LOGO_FRAMES 56 + +int grgLogoFrame[MAX_LOGO_FRAMES] = +{ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, + 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, + 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 +}; + + +extern int g_iVisibleMouse; + +float HUD_GetFOV( void ); + +extern cvar_t *sensitivity; + +// Think +void CHud::Think(void) +{ + int newfov; + HUDLIST *pList = m_pHudList; + + while (pList) + { + if (pList->p->m_iFlags & HUD_ACTIVE) + pList->p->Think(); + pList = pList->pNext; + } + + newfov = HUD_GetFOV(); + if ( newfov == 0 ) + { + m_iFOV = default_fov->value; + } + else + { + m_iFOV = newfov; + } + + // the clients fov is actually set in the client data update section of the hud + + // Set a new sensitivity + if ( m_iFOV == default_fov->value ) + { + // reset to saved sensitivity + m_flMouseSensitivity = 0; + } + else + { + // set a new sensitivity that is proportional to the change from the FOV default + m_flMouseSensitivity = sensitivity->value * ((float)newfov / (float)default_fov->value) * CVAR_GET_FLOAT("zoom_sensitivity_ratio"); + } + + // think about default fov + if ( m_iFOV == 0 ) + { // only let players adjust up in fov, and only if they are not overriden by something else + m_iFOV = max( default_fov->value, 90 ); + } +} + +// Redraw +// step through the local data, placing the appropriate graphics & text as appropriate +// returns 1 if they've changed, 0 otherwise +int CHud :: Redraw( float flTime, int intermission ) +{ + m_fOldTime = m_flTime; // save time of previous redraw + m_flTime = flTime; + m_flTimeDelta = (double)m_flTime - m_fOldTime; + static m_flShotTime = 0; + + // Clock was reset, reset delta + if ( m_flTimeDelta < 0 ) + m_flTimeDelta = 0; + + // Bring up the scoreboard during intermission + if (gViewPort) + { + if ( m_iIntermission && !intermission ) + { + // Have to do this here so the scoreboard goes away + m_iIntermission = intermission; + gViewPort->HideCommandMenu(); + gViewPort->HideScoreBoard(); + gViewPort->UpdateSpectatorPanel(); + } + else if ( !m_iIntermission && intermission ) + { + m_iIntermission = intermission; + gViewPort->HideCommandMenu(); + gViewPort->HideVGUIMenu(); + gViewPort->ShowScoreBoard(); + gViewPort->UpdateSpectatorPanel(); + + // Take a screenshot if the client's got the cvar set + if ( CVAR_GET_FLOAT( "hud_takesshots" ) != 0 ) + m_flShotTime = flTime + 1.0; // Take a screenshot in a second + } + } + + if (m_flShotTime && m_flShotTime < flTime) + { + gEngfuncs.pfnClientCmd("snapshot\n"); + m_flShotTime = 0; + } + + m_iIntermission = intermission; + + // if no redrawing is necessary + // return 0; + + if ( m_pCvarDraw->value ) + { + HUDLIST *pList = m_pHudList; + + while (pList) + { + if ( !intermission ) + { + if ( (pList->p->m_iFlags & HUD_ACTIVE) && !(m_iHideHUDDisplay & HIDEHUD_ALL) ) + pList->p->Draw(flTime); + } + else + { // it's an intermission, so only draw hud elements that are set to draw during intermissions + if ( pList->p->m_iFlags & HUD_INTERMISSION ) + pList->p->Draw( flTime ); + } + + pList = pList->pNext; + } + } + + // are we in demo mode? do we need to draw the logo in the top corner? + if (m_iLogo) + { + int x, y, i; + + if (m_hsprLogo == 0) + m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); + + SPR_Set(m_hsprLogo, 250, 250, 250 ); + + x = SPR_Width(m_hsprLogo, 0); + x = ScreenWidth - x; + y = SPR_Height(m_hsprLogo, 0)/2; + + // Draw the logo at 20 fps + int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; + i = grgLogoFrame[iFrame] - 1; + + SPR_DrawAdditive(i, x, y, NULL); + } + + /* + if ( g_iVisibleMouse ) + { + void IN_GetMousePos( int *mx, int *my ); + int mx, my; + + IN_GetMousePos( &mx, &my ); + + if (m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + m_hsprCursor = SPR_Load( sz ); + } + + SPR_Set(m_hsprCursor, 250, 250, 250 ); + + // Draw the logo at 20 fps + SPR_DrawAdditive( 0, mx, my, NULL ); + } + */ + + return 1; +} + +void ScaleColors( int &r, int &g, int &b, int a ) +{ + float x = (float)a / 255; + r = (int)(r * x); + g = (int)(g * x); + b = (int)(b * x); +} + +int CHud :: DrawHudString(int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) +{ + // draw the string until we hit the null character or a newline character + for ( ; *szIt != 0 && *szIt != '\n'; szIt++ ) + { + int next = xpos + gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool + if ( next > iMaxX ) + return xpos; + + TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); + xpos = next; + } + + return xpos; +} + +int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) +{ + char szString[32]; + sprintf( szString, "%d", iNumber ); + return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b ); + +} + +// draws a string from right to left (right-aligned) +int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) +{ + // find the end of the string + for ( char *szIt = szString; *szIt != 0; szIt++ ) + { // we should count the length? + } + + // iterate throug the string in reverse + for ( szIt--; szIt != (szString-1); szIt-- ) + { + int next = xpos - gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool + if ( next < iMinX ) + return xpos; + xpos = next; + + TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); + } + + return xpos; +} + +int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b) +{ + int iWidth = GetSpriteRect(m_HUD_number_0).right - GetSpriteRect(m_HUD_number_0).left; + int k; + + if (iNumber > 0) + { + // SPR_Draw 100's + if (iNumber >= 100) + { + k = iNumber/100; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & (DHN_3DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw 10's + if (iNumber >= 10) + { + k = (iNumber % 100)/10; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw ones + k = iNumber % 10; + SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); + SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); + x += iWidth; + } + else if (iFlags & DHN_DRAWZERO) + { + SPR_Set(GetSprite(m_HUD_number_0), r, g, b ); + + // SPR_Draw 100's + if (iFlags & (DHN_3DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + if (iFlags & (DHN_3DIGITS | DHN_2DIGITS)) + { + //SPR_DrawAdditive( 0, x, y, &rc ); + x += iWidth; + } + + // SPR_Draw ones + + SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0)); + x += iWidth; + } + + return x; +} + + +int CHud::GetNumWidth( int iNumber, int iFlags ) +{ + if (iFlags & (DHN_3DIGITS)) + return 3; + + if (iFlags & (DHN_2DIGITS)) + return 2; + + if (iNumber <= 0) + { + if (iFlags & (DHN_DRAWZERO)) + return 1; + else + return 0; + } + + if (iNumber < 10) + return 1; + + if (iNumber < 100) + return 2; + + return 3; + +} + + diff --git a/cl_dll/hud_servers.cpp b/cl_dll/hud_servers.cpp new file mode 100644 index 00000000..8bd42d33 --- /dev/null +++ b/cl_dll/hud_servers.cpp @@ -0,0 +1,1230 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// hud_servers.cpp +#include "hud.h" +#include "cl_util.h" +#include "hud_servers_priv.h" +#include "hud_servers.h" +#include "net_api.h" +#include +#include + +static int context_id; + +// Default master server address in case we can't read any from woncomm.lst file +#define VALVE_MASTER_ADDRESS "half-life.east.won.net" +#define PORT_MASTER 27010 +#define PORT_SERVER 27015 + +// File where we really should look for master servers +#define MASTER_PARSE_FILE "woncomm.lst" + +#define MAX_QUERIES 20 + +#define NET_API gEngfuncs.pNetAPI + +static CHudServers *g_pServers = NULL; + +/* +=================== +ListResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ListResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ListResponse( response ); + } +} + +/* +=================== +ServerResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK ServerResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->ServerResponse( response ); + } +} + +/* +=================== +PingResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PingResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PingResponse( response ); + } +} + +/* +=================== +RulesResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK RulesResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->RulesResponse( response ); + } +} +/* +=================== +PlayersResponse + +Callback from engine +=================== +*/ +void NET_CALLBACK PlayersResponse( struct net_response_s *response ) +{ + if ( g_pServers ) + { + g_pServers->PlayersResponse( response ); + } +} +/* +=================== +ListResponse + +=================== +*/ +void CHudServers::ListResponse( struct net_response_s *response ) +{ + request_t *list; + request_t *p; + int c = 0; + + if ( !( response->error == NET_SUCCESS ) ) + return; + + if ( response->type != NETAPI_REQUEST_SERVERLIST ) + return; + + if ( response->response ) + { + list = ( request_t * ) response->response; + while ( list ) + { + c++; + + //if ( c < 40 ) + { + // Copy from parsed stuff + p = new request_t; + p->context = -1; + p->remote_address = list->remote_address; + p->next = m_pServerList; + m_pServerList = p; + } + + // Move on + list = list->next; + } + } + + gEngfuncs.Con_Printf( "got list\n" ); + + m_nQuerying = 1; + m_nActiveQueries = 0; +} + +/* +=================== +ServerResponse + +=================== +*/ +void CHudServers::ServerResponse( struct net_response_s *response ) +{ + char *szresponse; + request_t *p; + server_t *browser; + int len; + char sz[ 32 ]; + + // Remove from active list + p = FindRequest( response->context, m_pActiveList ); + if ( p ) + { + RemoveServerFromList( &m_pActiveList, p ); + m_nActiveQueries--; + } + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_DETAILS: + if ( response->response ) + { + szresponse = (char *)response->response; + len = strlen( szresponse ) + 100 + 1; + sprintf( sz, "%i", (int)( 1000.0 * response->ping ) ); + + browser = new server_t; + browser->remote_address = response->remote_address; + browser->info = new char[ len ]; + browser->ping = (int)( 1000.0 * response->ping ); + strcpy( browser->info, szresponse ); + + NET_API->SetValueForKey( browser->info, "address", gEngfuncs.pNetAPI->AdrToString( &response->remote_address ), len ); + NET_API->SetValueForKey( browser->info, "ping", sz, len ); + + AddServer( &m_pServers, browser ); + } + break; + default: + break; + } +} + +/* +=================== +PingResponse + +=================== +*/ +void CHudServers::PingResponse( struct net_response_s *response ) +{ + char sz[ 32 ]; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PING: + sprintf( sz, "%.2f", 1000.0 * response->ping ); + + gEngfuncs.Con_Printf( "ping == %s\n", sz ); + break; + default: + break; + } +} + +/* +=================== +RulesResponse + +=================== +*/ +void CHudServers::RulesResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_RULES: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "rules %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +PlayersResponse + +=================== +*/ +void CHudServers::PlayersResponse( struct net_response_s *response ) +{ + char *szresponse; + + if ( response->error != NET_SUCCESS ) + return; + + switch ( response->type ) + { + case NETAPI_REQUEST_PLAYERS: + if ( response->response ) + { + szresponse = (char *)response->response; + + gEngfuncs.Con_Printf( "players %s\n", szresponse ); + } + break; + default: + break; + } +} + +/* +=================== +CompareServers + +Return 1 if p1 is "less than" p2, 0 otherwise +=================== +*/ +int CHudServers::CompareServers( server_t *p1, server_t *p2 ) +{ + const char *n1, *n2; + + if ( p1->ping < p2->ping ) + return 1; + + if ( p1->ping == p2->ping ) + { + // Pings equal, sort by second key: hostname + if ( p1->info && p2->info ) + { + n1 = NET_API->ValueForKey( p1->info, "hostname" ); + n2 = NET_API->ValueForKey( p2->info, "hostname" ); + + if ( n1 && n2 ) + { + if ( stricmp( n1, n2 ) < 0 ) + return 1; + } + } + } + + return 0; +} + +/* +=================== +AddServer + +=================== +*/ +void CHudServers::AddServer( server_t **ppList, server_t *p ) +{ +server_t *list; + + if ( !ppList || ! p ) + return; + + m_nServerCount++; + + // What sort key? Ping? + list = *ppList; + + // Head of list? + if ( !list ) + { + p->next = NULL; + *ppList = p; + return; + } + + // Put on head of list + if ( CompareServers( p, list ) ) + { + p->next = *ppList; + *ppList = p; + } + else + { + while ( list->next ) + { + // Insert before list next + if ( CompareServers( p, list->next ) ) + { + p->next = list->next->next; + list->next = p; + return; + } + + list = list->next; + } + + // Just add at end + p->next = NULL; + list->next = p; + } +} + +/* +=================== +Think + +=================== +*/ +void CHudServers::Think( double time ) +{ + m_fElapsed += time; + + if ( !m_nRequesting ) + return; + + if ( !m_nQuerying ) + return; + + QueryThink(); + + if ( ServerListSize() > 0 ) + return; + + m_dStarted = 0.0; + m_nRequesting = 0; + m_nDone = 0; + m_nQuerying = 0; + m_nActiveQueries = 0; +} + +/* +=================== +QueryThink + +=================== +*/ +void CHudServers::QueryThink( void ) +{ + request_t *p; + + if ( !m_nRequesting || m_nDone ) + return; + + if ( !m_nQuerying ) + return; + + if ( m_nActiveQueries > MAX_QUERIES ) + return; + + // Nothing left + if ( !m_pServerList ) + return; + + while ( 1 ) + { + p = m_pServerList; + + // No more in list? + if ( !p ) + break; + + // Move to next + m_pServerList = m_pServerList->next; + + // Setup context_id + p->context = context_id; + + // Start up query on this one + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, 0, 2.0, &p->remote_address, ::ServerResponse ); + + // Increment active list + m_nActiveQueries++; + + // Add to active list + p->next = m_pActiveList; + m_pActiveList = p; + + // Too many active? + if ( m_nActiveQueries > MAX_QUERIES ) + break; + } +} + +/* +================== +ServerListSize + +# of servers in active query and in pending to be queried lists +================== +*/ +int CHudServers::ServerListSize( void ) +{ + int c = 0; + request_t *p; + + p = m_pServerList; + while ( p ) + { + c++; + p = p->next; + } + + p = m_pActiveList; + while ( p ) + { + c++; + p = p->next; + } + + return c; +} + +/* +=================== +FindRequest + +Look up a request by context id +=================== +*/ +CHudServers::request_t *CHudServers::FindRequest( int context, request_t *pList ) +{ + request_t *p; + p = pList; + while ( p ) + { + if ( context == p->context ) + return p; + + p = p->next; + } + return NULL; +} + +/* +=================== +RemoveServerFromList + +Remote, but don't delete, item from *ppList +=================== +*/ +void CHudServers::RemoveServerFromList( request_t **ppList, request_t *item ) +{ + request_t *p, *n; + request_t *newlist = NULL; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + if ( p != item ) + { + p->next = newlist; + newlist = p; + } + p = n; + } + *ppList = newlist; +} + +/* +=================== +ClearRequestList + +=================== +*/ +void CHudServers::ClearRequestList( request_t **ppList ) +{ + request_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete p; + p = n; + } + *ppList = NULL; +} + +/* +=================== +ClearServerList + +=================== +*/ +void CHudServers::ClearServerList( server_t **ppList ) +{ + server_t *p, *n; + + if ( !ppList ) + return; + + p = *ppList; + while ( p ) + { + n = p->next; + delete[] p->info; + delete p; + p = n; + } + *ppList = NULL; +} + +int CompareField( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname, int iSortOrder ) +{ + const char *sz1, *sz2; + float fv1, fv2; + + sz1 = NET_API->ValueForKey( p1->info, fieldname ); + sz2 = NET_API->ValueForKey( p2->info, fieldname ); + + fv1 = atof( sz1 ); + fv2 = atof( sz2 ); + + if ( fv1 && fv2 ) + { + if ( fv1 > fv2 ) + return iSortOrder; + else if ( fv1 < fv2 ) + return -iSortOrder; + else + return 0; + } + + // String compare + return stricmp( sz1, sz2 ); +} + +int CALLBACK ServerListCompareFunc( CHudServers::server_t *p1, CHudServers::server_t *p2, const char *fieldname ) +{ + if (!p1 || !p2) // No meaningful comparison + return 0; + + int iSortOrder = 1; + + int retval = 0; + + retval = CompareField( p1, p2, fieldname, iSortOrder ); + + return retval; +} + +static char g_fieldname[ 256 ]; +int __cdecl FnServerCompare(const void *elem1, const void *elem2 ) +{ + CHudServers::server_t *list1, *list2; + + list1 = *(CHudServers::server_t **)elem1; + list2 = *(CHudServers::server_t **)elem2; + + return ServerListCompareFunc( list1, list2, g_fieldname ); +} + +void CHudServers::SortServers( const char *fieldname ) +{ + server_t *p; + // Create a list + if ( !m_pServers ) + return; + + strcpy( g_fieldname, fieldname ); + + int i; + int c = 0; + + p = m_pServers; + while ( p ) + { + c++; + p = p->next; + } + + server_t **pSortArray; + + pSortArray = new server_t *[ c ]; + memset( pSortArray, 0, c * sizeof( server_t * ) ); + + // Now copy the list into the pSortArray: + p = m_pServers; + i = 0; + while ( p ) + { + pSortArray[ i++ ] = p; + p = p->next; + } + + // Now do that actual sorting. + size_t nCount = c; + size_t nSize = sizeof( server_t * ); + + qsort( + pSortArray, + (size_t)nCount, + (size_t)nSize, + FnServerCompare + ); + + // Now rebuild the list. + m_pServers = pSortArray[0]; + for ( i = 0; i < c - 1; i++ ) + { + pSortArray[ i ]->next = pSortArray[ i + 1 ]; + } + pSortArray[ c - 1 ]->next = NULL; + + // Clean Up. + delete[] pSortArray; +} + +/* +=================== +GetServer + +Return particular server +=================== +*/ +CHudServers::server_t *CHudServers::GetServer( int server ) +{ + int c = 0; + server_t *p; + + p = m_pServers; + while ( p ) + { + if ( c == server ) + return p; + + c++; + p = p->next; + } + return NULL; +} + +/* +=================== +GetServerInfo + +Return info ( key/value ) string for particular server +=================== +*/ +char *CHudServers::GetServerInfo( int server ) +{ + server_t *p = GetServer( server ); + if ( p ) + { + return p->info; + } + return NULL; +} + +/* +=================== +CancelRequest + +Kill all pending requests in engine +=================== +*/ +void CHudServers::CancelRequest( void ) +{ + m_nRequesting = 0; + m_nQuerying = 0; + m_nDone = 1; + + NET_API->CancelAllRequests(); +} + +/* +================== +LoadMasterAddresses + +Loads the master server addresses from file and into the passed in array +================== +*/ +int CHudServers::LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ) +{ + int i; + char szMaster[ 256 ]; + char szMasterFile[256]; + char *pbuffer = NULL; + char *pstart = NULL ; + netadr_t adr; + char szAdr[64]; + int nPort; + int nCount = 0; + bool bIgnore; + int nDefaultPort; + + // Assume default master and master file + strcpy( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + strcpy( szMasterFile, MASTER_PARSE_FILE ); + + // See if there is a command line override + i = gEngfuncs.CheckParm( "-comm", &pstart ); + if ( i && pstart ) + { + strcpy (szMasterFile, pstart ); + } + + // Read them in from proper file + pbuffer = (char *)gEngfuncs.COM_LoadFile( szMasterFile, 5, NULL ); // Use malloc + if ( !pbuffer ) + { + goto finish_master; + } + + pstart = pbuffer; + + while ( nCount < maxservers ) + { + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if ( strlen(m_szToken) <= 0) + break; + + bIgnore = true; + + if ( !stricmp( m_szToken, "Master" ) ) + { + nDefaultPort = PORT_MASTER; + bIgnore = FALSE; + } + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + if ( strlen(m_szToken) <= 0 ) + break; + + if ( stricmp ( m_szToken, "{" ) ) + break; + + // Parse addresses until we get to "}" + while ( nCount < maxservers ) + { + char base[256]; + + // Now parse all addresses between { } + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( !stricmp ( m_szToken, "}" ) ) + break; + + sprintf( base, "%s", m_szToken ); + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + if ( stricmp( m_szToken, ":" ) ) + break; + + pstart = gEngfuncs.COM_ParseFile( pstart, m_szToken ); + + if (strlen(m_szToken) <= 0) + break; + + nPort = atoi ( m_szToken ); + if ( !nPort ) + nPort = nDefaultPort; + + sprintf( szAdr, "%s:%i", base, nPort ); + + // Can we resolve it any better + if ( !NET_API->StringToAdr( szAdr, &adr ) ) + bIgnore = true; + + if ( !bIgnore ) + { + padr[ nCount++ ] = adr; + } + } + } + +finish_master: + if ( !nCount ) + { + sprintf( szMaster, VALVE_MASTER_ADDRESS ); // IP:PORT string + + // Convert to netadr_t + if ( NET_API->StringToAdr ( szMaster, &adr ) ) + { + + padr[ nCount++ ] = adr; + } + } + + *count = nCount; + + if ( pbuffer ) + { + gEngfuncs.COM_FreeFile( pbuffer ); + } + + return ( nCount > 0 ) ? 1 : 0; +} + +/* +=================== +RequestList + +Request list of game servers from master +=================== +*/ +void CHudServers::RequestList( void ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + int count = 0; + netadr_t adr; + + if ( !LoadMasterAddresses( 1, &count, &adr ) ) + { + gEngfuncs.Con_DPrintf( "SendRequest: Unable to read master server addresses\n" ); + return; + } + + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Kill off left overs if any + NET_API->CancelAllRequests(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_SERVERLIST, 0, 5.0, &adr, ::ListResponse ); +} + +void CHudServers::RequestBroadcastList( int clearpending ) +{ + m_nRequesting = 1; + m_nDone = 0; + m_dStarted = m_fElapsed; + + netadr_t adr; + memset( &adr, 0, sizeof( adr ) ); + + if ( clearpending ) + { + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + } + + // Make sure to byte swap server if necessary ( using "host" to "net" conversion + adr.port = htons( PORT_SERVER ); + + // Make sure networking system has started. + NET_API->InitNetworking(); + + if ( clearpending ) + { + // Kill off left overs if any + NET_API->CancelAllRequests(); + } + + adr.type = NA_BROADCAST; + + // Request Servers from LAN via IP + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); + + adr.type = NA_BROADCAST_IPX; + + // Request Servers from LAN via IPX ( if supported ) + NET_API->SendRequest( context_id++, NETAPI_REQUEST_DETAILS, FNETAPI_MULTIPLE_RESPONSE, 5.0, &adr, ::ServerResponse ); +} + +void CHudServers::ServerPing( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PING, 0, 5.0, &p->remote_address, ::PingResponse ); +} + +void CHudServers::ServerRules( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_RULES, 0, 5.0, &p->remote_address, ::RulesResponse ); +} + +void CHudServers::ServerPlayers( int server ) +{ + server_t *p; + + p = GetServer( server ); + if ( !p ) + return; + + // Make sure networking system has started. + NET_API->InitNetworking(); + + // Request Server List from master + NET_API->SendRequest( context_id++, NETAPI_REQUEST_PLAYERS, 0, 5.0, &p->remote_address, ::PlayersResponse ); +} + +int CHudServers::isQuerying() +{ + return m_nRequesting ? 1 : 0; +} + + +/* +=================== +GetServerCount + +Return number of servers in browser list +=================== +*/ +int CHudServers::GetServerCount( void ) +{ + return m_nServerCount; +} + +/* +=================== +CHudServers + +=================== +*/ +CHudServers::CHudServers( void ) +{ + m_nRequesting = 0; + m_dStarted = 0.0; + m_nDone = 0; + m_pServerList = NULL; + m_pServers = NULL; + m_pActiveList = NULL; + m_nQuerying = 0; + m_nActiveQueries = 0; + + m_fElapsed = 0.0; + + + m_pPingRequest = NULL; + m_pRulesRequest = NULL; + m_pPlayersRequest = NULL; +} + +/* +=================== +~CHudServers + +=================== +*/ +CHudServers::~CHudServers( void ) +{ + ClearRequestList( &m_pActiveList ); + ClearRequestList( &m_pServerList ); + ClearServerList( &m_pServers ); + + m_nServerCount = 0; + + if ( m_pPingRequest ) + { + delete m_pPingRequest; + m_pPingRequest = NULL; + + } + + if ( m_pRulesRequest ) + { + delete m_pRulesRequest; + m_pRulesRequest = NULL; + } + + if ( m_pPlayersRequest ) + { + delete m_pPlayersRequest; + m_pPlayersRequest = NULL; + } +} + +/////////////////////////////// +// +// PUBLIC APIs +// +/////////////////////////////// + +/* +=================== +ServersGetCount + +=================== +*/ +int ServersGetCount( void ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerCount(); + } + return 0; +} + +int ServersIsQuerying( void ) +{ + if ( g_pServers ) + { + return g_pServers->isQuerying(); + } + return 0; +} + +/* +=================== +ServersGetInfo + +=================== +*/ +const char *ServersGetInfo( int server ) +{ + if ( g_pServers ) + { + return g_pServers->GetServerInfo( server ); + } + + return NULL; +} + +void SortServers( const char *fieldname ) +{ + if ( g_pServers ) + { + g_pServers->SortServers( fieldname ); + } +} + +/* +=================== +ServersShutdown + +=================== +*/ +void ServersShutdown( void ) +{ + if ( g_pServers ) + { + delete g_pServers; + g_pServers = NULL; + } +} + +/* +=================== +ServersInit + +=================== +*/ +void ServersInit( void ) +{ + // Kill any previous instance + ServersShutdown(); + + g_pServers = new CHudServers(); +} + +/* +=================== +ServersThink + +=================== +*/ +void ServersThink( double time ) +{ + if ( g_pServers ) + { + g_pServers->Think( time ); + } +} + +/* +=================== +ServersCancel + +=================== +*/ +void ServersCancel( void ) +{ + if ( g_pServers ) + { + g_pServers->CancelRequest(); + } +} + +// Requests +/* +=================== +ServersList + +=================== +*/ +void ServersList( void ) +{ + if ( g_pServers ) + { + g_pServers->RequestList(); + } +} + +void BroadcastServersList( int clearpending ) +{ + if ( g_pServers ) + { + g_pServers->RequestBroadcastList( clearpending ); + } +} + +void ServerPing( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPing( server ); + } +} + +void ServerRules( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerRules( server ); + } +} + +void ServerPlayers( int server ) +{ + if ( g_pServers ) + { + g_pServers->ServerPlayers( server ); + } +} \ No newline at end of file diff --git a/cl_dll/hud_servers.h b/cl_dll/hud_servers.h new file mode 100644 index 00000000..02bc8555 --- /dev/null +++ b/cl_dll/hud_servers.h @@ -0,0 +1,41 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_SERVERSH ) +#define HUD_SERVERSH +#pragma once + +#define NET_CALLBACK /* */ + +// Dispatchers +void NET_CALLBACK ListResponse( struct net_response_s *response ); +void NET_CALLBACK ServerResponse( struct net_response_s *response ); +void NET_CALLBACK PingResponse( struct net_response_s *response ); +void NET_CALLBACK RulesResponse( struct net_response_s *response ); +void NET_CALLBACK PlayersResponse( struct net_response_s *response ); + +void ServersInit( void ); +void ServersShutdown( void ); +void ServersThink( double time ); +void ServersCancel( void ); + +// Get list and get server info from each +void ServersList( void ); + +// Query for IP / IPX LAN servers +void BroadcastServersList( int clearpending ); + +void ServerPing( int server ); +void ServerRules( int server ); +void ServerPlayers( int server ); + +int ServersGetCount( void ); +const char *ServersGetInfo( int server ); +int ServersIsQuerying( void ); +void SortServers( const char *fieldname ); + +#endif // HUD_SERVERSH \ No newline at end of file diff --git a/cl_dll/hud_servers_priv.h b/cl_dll/hud_servers_priv.h new file mode 100644 index 00000000..1919a0a7 --- /dev/null +++ b/cl_dll/hud_servers_priv.h @@ -0,0 +1,98 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( HUD_SERVERS_PRIVH ) +#define HUD_SERVERS_PRIVH +#pragma once + +#include "netadr.h" + +class CHudServers +{ +public: + typedef struct request_s + { + struct request_s *next; + netadr_t remote_address; + int context; + } request_t; + + typedef struct server_s + { + struct server_s *next; + netadr_t remote_address; + char *info; + int ping; + } server_t; + + CHudServers(); + ~CHudServers(); + + void Think( double time ); + void QueryThink( void ); + int isQuerying( void ); + + int LoadMasterAddresses( int maxservers, int *count, netadr_t *padr ); + + void RequestList( void ); + void RequestBroadcastList( int clearpending ); + + void ServerPing( int server ); + void ServerRules( int server ); + void ServerPlayers( int server ); + + void CancelRequest( void ); + + int CompareServers( server_t *p1, server_t *p2 ); + + void ClearServerList( server_t **ppList ); + void ClearRequestList( request_t **ppList ); + + void AddServer( server_t **ppList, server_t *p ); + + void RemoveServerFromList( request_t **ppList, request_t *item ); + + request_t *FindRequest( int context, request_t *pList ); + + int ServerListSize( void ); + char *GetServerInfo( int server ); + int GetServerCount( void ); + void SortServers( const char *fieldname ); + + void ListResponse( struct net_response_s *response ); + void ServerResponse( struct net_response_s *response ); + void PingResponse( struct net_response_s *response ); + void RulesResponse( struct net_response_s *response ); + void PlayersResponse( struct net_response_s *response ); +private: + + server_t *GetServer( int server ); + + // + char m_szToken[ 1024 ]; + int m_nRequesting; + int m_nDone; + + double m_dStarted; + + request_t *m_pServerList; + request_t *m_pActiveList; + + server_t *m_pServers; + + int m_nServerCount; + + int m_nActiveQueries; + int m_nQuerying; + double m_fElapsed; + + request_t *m_pPingRequest; + request_t *m_pRulesRequest; + request_t *m_pPlayersRequest; +}; + +#endif // HUD_SERVERS_PRIVH \ No newline at end of file diff --git a/cl_dll/hud_spectator.cpp b/cl_dll/hud_spectator.cpp new file mode 100644 index 00000000..1df426a1 --- /dev/null +++ b/cl_dll/hud_spectator.cpp @@ -0,0 +1,1623 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_SpectatorPanel.h" +#include "hltv.h" + +#include "pm_shared.h" +#include "pm_defs.h" +#include "pmtrace.h" +#include "parsemsg.h" +#include "entity_types.h" + +// these are included for the math functions +#include "com_model.h" +#include "demo_api.h" +#include "event_api.h" +#include "studio_util.h" +#include "screenfade.h" + + +#pragma warning(disable: 4244) + +extern "C" int iJumpSpectator; +extern "C" float vJumpOrigin[3]; +extern "C" float vJumpAngles[3]; + + +extern void V_GetInEyePos(int entity, float * origin, float * angles ); +extern void V_ResetChaseCam(); +extern void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles); +extern void VectorAngles( const float *forward, float *angles ); +extern "C" void NormalizeAngles( float *angles ); +extern float * GetClientColor( int clientIndex ); + +extern vec3_t v_origin; // last view origin +extern vec3_t v_angles; // last view angle +extern vec3_t v_cl_angles; // last client/mouse angle +extern vec3_t v_sim_org; // last sim origin + +void SpectatorMode(void) +{ + + + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: spec_mode
[]\n" ); + return; + } + + // SetModes() will decide if command is executed on server or local + if ( gEngfuncs.Cmd_Argc() == 2 ) + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), -1 ); + else if ( gEngfuncs.Cmd_Argc() == 3 ) + gHUD.m_Spectator.SetModes( atoi( gEngfuncs.Cmd_Argv(1) ), atoi( gEngfuncs.Cmd_Argv(2) ) ); +} + +void SpectatorSpray(void) +{ + vec3_t forward; + char string[128]; + + if ( !gEngfuncs.IsSpectateOnly() ) + return; + + AngleVectors(v_angles,forward,NULL,NULL); + VectorScale(forward, 128, forward); + VectorAdd(forward, v_origin, forward); + pmtrace_t * trace = gEngfuncs.PM_TraceLine( v_origin, forward, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); + if ( trace->fraction != 1.0 ) + { + sprintf(string, "drc_spray %.2f %.2f %.2f %i", + trace->endpos[0], trace->endpos[1], trace->endpos[2], trace->ent ); + gEngfuncs.pfnServerCmd(string); + } + +} +void SpectatorHelp(void) +{ + if ( gViewPort ) + { + gViewPort->ShowVGUIMenu( MENU_SPECHELP ); + } + else + { + char *text = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); + + if ( text ) + { + while ( *text ) + { + if ( *text != 13 ) + gEngfuncs.Con_Printf( "%c", *text ); + text++; + } + } + } +} + +void SpectatorMenu( void ) +{ + if ( gEngfuncs.Cmd_Argc() <= 1 ) + { + gEngfuncs.Con_Printf( "usage: spec_menu <0|1>\n" ); + return; + } + + gViewPort->m_pSpectatorPanel->ShowMenu( atoi( gEngfuncs.Cmd_Argv(1))!=0 ); +} + +void ToggleScores( void ) +{ + if ( gViewPort ) + { + if (gViewPort->IsScoreBoardVisible() ) + { + gViewPort->HideScoreBoard(); + } + else + { + gViewPort->ShowScoreBoard(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudSpectator::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + m_flNextObserverInput = 0.0f; + m_zoomDelta = 0.0f; + m_moveDelta = 0.0f; + m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); + iJumpSpectator = 0; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + m_lastPrimaryObject = m_lastSecondaryObject = 0; + + gEngfuncs.pfnAddCommand ("spec_mode", SpectatorMode ); + gEngfuncs.pfnAddCommand ("spec_decal", SpectatorSpray ); + gEngfuncs.pfnAddCommand ("spec_help", SpectatorHelp ); + gEngfuncs.pfnAddCommand ("spec_menu", SpectatorMenu ); + gEngfuncs.pfnAddCommand ("togglescores", ToggleScores ); + + m_drawnames = gEngfuncs.pfnRegisterVariable("spec_drawnames","1",0); + m_drawcone = gEngfuncs.pfnRegisterVariable("spec_drawcone","1",0); + m_drawstatus = gEngfuncs.pfnRegisterVariable("spec_drawstatus","1",0); + m_autoDirector = gEngfuncs.pfnRegisterVariable("spec_autodirector","1",0); + m_pip = gEngfuncs.pfnRegisterVariable("spec_pip","1",0); + + if ( !m_drawnames || !m_drawcone || !m_drawstatus || !m_autoDirector || !m_pip) + { + gEngfuncs.Con_Printf("ERROR! Couldn't register all spectator variables.\n"); + return 0; + } + + return 1; +} + + +//----------------------------------------------------------------------------- +// UTIL_StringToVector originally from ..\dlls\util.cpp, slightly changed +//----------------------------------------------------------------------------- + +void UTIL_StringToVector( float * pVector, const char *pString ) +{ + char *pstr, *pfront, tempString[128]; + int j; + + strcpy( tempString, pString ); + pstr = pfront = tempString; + + for ( j = 0; j < 3; j++ ) + { + pVector[j] = atof( pfront ); + + while ( *pstr && *pstr != ' ' ) + pstr++; + if (!*pstr) + break; + pstr++; + pfront = pstr; + } + + if (j < 2) + { + for (j = j+1;j < 3; j++) + pVector[j] = 0; + } +} + +int UTIL_FindEntityInMap(char * name, float * origin, float * angle) +{ + int n,found = 0; + char keyname[256]; + char token[1024]; + + cl_entity_t * pEnt = gEngfuncs.GetEntityByIndex( 0 ); // get world model + + if ( !pEnt ) return 0; + + if ( !pEnt->model ) return 0; + + char * data = pEnt->model->entities; + + while (data) + { + data = gEngfuncs.COM_ParseFile(data, token); + + if ( (token[0] == '}') || (token[0]==0) ) + break; + + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + } + + if (token[0] != '{') + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: expected {\n"); + return 0; + } + + // we parse the first { now parse entities properties + + while ( 1 ) + { + // parse key + data = gEngfuncs.COM_ParseFile(data, token); + if (token[0] == '}') + break; // finish parsing this entity + + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + }; + + strcpy (keyname, token); + + // another hack to fix keynames with trailing spaces + n = strlen(keyname); + while (n && keyname[n-1] == ' ') + { + keyname[n-1] = 0; + n--; + } + + // parse value + data = gEngfuncs.COM_ParseFile(data, token); + if (!data) + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: EOF without closing brace\n"); + return 0; + }; + + if (token[0] == '}') + { + gEngfuncs.Con_DPrintf("UTIL_FindEntityInMap: closing brace without data"); + return 0; + } + + if (!strcmp(keyname,"classname")) + { + if (!strcmp(token, name )) + { + found = 1; // thats our entity + } + }; + + if( !strcmp( keyname, "angle" ) ) + { + float y = atof( token ); + + if (y >= 0) + { + angle[0] = 0.0f; + angle[1] = y; + } + else if ((int)y == -1) + { + angle[0] = -90.0f; + angle[1] = 0.0f;; + } + else + { + angle[0] = 90.0f; + angle[1] = 0.0f; + } + + angle[2] = 0.0f; + } + + if( !strcmp( keyname, "angles" ) ) + { + UTIL_StringToVector(angle, token); + } + + if (!strcmp(keyname,"origin")) + { + UTIL_StringToVector(origin, token); + + }; + + } // while (1) + + if (found) + return 1; + + } + + return 0; // we search all entities, but didn't found the correct + +} + +//----------------------------------------------------------------------------- +// SetSpectatorStartPosition(): +// Get valid map position and 'beam' spectator to this position +//----------------------------------------------------------------------------- + +void CHudSpectator::SetSpectatorStartPosition() +{ + // search for info_player start + if ( UTIL_FindEntityInMap( "trigger_camera", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_start", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_deathmatch", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + + else if ( UTIL_FindEntityInMap( "info_player_coop", m_cameraOrigin, m_cameraAngles ) ) + iJumpSpectator = 1; + else + { + // jump to 0,0,0 if no better position was found + VectorCopy(vec3_origin, m_cameraOrigin); + VectorCopy(vec3_origin, m_cameraAngles); + } + + VectorCopy(m_cameraOrigin, vJumpOrigin); + VectorCopy(m_cameraAngles, vJumpAngles); + + iJumpSpectator = 1; // jump anyway +} + +//----------------------------------------------------------------------------- +// Purpose: Loads new icons +//----------------------------------------------------------------------------- +int CHudSpectator::VidInit() +{ + m_hsprPlayer = SPR_Load("sprites/iplayer.spr"); + m_hsprPlayerBlue = SPR_Load("sprites/iplayerblue.spr"); + m_hsprPlayerRed = SPR_Load("sprites/iplayerred.spr"); + m_hsprPlayerDead = SPR_Load("sprites/iplayerdead.spr"); + m_hsprUnkownMap = SPR_Load("sprites/tile.spr"); + m_hsprBeam = SPR_Load("sprites/laserbeam.spr"); + m_hsprCamera = SPR_Load("sprites/camera.spr"); + m_hCrosshair = SPR_Load("sprites/crosshairs.spr"); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flTime - +// intermission - +//----------------------------------------------------------------------------- +int CHudSpectator::Draw(float flTime) +{ + int lx; + + char string[256]; + float * color; + + // draw only in spectator mode + if ( !g_iUser1 ) + return 0; + + // if user pressed zoom, aplly changes + if ( (m_zoomDelta != 0.0f) && ( g_iUser1 == OBS_MAP_FREE ) ) + { + m_mapZoom += m_zoomDelta; + + if ( m_mapZoom > 3.0f ) + m_mapZoom = 3.0f; + + if ( m_mapZoom < 0.5f ) + m_mapZoom = 0.5f; + } + + // if user moves in map mode, change map origin + if ( (m_moveDelta != 0.0f) && (g_iUser1 != OBS_ROAMING) ) + { + vec3_t right; + AngleVectors(v_angles, NULL, right, NULL); + VectorNormalize(right); + VectorScale(right, m_moveDelta, right ); + + VectorAdd( m_mapOrigin, right, m_mapOrigin ) + + } + + // Only draw the icon names only if map mode is in Main Mode + if ( g_iUser1 < OBS_MAP_FREE ) + return 1; + + if ( !m_drawnames->value ) + return 1; + + // make sure we have player info + gViewPort->GetAllPlayersInfo(); + + + // loop through all the players and draw additional infos to their sprites on the map + for (int i = 0; i < MAX_PLAYERS; i++) + { + + if ( m_vPlayerPos[i][2]<0 ) // marked as invisible ? + continue; + + // check if name would be in inset window + if ( m_pip->value != INSET_OFF ) + { + if ( m_vPlayerPos[i][0] > XRES( m_OverviewData.insetWindowX ) && + m_vPlayerPos[i][1] > YRES( m_OverviewData.insetWindowY ) && + m_vPlayerPos[i][0] < XRES( m_OverviewData.insetWindowX + m_OverviewData.insetWindowWidth ) && + m_vPlayerPos[i][1] < YRES( m_OverviewData.insetWindowY + m_OverviewData.insetWindowHeight) + ) continue; + } + + color = GetClientColor( i+1 ); + + // draw the players name and health underneath + sprintf(string, "%s", g_PlayerInfoList[i+1].name ); + + lx = strlen(string)*3; // 3 is avg. character length :) + + gEngfuncs.pfnDrawSetTextColor( color[0], color[1], color[2] ); + DrawConsoleString( m_vPlayerPos[i][0]-lx,m_vPlayerPos[i][1], string); + + } + + return 1; +} + + +void CHudSpectator::DirectorMessage( int iSize, void *pbuf ) +{ + float value; + char * string; + + BEGIN_READ( pbuf, iSize ); + + int cmd = READ_BYTE(); + + switch ( cmd ) // director command byte + { + case DRC_CMD_START : + // now we have to do some things clientside, since the proxy doesn't know our mod + g_iPlayerClass = 0; + g_iTeamNumber = 0; + + // fake a InitHUD & ResetHUD message + gHUD.MsgFunc_InitHUD(NULL,0, NULL); + gHUD.MsgFunc_ResetHUD(NULL, 0, NULL); + + break; + + case DRC_CMD_EVENT : + m_lastPrimaryObject = READ_WORD(); + m_lastSecondaryObject = READ_WORD(); + m_iObserverFlags = READ_LONG(); + + if ( m_autoDirector->value ) + { + if ( (g_iUser2 != m_lastPrimaryObject) || (g_iUser3 != m_lastSecondaryObject) ) + V_ResetChaseCam(); + + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + + // gEngfuncs.Con_Printf("Director Camera: %i %i\n", firstObject, secondObject); + break; + + case DRC_CMD_MODE : + if ( m_autoDirector->value ) + { + SetModes( READ_BYTE(), -1 ); + } + break; + + case DRC_CMD_CAMERA : + if ( m_autoDirector->value ) + { + vJumpOrigin[0] = READ_COORD(); // position + vJumpOrigin[1] = READ_COORD(); + vJumpOrigin[2] = READ_COORD(); + + vJumpAngles[0] = READ_COORD(); // view angle + vJumpAngles[1] = READ_COORD(); + vJumpAngles[2] = READ_COORD(); + + gEngfuncs.SetViewAngles( vJumpAngles ); + + iJumpSpectator = 1; + } + break; + + case DRC_CMD_MESSAGE: + { + client_textmessage_t * msg = &m_HUDMessages[m_lastHudMessage]; + + msg->effect = READ_BYTE(); // effect + + UnpackRGB( (int&)msg->r1, (int&)msg->g1, (int&)msg->b1, READ_LONG() ); // color + msg->r2 = msg->r1; + msg->g2 = msg->g1; + msg->b2 = msg->b1; + msg->a2 = msg->a1 = 0xFF; // not transparent + + msg->x = READ_FLOAT(); // x pos + msg->y = READ_FLOAT(); // y pos + + msg->fadein = READ_FLOAT(); // fadein + msg->fadeout = READ_FLOAT(); // fadeout + msg->holdtime = READ_FLOAT(); // holdtime + msg->fxtime = READ_FLOAT(); // fxtime; + + strncpy( m_HUDMessageText[m_lastHudMessage], READ_STRING(), 128 ); + m_HUDMessageText[m_lastHudMessage][127]=0; // text + + msg->pMessage = m_HUDMessageText[m_lastHudMessage]; + msg->pName = "HUD_MESSAGE"; + + gHUD.m_Message.MessageAdd( msg ); + + m_lastHudMessage++; + m_lastHudMessage %= MAX_SPEC_HUD_MESSAGES; + + } + + break; + + case DRC_CMD_SOUND : + string = READ_STRING(); + value = READ_FLOAT(); + + // gEngfuncs.Con_Printf("DRC_CMD_FX_SOUND: %s %.2f\n", string, value ); + gEngfuncs.pEventAPI->EV_PlaySound(0, v_origin, CHAN_BODY, string, value, ATTN_NORM, 0, PITCH_NORM ); + + break; + + case DRC_CMD_TIMESCALE : + value = READ_FLOAT(); + break; + + + + case DRC_CMD_STATUS: + READ_LONG(); // total number of spectator slots + m_iSpectatorNumber = READ_LONG(); // total number of spectator + READ_WORD(); // total number of relay proxies + + gViewPort->UpdateSpectatorPanel(); + break; + + case DRC_CMD_BANNER: + // gEngfuncs.Con_DPrintf("GUI: Banner %s\n",READ_STRING() ); // name of banner tga eg gfx/temp/7454562234563475.tga + gViewPort->m_pSpectatorPanel->m_TopBanner->LoadImage( READ_STRING() ); + gViewPort->UpdateSpectatorPanel(); + break; + + case DRC_CMD_FADE: + break; + + case DRC_CMD_STUFFTEXT: + ClientCmd( READ_STRING() ); + break; + + default : gEngfuncs.Con_DPrintf("CHudSpectator::DirectorMessage: unknown command %i.\n", cmd ); + } +} + +void CHudSpectator::FindNextPlayer(bool bReverse) +{ + // MOD AUTHORS: Modify the logic of this function if you want to restrict the observer to watching + // only a subset of the players. e.g. Make it check the target's team. + + int iStart; + cl_entity_t * pEnt = NULL; + + // if we are NOT in HLTV mode, spectator targets are set on server + if ( !gEngfuncs.IsSpectateOnly() ) + { + char cmdstring[32]; + // forward command to server + sprintf(cmdstring,"follownext %i",bReverse?1:0); + gEngfuncs.pfnServerCmd(cmdstring); + return; + } + + if ( g_iUser2 ) + iStart = g_iUser2; + else + iStart = 1; + + g_iUser2 = 0; + + int iCurrent = iStart; + + int iDir = bReverse ? -1 : 1; + + // make sure we have player info + gViewPort->GetAllPlayersInfo(); + + + do + { + iCurrent += iDir; + + // Loop through the clients + if (iCurrent > MAX_PLAYERS) + iCurrent = 1; + if (iCurrent < 1) + iCurrent = MAX_PLAYERS; + + pEnt = gEngfuncs.GetEntityByIndex( iCurrent ); + + if ( !IsActivePlayer( pEnt ) ) + continue; + + // MOD AUTHORS: Add checks on target here. + + g_iUser2 = iCurrent; + break; + + } while ( iCurrent != iStart ); + + // Did we find a target? + if ( !g_iUser2 ) + { + gEngfuncs.Con_DPrintf( "No observer targets.\n" ); + // take save camera position + VectorCopy(m_cameraOrigin, vJumpOrigin); + VectorCopy(m_cameraAngles, vJumpAngles); + } + else + { + // use new entity position for roaming + VectorCopy ( pEnt->origin, vJumpOrigin ); + VectorCopy ( pEnt->angles, vJumpAngles ); + } + iJumpSpectator = 1; +} + +void CHudSpectator::HandleButtonsDown( int ButtonPressed ) +{ + double time = gEngfuncs.GetClientTime(); + + int newMainMode = g_iUser1; + int newInsetMode = m_pip->value; + + // gEngfuncs.Con_Printf(" HandleButtons:%i\n", ButtonPressed ); + if ( !gViewPort ) + return; + + //Not in intermission. + if ( gHUD.m_iIntermission ) + return; + + if ( !g_iUser1 ) + return; // dont do anything if not in spectator mode + + // don't handle buttons during normal demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() && !gEngfuncs.IsSpectateOnly() ) + return; + // Slow down mouse clicks. + if ( m_flNextObserverInput > time ) + return; + + // enable spectator screen + if ( ButtonPressed & IN_DUCK ) + gViewPort->m_pSpectatorPanel->ShowMenu(!gViewPort->m_pSpectatorPanel->m_menuVisible); + + // 'Use' changes inset window mode + if ( ButtonPressed & IN_USE ) + { + newInsetMode = ToggleInset(true); + } + + // if not in HLTV mode, buttons are handled server side + if ( gEngfuncs.IsSpectateOnly() ) + { + // changing target or chase mode not in overviewmode without inset window + + // Jump changes main window modes + if ( ButtonPressed & IN_JUMP ) + { + if ( g_iUser1 == OBS_CHASE_LOCKED ) + newMainMode = OBS_CHASE_FREE; + + else if ( g_iUser1 == OBS_CHASE_FREE ) + newMainMode = OBS_IN_EYE; + + else if ( g_iUser1 == OBS_IN_EYE ) + newMainMode = OBS_ROAMING; + + else if ( g_iUser1 == OBS_ROAMING ) + newMainMode = OBS_MAP_FREE; + + else if ( g_iUser1 == OBS_MAP_FREE ) + newMainMode = OBS_MAP_CHASE; + + else + newMainMode = OBS_CHASE_FREE; // don't use OBS_CHASE_LOCKED anymore + } + + // Attack moves to the next player + if ( ButtonPressed & (IN_ATTACK | IN_ATTACK2) ) + { + FindNextPlayer( (ButtonPressed & IN_ATTACK2) ? true:false ); + + if ( g_iUser1 == OBS_ROAMING ) + { + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + + } + // lease directed mode if player want to see another player + m_autoDirector->value = 0.0f; + } + } + + SetModes(newMainMode, newInsetMode); + + if ( g_iUser1 == OBS_MAP_FREE ) + { + if ( ButtonPressed & IN_FORWARD ) + m_zoomDelta = 0.01f; + + if ( ButtonPressed & IN_BACK ) + m_zoomDelta = -0.01f; + + if ( ButtonPressed & IN_MOVELEFT ) + m_moveDelta = -12.0f; + + if ( ButtonPressed & IN_MOVERIGHT ) + m_moveDelta = 12.0f; + } + + m_flNextObserverInput = time + 0.2; +} + +void CHudSpectator::HandleButtonsUp( int ButtonPressed ) +{ + if ( !gViewPort ) + return; + + if ( !gViewPort->m_pSpectatorPanel->isVisible() ) + return; // dont do anything if not in spectator mode + + if ( ButtonPressed & (IN_FORWARD | IN_BACK) ) + m_zoomDelta = 0.0f; + + if ( ButtonPressed & (IN_MOVELEFT | IN_MOVERIGHT) ) + m_moveDelta = 0.0f; +} + +void CHudSpectator::SetModes(int iNewMainMode, int iNewInsetMode) +{ + // if value == -1 keep old value + if ( iNewMainMode == -1 ) + iNewMainMode = g_iUser1; + + if ( iNewInsetMode == -1 ) + iNewInsetMode = m_pip->value; + + // inset mode is handled only clients side + m_pip->value = iNewInsetMode; + + if ( iNewMainMode < OBS_CHASE_LOCKED || iNewMainMode > OBS_MAP_CHASE ) + { + gEngfuncs.Con_Printf("Invalid spectator mode.\n"); + return; + } + + // main modes ettings will override inset window settings + if ( iNewMainMode != g_iUser1 ) + { + // if we are NOT in HLTV mode, main spectator mode is set on server + if ( !gEngfuncs.IsSpectateOnly() ) + { + return; + } + + if ( !g_iUser2 && (iNewMainMode !=OBS_ROAMING ) ) // make sure we have a target + { + // choose last Director object if still available + if ( IsActivePlayer( gEngfuncs.GetEntityByIndex( m_lastPrimaryObject ) ) ) + { + g_iUser2 = m_lastPrimaryObject; + g_iUser3 = m_lastSecondaryObject; + } + else + FindNextPlayer(false); // find any target + } + + switch ( iNewMainMode ) + { + case OBS_CHASE_LOCKED: g_iUser1 = OBS_CHASE_LOCKED; + break; + + case OBS_CHASE_FREE : g_iUser1 = OBS_CHASE_FREE; + break; + + case OBS_ROAMING : // jump to current vJumpOrigin/angle + g_iUser1 = OBS_ROAMING; + if ( g_iUser2 ) + { + V_GetChasePos( g_iUser2, v_cl_angles, vJumpOrigin, vJumpAngles ); + gEngfuncs.SetViewAngles( vJumpAngles ); + iJumpSpectator = 1; + } + break; + + case OBS_IN_EYE : g_iUser1 = OBS_IN_EYE; + break; + + case OBS_MAP_FREE : g_iUser1 = OBS_MAP_FREE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + + case OBS_MAP_CHASE : g_iUser1 = OBS_MAP_CHASE; + // reset user values + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + break; + } + + if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + { + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; + m_crosshairRect.bottom = 24; + + SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); + } + else + { + memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); + } + + char string[128]; + sprintf(string, "#Spec_Mode%d", g_iUser1 ); + sprintf(string, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( string )); + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + + gViewPort->UpdateSpectatorPanel(); + +} + +bool CHudSpectator::IsActivePlayer(cl_entity_t * ent) +{ + return ( ent && + ent->player && + ent->curstate.solid != SOLID_NOT && + ent != gEngfuncs.GetLocalPlayer() && + g_PlayerInfoList[ent->index].name != NULL + ); +} + + +bool CHudSpectator::ParseOverviewFile( ) +{ + char filename[255]; + char levelname[255]; + char token[1024]; + float height; + + char *pfile = NULL; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + + // fill in standrd values + m_OverviewData.insetWindowX = 4; // upper left corner + m_OverviewData.insetWindowY = 4; + m_OverviewData.insetWindowHeight = 180; + m_OverviewData.insetWindowWidth = 240; + m_OverviewData.origin[0] = 0.0f; + m_OverviewData.origin[1] = 0.0f; + m_OverviewData.origin[2] = 0.0f; + m_OverviewData.zoom = 1.0f; + m_OverviewData.layers = 0; + m_OverviewData.layersHeights[0] = 0.0f; + strcpy( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ); + + if ( strlen( m_OverviewData.map ) == 0 ) + return false; // not active yet + + strcpy(levelname, m_OverviewData.map + 5); + levelname[strlen(levelname)-4] = 0; + + sprintf(filename, "overviews/%s.txt", levelname ); + + pfile = (char *)gEngfuncs.COM_LoadFile( filename, 5, NULL); + + if (!pfile) + { + gEngfuncs.Con_Printf("Couldn't open file %s. Using default values for overiew mode.\n", filename ); + return false; + } + + + while (true) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + + if (!pfile) + break; + + if ( !stricmp( token, "global" ) ) + { + // parse the global data + pfile = gEngfuncs.COM_ParseFile(pfile, token); + if ( stricmp( token, "{" ) ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + while (stricmp( token, "}") ) + { + if ( !stricmp( token, "zoom" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.zoom = atof( token ); + } + else if ( !stricmp( token, "origin" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + m_OverviewData.origin[0] = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.origin[1] = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile, token); + m_OverviewData.origin[2] = atof( token ); + } + else if ( !stricmp( token, "rotated" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.rotated = atoi( token ); + } + else if ( !stricmp( token, "inset" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowX = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowY = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowWidth = atof( token ); + pfile = gEngfuncs.COM_ParseFile(pfile,token); + m_OverviewData.insetWindowHeight = atof( token ); + + } + else + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + + } + } + else if ( !stricmp( token, "layer" ) ) + { + // parse a layer data + + if ( m_OverviewData.layers == OVERVIEW_MAX_LAYERS ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. ( too many layers )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + + if ( stricmp( token, "{" ) ) + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (expected { )\n", filename ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); + + while (stricmp( token, "}") ) + { + if ( !stricmp( token, "image" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + strcpy(m_OverviewData.layersImages[ m_OverviewData.layers ], token); + + + } + else if ( !stricmp( token, "height" ) ) + { + pfile = gEngfuncs.COM_ParseFile(pfile,token); + height = atof(token); + m_OverviewData.layersHeights[ m_OverviewData.layers ] = height; + } + else + { + gEngfuncs.Con_Printf("Error parsing overview file %s. (%s unkown)\n", filename, token ); + return false; + } + + pfile = gEngfuncs.COM_ParseFile(pfile,token); // parse next token + } + + m_OverviewData.layers++; + + } + } + + gEngfuncs.COM_FreeFile( pfile ); + + m_mapZoom = m_OverviewData.zoom; + m_mapOrigin = m_OverviewData.origin; + + return true; + +} + +void CHudSpectator::LoadMapSprites() +{ + // right now only support for one map layer + if (m_OverviewData.layers > 0 ) + { + m_MapSprite = gEngfuncs.LoadMapSprite( m_OverviewData.layersImages[0] ); + } + else + m_MapSprite = NULL; // the standard "unkown map" sprite will be used instead +} + +void CHudSpectator::DrawOverviewLayer() +{ + float screenaspect, xs, ys, xStep, yStep, x,y,z; + int ix,iy,i,xTiles,yTiles,frame; + + qboolean hasMapImage = m_MapSprite?TRUE:FALSE; + model_t * dummySprite = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprUnkownMap); + + if ( hasMapImage) + { + i = m_MapSprite->numframes / (4*3); + i = sqrt(i); + xTiles = i*4; + yTiles = i*3; + } + else + { + xTiles = 8; + yTiles = 6; + } + + + screenaspect = 4.0f/3.0f; + + + xs = m_OverviewData.origin[0]; + ys = m_OverviewData.origin[1]; + z = ( 90.0f - v_angles[0] ) / 90.0f; + z *= m_OverviewData.layersHeights[0]; // gOverviewData.z_min - 32; + + // i = r_overviewTexture + ( layer*OVERVIEW_X_TILES*OVERVIEW_Y_TILES ); + + gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + + frame = 0; + + + // rotated view ? + if ( m_OverviewData.rotated ) + { + xStep = (2*4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + + y = ys + (4096.0f / (m_OverviewData.zoom * screenaspect)); + + for (iy = 0; iy < yTiles; iy++) + { + x = xs - (4096.0f / (m_OverviewData.zoom)); + + for (ix = 0; ix < xTiles; ix++) + { + if (hasMapImage) + gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); + else + gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->End(); + + frame++; + x+= xStep; + } + + y+=yStep; + } + } + else + { + xStep = -(2*4096.0f / m_OverviewData.zoom ) / xTiles; + yStep = -(2*4096.0f / (m_OverviewData.zoom* screenaspect) ) / yTiles; + + + x = xs + (4096.0f / (m_OverviewData.zoom * screenaspect )); + + + + for (ix = 0; ix < yTiles; ix++) + { + + y = ys + (4096.0f / (m_OverviewData.zoom)); + + for (iy = 0; iy < xTiles; iy++) + { + if (hasMapImage) + gEngfuncs.pTriAPI->SpriteTexture( m_MapSprite, frame ); + else + gEngfuncs.pTriAPI->SpriteTexture( dummySprite, 0 ); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep ,y, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+xStep, y+yStep, z); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x, y+yStep, z); + gEngfuncs.pTriAPI->End(); + + frame++; + + y+=yStep; + } + + x+= xStep; + + } + } +} + +void CHudSpectator::DrawOverviewEntities() +{ + int i,ir,ig,ib; + struct model_s *hSpriteModel; + vec3_t origin, angles, point, forward, right, left, up, world, screen, offset; + float x,y,z, r,g,b, sizeScale = 4.0f; + cl_entity_t * ent; + float rmatrix[3][4]; // transformation matrix + + float zScale = (90.0f - v_angles[0] ) / 90.0f; + + + z = m_OverviewData.layersHeights[0] * zScale; + // get yellow/brown HUD color + UnpackRGB(ir,ig,ib, RGB_YELLOWISH); + r = (float)ir/255.0f; + g = (float)ig/255.0f; + b = (float)ib/255.0f; + + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + + for (i=0; i < MAX_PLAYERS; i++ ) + m_vPlayerPos[i][2] = -1; // mark as invisible + + // draw all players + for (i=0 ; i < MAX_OVERVIEW_ENTITIES ; i++) + { + if ( !m_OverviewEntities[i].hSprite ) + continue; + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_OverviewEntities[i].hSprite ); + ent = m_OverviewEntities[i].entity; + + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); + + // see R_DrawSpriteModel + // draws players sprite + + AngleVectors(ent->angles, right, up, NULL ); + + VectorCopy(ent->origin,origin); + + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + VectorMA (origin, 16.0f * sizeScale, up, point); + VectorMA (point, 16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + + VectorMA (origin, 16.0f * sizeScale, up, point); + VectorMA (point, -16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (0,1); + VectorMA (origin, -16.0f * sizeScale, up, point); + VectorMA (point, -16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->TexCoord2f (1,1); + VectorMA (origin, -16.0f * sizeScale, up, point); + VectorMA (point, 16.0f * sizeScale, right, point); + point[2] *= zScale; + gEngfuncs.pTriAPI->Vertex3fv (point); + + gEngfuncs.pTriAPI->End (); + + + if ( !ent->player) + continue; + // draw line under player icons + origin[2] *= zScale; + + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprBeam ); + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + + gEngfuncs.pTriAPI->Color4f(r, g, b, 0.3); + + gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]-4,z); + gEngfuncs.pTriAPI->TexCoord2f (1, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]+4,z); + gEngfuncs.pTriAPI->End (); + + gEngfuncs.pTriAPI->Begin ( TRI_QUADS ); + gEngfuncs.pTriAPI->TexCoord2f (1, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 0); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4, origin[2]-zScale); + gEngfuncs.pTriAPI->TexCoord2f (0, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]+4, origin[1]-4,z); + gEngfuncs.pTriAPI->TexCoord2f (1, 1); + gEngfuncs.pTriAPI->Vertex3f (origin[0]-4, origin[1]+4,z); + gEngfuncs.pTriAPI->End (); + + // calculate screen position for name and infromation in hud::draw() + if ( gEngfuncs.pTriAPI->WorldToScreen(origin,screen) ) + continue; // object is behind viewer + + screen[0] = XPROJECT(screen[0]); + screen[1] = YPROJECT(screen[1]); + screen[2] = 0.0f; + + // calculate some offset under the icon + origin[0]+=32.0f; + origin[1]+=32.0f; + + gEngfuncs.pTriAPI->WorldToScreen(origin,offset); + + offset[0] = XPROJECT(offset[0]); + offset[1] = YPROJECT(offset[1]); + offset[2] = 0.0f; + + VectorSubtract(offset, screen, offset ); + + int playerNum = ent->index - 1; + + m_vPlayerPos[playerNum][0] = screen[0]; + m_vPlayerPos[playerNum][1] = screen[1] + Length(offset); + m_vPlayerPos[playerNum][2] = 1; // mark player as visible + } + + if ( !m_pip->value || !m_drawcone->value ) + return; + + // get current camera position and angle + + if ( m_pip->value == INSET_IN_EYE || g_iUser1 == OBS_IN_EYE ) + { + V_GetInEyePos( g_iUser2, origin, angles ); + } + else if ( m_pip->value == INSET_CHASE_FREE || g_iUser1 == OBS_CHASE_FREE ) + { + V_GetChasePos( g_iUser2, v_cl_angles, origin, angles ); + } + else if ( g_iUser1 == OBS_ROAMING ) + { + VectorCopy( v_sim_org, origin ); + VectorCopy( v_cl_angles, angles ); + } + else + V_GetChasePos( g_iUser2, NULL, origin, angles ); + + + // draw camera sprite + + x = origin[0]; + y = origin[1]; + z = origin[2]; + + angles[0] = 0; // always show horizontal camera sprite + + hSpriteModel = (struct model_s *)gEngfuncs.GetSpritePointer( m_hsprCamera ); + gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); + gEngfuncs.pTriAPI->SpriteTexture( hSpriteModel, 0 ); + + + gEngfuncs.pTriAPI->Color4f( r, g, b, 1.0 ); + + AngleVectors(angles, forward, NULL, NULL ); + VectorScale (forward, 512.0f, forward); + + offset[0] = 0.0f; + offset[1] = 45.0f; + offset[2] = 0.0f; + + AngleMatrix(offset, rmatrix ); + VectorTransform(forward, rmatrix , right ); + + offset[1]= -45.0f; + AngleMatrix(offset, rmatrix ); + VectorTransform(forward, rmatrix , left ); + + gEngfuncs.pTriAPI->Begin (TRI_TRIANGLES); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x+right[0], y+right[1], (z+right[2]) * zScale); + + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x, y, z * zScale); + + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x+left[0], y+left[1], (z+left[2]) * zScale); + gEngfuncs.pTriAPI->End (); + +} + + + +void CHudSpectator::DrawOverview() +{ + // draw only in sepctator mode + if ( !g_iUser1 ) + return; + + // Only draw the overview if Map Mode is selected for this view + if ( m_iDrawCycle == 0 && ( (g_iUser1 != OBS_MAP_FREE) && (g_iUser1 != OBS_MAP_CHASE) ) ) + return; + + if ( m_iDrawCycle == 1 && m_pip->value < INSET_MAP_FREE ) + return; + + DrawOverviewLayer(); + DrawOverviewEntities(); + CheckOverviewEntities(); +} +void CHudSpectator::CheckOverviewEntities() +{ + double time = gEngfuncs.GetClientTime(); + + // removes old entities from list + for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + { + // remove entity from list if it is too old + if ( m_OverviewEntities[i].killTime < time ) + { + memset( &m_OverviewEntities[i], 0, sizeof (overviewEntity_t) ); + } + } +} + +bool CHudSpectator::AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname) +{ + HSPRITE hSprite = 0; + double duration = -1.0f; // duration -1 means show it only this frame; + + if ( !ent ) + return false; + + if ( type == ET_PLAYER ) + { + if ( ent->curstate.solid != SOLID_NOT) + { + switch ( g_PlayerExtraInfo[ent->index].teamnumber ) + { + // blue and red teams are swapped in CS and TFC + case 1 : hSprite = m_hsprPlayerBlue; break; + case 2 : hSprite = m_hsprPlayerRed; break; + default : hSprite = m_hsprPlayer; break; + } + } + else + return false; // it's an spectator + } + else if (type == ET_NORMAL) + { + return false; + } + else + return false; + + return AddOverviewEntityToList(hSprite, ent, gEngfuncs.GetClientTime() + duration ); +} + +void CHudSpectator::DeathMessage(int victim) +{ + // find out where the victim is + cl_entity_t *pl = gEngfuncs.GetEntityByIndex(victim); + + if (pl && pl->player) + AddOverviewEntityToList(m_hsprPlayerDead, pl, gEngfuncs.GetClientTime() + 2.0f ); +} + +bool CHudSpectator::AddOverviewEntityToList(HSPRITE sprite, cl_entity_t *ent, double killTime) +{ + for ( int i = 0; i< MAX_OVERVIEW_ENTITIES; i++ ) + { + // find empty entity slot + if ( m_OverviewEntities[i].entity == NULL) + { + m_OverviewEntities[i].entity = ent; + m_OverviewEntities[i].hSprite = sprite; + m_OverviewEntities[i].killTime = killTime; + return true; + } + } + + return false; // maximum overview entities reached +} +void CHudSpectator::CheckSettings() +{ + // disallow same inset mode as main mode: + + m_pip->value = (int)m_pip->value; + + if ( ( g_iUser1 < OBS_MAP_FREE ) && ( m_pip->value == INSET_CHASE_FREE || m_pip->value == INSET_IN_EYE ) ) + { + // otherwise both would show in World picures + m_pip->value = INSET_MAP_FREE; + } + + if ( ( g_iUser1 >= OBS_MAP_FREE ) && ( m_pip->value >= INSET_MAP_FREE ) ) + { + // both would show map views + m_pip->value = INSET_CHASE_FREE; + } + + // disble in intermission screen + if ( gHUD.m_iIntermission ) + m_pip->value = INSET_OFF; + + // check chat mode + if ( m_chatEnabled != (gHUD.m_SayText.m_HUD_saytext->value!=0) ) + { + // hud_saytext changed + m_chatEnabled = (gHUD.m_SayText.m_HUD_saytext->value!=0); + + if ( gEngfuncs.IsSpectateOnly() ) + { + // tell proxy our new chat mode + char chatcmd[32]; + sprintf(chatcmd, "ignoremsg %i", m_chatEnabled?0:1 ); + gEngfuncs.pfnServerCmd(chatcmd); + } + } + + // HL/TFC has no oberserver corsshair, so set it client side + if ( (g_iUser1 == OBS_IN_EYE) || (g_iUser1 == OBS_ROAMING) ) + { + m_crosshairRect.left = 24; + m_crosshairRect.top = 0; + m_crosshairRect.right = 48; + m_crosshairRect.bottom = 24; + + SetCrosshair( m_hCrosshair, m_crosshairRect, 255, 255, 255 ); + } + else + { + memset( &m_crosshairRect,0,sizeof(m_crosshairRect) ); + SetCrosshair( 0, m_crosshairRect, 0, 0, 0 ); + } + + + + // if we are a real player on server don't allow inset window + // in First Person mode since this is our resticted forcecamera mode 2 + // team number 3 = SPECTATOR see player.h + + if ( ( (g_iTeamNumber == 1) || (g_iTeamNumber == 2)) && (g_iUser1 == OBS_IN_EYE) ) + m_pip->value = INSET_OFF; + + // draw small border around inset view, adjust upper black bar + gViewPort->m_pSpectatorPanel->EnableInsetView( m_pip->value != INSET_OFF ); +} + +int CHudSpectator::ToggleInset(bool allowOff) +{ + int newInsetMode = (int)m_pip->value + 1; + + if ( g_iUser1 < OBS_MAP_FREE ) + { + if ( newInsetMode > INSET_MAP_CHASE ) + { + if (allowOff) + newInsetMode = INSET_OFF; + else + newInsetMode = INSET_MAP_FREE; + } + + if ( newInsetMode == INSET_CHASE_FREE ) + newInsetMode = INSET_MAP_FREE; + } + else + { + if ( newInsetMode > INSET_IN_EYE ) + { + if (allowOff) + newInsetMode = INSET_OFF; + else + newInsetMode = INSET_CHASE_FREE; + } + } + + return newInsetMode; +} +void CHudSpectator::Reset() +{ + // Reset HUD + if ( strcmp( m_OverviewData.map, gEngfuncs.pfnGetLevelName() ) ) + { + // update level overview if level changed + ParseOverviewFile(); + LoadMapSprites(); + } + + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + + SetSpectatorStartPosition(); +} + +void CHudSpectator::InitHUDData() +{ + m_lastPrimaryObject = m_lastSecondaryObject = 0; + m_flNextObserverInput = 0.0f; + m_lastHudMessage = 0; + m_iSpectatorNumber = 0; + iJumpSpectator = 0; + g_iUser1 = g_iUser2 = 0; + + memset( &m_OverviewData, 0, sizeof(m_OverviewData)); + memset( &m_OverviewEntities, 0, sizeof(m_OverviewEntities)); + + if ( gEngfuncs.IsSpectateOnly() || gEngfuncs.pDemoAPI->IsPlayingback() ) + m_autoDirector->value = 1.0f; + else + m_autoDirector->value = 0.0f; + + Reset(); + + SetModes( OBS_CHASE_FREE, INSET_OFF ); + + g_iUser2 = 0; // fake not target until first camera command + + // reset HUD FOV + gHUD.m_iFOV = CVAR_GET_FLOAT("default_fov"); +} + diff --git a/cl_dll/hud_spectator.h b/cl_dll/hud_spectator.h new file mode 100644 index 00000000..7f1a3610 --- /dev/null +++ b/cl_dll/hud_spectator.h @@ -0,0 +1,132 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef SPECTATOR_H +#define SPECTATOR_H +#pragma once + +#include "cl_entity.h" + + + +#define INSET_OFF 0 +#define INSET_CHASE_FREE 1 +#define INSET_IN_EYE 2 +#define INSET_MAP_FREE 3 +#define INSET_MAP_CHASE 4 + +#define MAX_SPEC_HUD_MESSAGES 8 + + + +#define OVERVIEW_TILE_SIZE 128 // don't change this +#define OVERVIEW_MAX_LAYERS 1 + +//----------------------------------------------------------------------------- +// Purpose: Handles the drawing of the spectator stuff (camera & top-down map and all the things on it ) +//----------------------------------------------------------------------------- + +typedef struct overviewInfo_s { + char map[64]; // cl.levelname or empty + vec3_t origin; // center of map + float zoom; // zoom of map images + int layers; // how may layers do we have + float layersHeights[OVERVIEW_MAX_LAYERS]; + char layersImages[OVERVIEW_MAX_LAYERS][255]; + qboolean rotated; // are map images rotated (90 degrees) ? + + int insetWindowX; + int insetWindowY; + int insetWindowHeight; + int insetWindowWidth; +} overviewInfo_t; + +typedef struct overviewEntity_s { + + HSPRITE hSprite; + struct cl_entity_s * entity; + double killTime; +} overviewEntity_t; + +#define MAX_OVERVIEW_ENTITIES 128 + +class CHudSpectator : public CHudBase +{ +public: + void Reset(); + int ToggleInset(bool allowOff); + void CheckSettings(); + void InitHUDData( void ); + bool AddOverviewEntityToList( HSPRITE sprite, cl_entity_t * ent, double killTime); + void DeathMessage(int victim); + bool AddOverviewEntity( int type, struct cl_entity_s *ent, const char *modelname ); + void CheckOverviewEntities(); + void DrawOverview(); + void DrawOverviewEntities(); + void GetMapPosition( float * returnvec ); + void DrawOverviewLayer(); + void LoadMapSprites(); + bool ParseOverviewFile(); + bool IsActivePlayer(cl_entity_t * ent); + void SetModes(int iMainMode, int iInsetMode); + void HandleButtonsDown(int ButtonPressed); + void HandleButtonsUp(int ButtonPressed); + void FindNextPlayer( bool bReverse ); + void DirectorMessage( int iSize, void *pbuf ); + void SetSpectatorStartPosition(); + int Init(); + int VidInit(); + + int Draw(float flTime); + + int m_iDrawCycle; + client_textmessage_t m_HUDMessages[MAX_SPEC_HUD_MESSAGES]; + char m_HUDMessageText[MAX_SPEC_HUD_MESSAGES][128]; + int m_lastHudMessage; + overviewInfo_t m_OverviewData; + overviewEntity_t m_OverviewEntities[MAX_OVERVIEW_ENTITIES]; + int m_iObserverFlags; + int m_iSpectatorNumber; + + float m_mapZoom; // zoom the user currently uses + vec3_t m_mapOrigin; // origin where user rotates around + cvar_t * m_drawnames; + cvar_t * m_drawcone; + cvar_t * m_drawstatus; + cvar_t * m_autoDirector; + cvar_t * m_pip; + + + qboolean m_chatEnabled; + + vec3_t m_cameraOrigin; // a help camera + vec3_t m_cameraAngles; // and it's angles + + +private: + vec3_t m_vPlayerPos[MAX_PLAYERS]; + HSPRITE m_hsprPlayerBlue; + HSPRITE m_hsprPlayerRed; + HSPRITE m_hsprPlayer; + HSPRITE m_hsprCamera; + HSPRITE m_hsprPlayerDead; + HSPRITE m_hsprViewcone; + HSPRITE m_hsprUnkownMap; + HSPRITE m_hsprBeam; + HSPRITE m_hCrosshair; + + wrect_t m_crosshairRect; + + struct model_s * m_MapSprite; // each layer image is saved in one sprite, where each tile is a sprite frame + float m_flNextObserverInput; + float m_zoomDelta; + float m_moveDelta; + int m_lastPrimaryObject; + int m_lastSecondaryObject; +}; + +#endif // SPECTATOR_H diff --git a/cl_dll/hud_update.cpp b/cl_dll/hud_update.cpp new file mode 100644 index 00000000..b3da6721 --- /dev/null +++ b/cl_dll/hud_update.cpp @@ -0,0 +1,54 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// hud_update.cpp +// + +#include +#include "hud.h" +#include "cl_util.h" +#include +#include + +int CL_ButtonBits( int ); +void CL_ResetButtonBits( int bits ); + +extern float v_idlescale; +float in_fov; +extern void HUD_SetCmdBits( int bits ); + +int CHud::UpdateClientData(client_data_t *cdata, float time) +{ + memcpy(m_vecOrigin, cdata->origin, sizeof(vec3_t)); + memcpy(m_vecAngles, cdata->viewangles, sizeof(vec3_t)); + + m_iKeyBits = CL_ButtonBits( 0 ); + m_iWeaponBits = cdata->iWeaponBits; + + in_fov = cdata->fov; + + Think(); + + cdata->fov = m_iFOV; + + v_idlescale = m_iConcussionEffect; + + CL_ResetButtonBits( m_iKeyBits ); + + // return 1 if in anything in the client_data struct has been changed, 0 otherwise + return 1; +} + + diff --git a/cl_dll/in_camera.cpp b/cl_dll/in_camera.cpp new file mode 100644 index 00000000..96dbdc7c --- /dev/null +++ b/cl_dll/in_camera.cpp @@ -0,0 +1,621 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" + +#include "windows.h" + +float CL_KeyState (kbutton_t *key); + +extern "C" +{ + void DLLEXPORT CAM_Think( void ); + int DLLEXPORT CL_IsThirdPerson( void ); + void DLLEXPORT CL_CameraOffset( float *ofs ); +} + +extern cl_enginefunc_t gEngfuncs; + +//-------------------------------------------------- Constants + +#define CAM_DIST_DELTA 1.0 +#define CAM_ANGLE_DELTA 2.5 +#define CAM_ANGLE_SPEED 2.5 +#define CAM_MIN_DIST 30.0 +#define CAM_ANGLE_MOVE .5 +#define MAX_ANGLE_DIFF 10.0 +#define PITCH_MAX 90.0 +#define PITCH_MIN 0 +#define YAW_MAX 135.0 +#define YAW_MIN -135.0 + +enum ECAM_Command +{ + CAM_COMMAND_NONE = 0, + CAM_COMMAND_TOTHIRDPERSON = 1, + CAM_COMMAND_TOFIRSTPERSON = 2 +}; + +//-------------------------------------------------- Global Variables + +cvar_t *cam_command; +cvar_t *cam_snapto; +cvar_t *cam_idealyaw; +cvar_t *cam_idealpitch; +cvar_t *cam_idealdist; +cvar_t *cam_contain; + +cvar_t *c_maxpitch; +cvar_t *c_minpitch; +cvar_t *c_maxyaw; +cvar_t *c_minyaw; +cvar_t *c_maxdistance; +cvar_t *c_mindistance; + +// pitch, yaw, dist +vec3_t cam_ofs; + + +// In third person +int cam_thirdperson; +int cam_mousemove; //true if we are moving the cam with the mouse, False if not +int iMouseInUse=0; +int cam_distancemove; +extern int mouse_x, mouse_y; //used to determine what the current x and y values are +int cam_old_mouse_x, cam_old_mouse_y; //holds the last ticks mouse movement +POINT cam_mouse; +//-------------------------------------------------- Local Variables + +static kbutton_t cam_pitchup, cam_pitchdown, cam_yawleft, cam_yawright; +static kbutton_t cam_in, cam_out, cam_move; + +//-------------------------------------------------- Prototypes + +void CAM_ToThirdPerson(void); +void CAM_ToFirstPerson(void); +void CAM_StartDistance(void); +void CAM_EndDistance(void); + + +//-------------------------------------------------- Local Functions + +float MoveToward( float cur, float goal, float maxspeed ) +{ + if( cur != goal ) + { + if( abs( cur - goal ) > 180.0 ) + { + if( cur < goal ) + cur += 360.0; + else + cur -= 360.0; + } + + if( cur < goal ) + { + if( cur < goal - 1.0 ) + cur += ( goal - cur ) / 4.0; + else + cur = goal; + } + else + { + if( cur > goal + 1.0 ) + cur -= ( cur - goal ) / 4.0; + else + cur = goal; + } + } + + + // bring cur back into range + if( cur < 0 ) + cur += 360.0; + else if( cur >= 360 ) + cur -= 360; + + return cur; +} + + +//-------------------------------------------------- Gobal Functions + +typedef struct +{ + vec3_t boxmins, boxmaxs;// enclose the test object along entire move + float *mins, *maxs; // size of the moving object + vec3_t mins2, maxs2; // size when clipping against mosnters + float *start, *end; + trace_t trace; + int type; + edict_t *passedict; + qboolean monsterclip; +} moveclip_t; + +extern trace_t SV_ClipMoveToEntity (edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end); + +void DLLEXPORT CAM_Think( void ) +{ + vec3_t origin; + vec3_t ext, pnt, camForward, camRight, camUp; + moveclip_t clip; + float dist; + vec3_t camAngles; + float flSensitivity; +#ifdef LATER + int i; +#endif + vec3_t viewangles; + + switch( (int) cam_command->value ) + { + case CAM_COMMAND_TOTHIRDPERSON: + CAM_ToThirdPerson(); + break; + + case CAM_COMMAND_TOFIRSTPERSON: + CAM_ToFirstPerson(); + break; + + case CAM_COMMAND_NONE: + default: + break; + } + + if( !cam_thirdperson ) + return; + +#ifdef LATER + if ( cam_contain->value ) + { + gEngfuncs.GetClientOrigin( origin ); + ext[0] = ext[1] = ext[2] = 0.0; + } +#endif + + camAngles[ PITCH ] = cam_idealpitch->value; + camAngles[ YAW ] = cam_idealyaw->value; + dist = cam_idealdist->value; + // + //movement of the camera with the mouse + // + if (cam_mousemove) + { + //get windows cursor position + GetCursorPos (&cam_mouse); + //check for X delta values and adjust accordingly + //eventually adjust YAW based on amount of movement + //don't do any movement of the cam using YAW/PITCH if we are zooming in/out the camera + if (!cam_distancemove) + { + + //keep the camera within certain limits around the player (ie avoid certain bad viewing angles) + if (cam_mouse.x>gEngfuncs.GetWindowCenterX()) + { + //if ((camAngles[YAW]>=225.0)||(camAngles[YAW]<135.0)) + if (camAngles[YAW]value) + { + camAngles[ YAW ] += (CAM_ANGLE_MOVE)*((cam_mouse.x-gEngfuncs.GetWindowCenterX())/2); + } + if (camAngles[YAW]>c_maxyaw->value) + { + + camAngles[YAW]=c_maxyaw->value; + } + } + else if (cam_mouse.x225.0)) + if (camAngles[YAW]>c_minyaw->value) + { + camAngles[ YAW ] -= (CAM_ANGLE_MOVE)* ((gEngfuncs.GetWindowCenterX()-cam_mouse.x)/2); + + } + if (camAngles[YAW]value) + { + camAngles[YAW]=c_minyaw->value; + + } + } + + //check for y delta values and adjust accordingly + //eventually adjust PITCH based on amount of movement + //also make sure camera is within bounds + if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + { + if(camAngles[PITCH]value) + { + camAngles[PITCH] +=(CAM_ANGLE_MOVE)* ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + } + if (camAngles[PITCH]>c_maxpitch->value) + { + camAngles[PITCH]=c_maxpitch->value; + } + } + else if (cam_mouse.yc_minpitch->value) + { + camAngles[PITCH] -= (CAM_ANGLE_MOVE)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + } + if (camAngles[PITCH]value) + { + camAngles[PITCH]=c_minpitch->value; + } + } + + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + + if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x=cam_mouse.x*flSensitivity; + cam_old_mouse_y=cam_mouse.y*flSensitivity; + } + else + { + cam_old_mouse_x=cam_mouse.x; + cam_old_mouse_y=cam_mouse.y; + } + SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } + } + + //Nathan code here + if( CL_KeyState( &cam_pitchup ) ) + camAngles[ PITCH ] += CAM_ANGLE_DELTA; + else if( CL_KeyState( &cam_pitchdown ) ) + camAngles[ PITCH ] -= CAM_ANGLE_DELTA; + + if( CL_KeyState( &cam_yawleft ) ) + camAngles[ YAW ] -= CAM_ANGLE_DELTA; + else if( CL_KeyState( &cam_yawright ) ) + camAngles[ YAW ] += CAM_ANGLE_DELTA; + + if( CL_KeyState( &cam_in ) ) + { + dist -= CAM_DIST_DELTA; + if( dist < CAM_MIN_DIST ) + { + // If we go back into first person, reset the angle + camAngles[ PITCH ] = 0; + camAngles[ YAW ] = 0; + dist = CAM_MIN_DIST; + } + + } + else if( CL_KeyState( &cam_out ) ) + dist += CAM_DIST_DELTA; + + if (cam_distancemove) + { + if (cam_mouse.y>gEngfuncs.GetWindowCenterY()) + { + if(distvalue) + { + dist +=CAM_DIST_DELTA * ((cam_mouse.y-gEngfuncs.GetWindowCenterY())/2); + } + if (dist>c_maxdistance->value) + { + dist=c_maxdistance->value; + } + } + else if (cam_mouse.yc_mindistance->value) + { + dist -= (CAM_DIST_DELTA)*((gEngfuncs.GetWindowCenterY()-cam_mouse.y)/2); + } + if (distvalue) + { + dist=c_mindistance->value; + } + } + //set old mouse coordinates to current mouse coordinates + //since we are done with the mouse + cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); + cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); + SetCursorPos (gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY()); + } +#ifdef LATER + if( cam_contain->value ) + { + // check new ideal + VectorCopy( origin, pnt ); + AngleVectors( camAngles, camForward, camRight, camUp ); + for (i=0 ; i<3 ; i++) + pnt[i] += -dist*camForward[i]; + + // check line from r_refdef.vieworg to pnt + memset ( &clip, 0, sizeof ( moveclip_t ) ); + clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); + if( clip.trace.fraction == 1.0 ) + { + // update ideal + cam_idealpitch->value = camAngles[ PITCH ]; + cam_idealyaw->value = camAngles[ YAW ]; + cam_idealdist->value = dist; + } + } + else +#endif + { + // update ideal + cam_idealpitch->value = camAngles[ PITCH ]; + cam_idealyaw->value = camAngles[ YAW ]; + cam_idealdist->value = dist; + } + + // Move towards ideal + VectorCopy( cam_ofs, camAngles ); + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if( cam_snapto->value ) + { + camAngles[ YAW ] = cam_idealyaw->value + viewangles[ YAW ]; + camAngles[ PITCH ] = cam_idealpitch->value + viewangles[ PITCH ]; + camAngles[ 2 ] = cam_idealdist->value; + } + else + { + if( camAngles[ YAW ] - viewangles[ YAW ] != cam_idealyaw->value ) + camAngles[ YAW ] = MoveToward( camAngles[ YAW ], cam_idealyaw->value + viewangles[ YAW ], CAM_ANGLE_SPEED ); + + if( camAngles[ PITCH ] - viewangles[ PITCH ] != cam_idealpitch->value ) + camAngles[ PITCH ] = MoveToward( camAngles[ PITCH ], cam_idealpitch->value + viewangles[ PITCH ], CAM_ANGLE_SPEED ); + + if( abs( camAngles[ 2 ] - cam_idealdist->value ) < 2.0 ) + camAngles[ 2 ] = cam_idealdist->value; + else + camAngles[ 2 ] += ( cam_idealdist->value - camAngles[ 2 ] ) / 4.0; + } +#ifdef LATER + if( cam_contain->value ) + { + // Test new position + dist = camAngles[ ROLL ]; + camAngles[ ROLL ] = 0; + + VectorCopy( origin, pnt ); + AngleVectors( camAngles, camForward, camRight, camUp ); + for (i=0 ; i<3 ; i++) + pnt[i] += -dist*camForward[i]; + + // check line from r_refdef.vieworg to pnt + memset ( &clip, 0, sizeof ( moveclip_t ) ); + ext[0] = ext[1] = ext[2] = 0.0; + clip.trace = SV_ClipMoveToEntity( sv.edicts, r_refdef.vieworg, ext, ext, pnt ); + if( clip.trace.fraction != 1.0 ) + return; + } +#endif + cam_ofs[ 0 ] = camAngles[ 0 ]; + cam_ofs[ 1 ] = camAngles[ 1 ]; + cam_ofs[ 2 ] = dist; +} + +extern void KeyDown (kbutton_t *b); // HACK +extern void KeyUp (kbutton_t *b); // HACK + +void CAM_PitchUpDown(void) { KeyDown( &cam_pitchup ); } +void CAM_PitchUpUp(void) { KeyUp( &cam_pitchup ); } +void CAM_PitchDownDown(void) { KeyDown( &cam_pitchdown ); } +void CAM_PitchDownUp(void) { KeyUp( &cam_pitchdown ); } +void CAM_YawLeftDown(void) { KeyDown( &cam_yawleft ); } +void CAM_YawLeftUp(void) { KeyUp( &cam_yawleft ); } +void CAM_YawRightDown(void) { KeyDown( &cam_yawright ); } +void CAM_YawRightUp(void) { KeyUp( &cam_yawright ); } +void CAM_InDown(void) { KeyDown( &cam_in ); } +void CAM_InUp(void) { KeyUp( &cam_in ); } +void CAM_OutDown(void) { KeyDown( &cam_out ); } +void CAM_OutUp(void) { KeyUp( &cam_out ); } + +void CAM_ToThirdPerson(void) +{ + vec3_t viewangles; + +#if !defined( _DEBUG ) + if ( gEngfuncs.GetMaxClients() > 1 ) + { + // no thirdperson in multiplayer. + return; + } +#endif + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + if( !cam_thirdperson ) + { + cam_thirdperson = 1; + + cam_ofs[ YAW ] = viewangles[ YAW ]; + cam_ofs[ PITCH ] = viewangles[ PITCH ]; + cam_ofs[ 2 ] = CAM_MIN_DIST; + } + + gEngfuncs.Cvar_SetValue( "cam_command", 0 ); +} + +void CAM_ToFirstPerson(void) +{ + cam_thirdperson = 0; + + gEngfuncs.Cvar_SetValue( "cam_command", 0 ); +} + +void CAM_ToggleSnapto( void ) +{ + cam_snapto->value = !cam_snapto->value; +} + +void CAM_Init( void ) +{ + gEngfuncs.pfnAddCommand( "+campitchup", CAM_PitchUpDown ); + gEngfuncs.pfnAddCommand( "-campitchup", CAM_PitchUpUp ); + gEngfuncs.pfnAddCommand( "+campitchdown", CAM_PitchDownDown ); + gEngfuncs.pfnAddCommand( "-campitchdown", CAM_PitchDownUp ); + gEngfuncs.pfnAddCommand( "+camyawleft", CAM_YawLeftDown ); + gEngfuncs.pfnAddCommand( "-camyawleft", CAM_YawLeftUp ); + gEngfuncs.pfnAddCommand( "+camyawright", CAM_YawRightDown ); + gEngfuncs.pfnAddCommand( "-camyawright", CAM_YawRightUp ); + gEngfuncs.pfnAddCommand( "+camin", CAM_InDown ); + gEngfuncs.pfnAddCommand( "-camin", CAM_InUp ); + gEngfuncs.pfnAddCommand( "+camout", CAM_OutDown ); + gEngfuncs.pfnAddCommand( "-camout", CAM_OutUp ); + gEngfuncs.pfnAddCommand( "thirdperson", CAM_ToThirdPerson ); + gEngfuncs.pfnAddCommand( "firstperson", CAM_ToFirstPerson ); + gEngfuncs.pfnAddCommand( "+cammousemove",CAM_StartMouseMove); + gEngfuncs.pfnAddCommand( "-cammousemove",CAM_EndMouseMove); + gEngfuncs.pfnAddCommand( "+camdistance", CAM_StartDistance ); + gEngfuncs.pfnAddCommand( "-camdistance", CAM_EndDistance ); + gEngfuncs.pfnAddCommand( "snapto", CAM_ToggleSnapto ); + + cam_command = gEngfuncs.pfnRegisterVariable ( "cam_command", "0", 0 ); // tells camera to go to thirdperson + cam_snapto = gEngfuncs.pfnRegisterVariable ( "cam_snapto", "0", 0 ); // snap to thirdperson view + cam_idealyaw = gEngfuncs.pfnRegisterVariable ( "cam_idealyaw", "90", 0 ); // thirdperson yaw + cam_idealpitch = gEngfuncs.pfnRegisterVariable ( "cam_idealpitch", "0", 0 ); // thirperson pitch + cam_idealdist = gEngfuncs.pfnRegisterVariable ( "cam_idealdist", "64", 0 ); // thirdperson distance + cam_contain = gEngfuncs.pfnRegisterVariable ( "cam_contain", "0", 0 ); // contain camera to world + + c_maxpitch = gEngfuncs.pfnRegisterVariable ( "c_maxpitch", "90.0", 0 ); + c_minpitch = gEngfuncs.pfnRegisterVariable ( "c_minpitch", "0.0", 0 ); + c_maxyaw = gEngfuncs.pfnRegisterVariable ( "c_maxyaw", "135.0", 0 ); + c_minyaw = gEngfuncs.pfnRegisterVariable ( "c_minyaw", "-135.0", 0 ); + c_maxdistance = gEngfuncs.pfnRegisterVariable ( "c_maxdistance", "200.0", 0 ); + c_mindistance = gEngfuncs.pfnRegisterVariable ( "c_mindistance", "30.0", 0 ); +} + +void CAM_ClearStates( void ) +{ + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + cam_pitchup.state = 0; + cam_pitchdown.state = 0; + cam_yawleft.state = 0; + cam_yawright.state = 0; + cam_in.state = 0; + cam_out.state = 0; + + cam_thirdperson = 0; + cam_command->value = 0; + cam_mousemove=0; + + cam_snapto->value = 0; + cam_distancemove = 0; + + cam_ofs[ 0 ] = 0.0; + cam_ofs[ 1 ] = 0.0; + cam_ofs[ 2 ] = CAM_MIN_DIST; + + cam_idealpitch->value = viewangles[ PITCH ]; + cam_idealyaw->value = viewangles[ YAW ]; + cam_idealdist->value = CAM_MIN_DIST; +} + +void CAM_StartMouseMove(void) +{ + float flSensitivity; + + //only move the cam with mouse if we are in third person. + if (cam_thirdperson) + { + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if (!cam_mousemove) + { + cam_mousemove=1; + iMouseInUse=1; + GetCursorPos (&cam_mouse); + + if ( ( flSensitivity = gHUD.GetSensitivity() ) != 0 ) + { + cam_old_mouse_x=cam_mouse.x*flSensitivity; + cam_old_mouse_y=cam_mouse.y*flSensitivity; + } + else + { + cam_old_mouse_x=cam_mouse.x; + cam_old_mouse_y=cam_mouse.y; + } + } + } + //we are not in 3rd person view..therefore do not allow camera movement + else + { + cam_mousemove=0; + iMouseInUse=0; + } +} + +//the key has been released for camera movement +//tell the engine that mouse camera movement is off +void CAM_EndMouseMove(void) +{ + cam_mousemove=0; + iMouseInUse=0; +} + + +//---------------------------------------------------------- +//routines to start the process of moving the cam in or out +//using the mouse +//---------------------------------------------------------- +void CAM_StartDistance(void) +{ + //only move the cam with mouse if we are in third person. + if (cam_thirdperson) + { + //set appropriate flags and initialize the old mouse position + //variables for mouse camera movement + if (!cam_distancemove) + { + cam_distancemove=1; + cam_mousemove=1; + iMouseInUse=1; + GetCursorPos (&cam_mouse); + cam_old_mouse_x=cam_mouse.x*gHUD.GetSensitivity(); + cam_old_mouse_y=cam_mouse.y*gHUD.GetSensitivity(); + } + } + //we are not in 3rd person view..therefore do not allow camera movement + else + { + cam_distancemove=0; + cam_mousemove=0; + iMouseInUse=0; + } +} + +//the key has been released for camera movement +//tell the engine that mouse camera movement is off +void CAM_EndDistance(void) +{ + cam_distancemove=0; + cam_mousemove=0; + iMouseInUse=0; +} + +int DLLEXPORT CL_IsThirdPerson( void ) +{ + return (cam_thirdperson ? 1 : 0) || (g_iUser1 && (g_iUser2 == gEngfuncs.GetLocalPlayer()->index) ); +} + +void DLLEXPORT CL_CameraOffset( float *ofs ) +{ + VectorCopy( cam_ofs, ofs ); +} \ No newline at end of file diff --git a/cl_dll/in_defs.h b/cl_dll/in_defs.h new file mode 100644 index 00000000..f5591896 --- /dev/null +++ b/cl_dll/in_defs.h @@ -0,0 +1,21 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( IN_DEFSH ) +#define IN_DEFSH +#pragma once + +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 + +#define DLLEXPORT __declspec( dllexport ) + +#endif \ No newline at end of file diff --git a/cl_dll/input.cpp b/cl_dll/input.cpp new file mode 100644 index 00000000..d68a56d1 --- /dev/null +++ b/cl_dll/input.cpp @@ -0,0 +1,1028 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// cl.input.c -- builds an intended movement command to send to the server + +//xxxxxx Move bob and pitch drifting code here and other stuff from view if needed + +// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All +// rights reserved. +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +extern "C" +{ +#include "kbutton.h" +} +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "view.h" +#include +#include + +#include "vgui_TeamFortressViewport.h" + + +extern "C" +{ + struct kbutton_s DLLEXPORT *KB_Find( const char *name ); + void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ); + void DLLEXPORT HUD_Shutdown( void ); + int DLLEXPORT HUD_Key_Event( int eventcode, int keynum, const char *pszCurrentBinding ); +} + +extern int g_iAlive; + +extern int g_weaponselect; +extern cl_enginefunc_t gEngfuncs; + +// Defined in pm_math.c +extern "C" float anglemod( float a ); + +void IN_Init (void); +void IN_Move ( float frametime, usercmd_t *cmd); +void IN_Shutdown( void ); +void V_Init( void ); +void VectorAngles( const float *forward, float *angles ); +int CL_ButtonBits( int ); + +// xxx need client dll function to get and clear impuse +extern cvar_t *in_joystick; + +int in_impulse = 0; +int in_cancel = 0; + +cvar_t *m_pitch; +cvar_t *m_yaw; +cvar_t *m_forward; +cvar_t *m_side; + +cvar_t *lookstrafe; +cvar_t *lookspring; +cvar_t *cl_pitchup; +cvar_t *cl_pitchdown; +cvar_t *cl_upspeed; +cvar_t *cl_forwardspeed; +cvar_t *cl_backspeed; +cvar_t *cl_sidespeed; +cvar_t *cl_movespeedkey; +cvar_t *cl_yawspeed; +cvar_t *cl_pitchspeed; +cvar_t *cl_anglespeedkey; +cvar_t *cl_vsmoothing; +/* +=============================================================================== + +KEY BUTTONS + +Continuous button event tracking is complicated by the fact that two different +input sources (say, mouse button 1 and the control key) can both press the +same button, but the button should only be released when both of the +pressing key have been released. + +When a key event issues a button command (+forward, +attack, etc), it appends +its key number as a parameter to the command so it can be matched up with +the release. + +state bit 0 is the current state of the key +state bit 1 is edge triggered on the up to down transition +state bit 2 is edge triggered on the down to up transition + +=============================================================================== +*/ + + +kbutton_t in_mlook; +kbutton_t in_klook; +kbutton_t in_jlook; +kbutton_t in_left; +kbutton_t in_right; +kbutton_t in_forward; +kbutton_t in_back; +kbutton_t in_lookup; +kbutton_t in_lookdown; +kbutton_t in_moveleft; +kbutton_t in_moveright; +kbutton_t in_strafe; +kbutton_t in_speed; +kbutton_t in_use; +kbutton_t in_jump; +kbutton_t in_attack; +kbutton_t in_attack2; +kbutton_t in_up; +kbutton_t in_down; +kbutton_t in_duck; +kbutton_t in_reload; +kbutton_t in_alt1; +kbutton_t in_score; +kbutton_t in_break; +kbutton_t in_graph; // Display the netgraph + +typedef struct kblist_s +{ + struct kblist_s *next; + kbutton_t *pkey; + char name[32]; +} kblist_t; + +kblist_t *g_kbkeys = NULL; + +/* +============ +KB_ConvertString + +Removes references to +use and replaces them with the keyname in the output string. If + a binding is unfound, then the original text is retained. +NOTE: Only works for text with +word in it. +============ +*/ +int KB_ConvertString( char *in, char **ppout ) +{ + char sz[ 4096 ]; + char binding[ 64 ]; + char *p; + char *pOut; + char *pEnd; + const char *pBinding; + + if ( !ppout ) + return 0; + + *ppout = NULL; + p = in; + pOut = sz; + while ( *p ) + { + if ( *p == '+' ) + { + pEnd = binding; + while ( *p && ( isalnum( *p ) || ( pEnd == binding ) ) && ( ( pEnd - binding ) < 63 ) ) + { + *pEnd++ = *p++; + } + + *pEnd = '\0'; + + pBinding = NULL; + if ( strlen( binding + 1 ) > 0 ) + { + // See if there is a binding for binding? + pBinding = gEngfuncs.Key_LookupBinding( binding + 1 ); + } + + if ( pBinding ) + { + *pOut++ = '['; + pEnd = (char *)pBinding; + } + else + { + pEnd = binding; + } + + while ( *pEnd ) + { + *pOut++ = *pEnd++; + } + + if ( pBinding ) + { + *pOut++ = ']'; + } + } + else + { + *pOut++ = *p++; + } + } + + *pOut = '\0'; + + pOut = ( char * )malloc( strlen( sz ) + 1 ); + strcpy( pOut, sz ); + *ppout = pOut; + + return 1; +} + +/* +============ +KB_Find + +Allows the engine to get a kbutton_t directly ( so it can check +mlook state, etc ) for saving out to .cfg files +============ +*/ +struct kbutton_s DLLEXPORT *KB_Find( const char *name ) +{ + kblist_t *p; + p = g_kbkeys; + while ( p ) + { + if ( !stricmp( name, p->name ) ) + return p->pkey; + + p = p->next; + } + return NULL; +} + +/* +============ +KB_Add + +Add a kbutton_t * to the list of pointers the engine can retrieve via KB_Find +============ +*/ +void KB_Add( const char *name, kbutton_t *pkb ) +{ + kblist_t *p; + kbutton_t *kb; + + kb = KB_Find( name ); + + if ( kb ) + return; + + p = ( kblist_t * )malloc( sizeof( kblist_t ) ); + memset( p, 0, sizeof( *p ) ); + + strcpy( p->name, name ); + p->pkey = pkb; + + p->next = g_kbkeys; + g_kbkeys = p; +} + +/* +============ +KB_Init + +Add kbutton_t definitions that the engine can query if needed +============ +*/ +void KB_Init( void ) +{ + g_kbkeys = NULL; + + KB_Add( "in_graph", &in_graph ); + KB_Add( "in_mlook", &in_mlook ); + KB_Add( "in_jlook", &in_jlook ); +} + +/* +============ +KB_Shutdown + +Clear kblist +============ +*/ +void KB_Shutdown( void ) +{ + kblist_t *p, *n; + p = g_kbkeys; + while ( p ) + { + n = p->next; + free( p ); + p = n; + } + g_kbkeys = NULL; +} + +/* +============ +KeyDown +============ +*/ +void KeyDown (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + k = -1; // typed manually at the console for continuous down + + if (k == b->down[0] || k == b->down[1]) + return; // repeating key + + if (!b->down[0]) + b->down[0] = k; + else if (!b->down[1]) + b->down[1] = k; + else + { + gEngfuncs.Con_DPrintf ("Three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c); + return; + } + + if (b->state & 1) + return; // still down + b->state |= 1 + 2; // down + impulse down +} + +/* +============ +KeyUp +============ +*/ +void KeyUp (kbutton_t *b) +{ + int k; + char *c; + + c = gEngfuncs.Cmd_Argv(1); + if (c[0]) + k = atoi(c); + else + { // typed manually at the console, assume for unsticking, so clear all + b->down[0] = b->down[1] = 0; + b->state = 4; // impulse up + return; + } + + if (b->down[0] == k) + b->down[0] = 0; + else if (b->down[1] == k) + b->down[1] = 0; + else + return; // key up without coresponding down (menu pass through) + if (b->down[0] || b->down[1]) + { + //Con_Printf ("Keys down for button: '%c' '%c' '%c' (%d,%d,%d)!\n", b->down[0], b->down[1], c, b->down[0], b->down[1], c); + return; // some other key is still holding it down + } + + if (!(b->state & 1)) + return; // still up (this should not happen) + + b->state &= ~1; // now up + b->state |= 4; // impulse up +} + +/* +============ +HUD_Key_Event + +Return 1 to allow engine to process the key, otherwise, act on it as needed +============ +*/ +int DLLEXPORT HUD_Key_Event( int down, int keynum, const char *pszCurrentBinding ) +{ + if (gViewPort) + return gViewPort->KeyInput(down, keynum, pszCurrentBinding); + + return 1; +} + +void IN_BreakDown( void ) { KeyDown( &in_break );}; +void IN_BreakUp( void ) { KeyUp( &in_break ); }; +void IN_KLookDown (void) {KeyDown(&in_klook);} +void IN_KLookUp (void) {KeyUp(&in_klook);} +void IN_JLookDown (void) {KeyDown(&in_jlook);} +void IN_JLookUp (void) {KeyUp(&in_jlook);} +void IN_MLookDown (void) {KeyDown(&in_mlook);} +void IN_UpDown(void) {KeyDown(&in_up);} +void IN_UpUp(void) {KeyUp(&in_up);} +void IN_DownDown(void) {KeyDown(&in_down);} +void IN_DownUp(void) {KeyUp(&in_down);} +void IN_LeftDown(void) {KeyDown(&in_left);} +void IN_LeftUp(void) {KeyUp(&in_left);} +void IN_RightDown(void) {KeyDown(&in_right);} +void IN_RightUp(void) {KeyUp(&in_right);} + +void IN_ForwardDown(void) +{ + KeyDown(&in_forward); + gHUD.m_Spectator.HandleButtonsDown( IN_FORWARD ); +} + +void IN_ForwardUp(void) +{ + KeyUp(&in_forward); + gHUD.m_Spectator.HandleButtonsUp( IN_FORWARD ); +} + +void IN_BackDown(void) +{ + KeyDown(&in_back); + gHUD.m_Spectator.HandleButtonsDown( IN_BACK ); +} + +void IN_BackUp(void) +{ + KeyUp(&in_back); + gHUD.m_Spectator.HandleButtonsUp( IN_BACK ); +} +void IN_LookupDown(void) {KeyDown(&in_lookup);} +void IN_LookupUp(void) {KeyUp(&in_lookup);} +void IN_LookdownDown(void) {KeyDown(&in_lookdown);} +void IN_LookdownUp(void) {KeyUp(&in_lookdown);} +void IN_MoveleftDown(void) +{ + KeyDown(&in_moveleft); + gHUD.m_Spectator.HandleButtonsDown( IN_MOVELEFT ); +} + +void IN_MoveleftUp(void) +{ + KeyUp(&in_moveleft); + gHUD.m_Spectator.HandleButtonsUp( IN_MOVELEFT ); +} + +void IN_MoverightDown(void) +{ + KeyDown(&in_moveright); + gHUD.m_Spectator.HandleButtonsDown( IN_MOVERIGHT ); +} + +void IN_MoverightUp(void) +{ + KeyUp(&in_moveright); + gHUD.m_Spectator.HandleButtonsUp( IN_MOVERIGHT ); +} +void IN_SpeedDown(void) {KeyDown(&in_speed);} +void IN_SpeedUp(void) {KeyUp(&in_speed);} +void IN_StrafeDown(void) {KeyDown(&in_strafe);} +void IN_StrafeUp(void) {KeyUp(&in_strafe);} + +// needs capture by hud/vgui also +extern void __CmdFunc_InputPlayerSpecial(void); + +void IN_Attack2Down(void) +{ + KeyDown(&in_attack2); + + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK2 ); +} + +void IN_Attack2Up(void) {KeyUp(&in_attack2);} +void IN_UseDown (void) +{ + KeyDown(&in_use); + gHUD.m_Spectator.HandleButtonsDown( IN_USE ); +} +void IN_UseUp (void) {KeyUp(&in_use);} +void IN_JumpDown (void) +{ + KeyDown(&in_jump); + gHUD.m_Spectator.HandleButtonsDown( IN_JUMP ); + +} +void IN_JumpUp (void) {KeyUp(&in_jump);} +void IN_DuckDown(void) +{ + KeyDown(&in_duck); + gHUD.m_Spectator.HandleButtonsDown( IN_DUCK ); + +} +void IN_DuckUp(void) {KeyUp(&in_duck);} +void IN_ReloadDown(void) {KeyDown(&in_reload);} +void IN_ReloadUp(void) {KeyUp(&in_reload);} +void IN_Alt1Down(void) {KeyDown(&in_alt1);} +void IN_Alt1Up(void) {KeyUp(&in_alt1);} +void IN_GraphDown(void) {KeyDown(&in_graph);} +void IN_GraphUp(void) {KeyUp(&in_graph);} + +void IN_AttackDown(void) +{ + KeyDown( &in_attack ); + gHUD.m_Spectator.HandleButtonsDown( IN_ATTACK ); +} + +void IN_AttackUp(void) +{ + KeyUp( &in_attack ); + in_cancel = 0; +} + +// Special handling +void IN_Cancel(void) +{ + in_cancel = 1; +} + +void IN_Impulse (void) +{ + in_impulse = atoi( gEngfuncs.Cmd_Argv(1) ); +} + +void IN_ScoreDown(void) +{ + KeyDown(&in_score); + if ( gViewPort ) + { + gViewPort->ShowScoreBoard(); + } +} + +void IN_ScoreUp(void) +{ + KeyUp(&in_score); + if ( gViewPort ) + { + gViewPort->HideScoreBoard(); + } +} + +void IN_MLookUp (void) +{ + KeyUp( &in_mlook ); + if ( !( in_mlook.state & 1 ) && lookspring->value ) + { + V_StartPitchDrift(); + } +} + +/* +=============== +CL_KeyState + +Returns 0.25 if a key was pressed and released during the frame, +0.5 if it was pressed and held +0 if held then released, and +1.0 if held for the entire time +=============== +*/ +float CL_KeyState (kbutton_t *key) +{ + float val = 0.0; + int impulsedown, impulseup, down; + + impulsedown = key->state & 2; + impulseup = key->state & 4; + down = key->state & 1; + + if ( impulsedown && !impulseup ) + { + // pressed and held this frame? + val = down ? 0.5 : 0.0; + } + + if ( impulseup && !impulsedown ) + { + // released this frame? + val = down ? 0.0 : 0.0; + } + + if ( !impulsedown && !impulseup ) + { + // held the entire frame? + val = down ? 1.0 : 0.0; + } + + if ( impulsedown && impulseup ) + { + if ( down ) + { + // released and re-pressed this frame + val = 0.75; + } + else + { + // pressed and released this frame + val = 0.25; + } + } + + // clear impulses + key->state &= 1; + return val; +} + +/* +================ +CL_AdjustAngles + +Moves the local angle positions +================ +*/ +void CL_AdjustAngles ( float frametime, float *viewangles ) +{ + float speed; + float up, down; + + if (in_speed.state & 1) + { + speed = frametime * cl_anglespeedkey->value; + } + else + { + speed = frametime; + } + + if (!(in_strafe.state & 1)) + { + viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); + viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); + viewangles[YAW] = anglemod(viewangles[YAW]); + } + if (in_klook.state & 1) + { + V_StopPitchDrift (); + viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); + viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); + } + + up = CL_KeyState (&in_lookup); + down = CL_KeyState(&in_lookdown); + + viewangles[PITCH] -= speed*cl_pitchspeed->value * up; + viewangles[PITCH] += speed*cl_pitchspeed->value * down; + + if (up || down) + V_StopPitchDrift (); + + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + if (viewangles[ROLL] > 50) + viewangles[ROLL] = 50; + if (viewangles[ROLL] < -50) + viewangles[ROLL] = -50; +} + +/* +================ +CL_CreateMove + +Send the intended movement message to the server +if active == 1 then we are 1) not playing back demos ( where our commands are ignored ) and +2 ) we have finished signing on to server +================ +*/ +void DLLEXPORT CL_CreateMove ( float frametime, struct usercmd_s *cmd, int active ) +{ + float spd; + vec3_t viewangles; + static vec3_t oldangles; + + if ( active ) + { + //memset( viewangles, 0, sizeof( vec3_t ) ); + //viewangles[ 0 ] = viewangles[ 1 ] = viewangles[ 2 ] = 0.0; + gEngfuncs.GetViewAngles( (float *)viewangles ); + + CL_AdjustAngles ( frametime, viewangles ); + + memset (cmd, 0, sizeof(*cmd)); + + gEngfuncs.SetViewAngles( (float *)viewangles ); + + if ( in_strafe.state & 1 ) + { + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); + } + + cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); + cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); + + cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); + cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); + + if ( !(in_klook.state & 1 ) ) + { + cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); + cmd->forwardmove -= cl_backspeed->value * CL_KeyState (&in_back); + } + + // adjust for speed key + if ( in_speed.state & 1 ) + { + cmd->forwardmove *= cl_movespeedkey->value; + cmd->sidemove *= cl_movespeedkey->value; + cmd->upmove *= cl_movespeedkey->value; + } + + // clip to maxspeed + spd = gEngfuncs.GetClientMaxspeed(); + if ( spd != 0.0 ) + { + // scale the 3 speeds so that the total velocity is not > cl.maxspeed + float fmov = sqrt( (cmd->forwardmove*cmd->forwardmove) + (cmd->sidemove*cmd->sidemove) + (cmd->upmove*cmd->upmove) ); + + if ( fmov > spd ) + { + float fratio = spd / fmov; + cmd->forwardmove *= fratio; + cmd->sidemove *= fratio; + cmd->upmove *= fratio; + } + } + + // Allow mice and other controllers to add their inputs + IN_Move ( frametime, cmd ); + } + + cmd->impulse = in_impulse; + in_impulse = 0; + + cmd->weaponselect = g_weaponselect; + g_weaponselect = 0; + // + // set button and flag bits + // + cmd->buttons = CL_ButtonBits( 1 ); + + // If they're in a modal dialog, ignore the attack button. + if( gViewPort && GetClientVoiceMgr()->IsInSquelchMode()) + cmd->buttons &= ~IN_ATTACK; + + // Using joystick? + if ( in_joystick->value ) + { + if ( cmd->forwardmove > 0 ) + { + cmd->buttons |= IN_FORWARD; + } + else if ( cmd->forwardmove < 0 ) + { + cmd->buttons |= IN_BACK; + } + } + + gEngfuncs.GetViewAngles( (float *)viewangles ); + // Set current view angles. + + if ( g_iAlive ) + { + VectorCopy( viewangles, cmd->viewangles ); + VectorCopy( viewangles, oldangles ); + } + else + { + VectorCopy( oldangles, cmd->viewangles ); + } + +} + +/* +============ +CL_IsDead + +Returns 1 if health is <= 0 +============ +*/ +int CL_IsDead( void ) +{ + return ( gHUD.m_Health.m_iHealth <= 0 ) ? 1 : 0; +} + +/* +============ +CL_ButtonBits + +Returns appropriate button info for keyboard and mouse state +Set bResetState to 1 to clear old state info +============ +*/ +int CL_ButtonBits( int bResetState ) +{ + int bits = 0; + + if ( in_attack.state & 3 ) + { + bits |= IN_ATTACK; + } + + if (in_duck.state & 3) + { + bits |= IN_DUCK; + } + + if (in_jump.state & 3) + { + bits |= IN_JUMP; + } + + if ( in_forward.state & 3 ) + { + bits |= IN_FORWARD; + } + + if (in_back.state & 3) + { + bits |= IN_BACK; + } + + if (in_use.state & 3) + { + bits |= IN_USE; + } + + if (in_cancel) + { + bits |= IN_CANCEL; + } + + if ( in_left.state & 3 ) + { + bits |= IN_LEFT; + } + + if (in_right.state & 3) + { + bits |= IN_RIGHT; + } + + if ( in_moveleft.state & 3 ) + { + bits |= IN_MOVELEFT; + } + + if (in_moveright.state & 3) + { + bits |= IN_MOVERIGHT; + } + + if (in_attack2.state & 3) + { + bits |= IN_ATTACK2; + } + + if (in_reload.state & 3) + { + bits |= IN_RELOAD; + } + + if (in_alt1.state & 3) + { + bits |= IN_ALT1; + } + + if ( in_score.state & 3 ) + { + bits |= IN_SCORE; + } + + // Dead or in intermission? Shore scoreboard, too + if ( CL_IsDead() || gHUD.m_iIntermission ) + { + bits |= IN_SCORE; + } + + if ( bResetState ) + { + in_attack.state &= ~2; + in_duck.state &= ~2; + in_jump.state &= ~2; + in_forward.state &= ~2; + in_back.state &= ~2; + in_use.state &= ~2; + in_left.state &= ~2; + in_right.state &= ~2; + in_moveleft.state &= ~2; + in_moveright.state &= ~2; + in_attack2.state &= ~2; + in_reload.state &= ~2; + in_alt1.state &= ~2; + in_score.state &= ~2; + } + + return bits; +} + +/* +============ +CL_ResetButtonBits + +============ +*/ +void CL_ResetButtonBits( int bits ) +{ + int bitsNew = CL_ButtonBits( 0 ) ^ bits; + + // Has the attack button been changed + if ( bitsNew & IN_ATTACK ) + { + // Was it pressed? or let go? + if ( bits & IN_ATTACK ) + { + KeyDown( &in_attack ); + } + else + { + // totally clear state + in_attack.state &= ~7; + } + } +} + +/* +============ +InitInput +============ +*/ +void InitInput (void) +{ + gEngfuncs.pfnAddCommand ("+moveup",IN_UpDown); + gEngfuncs.pfnAddCommand ("-moveup",IN_UpUp); + gEngfuncs.pfnAddCommand ("+movedown",IN_DownDown); + gEngfuncs.pfnAddCommand ("-movedown",IN_DownUp); + gEngfuncs.pfnAddCommand ("+left",IN_LeftDown); + gEngfuncs.pfnAddCommand ("-left",IN_LeftUp); + gEngfuncs.pfnAddCommand ("+right",IN_RightDown); + gEngfuncs.pfnAddCommand ("-right",IN_RightUp); + gEngfuncs.pfnAddCommand ("+forward",IN_ForwardDown); + gEngfuncs.pfnAddCommand ("-forward",IN_ForwardUp); + gEngfuncs.pfnAddCommand ("+back",IN_BackDown); + gEngfuncs.pfnAddCommand ("-back",IN_BackUp); + gEngfuncs.pfnAddCommand ("+lookup", IN_LookupDown); + gEngfuncs.pfnAddCommand ("-lookup", IN_LookupUp); + gEngfuncs.pfnAddCommand ("+lookdown", IN_LookdownDown); + gEngfuncs.pfnAddCommand ("-lookdown", IN_LookdownUp); + gEngfuncs.pfnAddCommand ("+strafe", IN_StrafeDown); + gEngfuncs.pfnAddCommand ("-strafe", IN_StrafeUp); + gEngfuncs.pfnAddCommand ("+moveleft", IN_MoveleftDown); + gEngfuncs.pfnAddCommand ("-moveleft", IN_MoveleftUp); + gEngfuncs.pfnAddCommand ("+moveright", IN_MoverightDown); + gEngfuncs.pfnAddCommand ("-moveright", IN_MoverightUp); + gEngfuncs.pfnAddCommand ("+speed", IN_SpeedDown); + gEngfuncs.pfnAddCommand ("-speed", IN_SpeedUp); + gEngfuncs.pfnAddCommand ("+attack", IN_AttackDown); + gEngfuncs.pfnAddCommand ("-attack", IN_AttackUp); + gEngfuncs.pfnAddCommand ("+attack2", IN_Attack2Down); + gEngfuncs.pfnAddCommand ("-attack2", IN_Attack2Up); + gEngfuncs.pfnAddCommand ("+use", IN_UseDown); + gEngfuncs.pfnAddCommand ("-use", IN_UseUp); + gEngfuncs.pfnAddCommand ("+jump", IN_JumpDown); + gEngfuncs.pfnAddCommand ("-jump", IN_JumpUp); + gEngfuncs.pfnAddCommand ("impulse", IN_Impulse); + gEngfuncs.pfnAddCommand ("+klook", IN_KLookDown); + gEngfuncs.pfnAddCommand ("-klook", IN_KLookUp); + gEngfuncs.pfnAddCommand ("+mlook", IN_MLookDown); + gEngfuncs.pfnAddCommand ("-mlook", IN_MLookUp); + gEngfuncs.pfnAddCommand ("+jlook", IN_JLookDown); + gEngfuncs.pfnAddCommand ("-jlook", IN_JLookUp); + gEngfuncs.pfnAddCommand ("+duck", IN_DuckDown); + gEngfuncs.pfnAddCommand ("-duck", IN_DuckUp); + gEngfuncs.pfnAddCommand ("+reload", IN_ReloadDown); + gEngfuncs.pfnAddCommand ("-reload", IN_ReloadUp); + gEngfuncs.pfnAddCommand ("+alt1", IN_Alt1Down); + gEngfuncs.pfnAddCommand ("-alt1", IN_Alt1Up); + gEngfuncs.pfnAddCommand ("+score", IN_ScoreDown); + gEngfuncs.pfnAddCommand ("-score", IN_ScoreUp); + gEngfuncs.pfnAddCommand ("+showscores", IN_ScoreDown); + gEngfuncs.pfnAddCommand ("-showscores", IN_ScoreUp); + gEngfuncs.pfnAddCommand ("+graph", IN_GraphDown); + gEngfuncs.pfnAddCommand ("-graph", IN_GraphUp); + gEngfuncs.pfnAddCommand ("+break",IN_BreakDown); + gEngfuncs.pfnAddCommand ("-break",IN_BreakUp); + + lookstrafe = gEngfuncs.pfnRegisterVariable ( "lookstrafe", "0", FCVAR_ARCHIVE ); + lookspring = gEngfuncs.pfnRegisterVariable ( "lookspring", "0", FCVAR_ARCHIVE ); + cl_anglespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_anglespeedkey", "0.67", 0 ); + cl_yawspeed = gEngfuncs.pfnRegisterVariable ( "cl_yawspeed", "210", 0 ); + cl_pitchspeed = gEngfuncs.pfnRegisterVariable ( "cl_pitchspeed", "225", 0 ); + cl_upspeed = gEngfuncs.pfnRegisterVariable ( "cl_upspeed", "320", 0 ); + cl_forwardspeed = gEngfuncs.pfnRegisterVariable ( "cl_forwardspeed", "400", FCVAR_ARCHIVE ); + cl_backspeed = gEngfuncs.pfnRegisterVariable ( "cl_backspeed", "400", FCVAR_ARCHIVE ); + cl_sidespeed = gEngfuncs.pfnRegisterVariable ( "cl_sidespeed", "400", 0 ); + cl_movespeedkey = gEngfuncs.pfnRegisterVariable ( "cl_movespeedkey", "0.3", 0 ); + cl_pitchup = gEngfuncs.pfnRegisterVariable ( "cl_pitchup", "89", 0 ); + cl_pitchdown = gEngfuncs.pfnRegisterVariable ( "cl_pitchdown", "89", 0 ); + + cl_vsmoothing = gEngfuncs.pfnRegisterVariable ( "cl_vsmoothing", "0.05", FCVAR_ARCHIVE ); + + m_pitch = gEngfuncs.pfnRegisterVariable ( "m_pitch","0.022", FCVAR_ARCHIVE ); + m_yaw = gEngfuncs.pfnRegisterVariable ( "m_yaw","0.022", FCVAR_ARCHIVE ); + m_forward = gEngfuncs.pfnRegisterVariable ( "m_forward","1", FCVAR_ARCHIVE ); + m_side = gEngfuncs.pfnRegisterVariable ( "m_side","0.8", FCVAR_ARCHIVE ); + + // Initialize third person camera controls. + CAM_Init(); + // Initialize inputs + IN_Init(); + // Initialize keyboard + KB_Init(); + // Initialize view system + V_Init(); +} + +/* +============ +ShutdownInput +============ +*/ +void ShutdownInput (void) +{ + IN_Shutdown(); + KB_Shutdown(); +} + +void DLLEXPORT HUD_Shutdown( void ) +{ + ShutdownInput(); +} diff --git a/cl_dll/inputw32.cpp b/cl_dll/inputw32.cpp new file mode 100644 index 00000000..7176746b --- /dev/null +++ b/cl_dll/inputw32.cpp @@ -0,0 +1,947 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// in_win.c -- windows 95 mouse and joystick code +// 02/21/97 JCB Added extended DirectInput code to support external controllers. + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "../engine/keydefs.h" +#include "view.h" +#include "windows.h" + +#define MOUSE_BUTTON_COUNT 5 + +// Set this to 1 to show mouse cursor. Experimental +int g_iVisibleMouse = 0; + +extern "C" +{ + void DLLEXPORT IN_ActivateMouse( void ); + void DLLEXPORT IN_DeactivateMouse( void ); + void DLLEXPORT IN_MouseEvent (int mstate); + void DLLEXPORT IN_Accumulate (void); + void DLLEXPORT IN_ClearStates (void); +} + +extern cl_enginefunc_t gEngfuncs; + +extern int iMouseInUse; + +extern kbutton_t in_strafe; +extern kbutton_t in_mlook; +extern kbutton_t in_speed; +extern kbutton_t in_jlook; + +extern cvar_t *m_pitch; +extern cvar_t *m_yaw; +extern cvar_t *m_forward; +extern cvar_t *m_side; + +extern cvar_t *lookstrafe; +extern cvar_t *lookspring; +extern cvar_t *cl_pitchdown; +extern cvar_t *cl_pitchup; +extern cvar_t *cl_yawspeed; +extern cvar_t *cl_sidespeed; +extern cvar_t *cl_forwardspeed; +extern cvar_t *cl_pitchspeed; +extern cvar_t *cl_movespeedkey; + +// mouse variables +cvar_t *m_filter; +cvar_t *sensitivity; + +int mouse_buttons; +int mouse_oldbuttonstate; +POINT current_pos; +int mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum; + +static int restore_spi; +static int originalmouseparms[3], newmouseparms[3] = {0, 0, 1}; +static int mouseactive; +int mouseinitialized; +static int mouseparmsvalid; +static int mouseshowtoggle = 1; + +// joystick defines and variables +// where should defines be moved? +#define JOY_ABSOLUTE_AXIS 0x00000000 // control like a joystick +#define JOY_RELATIVE_AXIS 0x00000010 // control like a mouse, spinner, trackball +#define JOY_MAX_AXES 6 // X, Y, Z, R, U, V +#define JOY_AXIS_X 0 +#define JOY_AXIS_Y 1 +#define JOY_AXIS_Z 2 +#define JOY_AXIS_R 3 +#define JOY_AXIS_U 4 +#define JOY_AXIS_V 5 + +enum _ControlList +{ + AxisNada = 0, + AxisForward, + AxisLook, + AxisSide, + AxisTurn +}; + +DWORD dwAxisFlags[JOY_MAX_AXES] = +{ + JOY_RETURNX, + JOY_RETURNY, + JOY_RETURNZ, + JOY_RETURNR, + JOY_RETURNU, + JOY_RETURNV +}; + +DWORD dwAxisMap[ JOY_MAX_AXES ]; +DWORD dwControlMap[ JOY_MAX_AXES ]; +PDWORD pdwRawValue[ JOY_MAX_AXES ]; + +// none of these cvars are saved over a session +// this means that advanced controller configuration needs to be executed +// each time. this avoids any problems with getting back to a default usage +// or when changing from one controller to another. this way at least something +// works. +cvar_t *in_joystick; +cvar_t *joy_name; +cvar_t *joy_advanced; +cvar_t *joy_advaxisx; +cvar_t *joy_advaxisy; +cvar_t *joy_advaxisz; +cvar_t *joy_advaxisr; +cvar_t *joy_advaxisu; +cvar_t *joy_advaxisv; +cvar_t *joy_forwardthreshold; +cvar_t *joy_sidethreshold; +cvar_t *joy_pitchthreshold; +cvar_t *joy_yawthreshold; +cvar_t *joy_forwardsensitivity; +cvar_t *joy_sidesensitivity; +cvar_t *joy_pitchsensitivity; +cvar_t *joy_yawsensitivity; +cvar_t *joy_wwhack1; +cvar_t *joy_wwhack2; + +int joy_avail, joy_advancedinit, joy_haspov; +DWORD joy_oldbuttonstate, joy_oldpovstate; + +int joy_id; +DWORD joy_flags; +DWORD joy_numbuttons; + +static JOYINFOEX ji; + +/* +=========== +Force_CenterView_f +=========== +*/ +void Force_CenterView_f (void) +{ + vec3_t viewangles; + + if (!iMouseInUse) + { + gEngfuncs.GetViewAngles( (float *)viewangles ); + viewangles[PITCH] = 0; + gEngfuncs.SetViewAngles( (float *)viewangles ); + } +} + +/* +=========== +IN_ActivateMouse +=========== +*/ +void DLLEXPORT IN_ActivateMouse (void) +{ + if (mouseinitialized) + { + if (mouseparmsvalid) + restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0); + mouseactive = 1; + } +} + +/* +=========== +IN_DeactivateMouse +=========== +*/ +void DLLEXPORT IN_DeactivateMouse (void) +{ + if (mouseinitialized) + { + if (restore_spi) + SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0); + + mouseactive = 0; + } +} + +/* +=========== +IN_StartupMouse +=========== +*/ +void IN_StartupMouse (void) +{ + if ( gEngfuncs.CheckParm ("-nomouse", NULL ) ) + return; + + mouseinitialized = 1; + mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0); + + if (mouseparmsvalid) + { + if ( gEngfuncs.CheckParm ("-noforcemspd", NULL ) ) + newmouseparms[2] = originalmouseparms[2]; + + if ( gEngfuncs.CheckParm ("-noforcemaccel", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + } + + if ( gEngfuncs.CheckParm ("-noforcemparms", NULL ) ) + { + newmouseparms[0] = originalmouseparms[0]; + newmouseparms[1] = originalmouseparms[1]; + newmouseparms[2] = originalmouseparms[2]; + } + } + + mouse_buttons = MOUSE_BUTTON_COUNT; +} + +/* +=========== +IN_Shutdown +=========== +*/ +void IN_Shutdown (void) +{ + IN_DeactivateMouse (); +} + +/* +=========== +IN_GetMousePos + +Ask for mouse position from engine +=========== +*/ +void IN_GetMousePos( int *mx, int *my ) +{ + gEngfuncs.GetMousePosition( mx, my ); +} + +/* +=========== +IN_ResetMouse + +FIXME: Call through to engine? +=========== +*/ +void IN_ResetMouse( void ) +{ + SetCursorPos ( gEngfuncs.GetWindowCenterX(), gEngfuncs.GetWindowCenterY() ); +} + +/* +=========== +IN_MouseEvent +=========== +*/ +void DLLEXPORT IN_MouseEvent (int mstate) +{ + int i; + + if ( iMouseInUse || g_iVisibleMouse ) + return; + + // perform button actions + for (i=0 ; ivalue) + { + mouse_x = (mx + old_mouse_x) * 0.5; + mouse_y = (my + old_mouse_y) * 0.5; + } + else + { + mouse_x = mx; + mouse_y = my; + } + + old_mouse_x = mx; + old_mouse_y = my; + + if ( gHUD.GetSensitivity() != 0 ) + { + mouse_x *= gHUD.GetSensitivity(); + mouse_y *= gHUD.GetSensitivity(); + } + else + { + mouse_x *= sensitivity->value; + mouse_y *= sensitivity->value; + } + + // add mouse X/Y movement to cmd + if ( (in_strafe.state & 1) || (lookstrafe->value && (in_mlook.state & 1) )) + cmd->sidemove += m_side->value * mouse_x; + else + viewangles[YAW] -= m_yaw->value * mouse_x; + + if ( (in_mlook.state & 1) && !(in_strafe.state & 1)) + { + viewangles[PITCH] += m_pitch->value * mouse_y; + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + } + else + { + if ((in_strafe.state & 1) && gEngfuncs.IsNoClipping() ) + { + cmd->upmove -= m_forward->value * mouse_y; + } + else + { + cmd->forwardmove -= m_forward->value * mouse_y; + } + } + + // if the mouse has moved, force it to the center, so there's room to move + if ( mx || my ) + { + IN_ResetMouse(); + } + } + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +/* +//#define TRACE_TEST +#if defined( TRACE_TEST ) + { + int mx, my; + void V_Move( int mx, int my ); + IN_GetMousePos( &mx, &my ); + V_Move( mx, my ); + } +#endif +*/ +} + +/* +=========== +IN_Accumulate +=========== +*/ +void DLLEXPORT IN_Accumulate (void) +{ + //only accumulate mouse if we are not moving the camera with the mouse + if ( !iMouseInUse && !g_iVisibleMouse ) + { + if (mouseactive) + { + GetCursorPos (¤t_pos); + + mx_accum += current_pos.x - gEngfuncs.GetWindowCenterX(); + my_accum += current_pos.y - gEngfuncs.GetWindowCenterY(); + + // force the mouse to the center, so there's room to move + IN_ResetMouse(); + } + } + +} + +/* +=================== +IN_ClearStates +=================== +*/ +void DLLEXPORT IN_ClearStates (void) +{ + if ( !mouseactive ) + return; + + mx_accum = 0; + my_accum = 0; + mouse_oldbuttonstate = 0; +} + +/* +=============== +IN_StartupJoystick +=============== +*/ +void IN_StartupJoystick (void) +{ + int numdevs; + JOYCAPS jc; + MMRESULT mmr; + + // assume no joystick + joy_avail = 0; + + // abort startup if user requests no joystick + if ( gEngfuncs.CheckParm ("-nojoy", NULL ) ) + return; + + // verify joystick driver is present + if ((numdevs = joyGetNumDevs ()) == 0) + { + gEngfuncs.Con_DPrintf ("joystick not found -- driver not present\n\n"); + return; + } + + // cycle through the joystick ids for the first valid one + for (joy_id=0 ; joy_idvalue == 0.0) + { + // default joystick initialization + // 2 axes only with joystick control + dwAxisMap[JOY_AXIS_X] = AxisTurn; + // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS; + dwAxisMap[JOY_AXIS_Y] = AxisForward; + // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS; + } + else + { + if ( strcmp ( joy_name->string, "joystick") != 0 ) + { + // notify user of advanced controller + gEngfuncs.Con_Printf ("\n%s configured\n\n", joy_name->string); + } + + // advanced initialization here + // data supplied by user via joy_axisn cvars + dwTemp = (DWORD) joy_advaxisx->value; + dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisy->value; + dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisz->value; + dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisr->value; + dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisu->value; + dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS; + dwTemp = (DWORD) joy_advaxisv->value; + dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f; + dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS; + } + + // compute the axes to collect from DirectInput + joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV; + for (i = 0; i < JOY_MAX_AXES; i++) + { + if (dwAxisMap[i] != AxisNada) + { + joy_flags |= dwAxisFlags[i]; + } + } +} + + +/* +=========== +IN_Commands +=========== +*/ +void IN_Commands (void) +{ + int i, key_index; + DWORD buttonstate, povstate; + + if (!joy_avail) + { + return; + } + + + // loop through the joystick buttons + // key a joystick event or auxillary event for higher number buttons for each state change + buttonstate = ji.dwButtons; + for (i=0 ; i < (int)joy_numbuttons ; i++) + { + if ( (buttonstate & (1<value != 0.0) + { + ji.dwUpos += 100; + } + return 1; + } + else + { + // read error occurred + // turning off the joystick seems too harsh for 1 read error,\ + // but what should be done? + // Con_Printf ("IN_ReadJoystick: no response\n"); + // joy_avail = 0; + return 0; + } +} + + +/* +=========== +IN_JoyMove +=========== +*/ +void IN_JoyMove ( float frametime, usercmd_t *cmd ) +{ + float speed, aspeed; + float fAxisValue, fTemp; + int i; + vec3_t viewangles; + + gEngfuncs.GetViewAngles( (float *)viewangles ); + + + // complete initialization if first time in + // this is needed as cvars are not available at initialization time + if( joy_advancedinit != 1 ) + { + Joy_AdvancedUpdate_f(); + joy_advancedinit = 1; + } + + // verify joystick is available and that the user wants to use it + if (!joy_avail || !in_joystick->value) + { + return; + } + + // collect the joystick data, if possible + if (IN_ReadJoystick () != 1) + { + return; + } + + if (in_speed.state & 1) + speed = cl_movespeedkey->value; + else + speed = 1; + + aspeed = speed * frametime; + + // loop through the axes + for (i = 0; i < JOY_MAX_AXES; i++) + { + // get the floating point zero-centered, potentially-inverted data for the current axis + fAxisValue = (float) *pdwRawValue[i]; + // move centerpoint to zero + fAxisValue -= 32768.0; + + if (joy_wwhack2->value != 0.0) + { + if (dwAxisMap[i] == AxisTurn) + { + // this is a special formula for the Logitech WingMan Warrior + // y=ax^b; where a = 300 and b = 1.3 + // also x values are in increments of 800 (so this is factored out) + // then bounds check result to level out excessively high spin rates + fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3); + if (fTemp > 14000.0) + fTemp = 14000.0; + // restore direction information + fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp; + } + } + + // convert range from -32768..32767 to -1..1 + fAxisValue /= 32768.0; + + switch (dwAxisMap[i]) + { + case AxisForward: + if ((joy_advanced->value == 0.0) && (in_jlook.state & 1)) + { + // user wants forward control to become look control + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // if mouse invert is on, invert the joystick pitch value + // only absolute control support here (joy_advanced is 0) + if (m_pitch->value < 0.0) + { + viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if(lookspring->value == 0.0) + { + V_StopPitchDrift(); + } + } + } + else + { + // user wants forward control to be forward control + if (fabs(fAxisValue) > joy_forwardthreshold->value) + { + cmd->forwardmove += (fAxisValue * joy_forwardsensitivity->value) * speed * cl_forwardspeed->value; + } + } + break; + + case AxisSide: + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove += (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + break; + + case AxisTurn: + if ((in_strafe.state & 1) || (lookstrafe->value && (in_jlook.state & 1))) + { + // user wants turn control to become side control + if (fabs(fAxisValue) > joy_sidethreshold->value) + { + cmd->sidemove -= (fAxisValue * joy_sidesensitivity->value) * speed * cl_sidespeed->value; + } + } + else + { + // user wants turn control to be turn control + if (fabs(fAxisValue) > joy_yawthreshold->value) + { + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * aspeed * cl_yawspeed->value; + } + else + { + viewangles[YAW] += (fAxisValue * joy_yawsensitivity->value) * speed * 180.0; + } + + } + } + break; + + case AxisLook: + if (in_jlook.state & 1) + { + if (fabs(fAxisValue) > joy_pitchthreshold->value) + { + // pitch movement detected and pitch movement desired by user + if(dwControlMap[i] == JOY_ABSOLUTE_AXIS) + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * aspeed * cl_pitchspeed->value; + } + else + { + viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity->value) * speed * 180.0; + } + V_StopPitchDrift(); + } + else + { + // no pitch movement + // disable pitch return-to-center unless requested by user + // *** this code can be removed when the lookspring bug is fixed + // *** the bug always has the lookspring feature on + if( lookspring->value == 0.0 ) + { + V_StopPitchDrift(); + } + } + } + break; + + default: + break; + } + } + + // bounds check pitch + if (viewangles[PITCH] > cl_pitchdown->value) + viewangles[PITCH] = cl_pitchdown->value; + if (viewangles[PITCH] < -cl_pitchup->value) + viewangles[PITCH] = -cl_pitchup->value; + + gEngfuncs.SetViewAngles( (float *)viewangles ); + +} + +/* +=========== +IN_Move +=========== +*/ +void IN_Move ( float frametime, usercmd_t *cmd) +{ + if ( !iMouseInUse && mouseactive ) + { + IN_MouseMove ( frametime, cmd); + } + + IN_JoyMove ( frametime, cmd); +} + +/* +=========== +IN_Init +=========== +*/ +void IN_Init (void) +{ + m_filter = gEngfuncs.pfnRegisterVariable ( "m_filter","0", FCVAR_ARCHIVE ); + sensitivity = gEngfuncs.pfnRegisterVariable ( "sensitivity","3", FCVAR_ARCHIVE ); // user mouse sensitivity setting. + + in_joystick = gEngfuncs.pfnRegisterVariable ( "joystick","0", FCVAR_ARCHIVE ); + joy_name = gEngfuncs.pfnRegisterVariable ( "joyname", "joystick", 0 ); + joy_advanced = gEngfuncs.pfnRegisterVariable ( "joyadvanced", "0", 0 ); + joy_advaxisx = gEngfuncs.pfnRegisterVariable ( "joyadvaxisx", "0", 0 ); + joy_advaxisy = gEngfuncs.pfnRegisterVariable ( "joyadvaxisy", "0", 0 ); + joy_advaxisz = gEngfuncs.pfnRegisterVariable ( "joyadvaxisz", "0", 0 ); + joy_advaxisr = gEngfuncs.pfnRegisterVariable ( "joyadvaxisr", "0", 0 ); + joy_advaxisu = gEngfuncs.pfnRegisterVariable ( "joyadvaxisu", "0", 0 ); + joy_advaxisv = gEngfuncs.pfnRegisterVariable ( "joyadvaxisv", "0", 0 ); + joy_forwardthreshold = gEngfuncs.pfnRegisterVariable ( "joyforwardthreshold", "0.15", 0 ); + joy_sidethreshold = gEngfuncs.pfnRegisterVariable ( "joysidethreshold", "0.15", 0 ); + joy_pitchthreshold = gEngfuncs.pfnRegisterVariable ( "joypitchthreshold", "0.15", 0 ); + joy_yawthreshold = gEngfuncs.pfnRegisterVariable ( "joyyawthreshold", "0.15", 0 ); + joy_forwardsensitivity = gEngfuncs.pfnRegisterVariable ( "joyforwardsensitivity", "-1.0", 0 ); + joy_sidesensitivity = gEngfuncs.pfnRegisterVariable ( "joysidesensitivity", "-1.0", 0 ); + joy_pitchsensitivity = gEngfuncs.pfnRegisterVariable ( "joypitchsensitivity", "1.0", 0 ); + joy_yawsensitivity = gEngfuncs.pfnRegisterVariable ( "joyyawsensitivity", "-1.0", 0 ); + joy_wwhack1 = gEngfuncs.pfnRegisterVariable ( "joywwhack1", "0.0", 0 ); + joy_wwhack2 = gEngfuncs.pfnRegisterVariable ( "joywwhack2", "0.0", 0 ); + + gEngfuncs.pfnAddCommand ("force_centerview", Force_CenterView_f); + gEngfuncs.pfnAddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f); + + IN_StartupMouse (); + IN_StartupJoystick (); +} \ No newline at end of file diff --git a/cl_dll/kbutton.h b/cl_dll/kbutton.h new file mode 100644 index 00000000..a772b3d3 --- /dev/null +++ b/cl_dll/kbutton.h @@ -0,0 +1,18 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( KBUTTONH ) +#define KBUTTONH +#pragma once + +typedef struct kbutton_s +{ + int down[2]; // key nums holding it down + int state; // low bit is down state +} kbutton_t; + +#endif // !KBUTTONH \ No newline at end of file diff --git a/client/hud/hud_menu.cpp b/cl_dll/menu.cpp similarity index 66% rename from client/hud/hud_menu.cpp rename to cl_dll/menu.cpp index ec98bfa9..1f0196b2 100644 --- a/client/hud/hud_menu.cpp +++ b/cl_dll/menu.cpp @@ -17,14 +17,21 @@ // // generic menu handler // -#include "extdll.h" -#include "utils.h" #include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" -#define MAX_MENU_STRING 512 +#include +#include + +#include "vgui_TeamFortressViewport.h" + +#define MAX_MENU_STRING 512 char g_szMenuString[MAX_MENU_STRING]; char g_szPrelocalisedMenuString[MAX_MENU_STRING]; +int KB_ConvertString( char *in, char **ppout ); + DECLARE_MESSAGE( m_Menu, ShowMenu ); int CHudMenu :: Init( void ) @@ -59,11 +66,10 @@ int CHudMenu :: VidInit( void ) int CHudMenu :: Draw( float flTime ) { // check for if menu is set to disappear - if( m_flShutoffTime > 0 ) + if ( m_flShutoffTime > 0 ) { - if( m_flShutoffTime <= gHUD.m_flTime ) - { - // times up, shutoff + if ( m_flShutoffTime <= gHUD.m_flTime ) + { // times up, shutoff m_fMenuDisplayed = 0; m_iFlags &= ~HUD_ACTIVE; return 1; @@ -71,16 +77,16 @@ int CHudMenu :: Draw( float flTime ) } // don't draw the menu if the scoreboard is being shown - if( gHUD.m_Scoreboard.m_iShowscoresHeld ) + if ( gViewPort && gViewPort->IsScoreBoardVisible() ) return 1; // draw the menu, along the left-hand side of the screen // count the number of newlines int nlc = 0; - for( int i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) + for ( int i = 0; i < MAX_MENU_STRING && g_szMenuString[i] != '\0'; i++ ) { - if( g_szMenuString[i] == '\n' ) + if ( g_szMenuString[i] == '\n' ) nlc++; } @@ -89,16 +95,17 @@ int CHudMenu :: Draw( float flTime ) int x = 20; i = 0; - while( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) + while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' ) { gHUD.DrawHudString( x, y, 320, g_szMenuString + i, 255, 255, 255 ); y += 12; - while( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) + while ( i < MAX_MENU_STRING && g_szMenuString[i] != '\0' && g_szMenuString[i] != '\n' ) i++; - if( g_szMenuString[i] == '\n' ) + if ( g_szMenuString[i] == '\n' ) i++; } + return 1; } @@ -106,11 +113,11 @@ int CHudMenu :: Draw( float flTime ) void CHudMenu :: SelectMenuItem( int menu_item ) { // if menu_item is in a valid slot, send a menuselect command to the server - if( (menu_item > 0) && (m_bitsValidSlots & (1<<(menu_item - 1))) ) + if ( (menu_item > 0) && (m_bitsValidSlots & (1 << (menu_item-1))) ) { char szbuf[32]; sprintf( szbuf, "menuselect %d\n", menu_item ); - CLIENT_COMMAND( szbuf ); + ClientCmd( szbuf ); // remove the menu m_fMenuDisplayed = 0; @@ -118,43 +125,51 @@ void CHudMenu :: SelectMenuItem( int menu_item ) } } + // Message handler for ShowMenu message // takes four values: -// short: a bitfield of keys that are valid input -// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen. -// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string -// string: menu string to display +// short: a bitfield of keys that are valid input +// char : the duration, in seconds, the menu should stay up. -1 means is stays until something is chosen. +// byte : a boolean, TRUE if there is more string yet to be received before displaying the menu, FALSE if it's the last string +// string: menu string to display // if this message is never received, then scores will simply be the combined totals of the players. - int CHudMenu :: MsgFunc_ShowMenu( const char *pszName, int iSize, void *pbuf ) { - BEGIN_READ( pszName, iSize, pbuf ); + char *temp = NULL; + + BEGIN_READ( pbuf, iSize ); m_bitsValidSlots = READ_SHORT(); int DisplayTime = READ_CHAR(); int NeedMore = READ_BYTE(); - if( DisplayTime > 0 ) + if ( DisplayTime > 0 ) m_flShutoffTime = DisplayTime + gHUD.m_flTime; - else m_flShutoffTime = -1; + else + m_flShutoffTime = -1; - if( m_bitsValidSlots ) + if ( m_bitsValidSlots ) { - if( !m_fWaitingForMore ) // this is the start of a new menu + if ( !m_fWaitingForMore ) // this is the start of a new menu { strncpy( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING ); } else - { - // append to the current menu string + { // append to the current menu string strncat( g_szPrelocalisedMenuString, READ_STRING(), MAX_MENU_STRING - strlen(g_szPrelocalisedMenuString) ); } g_szPrelocalisedMenuString[MAX_MENU_STRING-1] = 0; // ensure null termination (strncat/strncpy does not) - if( !NeedMore ) - { - // we have the whole string, so we can localise it now + if ( !NeedMore ) + { // we have the whole string, so we can localise it now strcpy( g_szMenuString, gHUD.m_TextMessage.BufferedLocaliseTextString( g_szPrelocalisedMenuString ) ); + + // Swap in characters + if ( KB_ConvertString( g_szMenuString, &temp ) ) + { + strcpy( g_szMenuString, temp ); + free( temp ); + } } m_fMenuDisplayed = 1; diff --git a/client/hud/hud_message.cpp b/cl_dll/message.cpp similarity index 73% rename from client/hud/hud_message.cpp rename to cl_dll/message.cpp index f478e6b2..61ea55a7 100644 --- a/client/hud/hud_message.cpp +++ b/cl_dll/message.cpp @@ -18,37 +18,42 @@ // implementation of CHudMessage class // -#include "extdll.h" -#include "utils.h" #include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" DECLARE_MESSAGE( m_Message, HudText ) DECLARE_MESSAGE( m_Message, GameTitle ) // 1 Global client_textmessage_t for custom messages that aren't in the titles.txt -client_textmessage_t g_pCustomMessage; +client_textmessage_t g_pCustomMessage; char *g_pCustomName = "Custom"; char g_pCustomText[1024]; -int CHudMessage :: Init( void ) +int CHudMessage::Init(void) { HOOK_MESSAGE( HudText ); HOOK_MESSAGE( GameTitle ); - gHUD.AddHudElem( this ); + gHUD.AddHudElem(this); + Reset(); return 1; -} +}; -int CHudMessage :: VidInit( void ) +int CHudMessage::VidInit( void ) { m_HUD_title_half = gHUD.GetSpriteIndex( "title_half" ); m_HUD_title_life = gHUD.GetSpriteIndex( "title_life" ); - return 1; -} -void CHudMessage :: Reset( void ) + return 1; +}; + + +void CHudMessage::Reset( void ) { memset( m_pMessages, 0, sizeof( m_pMessages[0] ) * maxHUDMessages ); memset( m_startTime, 0, sizeof( m_startTime[0] ) * maxHUDMessages ); @@ -57,34 +62,38 @@ void CHudMessage :: Reset( void ) m_pGameTitle = NULL; } -float CHudMessage :: FadeBlend( float fadein, float fadeout, float hold, float localTime ) + +float CHudMessage::FadeBlend( float fadein, float fadeout, float hold, float localTime ) { float fadeTime = fadein + hold; float fadeBlend; - if( localTime < 0 ) + if ( localTime < 0 ) return 0; - if( localTime < fadein ) + if ( localTime < fadein ) { fadeBlend = 1 - ((fadein - localTime) / fadein); } - else if( localTime > fadeTime ) + else if ( localTime > fadeTime ) { - if( fadeout > 0 ) + if ( fadeout > 0 ) fadeBlend = 1 - ((localTime - fadeTime) / fadeout); - else fadeBlend = 0; + else + fadeBlend = 0; } - else fadeBlend = 1; + else + fadeBlend = 1; return fadeBlend; } -int CHudMessage::XPosition( float x, int width, int totalWidth ) + +int CHudMessage::XPosition( float x, int width, int totalWidth ) { int xPos; - if( x == -1 ) + if ( x == -1 ) { xPos = (ScreenWidth - width) / 2; } @@ -96,38 +105,40 @@ int CHudMessage::XPosition( float x, int width, int totalWidth ) xPos = x * ScreenWidth; } - if( xPos + width > ScreenWidth ) + if ( xPos + width > ScreenWidth ) xPos = ScreenWidth - width; - else if( xPos < 0 ) + else if ( xPos < 0 ) xPos = 0; return xPos; } + int CHudMessage::YPosition( float y, int height ) { int yPos; - if( y == -1 ) // Centered? + if ( y == -1 ) // Centered? yPos = (ScreenHeight - height) * 0.5; else { // Alight bottom? - if( y < 0 ) + if ( y < 0 ) yPos = (1.0 + y) * ScreenHeight - height; // Alight bottom else // align top yPos = y * ScreenHeight; } - if( yPos + height > ScreenHeight ) + if ( yPos + height > ScreenHeight ) yPos = ScreenHeight - height; - else if( yPos < 0 ) + else if ( yPos < 0 ) yPos = 0; return yPos; } -void CHudMessage :: MessageScanNextChar( void ) + +void CHudMessage::MessageScanNextChar( void ) { int srcRed, srcGreen, srcBlue, destRed, destGreen, destBlue; int blend; @@ -139,7 +150,8 @@ void CHudMessage :: MessageScanNextChar( void ) switch( m_parms.pMessage->effect ) { - case 0: // Fade-in / Fade-out + // Fade-in / Fade-out + case 0: case 1: destRed = destGreen = destBlue = 0; blend = m_parms.fadeBlend; @@ -147,7 +159,7 @@ void CHudMessage :: MessageScanNextChar( void ) case 2: m_parms.charTime += m_parms.pMessage->fadein; - if( m_parms.charTime > m_parms.time ) + if ( m_parms.charTime > m_parms.time ) { srcRed = srcGreen = srcBlue = 0; blend = 0; // pure source @@ -157,77 +169,81 @@ void CHudMessage :: MessageScanNextChar( void ) float deltaTime = m_parms.time - m_parms.charTime; destRed = destGreen = destBlue = 0; - if( m_parms.time > m_parms.fadeTime ) + if ( m_parms.time > m_parms.fadeTime ) { blend = m_parms.fadeBlend; } - else if( deltaTime > m_parms.pMessage->fxtime ) + else if ( deltaTime > m_parms.pMessage->fxtime ) blend = 0; // pure dest else { destRed = m_parms.pMessage->r2; destGreen = m_parms.pMessage->g2; destBlue = m_parms.pMessage->b2; - blend = 255 - (deltaTime * (1.0 / m_parms.pMessage->fxtime) * 255.0 + 0.5); + blend = 255 - (deltaTime * (1.0/m_parms.pMessage->fxtime) * 255.0 + 0.5); } } break; } - - if( blend > 255 ) + if ( blend > 255 ) blend = 255; - else if( blend < 0 ) + else if ( blend < 0 ) blend = 0; m_parms.r = ((srcRed * (255-blend)) + (destRed * blend)) >> 8; m_parms.g = ((srcGreen * (255-blend)) + (destGreen * blend)) >> 8; m_parms.b = ((srcBlue * (255-blend)) + (destBlue * blend)) >> 8; - if( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) + if ( m_parms.pMessage->effect == 1 && m_parms.charTime != 0 ) { - if( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth ) + if ( m_parms.x >= 0 && m_parms.y >= 0 && (m_parms.x + gHUD.m_scrinfo.charWidths[ m_parms.text ]) <= ScreenWidth ) TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.pMessage->r2, m_parms.pMessage->g2, m_parms.pMessage->b2 ); } } -void CHudMessage :: MessageScanStart( void ) +void CHudMessage::MessageScanStart( void ) { switch( m_parms.pMessage->effect ) { - case 1: // Fade-in / out with flicker + // Fade-in / out with flicker + case 1: case 0: m_parms.fadeTime = m_parms.pMessage->fadein + m_parms.pMessage->holdtime; + - if( m_parms.time < m_parms.pMessage->fadein ) + if ( m_parms.time < m_parms.pMessage->fadein ) { m_parms.fadeBlend = ((m_parms.pMessage->fadein - m_parms.time) * (1.0/m_parms.pMessage->fadein) * 255); } - else if( m_parms.time > m_parms.fadeTime ) + else if ( m_parms.time > m_parms.fadeTime ) { if ( m_parms.pMessage->fadeout > 0 ) m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); else m_parms.fadeBlend = 255; // Pure dest (off) } - else m_parms.fadeBlend = 0; // Pure source (on) + else + m_parms.fadeBlend = 0; // Pure source (on) m_parms.charTime = 0; - if( m_parms.pMessage->effect == 1 && (rand() % 100 ) < 10 ) + if ( m_parms.pMessage->effect == 1 && (rand()%100) < 10 ) m_parms.charTime = 1; break; + case 2: m_parms.fadeTime = (m_parms.pMessage->fadein * m_parms.length) + m_parms.pMessage->holdtime; - if( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 ) + if ( m_parms.time > m_parms.fadeTime && m_parms.pMessage->fadeout > 0 ) m_parms.fadeBlend = (((m_parms.time - m_parms.fadeTime) / m_parms.pMessage->fadeout) * 255); - else m_parms.fadeBlend = 0; + else + m_parms.fadeBlend = 0; break; } } -void CHudMessage :: MessageDrawScan( client_textmessage_t *pMessage, float time ) +void CHudMessage::MessageDrawScan( client_textmessage_t *pMessage, float time ) { int i, j, length, width; const char *pText; @@ -241,8 +257,7 @@ void CHudMessage :: MessageDrawScan( client_textmessage_t *pMessage, float time length = 0; width = 0; m_parms.totalWidth = 0; - - while( *pText ) + while ( *pText ) { if ( *pText == '\n' ) { @@ -251,7 +266,8 @@ void CHudMessage :: MessageDrawScan( client_textmessage_t *pMessage, float time m_parms.totalWidth = width; width = 0; } - else width += gHUD.m_scrinfo.charWidths[*pText]; + else + width += gHUD.m_scrinfo.charWidths[*pText]; pText++; length++; } @@ -266,11 +282,11 @@ void CHudMessage :: MessageDrawScan( client_textmessage_t *pMessage, float time MessageScanStart(); - for( i = 0; i < m_parms.lines; i++ ) + for ( i = 0; i < m_parms.lines; i++ ) { m_parms.lineLength = 0; m_parms.width = 0; - while( *pText && *pText != '\n' ) + while ( *pText && *pText != '\n' ) { unsigned char c = *pText; line[m_parms.lineLength] = c; @@ -278,7 +294,7 @@ void CHudMessage :: MessageDrawScan( client_textmessage_t *pMessage, float time m_parms.lineLength++; pText++; } - pText++; // Skip LineFeed + pText++; // Skip LF line[m_parms.lineLength] = 0; m_parms.x = XPosition( pMessage->x, m_parms.width, m_parms.totalWidth ); @@ -293,12 +309,13 @@ void CHudMessage :: MessageDrawScan( client_textmessage_t *pMessage, float time TextMessageDrawChar( m_parms.x, m_parms.y, m_parms.text, m_parms.r, m_parms.g, m_parms.b ); m_parms.x = next; } + m_parms.y += gHUD.m_scrinfo.iCharHeight; } } -int CHudMessage :: Draw( float fTime ) +int CHudMessage::Draw( float fTime ) { int i, drawn; client_textmessage_t *pMessage; @@ -338,23 +355,19 @@ int CHudMessage :: Draw( float fTime ) drawn = 1; } } - - // fixup level transitions - for( i = 0; i < maxHUDMessages; i++ ) + // Fixup level transitions + for ( i = 0; i < maxHUDMessages; i++ ) { - // assume m_parms.time contains last time - if( m_pMessages[i] ) + // Assume m_parms.time contains last time + if ( m_pMessages[i] ) { pMessage = m_pMessages[i]; - if( m_startTime[i] > gHUD.m_flTime ) - { - // Server takes 0.2 seconds to spawn, adjust for this - m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; - } + if ( m_startTime[i] > gHUD.m_flTime ) + m_startTime[i] = gHUD.m_flTime + m_parms.time - m_startTime[i] + 0.2; // Server takes 0.2 seconds to spawn, adjust for this } } - for( i = 0; i < maxHUDMessages; i++ ) + for ( i = 0; i < maxHUDMessages; i++ ) { if ( m_pMessages[i] ) { @@ -374,7 +387,7 @@ int CHudMessage :: Draw( float fTime ) break; } - if( fTime <= endTime ) + if ( fTime <= endTime ) { float messageTime = fTime - m_startTime[i]; @@ -396,29 +409,30 @@ int CHudMessage :: Draw( float fTime ) // Remember the time -- to fix up level transitions m_parms.time = gHUD.m_flTime; - // Don't call until we get another message - if( !drawn ) m_iFlags &= ~HUD_ACTIVE; + if ( !drawn ) + m_iFlags &= ~HUD_ACTIVE; return 1; } -void CHudMessage :: MessageAdd( const char *pName, float time ) + +void CHudMessage::MessageAdd( const char *pName, float time ) { - int i, j; + int i,j; client_textmessage_t *tempMessage; - for( i = 0; i < maxHUDMessages; i++ ) + for ( i = 0; i < maxHUDMessages; i++ ) { - if( !m_pMessages[i] ) + if ( !m_pMessages[i] ) { // Trim off a leading # if it's there - if( pName[0] == '#' ) + if ( pName[0] == '#' ) tempMessage = TextMessageGet( pName+1 ); - else tempMessage = TextMessageGet( pName ); - + else + tempMessage = TextMessageGet( pName ); // If we couldnt find it in the titles.txt, just create it - if( !tempMessage ) + if ( !tempMessage ) { g_pCustomMessage.effect = 2; g_pCustomMessage.r1 = g_pCustomMessage.g1 = g_pCustomMessage.b1 = g_pCustomMessage.a1 = 100; @@ -439,18 +453,18 @@ void CHudMessage :: MessageAdd( const char *pName, float time ) tempMessage = &g_pCustomMessage; } - for( j = 0; j < maxHUDMessages; j++ ) + for ( j = 0; j < maxHUDMessages; j++ ) { - if( m_pMessages[j] ) + if ( m_pMessages[j] ) { // is this message already in the list - if( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) + if ( !strcmp( tempMessage->pMessage, m_pMessages[j]->pMessage ) ) { return; } // get rid of any other messages in same location (only one displays at a time) - if( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) + if ( fabs( tempMessage->y - m_pMessages[j]->y ) < 0.0001 ) { if ( fabs( tempMessage->x - m_pMessages[j]->x ) < 0.0001 ) { @@ -459,6 +473,7 @@ void CHudMessage :: MessageAdd( const char *pName, float time ) } } } + m_pMessages[i] = tempMessage; m_startTime[i] = time; return; @@ -466,9 +481,10 @@ void CHudMessage :: MessageAdd( const char *pName, float time ) } } + int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) { - BEGIN_READ( pszName, iSize, pbuf ); + BEGIN_READ( pbuf, iSize ); char *pString = READ_STRING(); @@ -477,39 +493,39 @@ int CHudMessage::MsgFunc_HudText( const char *pszName, int iSize, void *pbuf ) m_parms.time = gHUD.m_flTime; // Turn on drawing - if(!( m_iFlags & HUD_ACTIVE )) + if ( !(m_iFlags & HUD_ACTIVE) ) m_iFlags |= HUD_ACTIVE; - END_READ(); return 1; } + int CHudMessage::MsgFunc_GameTitle( const char *pszName, int iSize, void *pbuf ) { m_pGameTitle = TextMessageGet( "GAMETITLE" ); - - if( m_pGameTitle != NULL ) + if ( m_pGameTitle != NULL ) { m_gameTitleTime = gHUD.m_flTime; // Turn on drawing - if(!( m_iFlags & HUD_ACTIVE )) + if ( !(m_iFlags & HUD_ACTIVE) ) m_iFlags |= HUD_ACTIVE; } + return 1; } -void CHudMessage :: MessageAdd( client_textmessage_t *newMessage ) +void CHudMessage::MessageAdd(client_textmessage_t * newMessage ) { m_parms.time = gHUD.m_flTime; // Turn on drawing - if(!( m_iFlags & HUD_ACTIVE )) + if ( !(m_iFlags & HUD_ACTIVE) ) m_iFlags |= HUD_ACTIVE; - for( int i = 0; i < maxHUDMessages; i++ ) + for ( int i = 0; i < maxHUDMessages; i++ ) { - if( !m_pMessages[i] ) + if ( !m_pMessages[i] ) { m_pMessages[i] = newMessage; m_startTime[i] = gHUD.m_flTime; @@ -517,4 +533,4 @@ void CHudMessage :: MessageAdd( client_textmessage_t *newMessage ) } } -} \ No newline at end of file +} diff --git a/cl_dll/overview.cpp b/cl_dll/overview.cpp new file mode 100644 index 00000000..dd7741f0 --- /dev/null +++ b/cl_dll/overview.cpp @@ -0,0 +1,160 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "cl_util.h" +#include "cl_entity.h" +#include "triangleapi.h" +#include "vgui_TeamFortressViewport.h" + +// these are included for the math functions +#include "com_model.h" +#include "studio_util.h" + +#pragma warning(disable: 4244) + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +int CHudOverview::Init() +{ + gHUD.AddHudElem(this); + + m_iFlags |= HUD_ACTIVE; + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads new icons +//----------------------------------------------------------------------------- +int CHudOverview::VidInit() +{ + m_hsprPlayer = gEngfuncs.pfnSPR_Load("sprites/ring.spr"); + m_hsprViewcone = gEngfuncs.pfnSPR_Load("sprites/camera.spr"); + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flTime - +// intermission - +//----------------------------------------------------------------------------- +int CHudOverview::Draw(float flTime) +{ + // only draw in overview mode + if (!gEngfuncs.Overview_GetOverviewState()) + return 1; + + // make sure we have player info + gViewPort->GetAllPlayersInfo(); + + // calculate player size on the overview + int x1, y1, x2, y2; + float v0[3]={0,0,0}, v1[3]={64,64,0}; + gEngfuncs.Overview_WorldToScreen(v0, &x1, &y1); + gEngfuncs.Overview_WorldToScreen(v1, &x2, &y2); + float scale = abs(x2 - x1); + + // loop through all the players and draw them on the map + for (int i = 1; i < MAX_PLAYERS; i++) + { + cl_entity_t *pl = gEngfuncs.GetEntityByIndex(i); + + if (pl && pl->player && pl->curstate.health > 0 && pl->curstate.solid != SOLID_NOT) + { + int x, y, z = 0; + float v[3]={pl->origin[0], pl->origin[1], 0}; + gEngfuncs.Overview_WorldToScreen(v, &x, &y); + + // hack in some team colors + float r, g, bc; + if (g_PlayerExtraInfo[i].teamnumber == 1) + { + r = 0.0f; g = 0.0f; bc = 1.0f; + } + else if (g_PlayerExtraInfo[i].teamnumber == 2) + { + r = 1.0f; g = 0.0f; bc = 0.0f; + } + else + { + // just use the default orange color if the team isn't set + r = 1.0f; g = 0.7f; bc = 0.0f; + } + + // set the current texture + gEngfuncs.pTriAPI->SpriteTexture((struct model_s *)gEngfuncs.GetSpritePointer(m_hsprPlayer), 0); + + // additive render mode + gEngfuncs.pTriAPI->RenderMode(kRenderTransAdd); + + // no culling + gEngfuncs.pTriAPI->CullFace(TRI_NONE); + + // draw a square + gEngfuncs.pTriAPI->Begin(TRI_QUADS); + + // set the color to be that of the team + gEngfuncs.pTriAPI->Color4f(r, g, bc, 1.0f); + + // calculate rotational matrix + vec3_t a, b, angles; + float rmatrix[3][4]; // transformation matrix + VectorCopy(pl->angles, angles); + angles[0] = 0.0f; + angles[1] += 90.f; + angles[1] = -angles[1]; + angles[2] = 0.0f; + AngleMatrix(angles, rmatrix); + a[2] = 0; + + a[0] = -scale; a[1] = -scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f(x + b[0], y + b[1], z); + + a[0]=-scale; a[1] = scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + a[0]=scale; a[1] = scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + a[0]=scale; a[1] = -scale; + VectorTransform(a, rmatrix , b ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f (x + b[0], y + b[1], z); + + // finish up + gEngfuncs.pTriAPI->End(); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + + // draw the players name and health underneath + char string[256]; + sprintf(string, "%s (%i%%)", g_PlayerInfoList[i].name, pl->curstate.health); + DrawConsoleString(x, y + (1.1 * scale), string); + } + } + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: called every time a server is connected to +//----------------------------------------------------------------------------- +void CHudOverview::InitHUDData() +{ +// this block would force the spectator view to be on +// gEngfuncs.Overview_SetDrawOverview( 1 ); +// gEngfuncs.Overview_SetDrawInset( 0 ); +} + diff --git a/cl_dll/overview.h b/cl_dll/overview.h new file mode 100644 index 00000000..7f0502e3 --- /dev/null +++ b/cl_dll/overview.h @@ -0,0 +1,31 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef OVERVIEW_H +#define OVERVIEW_H +#pragma once + + +//----------------------------------------------------------------------------- +// Purpose: Handles the drawing of the top-down map and all the things on it +//----------------------------------------------------------------------------- +class CHudOverview : public CHudBase +{ +public: + int Init(); + int VidInit(); + + int Draw(float flTime); + void InitHUDData( void ); + +private: + HSPRITE m_hsprPlayer; + HSPRITE m_hsprViewcone; +}; + + +#endif // OVERVIEW_H diff --git a/cl_dll/parsemsg.cpp b/cl_dll/parsemsg.cpp new file mode 100644 index 00000000..bdfa4136 --- /dev/null +++ b/cl_dll/parsemsg.cpp @@ -0,0 +1,166 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// parsemsg.cpp +// +typedef unsigned char byte; +#define true 1 + +static byte *gpBuf; +static int giSize; +static int giRead; +static int giBadRead; + +void BEGIN_READ( void *buf, int size ) +{ + giRead = 0; + giBadRead = 0; + giSize = size; + gpBuf = (byte*)buf; +} + + +int READ_CHAR( void ) +{ + int c; + + if (giRead + 1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (signed char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_BYTE( void ) +{ + int c; + + if (giRead+1 > giSize) + { + giBadRead = true; + return -1; + } + + c = (unsigned char)gpBuf[giRead]; + giRead++; + + return c; +} + +int READ_SHORT( void ) +{ + int c; + + if (giRead+2 > giSize) + { + giBadRead = true; + return -1; + } + + c = (short)( gpBuf[giRead] + ( gpBuf[giRead+1] << 8 ) ); + + giRead += 2; + + return c; +} + +int READ_WORD( void ) +{ + return READ_SHORT(); +} + + +int READ_LONG( void ) +{ + int c; + + if (giRead+4 > giSize) + { + giBadRead = true; + return -1; + } + + c = gpBuf[giRead] + (gpBuf[giRead + 1] << 8) + (gpBuf[giRead + 2] << 16) + (gpBuf[giRead + 3] << 24); + + giRead += 4; + + return c; +} + +float READ_FLOAT( void ) +{ + union + { + byte b[4]; + float f; + int l; + } dat; + + dat.b[0] = gpBuf[giRead]; + dat.b[1] = gpBuf[giRead+1]; + dat.b[2] = gpBuf[giRead+2]; + dat.b[3] = gpBuf[giRead+3]; + giRead += 4; + +// dat.l = LittleLong (dat.l); + + return dat.f; +} + +char* READ_STRING( void ) +{ + static char string[2048]; + int l,c; + + string[0] = 0; + + l = 0; + do + { + if ( giRead+1 > giSize ) + break; // no more characters + + c = READ_CHAR(); + if (c == -1 || c == 0) + break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + + string[l] = 0; + + return string; +} + +float READ_COORD( void ) +{ + return (float)(READ_SHORT() * (1.0/8)); +} + +float READ_ANGLE( void ) +{ + return (float)(READ_CHAR() * (360.0/256)); +} + +float READ_HIRESANGLE( void ) +{ + return (float)(READ_SHORT() * (360.0/65536)); +} + diff --git a/cl_dll/parsemsg.h b/cl_dll/parsemsg.h new file mode 100644 index 00000000..ab8ff154 --- /dev/null +++ b/cl_dll/parsemsg.h @@ -0,0 +1,40 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// parsemsg.h +// + +#define ASSERT( x ) + +void BEGIN_READ( void *buf, int size ); +int READ_CHAR( void ); +int READ_BYTE( void ); +int READ_SHORT( void ); +int READ_WORD( void ); +int READ_LONG( void ); +float READ_FLOAT( void ); +char* READ_STRING( void ); +float READ_COORD( void ); +float READ_ANGLE( void ); +float READ_HIRESANGLE( void ); + + + + + + + + + diff --git a/client/readme.txt b/cl_dll/readme.txt similarity index 100% rename from client/readme.txt rename to cl_dll/readme.txt diff --git a/cl_dll/saytext.cpp b/cl_dll/saytext.cpp new file mode 100644 index 00000000..7f24cf4e --- /dev/null +++ b/cl_dll/saytext.cpp @@ -0,0 +1,321 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// saytext.cpp +// +// implementation of CHudSayText class +// + +#include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include + +#include "vgui_TeamFortressViewport.h" + +extern float *GetClientColor( int clientIndex ); + +#define MAX_LINES 5 +#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */ + +// allow 20 pixels on either side of the text +#define MAX_LINE_WIDTH ( ScreenWidth - 40 ) +#define LINE_START 10 +static float SCROLL_SPEED = 5; + +static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; +static float *g_pflNameColors[ MAX_LINES + 1 ]; +static int g_iNameLengths[ MAX_LINES + 1 ]; +static float flScrollTime = 0; // the time at which the lines next scroll up + +static int Y_START = 0; +static int line_height = 0; + +DECLARE_MESSAGE( m_SayText, SayText ); + +int CHudSayText :: Init( void ) +{ + gHUD.AddHudElem( this ); + + HOOK_MESSAGE( SayText ); + + InitHUDData(); + + m_HUD_saytext = gEngfuncs.pfnRegisterVariable( "hud_saytext", "1", 0 ); + m_HUD_saytext_time = gEngfuncs.pfnRegisterVariable( "hud_saytext_time", "5", 0 ); + + m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission + + return 1; +} + + +void CHudSayText :: InitHUDData( void ) +{ + memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); + memset( g_pflNameColors, 0, sizeof g_pflNameColors ); + memset( g_iNameLengths, 0, sizeof g_iNameLengths ); +} + +int CHudSayText :: VidInit( void ) +{ + return 1; +} + + +int ScrollTextUp( void ) +{ + ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer + g_szLineBuffer[MAX_LINES][0] = 0; + memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line + memmove( &g_pflNameColors[0], &g_pflNameColors[1], sizeof(g_pflNameColors) - sizeof(g_pflNameColors[0]) ); + memmove( &g_iNameLengths[0], &g_iNameLengths[1], sizeof(g_iNameLengths) - sizeof(g_iNameLengths[0]) ); + g_szLineBuffer[MAX_LINES-1][0] = 0; + + if ( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines + { + g_szLineBuffer[0][0] = 2; + return 1 + ScrollTextUp(); + } + + return 1; +} + +int CHudSayText :: Draw( float flTime ) +{ + int y = Y_START; + + if ( ( gViewPort && gViewPort->AllowedToPrintText() == FALSE) || !m_HUD_saytext->value ) + return 1; + + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset + flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); + + // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset + flScrollTime = min( flScrollTime, flTime + m_HUD_saytext_time->value ); + + if ( flScrollTime <= flTime ) + { + if ( *g_szLineBuffer[0] ) + { + flScrollTime = flTime + m_HUD_saytext_time->value; + // push the console up + ScrollTextUp(); + } + else + { // buffer is empty, just disable drawing of this section + m_iFlags &= ~HUD_ACTIVE; + } + } + + for ( int i = 0; i < MAX_LINES; i++ ) + { + if ( *g_szLineBuffer[i] ) + { + if ( *g_szLineBuffer[i] == 2 && g_pflNameColors[i] ) + { + // it's a saytext string + static char buf[MAX_PLAYER_NAME_LENGTH+32]; + + // draw the first x characters in the player color + strncpy( buf, g_szLineBuffer[i], min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+32) ); + buf[ min(g_iNameLengths[i], MAX_PLAYER_NAME_LENGTH+31) ] = 0; + gEngfuncs.pfnDrawSetTextColor( g_pflNameColors[i][0], g_pflNameColors[i][1], g_pflNameColors[i][2] ); + int x = DrawConsoleString( LINE_START, y, buf ); + + // color is reset after each string draw + DrawConsoleString( x, y, g_szLineBuffer[i] + g_iNameLengths[i] ); + } + else + { + // normal draw + DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); + } + } + + y += line_height; + } + + + return 1; +} + +int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int client_index = READ_BYTE(); // the client who spoke the message + SayTextPrint( READ_STRING(), iSize - 1, client_index ); + + return 1; +} + +void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) +{ + if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) + { + // Print it straight to the console + ConsolePrint( pszBuf ); + return; + } + + // find an empty string slot + for ( int i = 0; i < MAX_LINES; i++ ) + { + if ( ! *g_szLineBuffer[i] ) + break; + } + if ( i == MAX_LINES ) + { + // force scroll buffer up + ScrollTextUp(); + i = MAX_LINES - 1; + } + + g_iNameLengths[i] = 0; + g_pflNameColors[i] = NULL; + + // if it's a say message, search for the players name in the string + if ( *pszBuf == 2 && clientIndex > 0 ) + { + GetPlayerInfo( clientIndex, &g_PlayerInfoList[clientIndex] ); + const char *pName = g_PlayerInfoList[clientIndex].name; + + if ( pName ) + { + const char *nameInString = strstr( pszBuf, pName ); + + if ( nameInString ) + { + g_iNameLengths[i] = strlen( pName ) + (nameInString - pszBuf); + g_pflNameColors[i] = GetClientColor( clientIndex ); + } + } + } + + strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) ); + + // make sure the text fits in one line + EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); + + // Set scroll time + if ( i == 0 ) + { + flScrollTime = gHUD.m_flTime + m_HUD_saytext_time->value; + } + + m_iFlags |= HUD_ACTIVE; + PlaySound( "misc/talk.wav", 1 ); + + if ( ScreenHeight >= 480 ) + Y_START = ScreenHeight - 60; + else + Y_START = ScreenHeight - 45; + Y_START -= (line_height * (MAX_LINES+1)); + +} + +void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) +{ + int line_width = 0; + GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); + + if ( (line_width + LINE_START) > MAX_LINE_WIDTH ) + { // string is too long to fit on line + // scan the string until we find what word is too long, and wrap the end of the sentence after the word + int length = LINE_START; + int tmp_len = 0; + char *last_break = NULL; + for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) + { + // check for a color change, if so skip past it + if ( x[0] == '/' && x[1] == '(' ) + { + x += 2; + // skip forward until past mode specifier + while ( *x != 0 && *x != ')' ) + x++; + + if ( *x != 0 ) + x++; + + if ( *x == 0 ) + break; + } + + char buf[2]; + buf[1] = 0; + + if ( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character + last_break = x; + + buf[0] = *x; // get the length of the current character + GetConsoleStringSize( buf, &tmp_len, &line_height ); + length += tmp_len; + + if ( length > MAX_LINE_WIDTH ) + { // needs to be broken up + if ( !last_break ) + last_break = x-1; + + x = last_break; + + // find an empty string slot + int j; + do + { + for ( j = 0; j < MAX_LINES; j++ ) + { + if ( ! *g_szLineBuffer[j] ) + break; + } + if ( j == MAX_LINES ) + { + // need to make more room to display text, scroll stuff up then fix the pointers + int linesmoved = ScrollTextUp(); + line -= linesmoved; + last_break = last_break - (sizeof(g_szLineBuffer[0]) * linesmoved); + } + } + while ( j == MAX_LINES ); + + // copy remaining string into next buffer, making sure it starts with a space character + if ( (char)*last_break == (char)' ' ) + { + int linelen = strlen(g_szLineBuffer[j]); + int remaininglen = strlen(last_break); + + if ( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) + strcat( g_szLineBuffer[j], last_break ); + } + else + { + if ( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) + { + strcat( g_szLineBuffer[j], " " ); + strcat( g_szLineBuffer[j], last_break ); + } + } + + *last_break = 0; // cut off the last string + + EnsureTextFitsInOneLineAndWrapIfHaveTo( j ); + break; + } + } + } +} \ No newline at end of file diff --git a/cl_dll/soundsystem.cpp b/cl_dll/soundsystem.cpp new file mode 100644 index 00000000..a25084c4 --- /dev/null +++ b/cl_dll/soundsystem.cpp @@ -0,0 +1,162 @@ +//======== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. ======== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= +#include +#include +#include +#include "r_studioint.h" + +extern engine_studio_api_t IEngineStudio; + +#define RENDERTYPE_UNDEFINED 0 +#define RENDERTYPE_SOFTWARE 1 +#define RENDERTYPE_HARDWARE 2 + +#define ENGINE_LAUNCHER_API_VERSION 1 + +LPDIRECTSOUND lpDS = NULL; +LPDIRECTSOUNDBUFFER lpDSBuf = NULL; +LPHWAVEOUT lpHW = NULL; + +static HMODULE hEngine = 0; + +typedef struct engine_api_s +{ + int version; + int rendertype; + int size; + + // Functions + void ( *unused1 ) ( void ); + void ( *unused2 ) ( void ); + void ( *unused3 ) ( void ); + void ( *unused4 ) ( void ); + void ( *unused5 ) ( void ); + void ( *unused6 ) ( void ); + void ( *unused7 ) ( void ); + void ( *unused8 ) ( void ); + void ( *unused9 ) ( void ); + void ( *unused10 ) ( void ); + void ( *unused11 ) ( void ); + void ( *unused12 ) ( void ); + void ( *unused13 ) ( void ); + void ( *unused14 ) ( void ); + void ( *unused15 ) ( void ); + void ( *unused16 ) ( void ); + void ( *unused17 ) ( void ); + void ( *unused18 ) ( void ); + void ( *unused19 ) ( void ); + void ( *unused20 ) ( void ); + void ( *unused21 ) ( void ); + void ( *unused22 ) ( void ); + void ( *unused23 ) ( void ); + void ( *unused24 ) ( void ); + void ( *unused25 ) ( void ); + void ( *unused26 ) ( void ); + void ( *unused27 ) ( void ); + void ( *unused28 ) ( void ); + void ( *unused29 ) ( void ); + void ( *unused30 ) ( void ); + void ( *unused31 ) ( void ); + void ( *unused32 ) ( void ); + void ( *unused33 ) ( void ); + void ( *unused34 ) ( void ); + + void ( *S_GetDSPointer ) ( struct IDirectSound **lpDS, struct IDirectSoundBuffer **lpDSBuf ); + void *( *S_GetWAVPointer ) ( void ); + + void ( *unused35 ) ( void ); + void ( *unused36 ) ( void ); + void ( *unused37 ) ( void ); + void ( *unused38 ) ( void ); + void ( *unused39 ) ( void ); + void ( *unused40 ) ( void ); + void ( *unused41 ) ( void ); + void ( *unused42 ) ( void ); + void ( *unused43 ) ( void ); + void ( *unused44 ) ( void ); + void ( *unused45 ) ( void ); + void ( *unused46 ) ( void ); + void ( *unused47 ) ( void ); + void ( *unused48 ) ( void ); + void ( *unused49 ) ( void ); + void ( *unused50 ) ( void ); + void ( *unused51 ) ( void ); + void ( *unused52 ) ( void ); + void ( *unused53 ) ( void ); + void ( *unused54 ) ( void ); + void ( *unused55 ) ( void ); +} engine_api_t; + +static engine_api_t engineapi; + +typedef int (*engine_api_func)( int version, int size, struct engine_api_s *api ); + +//----------------------------------------------------------------------------- +// Purpose: Get launcher/engine interface from engine module +// Input : hMod - +// Output : int +//----------------------------------------------------------------------------- +int Eng_LoadFunctions( HMODULE hMod ) +{ + engine_api_func pfnEngineAPI; + + pfnEngineAPI = ( engine_api_func )GetProcAddress( hMod, "Sys_EngineAPI" ); + if ( !pfnEngineAPI ) + return 0; + + if ( !(*pfnEngineAPI)( ENGINE_LAUNCHER_API_VERSION, sizeof( engine_api_t ), &engineapi ) ) + return 0; + + // All is okay + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: Load proper engine .dll and get pointer to either DSound and primary buffer or HWAVEOUT ( NT 4.0, e.g. ) +//----------------------------------------------------------------------------- +void LoadSoundAPIs( void ) +{ + hEngine = ::LoadLibrary( IEngineStudio.IsHardware() ? "hw.dll" : "sw.dll" ); + if ( hEngine ) + { + if ( Eng_LoadFunctions( hEngine ) ) + { + if ( engineapi.S_GetDSPointer && engineapi.S_GetWAVPointer ) + { + engineapi.S_GetDSPointer(&lpDS, &lpDSBuf); + lpHW = (HWAVEOUT FAR *)engineapi.S_GetWAVPointer(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Close engine library, release sound pointers +//----------------------------------------------------------------------------- +void ShutdownSoundAPIs( void ) +{ + if( hEngine ) + { + FreeLibrary( hEngine ); + hEngine = 0; + } + + lpDS = 0; + lpDSBuf = 0; + lpHW = 0; +} diff --git a/client/hud/hud_icons.cpp b/cl_dll/status_icons.cpp similarity index 68% rename from client/hud/hud_icons.cpp rename to cl_dll/status_icons.cpp index 79643c39..5bbcec80 100644 --- a/client/hud/hud_icons.cpp +++ b/cl_dll/status_icons.cpp @@ -15,16 +15,24 @@ // // status_icons.cpp // -#include "extdll.h" -#include "utils.h" #include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include +#include +#include "parsemsg.h" +#include "event_api.h" DECLARE_MESSAGE( m_StatusIcons, StatusIcon ); int CHudStatusIcons::Init( void ) { HOOK_MESSAGE( StatusIcon ); + gHUD.AddHudElem( this ); + Reset(); return 1; @@ -32,6 +40,7 @@ int CHudStatusIcons::Init( void ) int CHudStatusIcons::VidInit( void ) { + return 1; } @@ -44,12 +53,14 @@ void CHudStatusIcons::Reset( void ) // Draw status icons along the left-hand side of the screen int CHudStatusIcons::Draw( float flTime ) { + if (gEngfuncs.IsSpectateOnly()) + return 1; // find starting position to draw from, along right-hand side of screen int x = 5; int y = ScreenHeight / 2; // loop through icon list, and draw any valid icons drawing up from the middle of screen - for( int i = 0; i < MAX_ICONSPRITES; i++ ) + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) { if ( m_IconList[i].spr ) { @@ -59,19 +70,20 @@ int CHudStatusIcons::Draw( float flTime ) SPR_DrawAdditive( 0, x, y, &m_IconList[i].rc ); } } + return 1; } // Message handler for StatusIcon message // accepts five values: -// byte : TRUE = ENABLE icon, FALSE = DISABLE icon -// string : the sprite name to display -// byte : red -// byte : green -// byte : blue +// byte : TRUE = ENABLE icon, FALSE = DISABLE icon +// string : the sprite name to display +// byte : red +// byte : green +// byte : blue int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *pbuf ) { - BEGIN_READ( pszName, iSize, pbuf ); + BEGIN_READ( pbuf, iSize ); int ShouldEnable = READ_BYTE(); char *pszIconName = READ_STRING(); @@ -87,33 +99,32 @@ int CHudStatusIcons::MsgFunc_StatusIcon( const char *pszName, int iSize, void *p { DisableIcon( pszIconName ); } - END_READ(); return 1; } // add the icon to the icon list, and set it's drawing color -void CHudStatusIcons::EnableIcon( char *pszIconName, byte red, byte green, byte blue ) +void CHudStatusIcons::EnableIcon( char *pszIconName, unsigned char red, unsigned char green, unsigned char blue ) { // check to see if the sprite is in the current list - for( int i = 0; i < MAX_ICONSPRITES; i++ ) + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) { if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) break; } - if( i == MAX_ICONSPRITES ) + if ( i == MAX_ICONSPRITES ) { // icon not in list, so find an empty slot to add to - for( i = 0; i < MAX_ICONSPRITES; i++ ) + for ( i = 0; i < MAX_ICONSPRITES; i++ ) { - if( !m_IconList[i].spr ) + if ( !m_IconList[i].spr ) break; } } // if we've run out of space in the list, overwrite the first icon - if( i == MAX_ICONSPRITES ) + if ( i == MAX_ICONSPRITES ) { i = 0; } @@ -128,23 +139,24 @@ void CHudStatusIcons::EnableIcon( char *pszIconName, byte red, byte green, byte m_IconList[i].b = blue; strcpy( m_IconList[i].szSpriteName, pszIconName ); - // HACKHACK: Play Timer sound when a grenade icon is played (in 0.8 seconds) - if( strstr( m_IconList[i].szSpriteName, "grenade" )) + // Hack: Play Timer sound when a grenade icon is played (in 0.8 seconds) + if ( strstr(m_IconList[i].szSpriteName, "grenade") ) { - PlaySound( "weapons/timer.wav", 1.0 ); + cl_entity_t *pthisplayer = gEngfuncs.GetLocalPlayer(); + gEngfuncs.pEventAPI->EV_PlaySound( pthisplayer->index, pthisplayer->origin, CHAN_STATIC, "weapons/timer.wav", 1.0, ATTN_NORM, 0, PITCH_NORM ); } } void CHudStatusIcons::DisableIcon( char *pszIconName ) { // find the sprite is in the current list - for( int i = 0; i < MAX_ICONSPRITES; i++ ) + for ( int i = 0; i < MAX_ICONSPRITES; i++ ) { - if( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) + if ( !stricmp( m_IconList[i].szSpriteName, pszIconName ) ) { // clear the item from the list memset( &m_IconList[i], 0, sizeof icon_sprite_t ); return; } } -} \ No newline at end of file +} diff --git a/client/hud/hud_statusbar.cpp b/cl_dll/statusbar.cpp similarity index 77% rename from client/hud/hud_statusbar.cpp rename to cl_dll/statusbar.cpp index 5d29dd52..28018da9 100644 --- a/client/hud/hud_statusbar.cpp +++ b/cl_dll/statusbar.cpp @@ -19,15 +19,21 @@ // runs across bottom of screen // -#include "extdll.h" -#include "utils.h" #include "hud.h" +#include "cl_util.h" +#include "parsemsg.h" + +#include +#include DECLARE_MESSAGE( m_StatusBar, StatusText ); DECLARE_MESSAGE( m_StatusBar, StatusValue ); #define STATUSBAR_ID_LINE 1 +float *GetClientColor( int clientIndex ); +extern float g_ColorYellow[3]; + int CHudStatusBar :: Init( void ) { gHUD.AddHudElem( this ); @@ -37,7 +43,7 @@ int CHudStatusBar :: Init( void ) Reset(); - CVAR_REGISTER( "hud_centerid", "0", FCVAR_ARCHIVE ); + CVAR_CREATE( "hud_centerid", "0", FCVAR_ARCHIVE ); return 1; } @@ -59,6 +65,10 @@ void CHudStatusBar :: Reset( void ) memset( m_iStatusValues, 0, sizeof m_iStatusValues ); m_iStatusValues[0] = 1; // 0 is the special index, which always returns true + + // reset our colors for the status bar lines (yellow is default) + for ( i = 0; i < MAX_STATUSBAR_LINES; i++ ) + m_pflNameColors[i] = g_ColorYellow; } void CHudStatusBar :: ParseStatusString( int line_num ) @@ -128,15 +138,17 @@ void CHudStatusBar :: ParseStatusString( int line_num ) switch ( valtype ) { case 'p': // player name - GetPlayerInfo( indexval, &gHUD.m_Scoreboard.m_PlayerInfoList[indexval] ); - if ( gHUD.m_Scoreboard.m_PlayerInfoList[indexval].name != NULL ) + GetPlayerInfo( indexval, &g_PlayerInfoList[indexval] ); + if ( g_PlayerInfoList[indexval].name != NULL ) { - strncpy( szRepString, gHUD.m_Scoreboard.m_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); + strncpy( szRepString, g_PlayerInfoList[indexval].name, MAX_PLAYER_NAME_LENGTH ); + m_pflNameColors[line_num] = GetClientColor( indexval ); } else { strcpy( szRepString, "******" ); } + break; case 'i': // number sprintf( szRepString, "%d", indexval ); @@ -165,7 +177,10 @@ int CHudStatusBar :: Draw( float fTime ) if ( m_bReparseString ) { for ( int i = 0; i < MAX_STATUSBAR_LINES; i++ ) + { + m_pflNameColors[i] = g_ColorYellow; ParseStatusString( i ); + } m_bReparseString = FALSE; } @@ -177,16 +192,19 @@ int CHudStatusBar :: Draw( float fTime ) int TextHeight, TextWidth; GetConsoleStringSize( m_szStatusBar[i], &TextWidth, &TextHeight ); - int Y_START = ScreenHeight - 45; int x = 4; int y = Y_START - ( 4 + TextHeight * i ); // draw along bottom of screen // let user set status ID bar centering - if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT( "hud_centerid" )) + if ( (i == STATUSBAR_ID_LINE) && CVAR_GET_FLOAT("hud_centerid") ) { - x = max( 0, max( 2, (ScreenWidth - TextWidth)) / 2 ); - y = (ScreenHeight / 2) + (TextHeight * CVAR_GET_FLOAT( "hud_centerid" )); + x = max( 0, max(2, (ScreenWidth - TextWidth)) / 2 ); + y = (ScreenHeight / 2) + (TextHeight*CVAR_GET_FLOAT("hud_centerid")); } + + if ( m_pflNameColors[i] ) + gEngfuncs.pfnDrawSetTextColor( m_pflNameColors[i][0], m_pflNameColors[i][1], m_pflNameColors[i][2] ); + DrawConsoleString( x, y, m_szStatusBar[i] ); } @@ -195,8 +213,8 @@ int CHudStatusBar :: Draw( float fTime ) // Message handler for StatusText message // accepts two values: -// byte: line number of status bar text -// string: status bar text +// byte: line number of status bar text +// string: status bar text // this string describes how the status bar should be drawn // a semi-regular expression: // ( slotnum ([a..z] [%pX] [%iX])*)* @@ -205,10 +223,9 @@ int CHudStatusBar :: Draw( float fTime ) // if StatusValue[slotnum] != 0, the following string is drawn, upto the next newline - otherwise the text is skipped upto next newline // %pX, where X is an integer, will substitute a player name here, getting the player index from StatusValue[X] // %iX, where X is an integer, will substitute a number here, getting the number from StatusValue[X] - int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *pbuf ) { - BEGIN_READ( pszName, iSize, pbuf ); + BEGIN_READ( pbuf, iSize ); int line = READ_BYTE(); @@ -218,31 +235,31 @@ int CHudStatusBar :: MsgFunc_StatusText( const char *pszName, int iSize, void *p strncpy( m_szStatusText[line], READ_STRING(), MAX_STATUSTEXT_LENGTH ); m_szStatusText[line][MAX_STATUSTEXT_LENGTH-1] = 0; // ensure it's null terminated ( strncpy() won't null terminate if read string too long) - if( m_szStatusText[0] == 0 ) + if ( m_szStatusText[0] == 0 ) m_iFlags &= ~HUD_ACTIVE; - else m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar + else + m_iFlags |= HUD_ACTIVE; // we have status text, so turn on the status bar m_bReparseString = TRUE; - END_READ(); return 1; } // Message handler for StatusText message // accepts two values: -// byte: index into the status value array -// short: value to store +// byte: index into the status value array +// short: value to store int CHudStatusBar :: MsgFunc_StatusValue( const char *pszName, int iSize, void *pbuf ) { - BEGIN_READ( pszName, iSize, pbuf ); + BEGIN_READ( pbuf, iSize ); int index = READ_BYTE(); - if( index < 1 || index >= MAX_STATUSBAR_VALUES ) + if ( index < 1 || index >= MAX_STATUSBAR_VALUES ) return 1; // index out of range m_iStatusValues[index] = READ_SHORT(); + m_bReparseString = TRUE; - END_READ(); return 1; } \ No newline at end of file diff --git a/cl_dll/studio_util.cpp b/cl_dll/studio_util.cpp new file mode 100644 index 00000000..ab14d96e --- /dev/null +++ b/cl_dll/studio_util.cpp @@ -0,0 +1,251 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "com_model.h" +#include "studio_util.h" + +/* +==================== +AngleMatrix + +==================== +*/ +void AngleMatrix (const float *angles, float (*matrix)[4] ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + angle = angles[YAW] * (M_PI*2 / 360); + sy = sin(angle); + cy = cos(angle); + angle = angles[PITCH] * (M_PI*2 / 360); + sp = sin(angle); + cp = cos(angle); + angle = angles[ROLL] * (M_PI*2 / 360); + sr = sin(angle); + cr = cos(angle); + + // matrix = (YAW * PITCH) * ROLL + matrix[0][0] = cp*cy; + matrix[1][0] = cp*sy; + matrix[2][0] = -sp; + matrix[0][1] = sr*sp*cy+cr*-sy; + matrix[1][1] = sr*sp*sy+cr*cy; + matrix[2][1] = sr*cp; + matrix[0][2] = (cr*sp*cy+-sr*-sy); + matrix[1][2] = (cr*sp*sy+-sr*cy); + matrix[2][2] = cr*cp; + matrix[0][3] = 0.0; + matrix[1][3] = 0.0; + matrix[2][3] = 0.0; +} + +/* +==================== +VectorCompare + +==================== +*/ +int VectorCompare (const float *v1, const float *v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (v1[i] != v2[i]) + return 0; + + return 1; +} + +/* +==================== +CrossProduct + +==================== +*/ +void CrossProduct (const float *v1, const float *v2, float *cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +/* +==================== +VectorTransform + +==================== +*/ +void VectorTransform (const float *in1, float in2[3][4], float *out) +{ + out[0] = DotProduct(in1, in2[0]) + in2[0][3]; + out[1] = DotProduct(in1, in2[1]) + in2[1][3]; + out[2] = DotProduct(in1, in2[2]) + in2[2][3]; +} + +/* +================ +ConcatTransforms + +================ +*/ +void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]) +{ + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + + in1[0][2] * in2[2][3] + in1[0][3]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + + in1[1][2] * in2[2][3] + in1[1][3]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; + out[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + + in1[2][2] * in2[2][3] + in1[2][3]; +} + +// angles index are not the same as ROLL, PITCH, YAW + +/* +==================== +AngleQuaternion + +==================== +*/ +void AngleQuaternion( float *angles, vec4_t quaternion ) +{ + float angle; + float sr, sp, sy, cr, cp, cy; + + // FIXME: rescale the inputs to 1/2 angle + angle = angles[2] * 0.5; + sy = sin(angle); + cy = cos(angle); + angle = angles[1] * 0.5; + sp = sin(angle); + cp = cos(angle); + angle = angles[0] * 0.5; + sr = sin(angle); + cr = cos(angle); + + quaternion[0] = sr*cp*cy-cr*sp*sy; // X + quaternion[1] = cr*sp*cy+sr*cp*sy; // Y + quaternion[2] = cr*cp*sy-sr*sp*cy; // Z + quaternion[3] = cr*cp*cy+sr*sp*sy; // W +} + +/* +==================== +QuaternionSlerp + +==================== +*/ +void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ) +{ + int i; + float omega, cosom, sinom, sclp, sclq; + + // decide if one of the quaternions is backwards + float a = 0; + float b = 0; + + for (i = 0; i < 4; i++) + { + a += (p[i]-q[i])*(p[i]-q[i]); + b += (p[i]+q[i])*(p[i]+q[i]); + } + if (a > b) + { + for (i = 0; i < 4; i++) + { + q[i] = -q[i]; + } + } + + cosom = p[0]*q[0] + p[1]*q[1] + p[2]*q[2] + p[3]*q[3]; + + if ((1.0 + cosom) > 0.000001) + { + if ((1.0 - cosom) > 0.000001) + { + omega = acos( cosom ); + sinom = sin( omega ); + sclp = sin( (1.0 - t)*omega) / sinom; + sclq = sin( t*omega ) / sinom; + } + else + { + sclp = 1.0 - t; + sclq = t; + } + for (i = 0; i < 4; i++) { + qt[i] = sclp * p[i] + sclq * q[i]; + } + } + else + { + qt[0] = -q[1]; + qt[1] = q[0]; + qt[2] = -q[3]; + qt[3] = q[2]; + sclp = sin( (1.0 - t) * (0.5 * M_PI)); + sclq = sin( t * (0.5 * M_PI)); + for (i = 0; i < 3; i++) + { + qt[i] = sclp * p[i] + sclq * qt[i]; + } + } +} + +/* +==================== +QuaternionMatrix + +==================== +*/ +void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ) +{ + matrix[0][0] = 1.0 - 2.0 * quaternion[1] * quaternion[1] - 2.0 * quaternion[2] * quaternion[2]; + matrix[1][0] = 2.0 * quaternion[0] * quaternion[1] + 2.0 * quaternion[3] * quaternion[2]; + matrix[2][0] = 2.0 * quaternion[0] * quaternion[2] - 2.0 * quaternion[3] * quaternion[1]; + + matrix[0][1] = 2.0 * quaternion[0] * quaternion[1] - 2.0 * quaternion[3] * quaternion[2]; + matrix[1][1] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[2] * quaternion[2]; + matrix[2][1] = 2.0 * quaternion[1] * quaternion[2] + 2.0 * quaternion[3] * quaternion[0]; + + matrix[0][2] = 2.0 * quaternion[0] * quaternion[2] + 2.0 * quaternion[3] * quaternion[1]; + matrix[1][2] = 2.0 * quaternion[1] * quaternion[2] - 2.0 * quaternion[3] * quaternion[0]; + matrix[2][2] = 1.0 - 2.0 * quaternion[0] * quaternion[0] - 2.0 * quaternion[1] * quaternion[1]; +} + +/* +==================== +MatrixCopy + +==================== +*/ +void MatrixCopy( float in[3][4], float out[3][4] ) +{ + memcpy( out, in, sizeof( float ) * 3 * 4 ); +} \ No newline at end of file diff --git a/cl_dll/studio_util.h b/cl_dll/studio_util.h new file mode 100644 index 00000000..e1cb980e --- /dev/null +++ b/cl_dll/studio_util.h @@ -0,0 +1,40 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( STUDIO_UTIL_H ) +#define STUDIO_UTIL_H +#if defined( WIN32 ) +#pragma once +#endif + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +#ifndef PITCH +// MOVEMENT INFO +// up / down +#define PITCH 0 +// left / right +#define YAW 1 +// fall over +#define ROLL 2 +#endif + +#define FDotProduct( a, b ) (fabs((a[0])*(b[0])) + fabs((a[1])*(b[1])) + fabs((a[2])*(b[2]))) + +void AngleMatrix (const float *angles, float (*matrix)[4] ); +int VectorCompare (const float *v1, const float *v2); +void CrossProduct (const float *v1, const float *v2, float *cross); +void VectorTransform (const float *in1, float in2[3][4], float *out); +void ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]); +void MatrixCopy( float in[3][4], float out[3][4] ); +void QuaternionMatrix( vec4_t quaternion, float (*matrix)[4] ); +void QuaternionSlerp( vec4_t p, vec4_t q, float t, vec4_t qt ); +void AngleQuaternion( float *angles, vec4_t quaternion ); + +#endif // STUDIO_UTIL_H \ No newline at end of file diff --git a/client/hud/hud_text.cpp b/cl_dll/text_message.cpp similarity index 92% rename from client/hud/hud_text.cpp rename to cl_dll/text_message.cpp index 83e66b28..c18dd25f 100644 --- a/client/hud/hud_text.cpp +++ b/cl_dll/text_message.cpp @@ -20,9 +20,13 @@ // this class routes messages through titles.txt for localisation // -#include "extdll.h" -#include "utils.h" #include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" + +#include "vgui_TeamFortressViewport.h" DECLARE_MESSAGE( m_TextMessage, TextMsg ); @@ -155,7 +159,7 @@ char* ConvertCRtoNL( char *str ) // the next (optional) one to four strings are parameters for that string (which can also be message names if they begin with '#') int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf ) { - BEGIN_READ( pszName, iSize, pbuf ); + BEGIN_READ( pbuf, iSize ); int msg_dest = READ_BYTE(); @@ -178,27 +182,32 @@ int CHudTextMessage::MsgFunc_TextMsg( const char *pszName, int iSize, void *pbuf StripEndNewlineFromString( sstr4 ); char *psz = szBuf[5]; + if ( gViewPort && gViewPort->AllowedToPrintText() == FALSE ) + return 1; + switch ( msg_dest ) { case HUD_PRINTCENTER: sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); CenterPrint( ConvertCRtoNL( psz ) ); break; + case HUD_PRINTNOTIFY: psz[0] = 1; // mark this message to go into the notify buffer sprintf( psz+1, msg_text, sstr1, sstr2, sstr3, sstr4 ); ConsolePrint( ConvertCRtoNL( psz ) ); break; + case HUD_PRINTTALK: sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); gHUD.m_SayText.SayTextPrint( ConvertCRtoNL( psz ), 128 ); break; + case HUD_PRINTCONSOLE: sprintf( psz, msg_text, sstr1, sstr2, sstr3, sstr4 ); ConsolePrint( ConvertCRtoNL( psz ) ); break; } - END_READ(); return 1; } diff --git a/cl_dll/tf_defs.h b/cl_dll/tf_defs.h new file mode 100644 index 00000000..f178c55b --- /dev/null +++ b/cl_dll/tf_defs.h @@ -0,0 +1,1389 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +****/ + +#ifndef __TF_DEFS_H +#define __TF_DEFS_H + +//=========================================================================== +// OLD OPTIONS.QC +//=========================================================================== +#define DEFAULT_AUTOZOOM FALSE +#define WEINER_SNIPER // autoaiming for sniper rifle +#define FLAME_MAXWORLDNUM 20 // maximum number of flames in the world. DO NOT PUT BELOW 20. + +//#define MAX_WORLD_PIPEBOMBS 15 // This is divided between teams - this is the most you should have on a net server +#define MAX_PLAYER_PIPEBOMBS 8 // maximum number of pipebombs any 1 player can have active +#define MAX_PLAYER_AMMOBOXES 3 // maximum number of ammoboxes any 1 player can have active + +//#define MAX_WORLD_FLARES 9 // This is the total number of flares allowed in the world at one time +//#define MAX_WORLD_AMMOBOXES 20 // This is divided between teams - this is the most you should have on a net server +#define GR_TYPE_MIRV_NO 4 // Number of Mirvs a Mirv Grenade breaks into +#define GR_TYPE_NAPALM_NO 8 // Number of flames napalm grenade breaks into (unused if net server) +#define MEDIKIT_IS_BIOWEAPON // Medikit acts as a bioweapon against enemies + +#define TEAM_HELP_RATE 60 // used only if teamplay bit 64 (help team with lower score) is set. + // 60 is a mild setting, and won't make too much difference + // increasing it _decreases_ the amount of help the losing team gets + // Minimum setting is 1, which would really help the losing team + +#define DISPLAY_CLASS_HELP TRUE // Change this to #OFF if you don't want the class help to + // appear whenever a player connects +#define NEVER_TEAMFRAGS FALSE // teamfrags options always off +#define ALWAYS_TEAMFRAGS FALSE // teamfrags options always on +#define CHECK_SPEEDS TRUE // makes sure players aren't moving too fast +#define SNIPER_RIFLE_RELOAD_TIME 1.5 // seconds + +#define MAPBRIEFING_MAXTEXTLENGTH 512 +#define PLAYER_PUSH_VELOCITY 50 // Players push teammates if they're moving under this speed + +// Debug Options +//#define MAP_DEBUG // Debug for Map code. I suggest running in a hi-res + // mode and/or piping the output from the server to a file. +#ifdef MAP_DEBUG + #define MDEBUG(x) x +#else + #define MDEBUG(x) +#endif +//#define VERBOSE // Verbose Debugging on/off + +//=========================================================================== +// OLD QUAKE Defs +//=========================================================================== +// items +#define IT_AXE 4096 +#define IT_SHOTGUN 1 +#define IT_SUPER_SHOTGUN 2 +#define IT_NAILGUN 4 +#define IT_SUPER_NAILGUN 8 +#define IT_GRENADE_LAUNCHER 16 +#define IT_ROCKET_LAUNCHER 32 +#define IT_LIGHTNING 64 +#define IT_EXTRA_WEAPON 128 + +#define IT_SHELLS 256 +#define IT_NAILS 512 +#define IT_ROCKETS 1024 +#define IT_CELLS 2048 + +#define IT_ARMOR1 8192 +#define IT_ARMOR2 16384 +#define IT_ARMOR3 32768 +#define IT_SUPERHEALTH 65536 + +#define IT_KEY1 131072 +#define IT_KEY2 262144 + +#define IT_INVISIBILITY 524288 +#define IT_INVULNERABILITY 1048576 +#define IT_SUIT 2097152 +#define IT_QUAD 4194304 +#define IT_HOOK 8388608 + +#define IT_KEY3 16777216 // Stomp invisibility +#define IT_KEY4 33554432 // Stomp invulnerability + +//=========================================================================== +// TEAMFORTRESS Defs +//=========================================================================== +// TeamFortress State Flags +#define TFSTATE_GRENPRIMED 1 // Whether the player has a primed grenade +#define TFSTATE_RELOADING 2 // Whether the player is reloading +#define TFSTATE_ALTKILL 4 // #TRUE if killed with a weapon not in self.weapon: NOT USED ANYMORE +#define TFSTATE_RANDOMPC 8 // Whether Playerclass is random, new one each respawn +#define TFSTATE_INFECTED 16 // set when player is infected by the bioweapon +#define TFSTATE_INVINCIBLE 32 // Player has permanent Invincibility (Usually by GoalItem) +#define TFSTATE_INVISIBLE 64 // Player has permanent Invisibility (Usually by GoalItem) +#define TFSTATE_QUAD 128 // Player has permanent Quad Damage (Usually by GoalItem) +#define TFSTATE_RADSUIT 256 // Player has permanent Radsuit (Usually by GoalItem) +#define TFSTATE_BURNING 512 // Is on fire +#define TFSTATE_GRENTHROWING 1024 // is throwing a grenade +#define TFSTATE_AIMING 2048 // is using the laser sight +#define TFSTATE_ZOOMOFF 4096 // doesn't want the FOV changed when zooming +#define TFSTATE_RESPAWN_READY 8192 // is waiting for respawn, and has pressed fire +#define TFSTATE_HALLUCINATING 16384 // set when player is hallucinating +#define TFSTATE_TRANQUILISED 32768 // set when player is tranquilised +#define TFSTATE_CANT_MOVE 65536 // set when player is setting a detpack +#define TFSTATE_RESET_FLAMETIME 131072 // set when the player has to have his flames increased in health + +// Defines used by TF_T_Damage (see combat.qc) +#define TF_TD_IGNOREARMOUR 1 // Bypasses the armour of the target +#define TF_TD_NOTTEAM 2 // Doesn't damage a team member (indicates direct fire weapon) +#define TF_TD_NOTSELF 4 // Doesn't damage self + +#define TF_TD_OTHER 0 // Ignore armorclass +#define TF_TD_SHOT 1 // Bullet damage +#define TF_TD_NAIL 2 // Nail damage +#define TF_TD_EXPLOSION 4 // Explosion damage +#define TF_TD_ELECTRICITY 8 // Electric damage +#define TF_TD_FIRE 16 // Fire damage +#define TF_TD_NOSOUND 256 // Special damage. Makes no sound/painframe, etc + +/*==================================================*/ +/* Toggleable Game Settings */ +/*==================================================*/ +#define TF_RESPAWNDELAY1 5 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY2 10 // seconds of waiting before player can respawn +#define TF_RESPAWNDELAY3 20 // seconds of waiting before player can respawn + +#define TEAMPLAY_NORMAL 1 +#define TEAMPLAY_HALFDIRECT 2 +#define TEAMPLAY_NODIRECT 4 +#define TEAMPLAY_HALFEXPLOSIVE 8 +#define TEAMPLAY_NOEXPLOSIVE 16 +#define TEAMPLAY_LESSPLAYERSHELP 32 +#define TEAMPLAY_LESSSCOREHELP 64 +#define TEAMPLAY_HALFDIRECTARMOR 128 +#define TEAMPLAY_NODIRECTARMOR 256 +#define TEAMPLAY_HALFEXPARMOR 512 +#define TEAMPLAY_NOEXPARMOR 1024 +#define TEAMPLAY_HALFDIRMIRROR 2048 +#define TEAMPLAY_FULLDIRMIRROR 4096 +#define TEAMPLAY_HALFEXPMIRROR 8192 +#define TEAMPLAY_FULLEXPMIRROR 16384 + +#define TEAMPLAY_TEAMDAMAGE (TEAMPLAY_NODIRECT | TEAMPLAY_HALFDIRECT | TEAMPLAY_HALFEXPLOSIVE | TEAMPLAY_NOEXPLOSIVE) +// FortressMap stuff +#define TEAM1_CIVILIANS 1 +#define TEAM2_CIVILIANS 2 +#define TEAM3_CIVILIANS 4 +#define TEAM4_CIVILIANS 8 + +// Defines for the playerclass +#define PC_UNDEFINED 0 + +#define PC_SCOUT 1 +#define PC_SNIPER 2 +#define PC_SOLDIER 3 +#define PC_DEMOMAN 4 +#define PC_MEDIC 5 +#define PC_HVYWEAP 6 +#define PC_PYRO 7 +#define PC_SPY 8 +#define PC_ENGINEER 9 + +// Insert new class definitions here + +// PC_RANDOM _MUST_ be the third last class +#define PC_RANDOM 10 // Random playerclass +#define PC_CIVILIAN 11 // Civilians are a special class. They cannot + // be chosen by players, only enforced by maps +#define PC_LASTCLASS 12 // Use this as the high-boundary for any loops + // through the playerclass. + +#define SENTRY_COLOR 10 // will be in the PC_RANDOM slot for team colors + +// These are just for the scanner +#define SCAN_SENTRY 13 +#define SCAN_GOALITEM 14 + +// Values returned by CheckArea +enum +{ + CAREA_CLEAR, + CAREA_BLOCKED, + CAREA_NOBUILD +}; + +/*==================================================*/ +/* Impulse Defines */ +/*==================================================*/ +// Alias check to see whether they already have the aliases +#define TF_ALIAS_CHECK 13 + +// CTF Support Impulses +#define HOOK_IMP1 22 +#define FLAG_INFO 23 +#define HOOK_IMP2 39 + +// Axe +#define AXE_IMP 40 + +// Camera Impulse +#define TF_CAM_TARGET 50 +#define TF_CAM_ZOOM 51 +#define TF_CAM_ANGLE 52 +#define TF_CAM_VEC 53 +#define TF_CAM_PROJECTILE 54 +#define TF_CAM_PROJECTILE_Z 55 +#define TF_CAM_REVANGLE 56 +#define TF_CAM_OFFSET 57 +#define TF_CAM_DROP 58 +#define TF_CAM_FADETOBLACK 59 +#define TF_CAM_FADEFROMBLACK 60 +#define TF_CAM_FADETOWHITE 61 +#define TF_CAM_FADEFROMWHITE 62 + +// Last Weapon impulse +#define TF_LAST_WEAPON 69 + +// Status Bar Resolution Settings. Same as CTF to maintain ease of use. +#define TF_STATUSBAR_RES_START 71 +#define TF_STATUSBAR_RES_END 81 + +// Clan Messages +#define TF_MESSAGE_1 82 +#define TF_MESSAGE_2 83 +#define TF_MESSAGE_3 84 +#define TF_MESSAGE_4 85 +#define TF_MESSAGE_5 86 + +#define TF_CHANGE_CLASS 99 // Bring up the Class Change menu + +// Added to PC_??? to get impulse to use if this clashes with your +// own impulses, just change this value, not the PC_?? +#define TF_CHANGEPC 100 +// The next few impulses are all the class selections +//PC_SCOUT 101 +//PC_SNIPER 102 +//PC_SOLDIER 103 +//PC_DEMOMAN 104 +//PC_MEDIC 105 +//PC_HVYWEAP 106 +//PC_PYRO 107 +//PC_RANDOM 108 +//PC_CIVILIAN 109 // Cannot be used +//PC_SPY 110 +//PC_ENGINEER 111 + +// Help impulses +#define TF_DISPLAYLOCATION 118 +#define TF_STATUS_QUERY 119 + +#define TF_HELP_MAP 131 + +// Information impulses +#define TF_INVENTORY 135 +#define TF_SHOWTF 136 +#define TF_SHOWLEGALCLASSES 137 + +// Team Impulses +#define TF_TEAM_1 140 // Join Team 1 +#define TF_TEAM_2 141 // Join Team 2 +#define TF_TEAM_3 142 // Join Team 3 +#define TF_TEAM_4 143 // Join Team 4 +#define TF_TEAM_CLASSES 144 // Impulse to display team classes +#define TF_TEAM_SCORES 145 // Impulse to display team scores +#define TF_TEAM_LIST 146 // Impulse to display the players in each team. + +// Grenade Impulses +#define TF_GRENADE_1 150 // Prime grenade type 1 +#define TF_GRENADE_2 151 // Prime grenade type 2 +#define TF_GRENADE_T 152 // Throw primed grenade + +// Impulses for new items +//#define TF_SCAN 159 // Scanner Pre-Impulse +#define TF_AUTO_SCAN 159 // Scanner On/Off +#define TF_SCAN_ENEMY 160 // Impulses to toggle scanning of enemies +#define TF_SCAN_FRIENDLY 161 // Impulses to toggle scanning of friendlies +//#define TF_SCAN_10 162 // Scan using 10 enery (1 cell) +#define TF_SCAN_SOUND 162 // Scanner sounds on/off +#define TF_SCAN_30 163 // Scan using 30 energy (2 cells) +#define TF_SCAN_100 164 // Scan using 100 energy (5 cells) +#define TF_DETPACK_5 165 // Detpack set to 5 seconds +#define TF_DETPACK_20 166 // Detpack set to 20 seconds +#define TF_DETPACK_50 167 // Detpack set to 50 seconds +#define TF_DETPACK 168 // Detpack Pre-Impulse +#define TF_DETPACK_STOP 169 // Impulse to stop setting detpack +#define TF_PB_DETONATE 170 // Detonate Pipebombs + +// Special skill +#define TF_SPECIAL_SKILL 171 + +// Ammo Drop impulse +#define TF_DROP_AMMO 172 + +// Reload impulse +#define TF_RELOAD 173 + +// auto-zoom toggle +#define TF_AUTOZOOM 174 + +// drop/pass commands +#define TF_DROPKEY 175 + +// Select Medikit +#define TF_MEDIKIT 176 + +// Spy Impulses +#define TF_SPY_SPY 177 // On net, go invisible, on LAN, change skin/color +#define TF_SPY_DIE 178 // Feign Death + +// Engineer Impulses +#define TF_ENGINEER_BUILD 179 +#define TF_ENGINEER_SANDBAG 180 + +// Medic +#define TF_MEDIC_HELPME 181 + +// Status bar +#define TF_STATUSBAR_ON 182 +#define TF_STATUSBAR_OFF 183 + +// Discard impulse +#define TF_DISCARD 184 + +// ID Player impulse +#define TF_ID 185 + +// Clan Battle impulses +#define TF_SHOWIDS 186 + +// More Engineer Impulses +#define TF_ENGINEER_DETDISP 187 +#define TF_ENGINEER_DETSENT 188 + +// Admin Commands +#define TF_ADMIN_DEAL_CYCLE 189 +#define TF_ADMIN_KICK 190 +#define TF_ADMIN_BAN 191 +#define TF_ADMIN_COUNTPLAYERS 192 +#define TF_ADMIN_CEASEFIRE 193 + +// Drop Goal Items +#define TF_DROPGOALITEMS 194 + +// More Admin Commands +#define TF_ADMIN_NEXT 195 + +// More Engineer Impulses +#define TF_ENGINEER_DETEXIT 196 +#define TF_ENGINEER_DETENTRANCE 197 + +// Yet MORE Admin Commands +#define TF_ADMIN_LISTIPS 198 + +// Silent Spy Feign +#define TF_SPY_SILENTDIE 199 + + +/*==================================================*/ +/* Defines for the ENGINEER's Building ability */ +/*==================================================*/ +// Ammo costs +#define AMMO_COST_SHELLS 2 // Metal needed to make 1 shell +#define AMMO_COST_NAILS 1 +#define AMMO_COST_ROCKETS 2 +#define AMMO_COST_CELLS 2 + +// Building types +#define BUILD_DISPENSER 1 +#define BUILD_SENTRYGUN 2 +#define BUILD_MORTAR 3 +#define BUILD_TELEPORTER_ENTRANCE 4 +#define BUILD_TELEPORTER_EXIT 5 + +// Building metal costs +#define BUILD_COST_DISPENSER 100 // Metal needed to built +#define BUILD_COST_SENTRYGUN 130 +#define BUILD_COST_MORTAR 150 +#define BUILD_COST_TELEPORTER 125 + +#define BUILD_COST_SANDBAG 20 // Built with a separate alias + +// Building times +#define BUILD_TIME_DISPENSER 2 // seconds to build +#define BUILD_TIME_SENTRYGUN 5 +#define BUILD_TIME_MORTAR 5 +#define BUILD_TIME_TELEPORTER 4 + +// Building health levels +#define BUILD_HEALTH_DISPENSER 150 // Health of the building +#define BUILD_HEALTH_SENTRYGUN 150 +#define BUILD_HEALTH_MORTAR 200 +#define BUILD_HEALTH_TELEPORTER 80 + +// Dispenser's maximum carrying capability +#define BUILD_DISPENSER_MAX_SHELLS 400 +#define BUILD_DISPENSER_MAX_NAILS 600 +#define BUILD_DISPENSER_MAX_ROCKETS 300 +#define BUILD_DISPENSER_MAX_CELLS 400 +#define BUILD_DISPENSER_MAX_ARMOR 500 + +// Build state sent down to client +#define BS_BUILDING (1<<0) +#define BS_HAS_DISPENSER (1<<1) +#define BS_HAS_SENTRYGUN (1<<2) +#define BS_CANB_DISPENSER (1<<3) +#define BS_CANB_SENTRYGUN (1<<4) +/*==================================================*/ +/* Ammo quantities for dropping & dispenser use */ +/*==================================================*/ +#define DROP_SHELLS 20 +#define DROP_NAILS 20 +#define DROP_ROCKETS 10 +#define DROP_CELLS 10 +#define DROP_ARMOR 40 + +/*==================================================*/ +/* Team Defines */ +/*==================================================*/ +#define TM_MAX_NO 4 // Max number of teams. Simply changing this value isn't enough. + // A new global to hold new team colors is needed, and more flags + // in the spawnpoint spawnflags may need to be used. + // Basically, don't change this unless you know what you're doing :) + +/*==================================================*/ +/* New Weapon Defines */ +/*==================================================*/ +#define WEAP_HOOK 1 +#define WEAP_BIOWEAPON 2 +#define WEAP_MEDIKIT 4 +#define WEAP_SPANNER 8 +#define WEAP_AXE 16 +#define WEAP_SNIPER_RIFLE 32 +#define WEAP_AUTO_RIFLE 64 +#define WEAP_SHOTGUN 128 +#define WEAP_SUPER_SHOTGUN 256 +#define WEAP_NAILGUN 512 +#define WEAP_SUPER_NAILGUN 1024 +#define WEAP_GRENADE_LAUNCHER 2048 +#define WEAP_FLAMETHROWER 4096 +#define WEAP_ROCKET_LAUNCHER 8192 +#define WEAP_INCENDIARY 16384 +#define WEAP_ASSAULT_CANNON 32768 +#define WEAP_LIGHTNING 65536 +#define WEAP_DETPACK 131072 +#define WEAP_TRANQ 262144 +#define WEAP_LASER 524288 +// still room for 12 more weapons +// but we can remove some by giving the weapons +// a weapon mode (like the rifle) + +// HL-compatible weapon numbers +#define WEAPON_HOOK 1 +#define WEAPON_BIOWEAPON (WEAPON_HOOK+1) +#define WEAPON_MEDIKIT (WEAPON_HOOK+2) +#define WEAPON_SPANNER (WEAPON_HOOK+3) +#define WEAPON_AXE (WEAPON_HOOK+4) +#define WEAPON_SNIPER_RIFLE (WEAPON_HOOK+5) +#define WEAPON_AUTO_RIFLE (WEAPON_HOOK+6) +#define WEAPON_TF_SHOTGUN (WEAPON_HOOK+7) +#define WEAPON_SUPER_SHOTGUN (WEAPON_HOOK+8) +#define WEAPON_NAILGUN (WEAPON_HOOK+9) +#define WEAPON_SUPER_NAILGUN (WEAPON_HOOK+10) +#define WEAPON_GRENADE_LAUNCHER (WEAPON_HOOK+11) +#define WEAPON_FLAMETHROWER (WEAPON_HOOK+12) +#define WEAPON_ROCKET_LAUNCHER (WEAPON_HOOK+13) +#define WEAPON_INCENDIARY (WEAPON_HOOK+14) +#define WEAPON_ASSAULT_CANNON (WEAPON_HOOK+16) +#define WEAPON_LIGHTNING (WEAPON_HOOK+17) +#define WEAPON_DETPACK (WEAPON_HOOK+18) +#define WEAPON_TRANQ (WEAPON_HOOK+19) +#define WEAPON_LASER (WEAPON_HOOK+20) +#define WEAPON_PIPEBOMB_LAUNCHER (WEAPON_HOOK+21) +#define WEAPON_KNIFE (WEAPON_HOOK+22) +#define WEAPON_BENCHMARK (WEAPON_HOOK+23) + +/*==================================================*/ +/* New Weapon Related Defines */ +/*==================================================*/ +// shots per reload +#define RE_SHOTGUN 8 +#define RE_SUPER_SHOTGUN 16 // 8 shots +#define RE_GRENADE_LAUNCHER 6 +#define RE_ROCKET_LAUNCHER 4 + +// reload times +#define RE_SHOTGUN_TIME 2 +#define RE_SUPER_SHOTGUN_TIME 3 +#define RE_GRENADE_LAUNCHER_TIME 4 +#define RE_ROCKET_LAUNCHER_TIME 5 + +// Maximum velocity you can move and fire the Sniper Rifle +#define WEAP_SNIPER_RIFLE_MAX_MOVE 50 + +// Medikit +#define WEAP_MEDIKIT_HEAL 200 // Amount medikit heals per hit +#define WEAP_MEDIKIT_OVERHEAL 50 // Amount of superhealth over max_health the medikit will dispense + +// Spanner +#define WEAP_SPANNER_REPAIR 10 + +// Detpack +#define WEAP_DETPACK_DISARMTIME 3 // Time it takes to disarm a Detpack +#define WEAP_DETPACK_SETTIME 3 // Time it takes to set a Detpack +#define WEAP_DETPACK_SIZE 700 // Explosion Size +#define WEAP_DETPACK_GOAL_SIZE 1500 // Explosion Size for goal triggering +#define WEAP_DETPACK_BITS_NO 12 // Bits that detpack explodes into + +// Tranquiliser Gun +#define TRANQ_TIME 15 + +// Grenades +#define GR_PRIMETIME 3 +#define GR_CALTROP_PRIME 0.5 +#define GR_TYPE_NONE 0 +#define GR_TYPE_NORMAL 1 +#define GR_TYPE_CONCUSSION 2 +#define GR_TYPE_NAIL 3 +#define GR_TYPE_MIRV 4 +#define GR_TYPE_NAPALM 5 +//#define GR_TYPE_FLARE 6 +#define GR_TYPE_GAS 7 +#define GR_TYPE_EMP 8 +#define GR_TYPE_CALTROP 9 +//#define GR_TYPE_FLASH 10 + +// Defines for WeaponMode +#define GL_NORMAL 0 +#define GL_PIPEBOMB 1 + +// Defines for OLD Concussion Grenade +#define GR_OLD_CONCUSS_TIME 5 +#define GR_OLD_CONCUSS_DEC 20 + +// Defines for Concussion Grenade +#define GR_CONCUSS_TIME 0.25 +#define GR_CONCUSS_DEC 10 +#define MEDIUM_PING 150 +#define HIGH_PING 200 + +// Defines for the Gas Grenade +#define GR_HALLU_TIME 0.3 +#define GR_OLD_HALLU_TIME 0.5 +#define GR_HALLU_DEC 2.5 + +// Defines for the BioInfection +#define BIO_JUMP_RADIUS 128 // The distance the bioinfection can jump between players + +/*==================================================*/ +/* New Items */ +/*==================================================*/ +#define NIT_SCANNER 1 + +#define NIT_SILVER_DOOR_OPENED #IT_KEY1 // 131072 +#define NIT_GOLD_DOOR_OPENED #IT_KEY2 // 262144 + +/*==================================================*/ +/* New Item Flags */ +/*==================================================*/ +#define NIT_SCANNER_ENEMY 1 // Detect enemies +#define NIT_SCANNER_FRIENDLY 2 // Detect friendlies (team members) +#define NIT_SCANNER_SOUND 4 // Motion detection. Only report moving entities. + +/*==================================================*/ +/* New Item Related Defines */ +/*==================================================*/ +#define NIT_SCANNER_POWER 25 // The amount of power spent on a scan with the scanner + // is multiplied by this to get the scanrange. +#define NIT_SCANNER_MAXCELL 50 // The maximum number of cells than can be used in one scan +#define NIT_SCANNER_MIN_MOVEMENT 50 // The minimum velocity an entity must have to be detected + // by scanners that only detect movement + +/*==================================================*/ +/* Variables used for New Weapons and Reloading */ +/*==================================================*/ +// Armor Classes : Bitfields. Use the "armorclass" of armor for the Armor Type. +#define AT_SAVESHOT 1 // Kevlar : Reduces bullet damage by 15% +#define AT_SAVENAIL 2 // Wood :) : Reduces nail damage by 15% +#define AT_SAVEEXPLOSION 4 // Blast : Reduces explosion damage by 15% +#define AT_SAVEELECTRICITY 8 // Shock : Reduces electricity damage by 15% +#define AT_SAVEFIRE 16 // Asbestos : Reduces fire damage by 15% + +/*==========================================================================*/ +/* TEAMFORTRESS CLASS DETAILS */ +/*==========================================================================*/ +// Class Details for SCOUT +#define PC_SCOUT_SKIN 4 // Skin for this class when Classkin is on. +#define PC_SCOUT_MAXHEALTH 75 // Maximum Health Level +#define PC_SCOUT_MAXSPEED 400 // Maximum movement speed +#define PC_SCOUT_MAXSTRAFESPEED 400 // Maximum strafing movement speed +#define PC_SCOUT_MAXARMOR 50 // Maximum Armor Level, of any armor class +#define PC_SCOUT_INITARMOR 25 // Armor level when respawned +#define PC_SCOUT_MAXARMORTYPE 0.3 // Maximum level of Armor absorption +#define PC_SCOUT_INITARMORTYPE 0.3 // Absorption Level of armor when respawned +#define PC_SCOUT_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL <-Armor Classes allowed for this class +#define PC_SCOUT_INITARMORCLASS 0 // Armorclass worn when respawned +#define PC_SCOUT_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_NAILGUN +#define PC_SCOUT_MAXAMMO_SHOT 50 // Maximum amount of shot ammo this class can carry +#define PC_SCOUT_MAXAMMO_NAIL 200 // Maximum amount of nail ammo this class can carry +#define PC_SCOUT_MAXAMMO_CELL 100 // Maximum amount of cell ammo this class can carry +#define PC_SCOUT_MAXAMMO_ROCKET 25 // Maximum amount of rocket ammo this class can carry +#define PC_SCOUT_INITAMMO_SHOT 25 // Amount of shot ammo this class has when respawned +#define PC_SCOUT_INITAMMO_NAIL 100 // Amount of nail ammo this class has when respawned +#define PC_SCOUT_INITAMMO_CELL 50 // Amount of cell ammo this class has when respawned +#define PC_SCOUT_INITAMMO_ROCKET 0 // Amount of rocket ammo this class has when respawned +#define PC_SCOUT_GRENADE_TYPE_1 GR_TYPE_CALTROP // <- 1st Type of Grenade this class has +#define PC_SCOUT_GRENADE_TYPE_2 GR_TYPE_CONCUSSION // <- 2nd Type of Grenade this class has +#define PC_SCOUT_GRENADE_INIT_1 2 // Number of grenades of Type 1 this class has when respawned +#define PC_SCOUT_GRENADE_INIT_2 3 // Number of grenades of Type 2 this class has when respawned +#define PC_SCOUT_TF_ITEMS NIT_SCANNER // <- TeamFortress Items this class has + +#define PC_SCOUT_MOTION_MIN_I 0.5 // < Short range +#define PC_SCOUT_MOTION_MIN_MOVE 50 // Minimum vlen of player velocity to be picked up by motion detector +#define PC_SCOUT_SCAN_TIME 2 // # of seconds between each scan pulse +#define PC_SCOUT_SCAN_RANGE 100 // Default scanner range +#define PC_SCOUT_SCAN_COST 2 // Default scanner cell useage per scan + +// Class Details for SNIPER +#define PC_SNIPER_SKIN 5 +#define PC_SNIPER_MAXHEALTH 90 +#define PC_SNIPER_MAXSPEED 300 +#define PC_SNIPER_MAXSTRAFESPEED 300 +#define PC_SNIPER_MAXARMOR 50 +#define PC_SNIPER_INITARMOR 0 +#define PC_SNIPER_MAXARMORTYPE 0.3 +#define PC_SNIPER_INITARMORTYPE 0.3 +#define PC_SNIPER_ARMORCLASSES 3 // #AT_SAVESHOT | #AT_SAVENAIL +#define PC_SNIPER_INITARMORCLASS 0 +#define PC_SNIPER_WEAPONS WEAP_SNIPER_RIFLE | WEAP_AUTO_RIFLE | WEAP_AXE | WEAP_NAILGUN +#define PC_SNIPER_MAXAMMO_SHOT 75 +#define PC_SNIPER_MAXAMMO_NAIL 100 +#define PC_SNIPER_MAXAMMO_CELL 50 +#define PC_SNIPER_MAXAMMO_ROCKET 25 +#define PC_SNIPER_INITAMMO_SHOT 60 +#define PC_SNIPER_INITAMMO_NAIL 50 +#define PC_SNIPER_INITAMMO_CELL 0 +#define PC_SNIPER_INITAMMO_ROCKET 0 +#define PC_SNIPER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SNIPER_GRENADE_TYPE_2 GR_TYPE_NONE +#define PC_SNIPER_GRENADE_INIT_1 2 +#define PC_SNIPER_GRENADE_INIT_2 0 +#define PC_SNIPER_TF_ITEMS 0 + +// Class Details for SOLDIER +#define PC_SOLDIER_SKIN 6 +#define PC_SOLDIER_MAXHEALTH 100 +#define PC_SOLDIER_MAXSPEED 240 +#define PC_SOLDIER_MAXSTRAFESPEED 240 +#define PC_SOLDIER_MAXARMOR 200 +#define PC_SOLDIER_INITARMOR 100 +#define PC_SOLDIER_MAXARMORTYPE 0.8 +#define PC_SOLDIER_INITARMORTYPE 0.8 +#define PC_SOLDIER_ARMORCLASSES 31 // ALL +#define PC_SOLDIER_INITARMORCLASS 0 +#define PC_SOLDIER_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_ROCKET_LAUNCHER +#define PC_SOLDIER_MAXAMMO_SHOT 100 +#define PC_SOLDIER_MAXAMMO_NAIL 100 +#define PC_SOLDIER_MAXAMMO_CELL 50 +#define PC_SOLDIER_MAXAMMO_ROCKET 50 +#define PC_SOLDIER_INITAMMO_SHOT 50 +#define PC_SOLDIER_INITAMMO_NAIL 0 +#define PC_SOLDIER_INITAMMO_CELL 0 +#define PC_SOLDIER_INITAMMO_ROCKET 10 +#define PC_SOLDIER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SOLDIER_GRENADE_TYPE_2 GR_TYPE_NAIL +#define PC_SOLDIER_GRENADE_INIT_1 2 +#define PC_SOLDIER_GRENADE_INIT_2 1 +#define PC_SOLDIER_TF_ITEMS 0 + +#define MAX_NAIL_GRENS 2 // Can only have 2 Nail grens active +#define MAX_NAPALM_GRENS 2 // Can only have 2 Napalm grens active +#define MAX_GAS_GRENS 2 // Can only have 2 Gas grenades active +#define MAX_MIRV_GRENS 2 // Can only have 2 Mirv's +#define MAX_CONCUSSION_GRENS 3 +#define MAX_CALTROP_CANS 3 + +// Class Details for DEMOLITION MAN +#define PC_DEMOMAN_SKIN 1 +#define PC_DEMOMAN_MAXHEALTH 90 +#define PC_DEMOMAN_MAXSPEED 280 +#define PC_DEMOMAN_MAXSTRAFESPEED 280 +#define PC_DEMOMAN_MAXARMOR 120 +#define PC_DEMOMAN_INITARMOR 50 +#define PC_DEMOMAN_MAXARMORTYPE 0.6 +#define PC_DEMOMAN_INITARMORTYPE 0.6 +#define PC_DEMOMAN_ARMORCLASSES 31 // ALL +#define PC_DEMOMAN_INITARMORCLASS 0 +#define PC_DEMOMAN_WEAPONS WEAP_AXE | WEAP_SHOTGUN | WEAP_GRENADE_LAUNCHER | WEAP_DETPACK +#define PC_DEMOMAN_MAXAMMO_SHOT 75 +#define PC_DEMOMAN_MAXAMMO_NAIL 50 +#define PC_DEMOMAN_MAXAMMO_CELL 50 +#define PC_DEMOMAN_MAXAMMO_ROCKET 50 +#define PC_DEMOMAN_MAXAMMO_DETPACK 1 +#define PC_DEMOMAN_INITAMMO_SHOT 30 +#define PC_DEMOMAN_INITAMMO_NAIL 0 +#define PC_DEMOMAN_INITAMMO_CELL 0 +#define PC_DEMOMAN_INITAMMO_ROCKET 20 +#define PC_DEMOMAN_INITAMMO_DETPACK 1 +#define PC_DEMOMAN_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_DEMOMAN_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_DEMOMAN_GRENADE_INIT_1 2 +#define PC_DEMOMAN_GRENADE_INIT_2 2 +#define PC_DEMOMAN_TF_ITEMS 0 + +// Class Details for COMBAT MEDIC +#define PC_MEDIC_SKIN 3 +#define PC_MEDIC_MAXHEALTH 90 +#define PC_MEDIC_MAXSPEED 320 +#define PC_MEDIC_MAXSTRAFESPEED 320 +#define PC_MEDIC_MAXARMOR 100 +#define PC_MEDIC_INITARMOR 50 +#define PC_MEDIC_MAXARMORTYPE 0.6 +#define PC_MEDIC_INITARMORTYPE 0.3 +#define PC_MEDIC_ARMORCLASSES 11 // ALL except EXPLOSION +#define PC_MEDIC_INITARMORCLASS 0 +#define PC_MEDIC_WEAPONS WEAP_BIOWEAPON | WEAP_MEDIKIT | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN | WEAP_SUPER_NAILGUN +#define PC_MEDIC_MAXAMMO_SHOT 75 +#define PC_MEDIC_MAXAMMO_NAIL 150 +#define PC_MEDIC_MAXAMMO_CELL 50 +#define PC_MEDIC_MAXAMMO_ROCKET 25 +#define PC_MEDIC_MAXAMMO_MEDIKIT 100 +#define PC_MEDIC_INITAMMO_SHOT 50 +#define PC_MEDIC_INITAMMO_NAIL 50 +#define PC_MEDIC_INITAMMO_CELL 0 +#define PC_MEDIC_INITAMMO_ROCKET 0 +#define PC_MEDIC_INITAMMO_MEDIKIT 50 +#define PC_MEDIC_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_MEDIC_GRENADE_TYPE_2 GR_TYPE_CONCUSSION +#define PC_MEDIC_GRENADE_INIT_1 2 +#define PC_MEDIC_GRENADE_INIT_2 2 +#define PC_MEDIC_TF_ITEMS 0 +#define PC_MEDIC_REGEN_TIME 3 // Number of seconds between each regen. +#define PC_MEDIC_REGEN_AMOUNT 2 // Amount of health regenerated each regen. + +// Class Details for HVYWEAP +#define PC_HVYWEAP_SKIN 2 +#define PC_HVYWEAP_MAXHEALTH 100 +#define PC_HVYWEAP_MAXSPEED 230 +#define PC_HVYWEAP_MAXSTRAFESPEED 230 +#define PC_HVYWEAP_MAXARMOR 300 +#define PC_HVYWEAP_INITARMOR 150 +#define PC_HVYWEAP_MAXARMORTYPE 0.8 +#define PC_HVYWEAP_INITARMORTYPE 0.8 +#define PC_HVYWEAP_ARMORCLASSES 31 // ALL +#define PC_HVYWEAP_INITARMORCLASS 0 +#define PC_HVYWEAP_WEAPONS WEAP_ASSAULT_CANNON | WEAP_AXE | WEAP_SHOTGUN | WEAP_SUPER_SHOTGUN +#define PC_HVYWEAP_MAXAMMO_SHOT 200 +#define PC_HVYWEAP_MAXAMMO_NAIL 200 +#define PC_HVYWEAP_MAXAMMO_CELL 50 +#define PC_HVYWEAP_MAXAMMO_ROCKET 25 +#define PC_HVYWEAP_INITAMMO_SHOT 200 +#define PC_HVYWEAP_INITAMMO_NAIL 0 +#define PC_HVYWEAP_INITAMMO_CELL 30 +#define PC_HVYWEAP_INITAMMO_ROCKET 0 +#define PC_HVYWEAP_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_HVYWEAP_GRENADE_TYPE_2 GR_TYPE_MIRV +#define PC_HVYWEAP_GRENADE_INIT_1 2 +#define PC_HVYWEAP_GRENADE_INIT_2 1 +#define PC_HVYWEAP_TF_ITEMS 0 +#define PC_HVYWEAP_CELL_USAGE 7 // Amount of cells spent to power up assault cannon + + + +// Class Details for PYRO +#define PC_PYRO_SKIN 21 +#define PC_PYRO_MAXHEALTH 100 +#define PC_PYRO_MAXSPEED 300 +#define PC_PYRO_MAXSTRAFESPEED 300 +#define PC_PYRO_MAXARMOR 150 +#define PC_PYRO_INITARMOR 50 +#define PC_PYRO_MAXARMORTYPE 0.6 +#define PC_PYRO_INITARMORTYPE 0.6 +#define PC_PYRO_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_PYRO_INITARMORCLASS 16 // #AT_SAVEFIRE +#define PC_PYRO_WEAPONS WEAP_INCENDIARY | WEAP_FLAMETHROWER | WEAP_AXE | WEAP_SHOTGUN +#define PC_PYRO_MAXAMMO_SHOT 40 +#define PC_PYRO_MAXAMMO_NAIL 50 +#define PC_PYRO_MAXAMMO_CELL 200 +#define PC_PYRO_MAXAMMO_ROCKET 20 +#define PC_PYRO_INITAMMO_SHOT 20 +#define PC_PYRO_INITAMMO_NAIL 0 +#define PC_PYRO_INITAMMO_CELL 120 +#define PC_PYRO_INITAMMO_ROCKET 5 +#define PC_PYRO_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_PYRO_GRENADE_TYPE_2 GR_TYPE_NAPALM +#define PC_PYRO_GRENADE_INIT_1 2 +#define PC_PYRO_GRENADE_INIT_2 4 +#define PC_PYRO_TF_ITEMS 0 +#define PC_PYRO_ROCKET_USAGE 3 // Number of rockets per incendiary cannon shot + +// Class Details for SPY +#define PC_SPY_SKIN 22 +#define PC_SPY_MAXHEALTH 90 +#define PC_SPY_MAXSPEED 300 +#define PC_SPY_MAXSTRAFESPEED 300 +#define PC_SPY_MAXARMOR 100 +#define PC_SPY_INITARMOR 25 +#define PC_SPY_MAXARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_INITARMORTYPE 0.6 // Was 0.3 +#define PC_SPY_ARMORCLASSES 27 // ALL except EXPLOSION +#define PC_SPY_INITARMORCLASS 0 +#define PC_SPY_WEAPONS WEAP_AXE | WEAP_TRANQ | WEAP_SUPER_SHOTGUN | WEAP_NAILGUN +#define PC_SPY_MAXAMMO_SHOT 40 +#define PC_SPY_MAXAMMO_NAIL 100 +#define PC_SPY_MAXAMMO_CELL 30 +#define PC_SPY_MAXAMMO_ROCKET 15 +#define PC_SPY_INITAMMO_SHOT 40 +#define PC_SPY_INITAMMO_NAIL 50 +#define PC_SPY_INITAMMO_CELL 10 +#define PC_SPY_INITAMMO_ROCKET 0 +#define PC_SPY_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_SPY_GRENADE_TYPE_2 GR_TYPE_GAS +#define PC_SPY_GRENADE_INIT_1 2 +#define PC_SPY_GRENADE_INIT_2 2 +#define PC_SPY_TF_ITEMS 0 +#define PC_SPY_CELL_REGEN_TIME 5 +#define PC_SPY_CELL_REGEN_AMOUNT 1 +#define PC_SPY_CELL_USAGE 3 // Amount of cells spent while invisible +#define PC_SPY_GO_UNDERCOVER_TIME 4 // Time it takes to go undercover + +// Class Details for ENGINEER +#define PC_ENGINEER_SKIN 22 // Not used anymore +#define PC_ENGINEER_MAXHEALTH 80 +#define PC_ENGINEER_MAXSPEED 300 +#define PC_ENGINEER_MAXSTRAFESPEED 300 +#define PC_ENGINEER_MAXARMOR 50 +#define PC_ENGINEER_INITARMOR 25 +#define PC_ENGINEER_MAXARMORTYPE 0.6 +#define PC_ENGINEER_INITARMORTYPE 0.3 +#define PC_ENGINEER_ARMORCLASSES 31 // ALL +#define PC_ENGINEER_INITARMORCLASS 0 +#define PC_ENGINEER_WEAPONS WEAP_SPANNER | WEAP_LASER | WEAP_SUPER_SHOTGUN +#define PC_ENGINEER_MAXAMMO_SHOT 50 +#define PC_ENGINEER_MAXAMMO_NAIL 50 +#define PC_ENGINEER_MAXAMMO_CELL 200 // synonymous with metal +#define PC_ENGINEER_MAXAMMO_ROCKET 30 +#define PC_ENGINEER_INITAMMO_SHOT 20 +#define PC_ENGINEER_INITAMMO_NAIL 25 +#define PC_ENGINEER_INITAMMO_CELL 100 // synonymous with metal +#define PC_ENGINEER_INITAMMO_ROCKET 0 +#define PC_ENGINEER_GRENADE_TYPE_1 GR_TYPE_NORMAL +#define PC_ENGINEER_GRENADE_TYPE_2 GR_TYPE_EMP +#define PC_ENGINEER_GRENADE_INIT_1 2 +#define PC_ENGINEER_GRENADE_INIT_2 2 +#define PC_ENGINEER_TF_ITEMS 0 + +// Class Details for CIVILIAN +#define PC_CIVILIAN_SKIN 22 +#define PC_CIVILIAN_MAXHEALTH 50 +#define PC_CIVILIAN_MAXSPEED 240 +#define PC_CIVILIAN_MAXSTRAFESPEED 240 +#define PC_CIVILIAN_MAXARMOR 0 +#define PC_CIVILIAN_INITARMOR 0 +#define PC_CIVILIAN_MAXARMORTYPE 0 +#define PC_CIVILIAN_INITARMORTYPE 0 +#define PC_CIVILIAN_ARMORCLASSES 0 +#define PC_CIVILIAN_INITARMORCLASS 0 +#define PC_CIVILIAN_WEAPONS WEAP_AXE +#define PC_CIVILIAN_MAXAMMO_SHOT 0 +#define PC_CIVILIAN_MAXAMMO_NAIL 0 +#define PC_CIVILIAN_MAXAMMO_CELL 0 +#define PC_CIVILIAN_MAXAMMO_ROCKET 0 +#define PC_CIVILIAN_INITAMMO_SHOT 0 +#define PC_CIVILIAN_INITAMMO_NAIL 0 +#define PC_CIVILIAN_INITAMMO_CELL 0 +#define PC_CIVILIAN_INITAMMO_ROCKET 0 +#define PC_CIVILIAN_GRENADE_TYPE_1 0 +#define PC_CIVILIAN_GRENADE_TYPE_2 0 +#define PC_CIVILIAN_GRENADE_INIT_1 0 +#define PC_CIVILIAN_GRENADE_INIT_2 0 +#define PC_CIVILIAN_TF_ITEMS 0 + + +/*==========================================================================*/ +/* TEAMFORTRESS GOALS */ +/*==========================================================================*/ +// For all these defines, see the tfortmap.txt that came with the zip +// for complete descriptions. +// Defines for Goal Activation types : goal_activation (in goals) +#define TFGA_TOUCH 1 // Activated when touched +#define TFGA_TOUCH_DETPACK 2 // Activated when touched by a detpack explosion +#define TFGA_REVERSE_AP 4 // Activated when AP details are _not_ met +#define TFGA_SPANNER 8 // Activated when hit by an engineer's spanner +#define TFGA_DROPTOGROUND 2048 // Drop to Ground when spawning + +// Defines for Goal Effects types : goal_effect +#define TFGE_AP 1 // AP is affected. Default. +#define TFGE_AP_TEAM 2 // All of the AP's team. +#define TFGE_NOT_AP_TEAM 4 // All except AP's team. +#define TFGE_NOT_AP 8 // All except AP. +#define TFGE_WALL 16 // If set, walls stop the Radius effects +#define TFGE_SAME_ENVIRONMENT 32 // If set, players in a different environment to the Goal are not affected +#define TFGE_TIMER_CHECK_AP 64 // If set, Timer Goals check their critera for all players fitting their effects + +// Defines for Goal Result types : goal_result +#define TFGR_SINGLE 1 // Goal can only be activated once +#define TFGR_ADD_BONUSES 2 // Any Goals activated by this one give their bonuses +#define TFGR_ENDGAME 4 // Goal fires Intermission, displays scores, and ends level +#define TFGR_NO_ITEM_RESULTS 8 // GoalItems given by this Goal don't do results +#define TFGR_REMOVE_DISGUISE 16 // Prevent/Remove undercover from any Spy +#define TFGR_FORCE_RESPAWN 32 // Forces the player to teleport to a respawn point +#define TFGR_DESTROY_BUILDINGS 64 // Destroys this player's buildings, if anys + +// Defines for Goal Group Result types : goal_group +// None! +// But I'm leaving this variable in there, since it's fairly likely +// that some will show up sometime. + +// Defines for Goal Item types, : goal_activation (in items) +#define TFGI_GLOW 1 // Players carrying this GoalItem will glow +#define TFGI_SLOW 2 // Players carrying this GoalItem will move at half-speed +#define TFGI_DROP 4 // Players dying with this item will drop it +#define TFGI_RETURN_DROP 8 // Return if a player with it dies +#define TFGI_RETURN_GOAL 16 // Return if a player with it has it removed by a goal's activation +#define TFGI_RETURN_REMOVE 32 // Return if it is removed by TFGI_REMOVE +#define TFGI_REVERSE_AP 64 // Only pickup if the player _doesn't_ match AP Details +#define TFGI_REMOVE 128 // Remove if left untouched for 2 minutes after being dropped +#define TFGI_KEEP 256 // Players keep this item even when they die +#define TFGI_ITEMGLOWS 512 // Item glows when on the ground +#define TFGI_DONTREMOVERES 1024 // Don't remove results when the item is removed +#define TFGI_DROPTOGROUND 2048 // Drop To Ground when spawning +#define TFGI_CANBEDROPPED 4096 // Can be voluntarily dropped by players +#define TFGI_SOLID 8192 // Is solid... blocks bullets, etc + +// Defines for methods of GoalItem returning +#define GI_RET_DROP_DEAD 0 // Dropped by a dead player +#define GI_RET_DROP_LIVING 1 // Dropped by a living player +#define GI_RET_GOAL 2 // Returned by a Goal +#define GI_RET_TIME 3 // Returned due to timeout + +// Defines for TeamSpawnpoints : goal_activation (in teamspawns) +#define TFSP_MULTIPLEITEMS 1 // Give out the GoalItem multiple times +#define TFSP_MULTIPLEMSGS 2 // Display the message multiple times + +// Defines for TeamSpawnpoints : goal_effects (in teamspawns) +#define TFSP_REMOVESELF 1 // Remove itself after being spawned on + +// Defines for Goal States +#define TFGS_ACTIVE 1 +#define TFGS_INACTIVE 2 +#define TFGS_REMOVED 3 +#define TFGS_DELAYED 4 + +// Defines for GoalItem Removing from Player Methods +#define GI_DROP_PLAYERDEATH 0 // Dropped by a dying player +#define GI_DROP_REMOVEGOAL 1 // Removed by a Goal +#define GI_DROP_PLAYERDROP 2 // Dropped by a player + +// Legal Playerclass Handling +#define TF_ILL_SCOUT 1 +#define TF_ILL_SNIPER 2 +#define TF_ILL_SOLDIER 4 +#define TF_ILL_DEMOMAN 8 +#define TF_ILL_MEDIC 16 +#define TF_ILL_HVYWEP 32 +#define TF_ILL_PYRO 64 +#define TF_ILL_RANDOMPC 128 +#define TF_ILL_SPY 256 +#define TF_ILL_ENGINEER 512 + +// Addition classes +#define CLASS_TFGOAL 128 +#define CLASS_TFGOAL_TIMER 129 +#define CLASS_TFGOAL_ITEM 130 +#define CLASS_TFSPAWN 131 + +/*==========================================================================*/ +/* Flamethrower */ +/*==========================================================================*/ +#define FLAME_PLYRMAXTIME 5.0 // lifetime in seconds of a flame on a player +#define FLAME_MAXBURNTIME 8 // lifetime in seconds of a flame on the world (big ones) +#define NAPALM_MAXBURNTIME 20 // lifetime in seconds of flame from a napalm grenade +#define FLAME_MAXPLYRFLAMES 4 // maximum number of flames on a player +#define FLAME_NUMLIGHTS 1 // maximum number of light flame +#define FLAME_BURNRATIO 0.3 // the chance of a flame not 'sticking' +#define GR_TYPE_FLAMES_NO 15 // number of flames spawned when a grenade explode +#define FLAME_DAMAGE_TIME 1 // Interval between damage burns from flames +#define FLAME_EFFECT_TIME 0.2 // frequency at which we display flame effects. +#define FLAME_THINK_TIME 0.1 // Seconds between times the flame checks burn +#define PER_FLAME_DAMAGE 2 // Damage taken per second per flame by burning players + +/*==================================================*/ +/* CTF Support defines */ +/*==================================================*/ +#define CTF_FLAG1 1 +#define CTF_FLAG2 2 +#define CTF_DROPOFF1 3 +#define CTF_DROPOFF2 4 +#define CTF_SCORE1 5 +#define CTF_SCORE2 6 + +//.float hook_out; + +/*==================================================*/ +/* Camera defines */ +/*==================================================*/ +/* +float live_camera; +.float camdist; +.vector camangle; +.entity camera_list; +*/ + +/*==================================================*/ +/* QuakeWorld defines */ +/*==================================================*/ +/* +float already_chosen_map; + +// grappling hook variables +.entity hook; +.float on_hook; +.float fire_held_down;// flag - TRUE if player is still holding down the + // fire button after throwing a hook. +*/ +/*==================================================*/ +/* Server Settings */ +/*==================================================*/ +// Admin modes +#define ADMIN_MODE_NONE 0 +#define ADMIN_MODE_DEAL 1 + +/*==================================================*/ +/* Death Message defines */ +/*==================================================*/ +#define DMSG_SHOTGUN 1 +#define DMSG_SSHOTGUN 2 +#define DMSG_NAILGUN 3 +#define DMSG_SNAILGUN 4 +#define DMSG_GRENADEL 5 +#define DMSG_ROCKETL 6 +#define DMSG_LIGHTNING 7 +#define DMSG_GREN_HAND 8 +#define DMSG_GREN_NAIL 9 +#define DMSG_GREN_MIRV 10 +#define DMSG_GREN_PIPE 11 +#define DMSG_DETPACK 12 +#define DMSG_BIOWEAPON 13 +#define DMSG_BIOWEAPON_ATT 14 +#define DMSG_FLAME 15 +#define DMSG_DETPACK_DIS 16 +#define DMSG_AXE 17 +#define DMSG_SNIPERRIFLE 18 +#define DMSG_AUTORIFLE 19 +#define DMSG_ASSAULTCANNON 20 +#define DMSG_HOOK 21 +#define DMSG_BACKSTAB 22 +#define DMSG_MEDIKIT 23 +#define DMSG_GREN_GAS 24 +#define DMSG_TRANQ 25 +#define DMSG_LASERBOLT 26 +#define DMSG_SENTRYGUN_BULLET 27 +#define DMSG_SNIPERLEGSHOT 28 +#define DMSG_SNIPERHEADSHOT 29 +#define DMSG_GREN_EMP 30 +#define DMSG_GREN_EMP_AMMO 31 +#define DMSG_SPANNER 32 +#define DMSG_INCENDIARY 33 +#define DMSG_SENTRYGUN_ROCKET 34 +#define DMSG_GREN_FLASH 35 +#define DMSG_TRIGGER 36 +#define DMSG_MIRROR 37 +#define DMSG_SENTRYDEATH 38 +#define DMSG_DISPENSERDEATH 39 +#define DMSG_GREN_AIRPIPE 40 +#define DMSG_CALTROP 41 + +/*==================================================*/ +// TOGGLEFLAGS +/*==================================================*/ +// Some of the toggleflags aren't used anymore, but the bits are still +// there to provide compatability with old maps +#define TFLAG_CLASS_PERSIST (1 << 0) // Persistent Classes Bit +#define TFLAG_CHEATCHECK (1 << 1) // Cheatchecking Bit +#define TFLAG_RESPAWNDELAY (1 << 2) // RespawnDelay bit +//#define TFLAG_UN (1 << 3) // NOT USED ANYMORE +#define TFLAG_OLD_GRENS (1 << 3) // Use old concussion grenade and flash grenade +#define TFLAG_UN2 (1 << 4) // NOT USED ANYMORE +#define TFLAG_UN3 (1 << 5) // NOT USED ANYMORE +#define TFLAG_UN4 (1 << 6) // NOT USED ANYMORE: Was Autoteam. CVAR tfc_autoteam used now. +#define TFLAG_TEAMFRAGS (1 << 7) // Individual Frags, or Frags = TeamScore +#define TFLAG_FIRSTENTRY (1 << 8) // Used to determine the first time toggleflags is set + // In a map. Cannot be toggled by players. +#define TFLAG_SPYINVIS (1 << 9) // Spy invisible only +#define TFLAG_GRAPPLE (1 << 10) // Grapple on/off +//#define TFLAG_FULLTEAMSCORE (1 << 11) // Each Team's score is TeamScore + Frags +#define TFLAG_FLAGEMULATION (1 << 12) // Flag emulation on for old TF maps +#define TFLAG_USE_STANDARD (1 << 13) // Use the TF War standard for Flag emulation + +#define TFLAG_FRAGSCORING (1 << 14) // Use frag scoring only + +/*======================*/ +// Menu stuff // +/*======================*/ + +#define MENU_DEFAULT 1 +#define MENU_TEAM 2 +#define MENU_CLASS 3 +#define MENU_MAPBRIEFING 4 +#define MENU_INTRO 5 +#define MENU_CLASSHELP 6 +#define MENU_CLASSHELP2 7 +#define MENU_REPEATHELP 8 + +#define MENU_SPECHELP 9 + + +#define MENU_SPY 12 +#define MENU_SPY_SKIN 13 +#define MENU_SPY_COLOR 14 +#define MENU_ENGINEER 15 +#define MENU_ENGINEER_FIX_DISPENSER 16 +#define MENU_ENGINEER_FIX_SENTRYGUN 17 +#define MENU_ENGINEER_FIX_MORTAR 18 +#define MENU_DISPENSER 19 +#define MENU_CLASS_CHANGE 20 +#define MENU_TEAM_CHANGE 21 + +#define MENU_REFRESH_RATE 25 + +#define MENU_VOICETWEAK 50 + +//============================ +// Timer Types +#define TF_TIMER_ANY 0 +#define TF_TIMER_CONCUSSION 1 +#define TF_TIMER_INFECTION 2 +#define TF_TIMER_HALLUCINATION 3 +#define TF_TIMER_TRANQUILISATION 4 +#define TF_TIMER_ROTHEALTH 5 +#define TF_TIMER_REGENERATION 6 +#define TF_TIMER_GRENPRIME 7 +#define TF_TIMER_CELLREGENERATION 8 +#define TF_TIMER_DETPACKSET 9 +#define TF_TIMER_DETPACKDISARM 10 +#define TF_TIMER_BUILD 11 +#define TF_TIMER_CHECKBUILDDISTANCE 12 +#define TF_TIMER_DISGUISE 13 +#define TF_TIMER_DISPENSERREFILL 14 + +// Non Player timers +#define TF_TIMER_RETURNITEM 100 +#define TF_TIMER_DELAYEDGOAL 101 +#define TF_TIMER_ENDROUND 102 + +//============================ +// Teamscore printing +#define TS_PRINT_SHORT 1 +#define TS_PRINT_LONG 2 +#define TS_PRINT_LONG_TO_ALL 3 + +#ifndef TF_DEFS_ONLY + +typedef struct +{ + int topColor; + int bottomColor; +} team_color_t; + + +/*==================================================*/ +/* GLOBAL VARIABLES */ +/*==================================================*/ +// FortressMap stuff +extern float number_of_teams; // number of teams supported by the map +extern int illegalclasses[5]; // Illegal playerclasses for all teams +extern int civilianteams; // Bitfield holding Civilian teams +extern Vector rgbcolors[5]; // RGB colors for each of the 4 teams + +extern team_color_t teamcolors[5][PC_LASTCLASS]; // Colors for each of the 4 teams + +extern int teamscores[5]; // Goal Score of each team +extern int g_iOrderedTeams[5]; // Teams ordered into order of winners->losers +extern int teamfrags[5]; // Total Frags for each team +extern int teamlives[5]; // Number of lives each team's players have +extern int teammaxplayers[5]; // Max number of players allowed in each team +extern float teamadvantage[5]; // only used if the teamplay equalisation bits are set + // stores the damage ratio players take/give +extern int teamallies[5]; // Keeps track of which teams are allied +extern string_t team_names[5]; + +extern BOOL CTF_Map; +extern BOOL birthday; +extern BOOL christmas; + +extern float num_world_flames; + +// Clan Battle stuff +extern float clan_scores_dumped; +extern float cb_prematch_time; +extern float fOldPrematch; +extern float fOldCeaseFire; +extern float cb_ceasefire_time; +extern float last_id; +extern float spy_off; +extern float old_grens; +extern float flagem_checked; +extern float flNextEqualisationCalc; +extern BOOL cease_fire; +extern BOOL no_cease_fire_text; +extern BOOL initial_cease_fire; +extern BOOL last_cease_fire; +// Autokick stuff +extern float autokick_kills; + +extern float deathmsg; // Global, which is set before every T_Damage, to indicate + // the death message that should be used. + +extern char *sTeamSpawnNames[]; +extern char *sClassNames[]; +extern char *sNewClassModelFiles[]; +extern char *sOldClassModelFiles[]; +extern char *sClassModels[]; +extern char *sClassCfgs[]; +extern char *sGrenadeNames[]; +extern string_t team_menu_string; + +extern int toggleflags; // toggleable flags + +extern CBaseEntity* g_pLastSpawns[5]; +extern BOOL g_bFirstClient; + +extern float g_fNextPrematchAlert; + +typedef struct +{ + int ip; + edict_t *pEdict; +} ip_storage_t; + +extern ip_storage_t g_IpStorage[32]; + +class CGhost; +/*==========================================================================*/ +BOOL ClassIsRestricted(float tno, int pc); +char* GetTeamName(int tno); +int TeamFortress_GetNoPlayers(); +void DestroyBuilding(CBaseEntity *eng, char *bld); +void teamsprint( int tno, CBaseEntity *ignore, int msg_dest, const char *st, const char *param1 = NULL, const char *param2 = NULL, const char *param3 = NULL ); +float anglemod( float v ); + +// Team Funcs +BOOL TeamFortress_TeamIsCivilian(float tno); +void TeamFortress_TeamShowScores(BOOL bLong, CBasePlayer *pPlayer); +BOOL TeamFortress_TeamPutPlayerInTeam(); +void TeamFortress_TeamSetColor(int tno); +void TeamFortress_TeamIncreaseScore(int tno, int scoretoadd); +int TeamFortress_TeamGetScoreFrags(int tno); +int TeamFortress_TeamGetNoPlayers(int tno); +float TeamEqualiseDamage(CBaseEntity *targ, CBaseEntity *attacker, float damage); +BOOL IsSpawnPointValid( Vector &pos ); +BOOL TeamFortress_SortTeams( void ); +void DumpClanScores( void ); +void CalculateTeamEqualiser(); + +// mapscript funcs +void ParseTFServerSettings(); +void ParseTFMapSettings(); +CBaseEntity* Finditem(int ino); +CBaseEntity* Findgoal(int gno); +CBaseEntity* Findteamspawn(int gno); +void RemoveGoal(CBaseEntity *Goal); +void tfgoalitem_GiveToPlayer(CBaseEntity *Item, CBasePlayer *AP, CBaseEntity *Goal); +void dremove( CBaseEntity *te ); +void tfgoalitem_RemoveFromPlayer(CBaseEntity *Item, CBasePlayer *AP, int iMethod); +void tfgoalitem_drop(CBaseEntity *Item, BOOL PAlive, CBasePlayer *P); +void DisplayItemStatus(CBaseEntity *Goal, CBasePlayer *Player, CBaseEntity *Item); +void tfgoalitem_checkgoalreturn(CBaseEntity *Item); +void DoGoalWork(CBaseEntity *Goal, CBasePlayer *AP); +void DoResults(CBaseEntity *Goal, CBasePlayer *AP, BOOL bAddBonuses); +void DoGroupWork(CBaseEntity *Goal, CBasePlayer *AP); +// hooks into the mapscript for all entities +BOOL ActivateDoResults(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); +BOOL ActivationSucceeded(CBaseEntity *Goal, CBasePlayer *AP, CBaseEntity *ActivatingGoal); + +// prematch & ceasefire +void Display_Prematch(); +void Check_Ceasefire(); + +// admin +void KickPlayer( CBaseEntity *pTarget ); +void BanPlayer( CBaseEntity *pTarget ); +CGhost *FindGhost( int iGhostID ); +int GetBattleID( edict_t *pEntity ); + +extern cvar_t tfc_spam_penalty1;// the initial gag penalty for a spammer (seconds) +extern cvar_t tfc_spam_penalty2;// incremental gag penalty (seconds) for each time gagged spammer continues to speak. +extern cvar_t tfc_spam_limit; // at this many points, gag the spammer +extern cvar_t tfc_clanbattle, tfc_clanbattle_prematch, tfc_prematch, tfc_clanbattle_ceasefire, tfc_balance_teams, tfc_balance_scores; +extern cvar_t tfc_clanbattle_locked, tfc_birthday, tfc_autokick_kills, tfc_fragscoring, tfc_autokick_time, tfc_adminpwd; +extern cvar_t weaponstay, footsteps, flashlight, aimcrosshair, falldamage, teamplay; +extern cvar_t allow_spectators; + +/*==========================================================================*/ +class CTFFlame : public CBaseMonster +{ +public: + void Spawn( void ); + void Precache( void ); + void EXPORT FlameThink( void ); + static CTFFlame *FlameSpawn( CBaseEntity *pOwner, CBaseEntity *pTarget ); + void FlameDestroy( void ); + + float m_flNextDamageTime; +}; + +/*==========================================================================*/ +// MAPSCRIPT CLASSES +class CTFGoal : public CBaseAnimating +{ +public: + void Spawn( void ); + void StartGoal( void ); + void EXPORT PlaceGoal( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + int Classify ( void ) { return CLASS_TFGOAL; } + + void SetObjectCollisionBox( void ); +}; + +class CTFGoalItem : public CTFGoal +{ +public: + void Spawn( void ); + void StartItem( void ); + void EXPORT PlaceItem( void ); + int Classify ( void ) { return CLASS_TFGOAL_ITEM; } + + float m_flDroppedAt; +}; + +class CTFTimerGoal : public CTFGoal +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL_TIMER; } +}; + +class CTFSpawn : public CBaseEntity +{ +public: + void Spawn( void ); + void Activate( void ); + int Classify ( void ) { return CLASS_TFSPAWN; } + BOOL CheckTeam( int iTeamNo ); + + EHANDLE m_pTeamCheck; +}; + +class CTFDetect : public CBaseEntity +{ +public: + void Spawn( void ); + int Classify ( void ) { return CLASS_TFGOAL; } +}; + +class CTelefragDeath : public CBaseEntity +{ +public: + void Spawn( void ); + void EXPORT DeathTouch( CBaseEntity *pOther ); +}; + +class CTeamCheck : public CBaseDelay +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); + BOOL TeamMatches( int iTeam ); +}; + +class CTeamSet : public CBaseDelay +{ +public: + void Spawn( void ); + void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); +}; + +#endif // TF_DEFS_ONLY +#endif // __TF_DEFS_H + + diff --git a/client/hud/hud_train.cpp b/cl_dll/train.cpp similarity index 62% rename from client/hud/hud_train.cpp rename to cl_dll/train.cpp index 9cc3c348..d16a1046 100644 --- a/client/hud/hud_train.cpp +++ b/cl_dll/train.cpp @@ -18,62 +18,68 @@ // implementation of CHudAmmo class // -#include "extdll.h" -#include "utils.h" #include "hud.h" +#include "cl_util.h" +#include +#include +#include "parsemsg.h" -DECLARE_MESSAGE( m_Train, Train ) +DECLARE_MESSAGE(m_Train, Train ) -int CHudTrain :: Init( void ) + +int CHudTrain::Init(void) { HOOK_MESSAGE( Train ); m_iPos = 0; m_iFlags = 0; - gHUD.AddHudElem( this ); + gHUD.AddHudElem(this); return 1; -} +}; -int CHudTrain::VidInit( void ) +int CHudTrain::VidInit(void) { m_hSprite = 0; + return 1; -} +}; int CHudTrain::Draw(float fTime) { if ( !m_hSprite ) m_hSprite = LoadSprite("sprites/%d_train.spr"); - if( m_iPos ) + if (m_iPos) { int r, g, b, x, y; - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - SPR_Set( m_hSprite, r, g, b ); + UnpackRGB(r,g,b, RGB_YELLOWISH); + SPR_Set(m_hSprite, r, g, b ); // This should show up to the right and part way up the armor number - y = ScreenHeight - SPR_Height( m_hSprite, 0 ) - gHUD.m_iFontHeight; - x = ScreenWidth / 3 + SPR_Width( m_hSprite, 0 ) / 4; + y = ScreenHeight - SPR_Height(m_hSprite,0) - gHUD.m_iFontHeight; + x = ScreenWidth/3 + SPR_Width(m_hSprite,0)/4; SPR_DrawAdditive( m_iPos - 1, x, y, NULL); + } + return 1; } -int CHudTrain::MsgFunc_Train( const char *pszName, int iSize, void *pbuf ) +int CHudTrain::MsgFunc_Train(const char *pszName, int iSize, void *pbuf) { - BEGIN_READ( pszName, iSize, pbuf ); + BEGIN_READ( pbuf, iSize ); // update Train data m_iPos = READ_BYTE(); - if( m_iPos ) + if (m_iPos) m_iFlags |= HUD_ACTIVE; - else m_iFlags &= ~HUD_ACTIVE; - END_READ(); + else + m_iFlags &= ~HUD_ACTIVE; return 1; } diff --git a/cl_dll/tri.cpp b/cl_dll/tri.cpp new file mode 100644 index 00000000..fc7fb8fb --- /dev/null +++ b/cl_dll/tri.cpp @@ -0,0 +1,124 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// Triangle rendering, if any + +#include "hud.h" +#include "cl_util.h" + +// Triangle rendering apis are in gEngfuncs.pTriAPI + +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "triangleapi.h" + +#define DLLEXPORT __declspec( dllexport ) + +extern "C" +{ + void DLLEXPORT HUD_DrawNormalTriangles( void ); + void DLLEXPORT HUD_DrawTransparentTriangles( void ); +}; + +//#define TEST_IT +#if defined( TEST_IT ) + +/* +================= +Draw_Triangles + +Example routine. Draws a sprite offset from the player origin. +================= +*/ +void Draw_Triangles( void ) +{ + cl_entity_t *player; + vec3_t org; + + // Load it up with some bogus data + player = gEngfuncs.GetLocalPlayer(); + if ( !player ) + return; + + org = player->origin; + + org.x += 50; + org.y += 50; + + if (gHUD.m_hsprCursor == 0) + { + char sz[256]; + sprintf( sz, "sprites/cursor.spr" ); + gHUD.m_hsprCursor = SPR_Load( sz ); + } + + if ( !gEngfuncs.pTriAPI->SpriteTexture( (struct model_s *)gEngfuncs.GetSpritePointer( gHUD.m_hsprCursor ), 0 )) + { + return; + } + + // Create a triangle, sigh + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); + gEngfuncs.pTriAPI->CullFace( TRI_NONE ); + gEngfuncs.pTriAPI->Begin( TRI_QUADS ); + // Overload p->color with index into tracer palette, p->packedColor with brightness + gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, 1.0 ); + // UNDONE: This gouraud shading causes tracers to disappear on some cards (permedia2) + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); + gEngfuncs.pTriAPI->Vertex3f( org.x, org.y, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); + gEngfuncs.pTriAPI->Vertex3f( org.x, org.y + 50, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); + gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y + 50, org.z ); + + gEngfuncs.pTriAPI->Brightness( 1 ); + gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); + gEngfuncs.pTriAPI->Vertex3f( org.x + 50, org.y, org.z ); + + gEngfuncs.pTriAPI->End(); + gEngfuncs.pTriAPI->RenderMode( kRenderNormal ); +} + +#endif + +/* +================= +HUD_DrawNormalTriangles + +Non-transparent triangles-- add them here +================= +*/ +void DLLEXPORT HUD_DrawNormalTriangles( void ) +{ + + gHUD.m_Spectator.DrawOverview(); + +#if defined( TEST_IT ) +// Draw_Triangles(); +#endif +} + +/* +================= +HUD_DrawTransparentTriangles + +Render any triangles with transparent rendermode needs here +================= +*/ +void DLLEXPORT HUD_DrawTransparentTriangles( void ) +{ + +#if defined( TEST_IT ) +// Draw_Triangles(); +#endif +} \ No newline at end of file diff --git a/cl_dll/util.cpp b/cl_dll/util.cpp new file mode 100644 index 00000000..f2e3f318 --- /dev/null +++ b/cl_dll/util.cpp @@ -0,0 +1,133 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// +// util.cpp +// +// implementation of class-less helper functions +// + +#include "STDIO.H" +#include "STDLIB.H" +#include "MATH.H" + +#include "hud.h" +#include "cl_util.h" +#include + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +vec3_t vec3_origin( 0, 0, 0 ); + +double sqrt(double x); + +float Length(const float *v) +{ + int i; + float length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +void VectorAngles( const float *forward, float *angles ) +{ + float tmp, yaw, pitch; + + if (forward[1] == 0 && forward[0] == 0) + { + yaw = 0; + if (forward[2] > 0) + pitch = 90; + else + pitch = 270; + } + else + { + yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); + if (yaw < 0) + yaw += 360; + + tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); + pitch = (atan2(forward[2], tmp) * 180 / M_PI); + if (pitch < 0) + pitch += 360; + } + + angles[0] = pitch; + angles[1] = yaw; + angles[2] = 0; +} + +float VectorNormalize (float *v) +{ + float length, ilength; + + length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; + length = sqrt (length); // FIXME + + if (length) + { + ilength = 1/length; + v[0] *= ilength; + v[1] *= ilength; + v[2] *= ilength; + } + + return length; + +} + +void VectorInverse ( float *v ) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void VectorScale (const float *in, float scale, float *out) +{ + out[0] = in[0]*scale; + out[1] = in[1]*scale; + out[2] = in[2]*scale; +} + +void VectorMA (const float *veca, float scale, const float *vecb, float *vecc) +{ + vecc[0] = veca[0] + scale*vecb[0]; + vecc[1] = veca[1] + scale*vecb[1]; + vecc[2] = veca[2] + scale*vecb[2]; +} + +HSPRITE LoadSprite(const char *pszName) +{ + int i; + char sz[256]; + + if (ScreenWidth < 640) + i = 320; + else + i = 640; + + sprintf(sz, pszName, i); + + return SPR_Load(sz); +} + diff --git a/cl_dll/util_vector.h b/cl_dll/util_vector.h new file mode 100644 index 00000000..4a1ba9cf --- /dev/null +++ b/cl_dll/util_vector.h @@ -0,0 +1,121 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ +// Vector.h +// A subset of the extdll.h in the project HL Entity DLL +// + +// Misc C-runtime library headers +#include "STDIO.H" +#include "STDLIB.H" +#include "MATH.H" + +// Header file containing definition of globalvars_t and entvars_t +typedef int func_t; // +typedef int string_t; // from engine's pr_comp.h; +typedef float vec_t; // needed before including progdefs.h + +//========================================================= +// 2DVector - used for many pathfinding and many other +// operations that are treated as planar rather than 3d. +//========================================================= +class Vector2D +{ +public: + inline Vector2D(void) { } + inline Vector2D(float X, float Y) { x = X; y = Y; } + inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); } + inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); } + inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); } + inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); } + + inline float Length(void) const { return (float)sqrt(x*x + y*y ); } + + inline Vector2D Normalize ( void ) const + { + Vector2D vec2; + + float flLen = Length(); + if ( flLen == 0 ) + { + return Vector2D( (float)0, (float)0 ); + } + else + { + flLen = 1 / flLen; + return Vector2D( x * flLen, y * flLen ); + } + } + + vec_t x, y; +}; + +inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); } +inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; } + +//========================================================= +// 3D Vector +//========================================================= +class Vector // same data-layout as engine's vec3_t, +{ // which is a vec_t[3] +public: + // Construction/destruction + inline Vector(void) { } + inline Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; } + inline Vector(double X, double Y, double Z) { x = (float)X; y = (float)Y; z = (float)Z; } + inline Vector(int X, int Y, int Z) { x = (float)X; y = (float)Y; z = (float)Z; } + inline Vector(const Vector& v) { x = v.x; y = v.y; z = v.z; } + inline Vector(float rgfl[3]) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } + + // Operators + inline Vector operator-(void) const { return Vector(-x,-y,-z); } + inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; } + inline int operator!=(const Vector& v) const { return !(*this==v); } + inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); } + inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); } + inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); } + inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); } + + // Methods + inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; } + inline float Length(void) const { return (float)sqrt(x*x + y*y + z*z); } + operator float *() { return &x; } // Vectors will now automatically convert to float * when needed + operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed + inline Vector Normalize(void) const + { + float flLen = Length(); + if (flLen == 0) return Vector(0,0,1); // ???? + flLen = 1 / flLen; + return Vector(x * flLen, y * flLen, z * flLen); + } + + inline Vector2D Make2D ( void ) const + { + Vector2D Vec2; + + Vec2.x = x; + Vec2.y = y; + + return Vec2; + } + inline float Length2D(void) const { return (float)sqrt(x*x + y*y); } + + // Members + vec_t x, y, z; +}; +inline Vector operator*(float fl, const Vector& v) { return v * fl; } +inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); } +inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); } + +#define vec3_t Vector diff --git a/cl_dll/vgui_ClassMenu.cpp b/cl_dll/vgui_ClassMenu.cpp new file mode 100644 index 00000000..ba94fd01 --- /dev/null +++ b/cl_dll/vgui_ClassMenu.cpp @@ -0,0 +1,432 @@ +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: TFC Class Menu +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "parsemsg.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +// Class Menu Dimensions +#define CLASSMENU_TITLE_X XRES(40) +#define CLASSMENU_TITLE_Y YRES(32) +#define CLASSMENU_TOPLEFT_BUTTON_X XRES(40) +#define CLASSMENU_TOPLEFT_BUTTON_Y YRES(80) +#define CLASSMENU_BUTTON_SIZE_X XRES(124) +#define CLASSMENU_BUTTON_SIZE_Y YRES(24) +#define CLASSMENU_BUTTON_SPACER_Y YRES(8) +#define CLASSMENU_WINDOW_X XRES(176) +#define CLASSMENU_WINDOW_Y YRES(80) +#define CLASSMENU_WINDOW_SIZE_X XRES(424) +#define CLASSMENU_WINDOW_SIZE_Y YRES(312) +#define CLASSMENU_WINDOW_TEXT_X XRES(150) +#define CLASSMENU_WINDOW_TEXT_Y YRES(80) +#define CLASSMENU_WINDOW_NAME_X XRES(150) +#define CLASSMENU_WINDOW_NAME_Y YRES(8) +#define CLASSMENU_WINDOW_PLAYERS_Y YRES(42) + +// Creation +CClassMenuPanel::CClassMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall) +{ + // don't show class graphics at below 640x480 resolution + bool bShowClassGraphic = true; + if ( ScreenWidth < 640 ) + { + bShowClassGraphic = false; + } + + memset( m_pClassImages, 0, sizeof(m_pClassImages) ); + + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hClassWindowText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the title + Label *pLabel = new Label( "", CLASSMENU_TITLE_X, CLASSMENU_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Title_SelectYourClass")); + + // Create the Scroll panel + m_pScrollPanel = new CTFScrollPanel( CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y ); + m_pScrollPanel->setParent(this); + //force the scrollbars on, so after the validate clientClip will be smaller + m_pScrollPanel->setScrollBarAutoVisible(false, false); + m_pScrollPanel->setScrollBarVisible(true, true); + m_pScrollPanel->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0) ) ); + m_pScrollPanel->validate(); + + int clientWide=m_pScrollPanel->getClient()->getWide(); + + //turn scrollpanel back into auto show scrollbar mode and validate + m_pScrollPanel->setScrollBarAutoVisible(false,true); + m_pScrollPanel->setScrollBarVisible(false,false); + m_pScrollPanel->validate(); + + // Create the Class buttons + for (int i = 0; i <= PC_RANDOM; i++) + { + char sz[256]; + int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y + ( (CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y) * i ); + + ActionSignal *pASignal = new CMenuHandler_StringCommandClassSelect( sTFClassSelection[i], true ); + + // Class button + sprintf(sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ) ); + m_pButtons[i] = new ClassButton( i, sz, CLASSMENU_TOPLEFT_BUTTON_X, iYPos, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y, true); + // RandomPC uses '0' + if ( i >= 1 && i <= 9 ) + { + sprintf(sz,"%d",i); + } + else + { + sprintf(sz,"0"); + } + m_pButtons[i]->setBoundKey( sz[0] ); + m_pButtons[i]->setContentAlignment( vgui::Label::a_west ); + m_pButtons[i]->addActionSignal( pASignal ); + m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) ); + m_pButtons[i]->setParent( this ); + + // Create the Class Info Window + //m_pClassInfoPanel[i] = new CTransparentPanel( 255, CLASSMENU_WINDOW_X, CLASSMENU_WINDOW_Y, CLASSMENU_WINDOW_SIZE_X, CLASSMENU_WINDOW_SIZE_Y ); + m_pClassInfoPanel[i] = new CTransparentPanel( 255, 0, 0, clientWide, CLASSMENU_WINDOW_SIZE_Y ); + m_pClassInfoPanel[i]->setParent( m_pScrollPanel->getClient() ); + //m_pClassInfoPanel[i]->setVisible( false ); + + // don't show class pic in lower resolutions + int textOffs = XRES(8); + + if ( bShowClassGraphic ) + { + textOffs = CLASSMENU_WINDOW_NAME_X; + } + + // Create the Class Name Label + sprintf(sz, "#Title_%s", sTFClassSelection[i]); + char* localName=CHudTextMessage::BufferedLocaliseTextString( sz ); + Label *pNameLabel = new Label( "", textOffs, CLASSMENU_WINDOW_NAME_Y ); + pNameLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pNameLabel->setParent( m_pClassInfoPanel[i] ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pNameLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pNameLabel->setBgColor( r, g, b, a ); + pNameLabel->setContentAlignment( vgui::Label::a_west ); + //pNameLabel->setBorder(new LineBorder()); + pNameLabel->setText(localName); + + // Create the Class Image + if ( bShowClassGraphic ) + { + for ( int team = 0; team < 2; team++ ) + { + if ( team == 1 ) + { + sprintf( sz, "%sred", sTFClassSelection[i] ); + } + else + { + sprintf( sz, "%sblue", sTFClassSelection[i] ); + } + + m_pClassImages[team][i] = new CImageLabel( sz, 0, 0, CLASSMENU_WINDOW_TEXT_X, CLASSMENU_WINDOW_TEXT_Y ); + + CImageLabel *pLabel = m_pClassImages[team][i]; + pLabel->setParent( m_pClassInfoPanel[i] ); + //pLabel->setBorder(new LineBorder()); + + if ( team != 1 ) + { + pLabel->setVisible( false ); + } + + // Reposition it based upon it's size + int xOut, yOut; + pNameLabel->getTextSize( xOut, yOut ); + pLabel->setPos( (CLASSMENU_WINDOW_TEXT_X - pLabel->getWide()) / 2, yOut /2 ); + } + } + + // Create the Player count string + gHUD.m_TextMessage.LocaliseTextString( "#Title_CurrentlyOnYourTeam", m_sPlayersOnTeamString, STRLENMAX_PLAYERSONTEAM ); + m_pPlayers[i] = new Label( "", textOffs, CLASSMENU_WINDOW_PLAYERS_Y ); + m_pPlayers[i]->setParent( m_pClassInfoPanel[i] ); + m_pPlayers[i]->setBgColor( 0, 0, 0, 255 ); + m_pPlayers[i]->setContentAlignment( vgui::Label::a_west ); + m_pPlayers[i]->setFont( pSchemes->getFont(hClassWindowText) ); + + // Open up the Class Briefing File + sprintf(sz, "classes/short_%s.txt", sTFClassSelection[i]); + char *cText = "Class Description not available."; + char *pfile = (char *)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + { + cText = pfile; + } + + // Create the Text info window + TextPanel *pTextWindow = new TextPanel(cText, textOffs, CLASSMENU_WINDOW_TEXT_Y, (CLASSMENU_WINDOW_SIZE_X - textOffs)-5, CLASSMENU_WINDOW_SIZE_Y - CLASSMENU_WINDOW_TEXT_Y); + pTextWindow->setParent( m_pClassInfoPanel[i] ); + pTextWindow->setFont( pSchemes->getFont(hClassWindowText) ); + pSchemes->getFgColor( hClassWindowText, r, g, b, a ); + pTextWindow->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hClassWindowText, r, g, b, a ); + pTextWindow->setBgColor( r, g, b, a ); + + // Resize the Info panel to fit it all + int wide,tall; + pTextWindow->getTextImage()->getTextSizeWrapped( wide,tall); + pTextWindow->setSize(wide,tall); + + int xx,yy; + pTextWindow->getPos(xx,yy); + int maxX=xx+wide; + int maxY=yy+tall; + + //check to see if the image goes lower than the text + //just use the red teams [0] images + if(m_pClassImages[0][i]!=null) + { + m_pClassImages[0][i]->getPos(xx,yy); + if((yy+m_pClassImages[0][i]->getTall())>maxY) + { + maxY=yy+m_pClassImages[0][i]->getTall(); + } + } + + m_pClassInfoPanel[i]->setSize( maxX , maxY ); + if (pfile) gEngfuncs.COM_FreeFile( pfile ); + //m_pClassInfoPanel[i]->setBorder(new LineBorder()); + + } + + // Create the Cancel button + m_pCancelButton = new CommandButton( gHUD.m_TextMessage.BufferedLocaliseTextString( "#Menu_Cancel" ), CLASSMENU_TOPLEFT_BUTTON_X, 0, CLASSMENU_BUTTON_SIZE_X, CLASSMENU_BUTTON_SIZE_Y); + m_pCancelButton->setParent( this ); + m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow(HIDE_TEXTWINDOW) ); + + m_iCurrentInfo = 0; + +} + + +// Update +void CClassMenuPanel::Update() +{ + // Don't allow the player to join a team if they're not in a team + if (!g_iTeamNumber) + return; + + int iYPos = CLASSMENU_TOPLEFT_BUTTON_Y; + + // Cycle through the rest of the buttons + for (int i = 0; i <= PC_RANDOM; i++) + { + bool bCivilian = (gViewPort->GetValidClasses(g_iTeamNumber) == -1); + + if ( bCivilian ) + { + // If this team can only be civilians, only the civilian button's visible + if (i == 0) + { + m_pButtons[0]->setVisible( true ); + SetActiveInfo( 0 ); + iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y; + } + else + { + m_pButtons[i]->setVisible( false ); + } + } + else + { + if ( m_pButtons[i]->IsNotValid() || i == 0 ) + { + m_pButtons[i]->setVisible( false ); + } + else + { + m_pButtons[i]->setVisible( true ); + m_pButtons[i]->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += CLASSMENU_BUTTON_SIZE_Y + CLASSMENU_BUTTON_SPACER_Y; + + // Start with the first option up + if (!m_iCurrentInfo) + SetActiveInfo( i ); + } + } + + // Now count the number of teammembers of this class + int iTotal = 0; + for ( int j = 1; j < MAX_PLAYERS; j++ ) + { + if ( g_PlayerInfoList[j].name == NULL ) + continue; // empty player slot, skip + if ( g_PlayerExtraInfo[j].teamname[0] == 0 ) + continue; // skip over players who are not in a team + if ( g_PlayerInfoList[j].thisplayer ) + continue; // skip this player + if ( g_PlayerExtraInfo[j].teamnumber != g_iTeamNumber ) + continue; // skip over players in other teams + + // If this team is forced to be civilians, just count the number of teammates + if ( g_PlayerExtraInfo[j].playerclass != i && !bCivilian ) + continue; + + iTotal++; + } + + char sz[256]; + sprintf(sz, m_sPlayersOnTeamString, iTotal); + m_pPlayers[i]->setText( sz ); + + // Set the text color to the teamcolor + m_pPlayers[i]->setFgColor( iTeamColors[g_iTeamNumber % iNumberOfTeamColors][0], + iTeamColors[g_iTeamNumber % iNumberOfTeamColors][1], + iTeamColors[g_iTeamNumber % iNumberOfTeamColors][2], + 0 ); + + // set the graphic to be the team pick + for ( int team = 0; team < MAX_TEAMS; team++ ) + { + // unset all the other images + if ( m_pClassImages[team][i] ) + { + m_pClassImages[team][i]->setVisible( false ); + } + + // set the current team image + if ( m_pClassImages[g_iTeamNumber-1][i] != NULL ) + { + m_pClassImages[g_iTeamNumber-1][i]->setVisible( true ); + } + else if ( m_pClassImages[0][i] ) + { + m_pClassImages[0][i]->setVisible( true ); + } + } + } + + // If the player already has a class, make the cancel button visible + if ( g_iPlayerClass ) + { + m_pCancelButton->setPos( CLASSMENU_TOPLEFT_BUTTON_X, iYPos ); + m_pCancelButton->setVisible( true ); + } + else + { + m_pCancelButton->setVisible( false ); + } +} + +//====================================== +// Key inputs for the Class Menu +bool CClassMenuPanel::SlotInput( int iSlot ) +{ + if ( (iSlot < 0) || (iSlot > 9) ) + return false; + if ( !m_pButtons[ iSlot ] ) + return false; + + // Is the button pushable? (0 is special case) + if (iSlot == 0) + { + // Selects Civilian and RandomPC + if ( gViewPort->GetValidClasses(g_iTeamNumber) == -1 ) + { + m_pButtons[ 0 ]->fireActionSignal(); + return true; + } + + // Select RandomPC + iSlot = 10; + } + + if ( !(m_pButtons[ iSlot ]->IsNotValid()) ) + { + m_pButtons[ iSlot ]->fireActionSignal(); + return true; + } + + return false; +} + +//====================================== +// Update the Class menu before opening it +void CClassMenuPanel::Open( void ) +{ + Update(); + CMenuPanel::Open(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void CClassMenuPanel::Initialize( void ) +{ + setVisible( false ); + m_pScrollPanel->setScrollValue( 0, 0 ); +} + +//====================================== +// Mouse is over a class button, bring up the class info +void CClassMenuPanel::SetActiveInfo( int iInput ) +{ + // Remove all the Info panels and bring up the specified one + for (int i = 0; i <= PC_RANDOM; i++) + { + m_pButtons[i]->setArmed( false ); + m_pClassInfoPanel[i]->setVisible( false ); + } + + if ( iInput > PC_RANDOM || iInput < 0 ) + iInput = 0; + + m_pButtons[iInput]->setArmed( true ); + m_pClassInfoPanel[iInput]->setVisible( true ); + m_iCurrentInfo = iInput; + + m_pScrollPanel->setScrollValue(0,0); + m_pScrollPanel->validate(); +} + diff --git a/cl_dll/vgui_ConsolePanel.cpp b/cl_dll/vgui_ConsolePanel.cpp new file mode 100644 index 00000000..a8b304c5 --- /dev/null +++ b/cl_dll/vgui_ConsolePanel.cpp @@ -0,0 +1,101 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include"vgui_ConsolePanel.h" +#include"hud.h" +#include +#include +#include +#include +#include + +using namespace vgui; + + +namespace +{ + +class Handler : public ActionSignal +{ +private: + + ConsolePanel* _consolePanel; + +public: + + Handler(ConsolePanel* consolePanel) + { + _consolePanel=consolePanel; + } + +public: + + virtual void actionPerformed(Panel* panel) + { + _consolePanel->doExecCommand(); + } + +}; + +} + + + +ConsolePanel::ConsolePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setBorder(new EtchedBorder()); + + _textGrid=new TextGrid(80,21,5,5,200,100); + _textGrid->setBorder(new LoweredBorder()); + _textGrid->setParent(this); + + _textEntry=new TextEntry("",5,5,200,20); + _textEntry->setParent(this); + _textEntry->addActionSignal(new Handler(this)); +} + +int ConsolePanel::print(const char* text) +{ + return _textGrid->printf("%s",text); +} + +int ConsolePanel::vprintf(const char* format,va_list argList) +{ + return _textGrid->vprintf(format,argList); +} + +int ConsolePanel::printf(const char* format,...) +{ + va_list argList; + va_start(argList,format); + int ret=vprintf(format,argList); + va_end(argList); + return ret; +} + +void ConsolePanel::doExecCommand() +{ + char buf[2048]; + _textEntry->getText(0,buf,2048); + _textEntry->setText(null,0); + gEngfuncs.pfnClientCmd(buf); +} + +void ConsolePanel::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + getPaintSize(wide,tall); + + _textGrid->setBounds(5,5,wide-10,tall-35); + _textEntry->setBounds(5,tall-25,wide-10,20); +} + + + + + diff --git a/cl_dll/vgui_ConsolePanel.h b/cl_dll/vgui_ConsolePanel.h new file mode 100644 index 00000000..84821f7f --- /dev/null +++ b/cl_dll/vgui_ConsolePanel.h @@ -0,0 +1,38 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef CONSOLEPANEL_H +#define CONSOLEPANEL_H + +#include +#include + +namespace vgui +{ +class TextGrid; +class TextEntry; +} + + +class ConsolePanel : public vgui::Panel +{ +private: + vgui::TextGrid* _textGrid; + vgui::TextEntry* _textEntry; +public: + ConsolePanel(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); + virtual int print(const char* text); + virtual int vprintf(const char* format,va_list argList); + virtual int printf(const char* format,...); + virtual void doExecCommand(); +}; + + + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_ControlConfigPanel.cpp b/cl_dll/vgui_ControlConfigPanel.cpp new file mode 100644 index 00000000..0fd52641 --- /dev/null +++ b/cl_dll/vgui_ControlConfigPanel.cpp @@ -0,0 +1,212 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include"vgui_ControlConfigPanel.h" +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace vgui; + +namespace +{ +class FooTablePanel : public TablePanel +{ +private: + Label* _label; + TextEntry* _textEntry; + ControlConfigPanel* _controlConfigPanel; +public: + FooTablePanel(ControlConfigPanel* controlConfigPanel,int x,int y,int wide,int tall,int columnCount) : TablePanel(x,y,wide,tall,columnCount) + { + _controlConfigPanel=controlConfigPanel; + _label=new Label("You are a dumb monkey",0,0,100,20); + _label->setBgColor(Scheme::sc_primary3); + _label->setFgColor(Scheme::sc_primary1); + _label->setFont(Scheme::sf_primary3); + + _textEntry=new TextEntry("",0,0,100,20); + //_textEntry->setFont(Scheme::sf_primary3); + } +public: + virtual int getRowCount() + { + return _controlConfigPanel->GetCVarCount(); + } + virtual int getCellTall(int row) + { + return 12; + } + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) + { + char cvar[128],desc[128],bind[128],bindAlt[128]; + _controlConfigPanel->GetCVar(row,cvar,128,desc,128); + + if(cellSelected) + { + _label->setBgColor(Scheme::sc_primary1); + _label->setFgColor(Scheme::sc_primary3); + } + else + if(rowSelected) + { + _label->setBgColor(Scheme::sc_primary2); + _label->setFgColor(Scheme::sc_primary1); + } + else + { + _label->setBgColor(Scheme::sc_primary3); + _label->setFgColor(Scheme::sc_primary1); + } + + switch(column) + { + case 0: + { + _label->setText(desc); + _label->setContentAlignment(Label::a_west); + break; + } + case 1: + { + _controlConfigPanel->GetCVarBind(cvar,bind,128,bindAlt,128); + _label->setText(bind); + _label->setContentAlignment(Label::a_center); + break; + } + case 2: + { + _controlConfigPanel->GetCVarBind(cvar,bind,128,bindAlt,128); + _label->setText(bindAlt); + _label->setContentAlignment(Label::a_center); + break; + } + default: + { + _label->setText(""); + break; + } + } + + return _label; + } + virtual Panel* startCellEditing(int column,int row) + { + _textEntry->setText("Goat",strlen("Goat")); + _textEntry->requestFocus(); + return _textEntry; + } +}; +} + +ControlConfigPanel::ControlConfigPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + setPaintBorderEnabled(false); + setPaintBackgroundEnabled(false); + setPaintEnabled(false); + + _actionLabel=new Label("Action"); + _actionLabel->setBgColor(Scheme::sc_primary3); + _actionLabel->setFgColor(Scheme::sc_primary3); + + _keyButtonLabel=new Label("Key / Button"); + _keyButtonLabel->setBgColor(Scheme::sc_primary3); + _keyButtonLabel->setFgColor(Scheme::sc_primary3); + + _alternateLabel=new Label("Alternate"); + _alternateLabel->setBgColor(Scheme::sc_primary3); + _alternateLabel->setFgColor(Scheme::sc_primary3); + + _headerPanel=new HeaderPanel(0,0,wide,20); + _headerPanel->setParent(this); + + _headerPanel->addSectionPanel(_actionLabel); + _headerPanel->addSectionPanel(_keyButtonLabel); + _headerPanel->addSectionPanel(_alternateLabel); + + _headerPanel->setSliderPos( 0, wide/2 ); + _headerPanel->setSliderPos( 1, (wide/2) + (wide/4) ); + _headerPanel->setSliderPos( 2, wide ); + + _scrollPanel=new ScrollPanel(0,20,wide,tall-20); + _scrollPanel->setParent(this); + _scrollPanel->setPaintBorderEnabled(false); + _scrollPanel->setPaintBackgroundEnabled(false); + _scrollPanel->setPaintEnabled(false); + _scrollPanel->getClient()->setPaintBorderEnabled(false); + _scrollPanel->getClient()->setPaintBackgroundEnabled(false); + _scrollPanel->getClient()->setPaintEnabled(false); + _scrollPanel->setScrollBarVisible(false,true); + + _tablePanel=new FooTablePanel(this,0,0,_scrollPanel->getClient()->getWide(),800, 3); + _tablePanel->setParent(_scrollPanel->getClient()); + _tablePanel->setHeaderPanel(_headerPanel); + _tablePanel->setBgColor(Color(200,0,0,255)); + _tablePanel->setFgColor(Color(Scheme::sc_primary2)); + _tablePanel->setGridVisible(true,true); + _tablePanel->setGridSize(1,1); +} + +void ControlConfigPanel::AddCVar(const char* cvar,const char* desc) +{ + _cvarDar.addElement(vgui_strdup(cvar)); + _descDar.addElement(vgui_strdup(desc)); +} + +int ControlConfigPanel::GetCVarCount() +{ + return _cvarDar.getCount(); +} + +void ControlConfigPanel::GetCVar(int index,char* cvar,int cvarLen,char* desc,int descLen) +{ + vgui_strcpy(cvar,cvarLen,_cvarDar[index]); + vgui_strcpy(desc,descLen,_descDar[index]); +} + +void ControlConfigPanel::AddCVarFromInputStream(InputStream* is) +{ + if(is==null) + { + return; + } + + DataInputStream dis(is); + + bool success; + + while(1) + { + char buf[256],cvar[128],desc[128]; + dis.readLine(buf,256,success); + if(!success) + { + break; + } + if(sscanf(buf,"\"%[^\"]\" \"%[^\"]\"",cvar,desc)==2) + { + AddCVar(cvar,desc); + } + } +} + +void ControlConfigPanel::GetCVarBind(const char* cvar,char* bind,int bindLen,char* bindAlt,int bindAltLen) +{ + sprintf(bind,"%s : Bind",cvar); + sprintf(bindAlt,"%s : BindAlt",cvar); +} + +void ControlConfigPanel::SetCVarBind(const char* cvar,const char* bind,const char* bindAlt) +{ +} + diff --git a/cl_dll/vgui_ControlConfigPanel.h b/cl_dll/vgui_ControlConfigPanel.h new file mode 100644 index 00000000..15ca3fdc --- /dev/null +++ b/cl_dll/vgui_ControlConfigPanel.h @@ -0,0 +1,47 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef CONTROLCONFIGPANEL_H +#define CONTROLCONFIGPANEL_H + +#include +#include + +namespace vgui +{ +class HeaderPanel; +class TablePanel; +class ScrollPanel; +class InputStream; +class Label; +} + +class ControlConfigPanel : public vgui::Panel +{ +private: + vgui::HeaderPanel* _headerPanel; + vgui::TablePanel* _tablePanel; + vgui::ScrollPanel* _scrollPanel; + vgui::Dar _cvarDar; + vgui::Dar _descDar; + vgui::Label* _actionLabel; + vgui::Label* _keyButtonLabel; + vgui::Label* _alternateLabel; +public: + ControlConfigPanel(int x,int y,int wide,int tall); +public: + void AddCVar(const char* cvar,const char* desc); + void AddCVarFromInputStream(vgui::InputStream* is); + int GetCVarCount(); + void GetCVar(int index,char* cvar,int cvarLen,char* desc,int descLen); + void GetCVarBind(const char* cvar,char* bind,int bindLen,char* bindAlt,int bindAltLen); + void SetCVarBind(const char* cvar,const char* bind,const char* bindAlt); +}; + + + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_CustomObjects.cpp b/cl_dll/vgui_CustomObjects.cpp new file mode 100644 index 00000000..441a50e2 --- /dev/null +++ b/cl_dll/vgui_CustomObjects.cpp @@ -0,0 +1,536 @@ +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Contains implementation of various VGUI-derived objects +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "parsemsg.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" +#include "..\game_shared\vgui_LoadTGA.h" + +// Arrow filenames +char *sArrowFilenames[] = +{ + "arrowup", + "arrowdn", + "arrowlt", + "arrowrt", +}; + +// Get the name of TGA file, without a gamedir +char *GetTGANameForRes(const char *pszName) +{ + int i; + char sz[256]; + static char gd[256]; + if (ScreenWidth < 640) + i = 320; + else + i = 640; + sprintf(sz, pszName, i); + sprintf(gd, "gfx/vgui/%s.tga", sz); + return gd; +} + +//----------------------------------------------------------------------------- +// Purpose: Loads a .tga file and returns a pointer to the VGUI tga object +//----------------------------------------------------------------------------- +BitmapTGA *LoadTGAForRes( const char* pImageName ) +{ + BitmapTGA *pTGA; + + char sz[256]; + sprintf(sz, "%%d_%s", pImageName); + pTGA = vgui_LoadTGA(GetTGANameForRes(sz)); + + return pTGA; +} + +//=========================================================== +// All TFC Hud buttons are derived from this one. +CommandButton::CommandButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight) : Button("",x,y,wide,tall) +{ + m_iPlayerClass = 0; + m_bNoHighlight = bNoHighlight; + m_bFlat = false; + Init(); + setText( text ); +} + +CommandButton::CommandButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall, bool bFlat) : Button("",x,y,wide,tall) +{ + m_iPlayerClass = iPlayerClass; + m_bNoHighlight = false; + m_bFlat = bFlat; + Init(); + setText( text ); +} + +CommandButton::CommandButton(const char *text, int x, int y, int wide, int tall, bool bNoHighlight, bool bFlat) : Button("",x,y,wide,tall) +{ + m_iPlayerClass = 0; + m_bFlat = bFlat; + m_bNoHighlight = bNoHighlight; + Init(); + setText( text ); +} + +void CommandButton::Init( void ) +{ + m_pSubMenu = NULL; + m_pSubLabel = NULL; + m_pParentMenu = NULL; + + // Set text color to orange + setFgColor(Scheme::sc_primary1); + + // left align + setContentAlignment( vgui::Label::a_west ); + + // Add the Highlight signal + if (!m_bNoHighlight) + addInputSignal( new CHandler_CommandButtonHighlight(this) ); + + // not bound to any button yet + m_cBoundKey = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Prepends the button text with the current bound key +// if no bound key, then a clear space ' ' instead +//----------------------------------------------------------------------------- +void CommandButton::RecalculateText( void ) +{ + char szBuf[128]; + + if ( m_cBoundKey != 0 ) + { + if ( m_cBoundKey == (char)255 ) + { + strcpy( szBuf, m_sMainText ); + } + else + { + sprintf( szBuf, " %c %s", m_cBoundKey, m_sMainText ); + } + szBuf[MAX_BUTTON_SIZE-1] = 0; + } + else + { + // just draw a space if no key bound + sprintf( szBuf, " %s", m_sMainText ); + szBuf[MAX_BUTTON_SIZE-1] = 0; + } + + Button::setText( szBuf ); +} + +void CommandButton::setText( const char *text ) +{ + strncpy( m_sMainText, text, MAX_BUTTON_SIZE ); + m_sMainText[MAX_BUTTON_SIZE-1] = 0; + + RecalculateText(); +} + +void CommandButton::setBoundKey( char boundKey ) +{ + m_cBoundKey = boundKey; + RecalculateText(); +} + +char CommandButton::getBoundKey( void ) +{ + return m_cBoundKey; +} + +void CommandButton::AddSubMenu( CCommandMenu *pNewMenu ) +{ + m_pSubMenu = pNewMenu; + + // Prevent this button from being pushed + setMouseClickEnabled( MOUSE_LEFT, false ); +} + +void CommandButton::UpdateSubMenus( int iAdjustment ) +{ + if ( m_pSubMenu ) + m_pSubMenu->RecalculatePositions( iAdjustment ); +} + +void CommandButton::paint() +{ + // Make the sub label paint the same as the button + if ( m_pSubLabel ) + { + if ( isSelected() ) + m_pSubLabel->PushDown(); + else + m_pSubLabel->PushUp(); + } + + // draw armed button text in white + if ( isArmed() ) + { + setFgColor( Scheme::sc_secondary2 ); + } + else + { + setFgColor( Scheme::sc_primary1 ); + } + + Button::paint(); +} + +void CommandButton::paintBackground() +{ + if ( m_bFlat ) + { + if ( isArmed() ) + { + // Orange Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect(0,0,_size[0],_size[1]); + } + } + else + { + if ( isArmed() ) + { + // Orange highlight background + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect(0,0,_size[0],_size[1]); + } + + // Orange Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect(0,0,_size[0],_size[1]); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Highlights the current button, and all it's parent menus +//----------------------------------------------------------------------------- +void CommandButton::cursorEntered( void ) +{ + // unarm all the other buttons in this menu + CCommandMenu *containingMenu = getParentMenu(); + if ( containingMenu ) + { + containingMenu->ClearButtonsOfArmedState(); + + // make all our higher buttons armed + CCommandMenu *pCParent = containingMenu->GetParentMenu(); + if ( pCParent ) + { + CommandButton *pParentButton = pCParent->FindButtonWithSubmenu( containingMenu ); + + pParentButton->cursorEntered(); + } + } + + // arm ourselves + setArmed( true ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CommandButton::cursorExited( void ) +{ + // only clear ourselves if we have do not have a containing menu + // only stay armed if we have a sub menu + // the buttons only unarm themselves when another button is armed instead + if ( !getParentMenu() || !GetSubMenu() ) + { + setArmed( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the command menu that the button is part of, if any +// Output : CCommandMenu * +//----------------------------------------------------------------------------- +CCommandMenu *CommandButton::getParentMenu( void ) +{ + return m_pParentMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: Sets the menu that contains this button +// Input : *pParentMenu - +//----------------------------------------------------------------------------- +void CommandButton::setParentMenu( CCommandMenu *pParentMenu ) +{ + m_pParentMenu = pParentMenu; +} + + +//=========================================================== +int ClassButton::IsNotValid() +{ + // If this is the main ChangeClass button, remove it if the player's only able to be civilians + if ( m_iPlayerClass == -1 ) + { + if (gViewPort->GetValidClasses(g_iTeamNumber) == -1) + return true; + + return false; + } + + // Is it an illegal class? + if ((gViewPort->GetValidClasses(0) & sTFValidClassInts[ m_iPlayerClass ]) || (gViewPort->GetValidClasses(g_iTeamNumber) & sTFValidClassInts[ m_iPlayerClass ])) + return true; + + // Only check current class if they've got autokill on + bool bAutoKill = CVAR_GET_FLOAT( "hud_classautokill" ) != 0; + if ( bAutoKill ) + { + // Is it the player's current class? + if ( (gViewPort->IsRandomPC() && m_iPlayerClass == PC_RANDOM) || (!gViewPort->IsRandomPC() && (m_iPlayerClass == g_iPlayerClass)) ) + return true; + } + + return false; +} + +//=========================================================== +// Button with Class image beneath it +CImageLabel::CImageLabel( const char* pImageName,int x,int y ) : Label( "", x,y ) +{ + setContentFitted(true); + m_pTGA = LoadTGAForRes(pImageName); + setImage( m_pTGA ); +} + +CImageLabel::CImageLabel( const char* pImageName,int x,int y,int wide,int tall ) : Label( "", x,y,wide,tall ) +{ + setContentFitted(true); + m_pTGA = LoadTGAForRes(pImageName); + setImage( m_pTGA ); +} + +//=========================================================== +// Image size +int CImageLabel::getImageWide( void ) +{ + if( m_pTGA ) + { + int iXSize, iYSize; + m_pTGA->getSize( iXSize, iYSize ); + return iXSize; + } + else + { + return 1; + } +} + +int CImageLabel::getImageTall( void ) +{ + if( m_pTGA ) + { + int iXSize, iYSize; + m_pTGA->getSize( iXSize, iYSize ); + return iYSize; + } + else + { + return 1; + } +} + +void CImageLabel::LoadImage(const char * pImageName) +{ + if ( m_pTGA ) + delete m_pTGA; + + // Load the Image + m_pTGA = LoadTGAForRes(pImageName); + + if ( m_pTGA == NULL ) + { + // we didn't find a matching image file for this resolution + // try to load file resolution independent + + char sz[256]; + sprintf(sz, "%s/%s",gEngfuncs.pfnGetGameDirectory(), pImageName ); + FileInputStream* fis = new FileInputStream( sz, false ); + m_pTGA = new BitmapTGA(fis,true); + fis->close(); + } + + if ( m_pTGA == NULL ) + return; // unable to load image + + int w,t; + + m_pTGA->getSize( w, t ); + + setSize( XRES (w),YRES (t) ); + setImage( m_pTGA ); +} + +//=========================================================== +// Various overloaded paint functions for Custom VGUI objects +void CCommandMenu::paintBackground() +{ + // Transparent black background + + if ( m_iSpectCmdMenu ) + drawSetColor( 0, 0, 0, 64 ); + else + drawSetColor(Scheme::sc_primary3); + + drawFilledRect(0,0,_size[0],_size[1]); +} + +//================================================================================= +// CUSTOM SCROLLPANEL +//================================================================================= +CTFScrollButton::CTFScrollButton(int iArrow, const char* text,int x,int y,int wide,int tall) : CommandButton(text,x,y,wide,tall) +{ + // Set text color to orange + setFgColor(Scheme::sc_primary1); + + // Load in the arrow + m_pTGA = LoadTGAForRes( sArrowFilenames[iArrow] ); + setImage( m_pTGA ); + + // Highlight signal + InputSignal *pISignal = new CHandler_CommandButtonHighlight(this); + addInputSignal(pISignal); +} + +void CTFScrollButton::paint( void ) +{ + if (!m_pTGA) + return; + + // draw armed button text in white + if ( isArmed() ) + { + m_pTGA->setColor( Color(255,255,255, 0) ); + } + else + { + m_pTGA->setColor( Color(255,255,255, 128) ); + } + + m_pTGA->doPaint(this); +} + +void CTFScrollButton::paintBackground( void ) +{ +/* + if ( isArmed() ) + { + // Orange highlight background + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect(0,0,_size[0],_size[1]); + } + + // Orange Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect(0,0,_size[0]-1,_size[1]); +*/ +} + +void CTFSlider::paintBackground( void ) +{ + int wide,tall,nobx,noby; + getPaintSize(wide,tall); + getNobPos(nobx,noby); + + // Border + drawSetColor( Scheme::sc_secondary1 ); + drawOutlinedRect( 0,0,wide,tall ); + + if( isVertical() ) + { + // Nob Fill + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect( 0,nobx,wide,noby ); + + // Nob Outline + drawSetColor( Scheme::sc_primary1 ); + drawOutlinedRect( 0,nobx,wide,noby ); + } + else + { + // Nob Fill + drawSetColor( Scheme::sc_primary2 ); + drawFilledRect( nobx,0,noby,tall ); + + // Nob Outline + drawSetColor( Scheme::sc_primary1 ); + drawOutlinedRect( nobx,0,noby,tall ); + } +} + +CTFScrollPanel::CTFScrollPanel(int x,int y,int wide,int tall) : ScrollPanel(x,y,wide,tall) +{ + ScrollBar *pScrollBar = getVerticalScrollBar(); + pScrollBar->setButton( new CTFScrollButton( ARROW_UP, "", 0,0,16,16 ), 0 ); + pScrollBar->setButton( new CTFScrollButton( ARROW_DOWN, "", 0,0,16,16 ), 1 ); + pScrollBar->setSlider( new CTFSlider(0,wide-1,wide,(tall-(wide*2))+2,true) ); + pScrollBar->setPaintBorderEnabled(false); + pScrollBar->setPaintBackgroundEnabled(false); + pScrollBar->setPaintEnabled(false); + + pScrollBar = getHorizontalScrollBar(); + pScrollBar->setButton( new CTFScrollButton( ARROW_LEFT, "", 0,0,16,16 ), 0 ); + pScrollBar->setButton( new CTFScrollButton( ARROW_RIGHT, "", 0,0,16,16 ), 1 ); + pScrollBar->setSlider( new CTFSlider(tall,0,wide-(tall*2),tall,false) ); + pScrollBar->setPaintBorderEnabled(false); + pScrollBar->setPaintBackgroundEnabled(false); + pScrollBar->setPaintEnabled(false); +} + + +//================================================================================= +// CUSTOM HANDLERS +//================================================================================= +void CHandler_MenuButtonOver::cursorEntered(Panel *panel) +{ + if ( gViewPort && m_pMenuPanel ) + { + m_pMenuPanel->SetActiveInfo( m_iButton ); + } +} + +void CMenuHandler_StringCommandClassSelect::actionPerformed(Panel* panel) +{ + CMenuHandler_StringCommand::actionPerformed( panel ); + + bool bAutoKill = CVAR_GET_FLOAT( "hud_classautokill" ) != 0; + if ( bAutoKill && g_iPlayerClass != 0 ) + gEngfuncs.pfnClientCmd("kill"); +} + diff --git a/cl_dll/vgui_MOTDWindow.cpp b/cl_dll/vgui_MOTDWindow.cpp new file mode 100644 index 00000000..b6f46dd7 --- /dev/null +++ b/cl_dll/vgui_MOTDWindow.cpp @@ -0,0 +1,154 @@ +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Font.h" +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" + +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "const.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +#define MOTD_TITLE_X XRES(16) +#define MOTD_TITLE_Y YRES(16) + +#define MOTD_WINDOW_X XRES(112) +#define MOTD_WINDOW_Y YRES(80) +#define MOTD_WINDOW_SIZE_X XRES(424) +#define MOTD_WINDOW_SIZE_Y YRES(312) + +//----------------------------------------------------------------------------- +// Purpose: Displays the MOTD and basic server information +//----------------------------------------------------------------------------- +class CMessageWindowPanel : public CMenuPanel +{ +public: + CMessageWindowPanel( const char *szMOTD, const char *szTitle, int iShadeFullScreen, int iRemoveMe, int x, int y, int wide, int tall ); + +private: + CTransparentPanel *m_pBackgroundPanel; + +}; + +//----------------------------------------------------------------------------- +// Purpose: Creates a new CMessageWindowPanel +// Output : CMenuPanel - interface to the panel +//----------------------------------------------------------------------------- +CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ) +{ + return new CMessageWindowPanel( szMOTD, szTitle, iShadeFullscreen, iRemoveMe, x, y, wide, tall ); +} + +//----------------------------------------------------------------------------- +// Purpose: Constructs a message panel +//----------------------------------------------------------------------------- +CMessageWindowPanel::CMessageWindowPanel( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ) : CMenuPanel( iShadeFullscreen ? 100 : 255, iRemoveMe, x, y, wide, tall ) +{ + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hMOTDText = pSchemes->getSchemeHandle( "Briefing Text" ); + + // color schemes + int r, g, b, a; + + // Create the window + m_pBackgroundPanel = new CTransparentPanel( iShadeFullscreen ? 255 : 100, MOTD_WINDOW_X, MOTD_WINDOW_Y, MOTD_WINDOW_SIZE_X, MOTD_WINDOW_SIZE_Y ); + m_pBackgroundPanel->setParent( this ); + m_pBackgroundPanel->setBorder( new LineBorder( Color(255 * 0.7,170 * 0.7,0,0)) ); + m_pBackgroundPanel->setVisible( true ); + + int iXSize,iYSize,iXPos,iYPos; + m_pBackgroundPanel->getPos( iXPos,iYPos ); + m_pBackgroundPanel->getSize( iXSize,iYSize ); + + // Create the title + Label *pLabel = new Label( "", iXPos + MOTD_TITLE_X, iYPos + MOTD_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pSchemes->getFont(hTitleScheme) ); + pLabel->setFont( Scheme::sf_primary1 ); + + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pLabel->setFgColor( Scheme::sc_primary1 ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(szTitle); + + // Create the Scroll panel + ScrollPanel *pScrollPanel = new CTFScrollPanel( iXPos + XRES(16), iYPos + MOTD_TITLE_Y*2 + YRES(16), iXSize - XRES(32), iYSize - (YRES(48) + BUTTON_SIZE_Y*2) ); + pScrollPanel->setParent(this); + + //force the scrollbars on so clientClip will take them in account after the validate + pScrollPanel->setScrollBarAutoVisible(false, false); + pScrollPanel->setScrollBarVisible(true, true); + pScrollPanel->validate(); + + // Create the text panel + TextPanel *pText = new TextPanel( "", 0,0, 64,64); + pText->setParent( pScrollPanel->getClient() ); + + // get the font and colors from the scheme + pText->setFont( pSchemes->getFont(hMOTDText) ); + pSchemes->getFgColor( hMOTDText, r, g, b, a ); + pText->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hMOTDText, r, g, b, a ); + pText->setBgColor( r, g, b, a ); + pText->setText(szMOTD); + + // Get the total size of the MOTD text and resize the text panel + int iScrollSizeX, iScrollSizeY; + + // First, set the size so that the client's wdith is correct at least because the + // width is critical for getting the "wrapped" size right. + // You'll see a horizontal scroll bar if there is a single word that won't wrap in the + // specified width. + pText->getTextImage()->setSize(pScrollPanel->getClientClip()->getWide(), pScrollPanel->getClientClip()->getTall()); + pText->getTextImage()->getTextSizeWrapped( iScrollSizeX, iScrollSizeY ); + + // Now resize the textpanel to fit the scrolled size + pText->setSize( iScrollSizeX , iScrollSizeY ); + + //turn the scrollbars back into automode + pScrollPanel->setScrollBarAutoVisible(true, true); + pScrollPanel->setScrollBarVisible(false, false); + + pScrollPanel->validate(); + + CommandButton *pButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_OK" ), iXPos + XRES(16), iYPos + iYSize - YRES(16) - BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_TextWindow(HIDE_TEXTWINDOW)); + pButton->setParent(this); + +} + + + + + + diff --git a/cl_dll/vgui_SchemeManager.cpp b/cl_dll/vgui_SchemeManager.cpp new file mode 100644 index 00000000..571dca37 --- /dev/null +++ b/cl_dll/vgui_SchemeManager.cpp @@ -0,0 +1,544 @@ +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "hud.h" +#include "vgui_SchemeManager.h" +#include "cvardef.h" + +#include + + +cvar_t *g_CV_BitmapFonts; + + +void Scheme_Init() +{ + g_CV_BitmapFonts = gEngfuncs.pfnRegisterVariable("bitmapfonts", "1", 0); +} + + + +//----------------------------------------------------------------------------- +// Purpose: Scheme managers data container +//----------------------------------------------------------------------------- +class CSchemeManager::CScheme +{ +public: + enum { + SCHEME_NAME_LENGTH = 32, + FONT_NAME_LENGTH = 48, + FONT_FILENAME_LENGTH = 64, + }; + + // name + char schemeName[SCHEME_NAME_LENGTH]; + + // font + char fontName[FONT_NAME_LENGTH]; + + int fontSize; + int fontWeight; + + vgui::Font *font; + int ownFontPointer; // true if the font is ours to delete + + // scheme + byte fgColor[4]; + byte bgColor[4]; + byte armedFgColor[4]; + byte armedBgColor[4]; + byte mousedownFgColor[4]; + byte mousedownBgColor[4]; + byte borderColor[4]; + + // construction/destruction + CScheme(); + ~CScheme(); +}; + +CSchemeManager::CScheme::CScheme() +{ + schemeName[0] = 0; + fontName[0] = 0; + fontSize = 0; + fontWeight = 0; + font = NULL; + ownFontPointer = false; +} + +CSchemeManager::CScheme::~CScheme() +{ + // only delete our font pointer if we own it + if ( ownFontPointer ) + { + delete font; + } +} + +//----------------------------------------------------------------------------- +// Purpose: resolution information +// !! needs to be shared out +//----------------------------------------------------------------------------- +static int g_ResArray[] = +{ + 320, + 400, + 512, + 640, + 800, + 1024, + 1152, + 1280, + 1600 +}; +static int g_NumReses = sizeof(g_ResArray) / sizeof(int); + +static byte *LoadFileByResolution( const char *filePrefix, int xRes, const char *filePostfix ) +{ + // find our resolution in the res array + int resNum = g_NumReses - 1; + while ( g_ResArray[resNum] > xRes ) + { + resNum--; + + if ( resNum < 0 ) + return NULL; + } + + // try open the file + byte *pFile = NULL; + while ( 1 ) + { + + // try load + char fname[256]; + sprintf( fname, "%s%d%s", filePrefix, g_ResArray[resNum], filePostfix ); + pFile = gEngfuncs.COM_LoadFile( fname, 5, NULL ); + + if ( pFile ) + break; + + if ( resNum == 0 ) + return NULL; + + resNum--; + }; + + return pFile; +} + +static void ParseRGBAFromString( byte colorArray[4], const char *colorVector ) +{ + int r, g, b, a; + sscanf( colorVector, "%d %d %d %d", &r, &g, &b, &a ); + colorArray[0] = r; + colorArray[1] = g; + colorArray[2] = b; + colorArray[3] = a; +} + +//----------------------------------------------------------------------------- +// Purpose: initializes the scheme manager +// loading the scheme files for the current resolution +// Input : xRes - +// yRes - dimensions of output window +//----------------------------------------------------------------------------- +CSchemeManager::CSchemeManager( int xRes, int yRes ) +{ + // basic setup + m_pSchemeList = NULL; + m_iNumSchemes = 0; + + // find the closest matching scheme file to our resolution + char token[1024]; + char *pFile = (char*)LoadFileByResolution( "", xRes, "_textscheme.txt" ); + m_xRes = xRes; + + char *pFileStart = pFile; + + byte *pFontData; + int fontFileLength; + char fontFilename[512]; + + // + // Read the scheme descriptions from the text file, into a temporary array + // format is simply: + // = + // + // a of "SchemeName" signals a new scheme is being described + // + + const static int numTmpSchemes = 64; + static CScheme tmpSchemes[numTmpSchemes]; + memset( tmpSchemes, 0, sizeof(tmpSchemes) ); + int currentScheme = -1; + CScheme *pScheme = NULL; + + if ( !pFile ) + { + gEngfuncs.Con_DPrintf( "Unable to find *_textscheme.txt\n"); + goto buildDefaultFont; + } + + // record what has been entered so we can create defaults from the different values + bool hasFgColor, hasBgColor, hasArmedFgColor, hasArmedBgColor, hasMouseDownFgColor, hasMouseDownBgColor; + + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + while ( strlen(token) > 0 && (currentScheme < numTmpSchemes) ) + { + // get the paramName name + static const int tokenSize = 64; + char paramName[tokenSize], paramValue[tokenSize]; + + strncpy( paramName, token, tokenSize ); + paramName[tokenSize-1] = 0; // ensure null termination + + // get the '=' character + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + if ( stricmp( token, "=" ) ) + { + if ( currentScheme < 0 ) + { + gEngfuncs.Con_Printf( "error parsing font scheme text file at file start - expected '=', found '%s''\n", token ); + } + else + { + gEngfuncs.Con_Printf( "error parsing font scheme text file at scheme '%s' - expected '=', found '%s''\n", tmpSchemes[currentScheme].schemeName, token ); + } + break; + } + + // get paramValue + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + strncpy( paramValue, token, tokenSize ); + paramValue[tokenSize-1] = 0; // ensure null termination + + // is this a new scheme? + if ( !stricmp(paramName, "SchemeName") ) + { + // setup the defaults for the current scheme + if ( pScheme ) + { + // foreground color defaults (normal -> armed -> mouse down) + if ( !hasFgColor ) + { + pScheme->fgColor[0] = pScheme->fgColor[1] = pScheme->fgColor[2] = pScheme->fgColor[3] = 255; + } + if ( !hasArmedFgColor ) + { + memcpy( pScheme->armedFgColor, pScheme->fgColor, sizeof(pScheme->armedFgColor) ); + } + if ( !hasMouseDownFgColor ) + { + memcpy( pScheme->mousedownFgColor, pScheme->armedFgColor, sizeof(pScheme->mousedownFgColor) ); + } + + // background color (normal -> armed -> mouse down) + if ( !hasBgColor ) + { + pScheme->bgColor[0] = pScheme->bgColor[1] = pScheme->bgColor[2] = pScheme->bgColor[3] = 0; + } + if ( !hasArmedBgColor ) + { + memcpy( pScheme->armedBgColor, pScheme->bgColor, sizeof(pScheme->armedBgColor) ); + } + if ( !hasMouseDownBgColor ) + { + memcpy( pScheme->mousedownBgColor, pScheme->armedBgColor, sizeof(pScheme->mousedownBgColor) ); + } + + // font size + if ( !pScheme->fontSize ) + { + pScheme->fontSize = 17; + } + if ( !pScheme->fontName[0] ) + { + strcpy( pScheme->fontName, "Arial" ); + } + } + + // create the new scheme + currentScheme++; + pScheme = &tmpSchemes[currentScheme]; + hasFgColor = hasBgColor = hasArmedFgColor = hasArmedBgColor = hasMouseDownFgColor = hasMouseDownBgColor = false; + + strncpy( pScheme->schemeName, paramValue, CScheme::SCHEME_NAME_LENGTH ); + pScheme->schemeName[CScheme::SCHEME_NAME_LENGTH-1] = '\0'; // ensure null termination of string + } + + if ( !pScheme ) + { + gEngfuncs.Con_Printf( "font scheme text file MUST start with a 'SchemeName'\n"); + break; + } + + // pull the data out into the scheme + if ( !stricmp(paramName, "FontName") ) + { + strncpy( pScheme->fontName, paramValue, CScheme::FONT_NAME_LENGTH ); + pScheme->fontName[CScheme::FONT_NAME_LENGTH-1] = 0; + } + else if ( !stricmp(paramName, "FontSize") ) + { + pScheme->fontSize = atoi( paramValue ); + } + else if ( !stricmp(paramName, "FontWeight") ) + { + pScheme->fontWeight = atoi( paramValue ); + } + else if ( !stricmp(paramName, "FgColor") ) + { + ParseRGBAFromString( pScheme->fgColor, paramValue ); + hasFgColor = true; + } + else if ( !stricmp(paramName, "BgColor") ) + { + ParseRGBAFromString( pScheme->bgColor, paramValue ); + hasBgColor = true; + } + else if ( !stricmp(paramName, "FgColorArmed") ) + { + ParseRGBAFromString( pScheme->armedFgColor, paramValue ); + hasArmedFgColor = true; + } + else if ( !stricmp(paramName, "BgColorArmed") ) + { + ParseRGBAFromString( pScheme->armedBgColor, paramValue ); + hasArmedBgColor = true; + } + else if ( !stricmp(paramName, "FgColorMousedown") ) + { + ParseRGBAFromString( pScheme->mousedownFgColor, paramValue ); + hasMouseDownFgColor = true; + } + else if ( !stricmp(paramName, "BgColorMousedown") ) + { + ParseRGBAFromString( pScheme->mousedownBgColor, paramValue ); + hasMouseDownBgColor = true; + } + else if ( !stricmp(paramName, "BorderColor") ) + { + ParseRGBAFromString( pScheme->borderColor, paramValue ); + hasMouseDownBgColor = true; + } + + // get the new token last, so we now if the loop needs to be continued or not + pFile = gEngfuncs.COM_ParseFile( pFile, token ); + } + + // free the file + gEngfuncs.COM_FreeFile( pFileStart ); + + +buildDefaultFont: + + // make sure we have at least 1 valid font + if ( currentScheme < 0 ) + { + currentScheme = 0; + strcpy( tmpSchemes[0].schemeName, "Default Scheme" ); + strcpy( tmpSchemes[0].fontName, "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; + tmpSchemes[0].mousedownFgColor[0] = tmpSchemes[0].mousedownFgColor[1] = tmpSchemes[0].mousedownFgColor[2] = tmpSchemes[0].mousedownFgColor[3] = 255; + } + + // we have the full list of schemes in the tmpSchemes array + // now allocate the correct sized list + m_iNumSchemes = currentScheme + 1; // 0-based index + m_pSchemeList = new CScheme[ m_iNumSchemes ]; + + // copy in the data + memcpy( m_pSchemeList, tmpSchemes, sizeof(CScheme) * m_iNumSchemes ); + + // create the fonts + for ( int i = 0; i < m_iNumSchemes; i++ ) + { + m_pSchemeList[i].font = NULL; + + // see if the current font values exist in a previously loaded font + for ( int j = 0; j < i; j++ ) + { + // check if the font name, size, and weight are the same + if ( !stricmp(m_pSchemeList[i].fontName, m_pSchemeList[j].fontName) + && m_pSchemeList[i].fontSize == m_pSchemeList[j].fontSize + && m_pSchemeList[i].fontWeight == m_pSchemeList[j].fontWeight ) + { + // copy the pointer, but mark i as not owning it + m_pSchemeList[i].font = m_pSchemeList[j].font; + m_pSchemeList[i].ownFontPointer = false; + } + } + + // if we haven't found the font already, load it ourselves + if ( !m_pSchemeList[i].font ) + { + fontFileLength = -1; + pFontData = NULL; + + if(g_CV_BitmapFonts && g_CV_BitmapFonts->value) + { + sprintf(fontFilename, "gfx\\vgui\\fonts\\%d_%s.tga", m_xRes, m_pSchemeList[i].schemeName); + pFontData = gEngfuncs.COM_LoadFile( fontFilename, 5, &fontFileLength ); + if(!pFontData) + gEngfuncs.Con_Printf("Missing bitmap font: %s\n", fontFilename); + } + + m_pSchemeList[i].font = new vgui::Font( + m_pSchemeList[i].fontName, + pFontData, + fontFileLength, + m_pSchemeList[i].fontSize, + 0, + 0, + m_pSchemeList[i].fontWeight, + false, + false, + false, + false); + + m_pSchemeList[i].ownFontPointer = true; + } + + // fix up alpha values; VGUI uses 1-A (A=0 being solid, A=255 transparent) + m_pSchemeList[i].fgColor[3] = 255 - m_pSchemeList[i].fgColor[3]; + m_pSchemeList[i].bgColor[3] = 255 - m_pSchemeList[i].bgColor[3]; + m_pSchemeList[i].armedFgColor[3] = 255 - m_pSchemeList[i].armedFgColor[3]; + m_pSchemeList[i].armedBgColor[3] = 255 - m_pSchemeList[i].armedBgColor[3]; + m_pSchemeList[i].mousedownFgColor[3] = 255 - m_pSchemeList[i].mousedownFgColor[3]; + m_pSchemeList[i].mousedownBgColor[3] = 255 - m_pSchemeList[i].mousedownBgColor[3]; + } +} + +//----------------------------------------------------------------------------- +// Purpose: frees all the memory used by the scheme manager +//----------------------------------------------------------------------------- +CSchemeManager::~CSchemeManager() +{ + delete [] m_pSchemeList; + m_iNumSchemes = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: Finds a scheme in the list, by name +// Input : char *schemeName - string name of the scheme +// Output : SchemeHandle_t handle to the scheme +//----------------------------------------------------------------------------- +SchemeHandle_t CSchemeManager::getSchemeHandle( const char *schemeName ) +{ + // iterate through the list + for ( int i = 0; i < m_iNumSchemes; i++ ) + { + if ( !stricmp(schemeName, m_pSchemeList[i].schemeName) ) + return i; + } + + return 0; +} + +//----------------------------------------------------------------------------- +// Purpose: always returns a valid scheme handle +// Input : schemeHandle - +// Output : CScheme +//----------------------------------------------------------------------------- +CSchemeManager::CScheme *CSchemeManager::getSafeScheme( SchemeHandle_t schemeHandle ) +{ + if ( schemeHandle < m_iNumSchemes ) + return m_pSchemeList + schemeHandle; + + return m_pSchemeList; +} + + +//----------------------------------------------------------------------------- +// Purpose: Returns the schemes pointer to a font +// Input : schemeHandle - +// Output : vgui::Font +//----------------------------------------------------------------------------- +vgui::Font *CSchemeManager::getFont( SchemeHandle_t schemeHandle ) +{ + return getSafeScheme( schemeHandle )->font; +} + +void CSchemeManager::getFgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->fgColor[0]; + g = pScheme->fgColor[1]; + b = pScheme->fgColor[2]; + a = pScheme->fgColor[3]; +} + +void CSchemeManager::getBgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->bgColor[0]; + g = pScheme->bgColor[1]; + b = pScheme->bgColor[2]; + a = pScheme->bgColor[3]; +} + +void CSchemeManager::getFgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->armedFgColor[0]; + g = pScheme->armedFgColor[1]; + b = pScheme->armedFgColor[2]; + a = pScheme->armedFgColor[3]; +} + +void CSchemeManager::getBgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->armedBgColor[0]; + g = pScheme->armedBgColor[1]; + b = pScheme->armedBgColor[2]; + a = pScheme->armedBgColor[3]; +} + +void CSchemeManager::getFgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->mousedownFgColor[0]; + g = pScheme->mousedownFgColor[1]; + b = pScheme->mousedownFgColor[2]; + a = pScheme->mousedownFgColor[3]; +} + +void CSchemeManager::getBgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->mousedownBgColor[0]; + g = pScheme->mousedownBgColor[1]; + b = pScheme->mousedownBgColor[2]; + a = pScheme->mousedownBgColor[3]; +} + +void CSchemeManager::getBorderColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ) +{ + CScheme *pScheme = getSafeScheme( schemeHandle ); + r = pScheme->borderColor[0]; + g = pScheme->borderColor[1]; + b = pScheme->borderColor[2]; + a = pScheme->borderColor[3]; +} + + + diff --git a/cl_dll/vgui_SchemeManager.h b/cl_dll/vgui_SchemeManager.h new file mode 100644 index 00000000..45c2a06b --- /dev/null +++ b/cl_dll/vgui_SchemeManager.h @@ -0,0 +1,54 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include + + +// handle to an individual scheme +typedef int SchemeHandle_t; + + +// Register console variables, etc.. +void Scheme_Init(); + + +//----------------------------------------------------------------------------- +// Purpose: Handles the loading of text scheme description from disk +// supports different font/color/size schemes at different resolutions +//----------------------------------------------------------------------------- +class CSchemeManager +{ +public: + // initialization + CSchemeManager( int xRes, int yRes ); + virtual ~CSchemeManager(); + + // scheme handling + SchemeHandle_t getSchemeHandle( const char *schemeName ); + + // getting info from schemes + vgui::Font *getFont( SchemeHandle_t schemeHandle ); + void getFgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getFgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgArmedColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getFgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBgMousedownColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + void getBorderColor( SchemeHandle_t schemeHandle, int &r, int &g, int &b, int &a ); + +private: + class CScheme; + CScheme *m_pSchemeList; + int m_iNumSchemes; + + // Resolution we were initted at. + int m_xRes; + + CScheme *getSafeScheme( SchemeHandle_t schemeHandle ); +}; + + diff --git a/cl_dll/vgui_ScorePanel.cpp b/cl_dll/vgui_ScorePanel.cpp new file mode 100644 index 00000000..bea050dc --- /dev/null +++ b/cl_dll/vgui_ScorePanel.cpp @@ -0,0 +1,1095 @@ +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: VGUI scoreboard +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + + +#include + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ScorePanel.h" +#include "..\game_shared\vgui_helpers.h" +#include "..\game_shared\vgui_loadtga.h" +#include "vgui_SpectatorPanel.h" + +hud_player_info_t g_PlayerInfoList[MAX_PLAYERS+1]; // player info from the engine +extra_player_info_t g_PlayerExtraInfo[MAX_PLAYERS+1]; // additional player info sent directly to the client dll +team_info_t g_TeamInfo[MAX_TEAMS+1]; +int g_IsSpectator[MAX_PLAYERS+1]; + +int HUD_IsGame( const char *game ); +int EV_TFC_IsAllyTeam( int iTeam1, int iTeam2 ); + +// Scoreboard dimensions +#define SBOARD_TITLE_SIZE_Y YRES(22) + +#define X_BORDER XRES(4) + +// Column sizes +class SBColumnInfo +{ +public: + char *m_pTitle; // If null, ignore, if starts with #, it's localized, otherwise use the string directly. + int m_Width; // Based on 640 width. Scaled to fit other resolutions. + Label::Alignment m_Alignment; +}; + +// grid size is marked out for 640x480 screen + +SBColumnInfo g_ColumnInfo[NUM_COLUMNS] = +{ + {NULL, 24, Label::a_east}, + {NULL, 140, Label::a_east}, // name + {NULL, 56, Label::a_east}, // class + {"#SCORE", 40, Label::a_east}, + {"#DEATHS", 46, Label::a_east}, + {"#LATENCY", 46, Label::a_east}, + {"#VOICE", 40, Label::a_east}, + {NULL, 2, Label::a_east}, // blank column to take up the slack +}; + + +#define TEAM_NO 0 +#define TEAM_YES 1 +#define TEAM_SPECTATORS 2 +#define TEAM_BLANK 3 + + +//----------------------------------------------------------------------------- +// ScorePanel::HitTestPanel. +//----------------------------------------------------------------------------- + +void ScorePanel::HitTestPanel::internalMousePressed(MouseCode code) +{ + for(int i=0;i<_inputSignalDar.getCount();i++) + { + _inputSignalDar[i]->mousePressed(code,this); + } +} + + + +//----------------------------------------------------------------------------- +// Purpose: Create the ScoreBoard panel +//----------------------------------------------------------------------------- +ScorePanel::ScorePanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); + SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); + Font *tfont = pSchemes->getFont(hTitleScheme); + Font *smallfont = pSchemes->getFont(hSmallScheme); + + setBgColor(0, 0, 0, 96); + m_pCurrentHighlightLabel = NULL; + m_iHighlightRow = -1; + + // Initialize the top title. + m_TitleLabel.setFont(tfont); + m_TitleLabel.setText(""); + m_TitleLabel.setBgColor( 0, 0, 0, 255 ); + m_TitleLabel.setFgColor( Scheme::sc_primary1 ); + m_TitleLabel.setContentAlignment( vgui::Label::a_west ); + + LineBorder *border = new LineBorder(Color(60, 60, 60, 128)); + setBorder(border); + setPaintBorderEnabled(true); + + int xpos = g_ColumnInfo[0].m_Width + 3; + if (ScreenWidth >= 640) + { + // only expand column size for res greater than 640 + xpos = XRES(xpos); + } + m_TitleLabel.setBounds(xpos, 4, wide, SBOARD_TITLE_SIZE_Y); + m_TitleLabel.setContentFitted(false); + m_TitleLabel.setParent(this); + + // Setup the header (labels like "name", "class", etc..). + m_HeaderGrid.SetDimensions(NUM_COLUMNS, 1); + m_HeaderGrid.SetSpacing(0, 0); + + for(int i=0; i < NUM_COLUMNS; i++) + { + if (g_ColumnInfo[i].m_pTitle && g_ColumnInfo[i].m_pTitle[0] == '#') + m_HeaderLabels[i].setText(CHudTextMessage::BufferedLocaliseTextString(g_ColumnInfo[i].m_pTitle)); + else if(g_ColumnInfo[i].m_pTitle) + m_HeaderLabels[i].setText(g_ColumnInfo[i].m_pTitle); + + int xwide = g_ColumnInfo[i].m_Width; + if (ScreenWidth >= 640) + { + xwide = XRES(xwide); + } + else if (ScreenWidth == 400) + { + // hack to make 400x300 resolution scoreboard fit + if (i == 1) + { + // reduces size of player name cell + xwide -= 28; + } + else if (i == 0) + { + xwide -= 8; + } + } + + m_HeaderGrid.SetColumnWidth(i, xwide); + m_HeaderGrid.SetEntry(i, 0, &m_HeaderLabels[i]); + + m_HeaderLabels[i].setBgColor(0,0,0,255); + m_HeaderLabels[i].setFgColor(Scheme::sc_primary1); + m_HeaderLabels[i].setFont(smallfont); + m_HeaderLabels[i].setContentAlignment(g_ColumnInfo[i].m_Alignment); + + int yres = 12; + if (ScreenHeight >= 480) + { + yres = YRES(yres); + } + m_HeaderLabels[i].setSize(50, yres); + } + + // Set the width of the last column to be the remaining space. + int ex, ey, ew, eh; + m_HeaderGrid.GetEntryBox(NUM_COLUMNS - 2, 0, ex, ey, ew, eh); + m_HeaderGrid.SetColumnWidth(NUM_COLUMNS - 1, (wide - X_BORDER) - (ex + ew)); + + m_HeaderGrid.AutoSetRowHeights(); + m_HeaderGrid.setBounds(X_BORDER, SBOARD_TITLE_SIZE_Y, wide - X_BORDER*2, m_HeaderGrid.GetRowHeight(0)); + m_HeaderGrid.setParent(this); + m_HeaderGrid.setBgColor(0,0,0,255); + + + // Now setup the listbox with the actual player data in it. + int headerX, headerY, headerWidth, headerHeight; + m_HeaderGrid.getBounds(headerX, headerY, headerWidth, headerHeight); + m_PlayerList.setBounds(headerX, headerY+headerHeight, headerWidth, tall - headerY - headerHeight - 6); + m_PlayerList.setBgColor(0,0,0,255); + m_PlayerList.setParent(this); + + for(int row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + + pGridRow->SetDimensions(NUM_COLUMNS, 1); + + for(int col=0; col < NUM_COLUMNS; col++) + { + m_PlayerEntries[col][row].setContentFitted(false); + m_PlayerEntries[col][row].setRow(row); + m_PlayerEntries[col][row].addInputSignal(this); + pGridRow->SetEntry(col, 0, &m_PlayerEntries[col][row]); + } + + pGridRow->setBgColor(0,0,0,255); +// pGridRow->SetSpacing(2, 0); + pGridRow->SetSpacing(0, 0); + pGridRow->CopyColumnWidths(&m_HeaderGrid); + pGridRow->AutoSetRowHeights(); + pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); + pGridRow->RepositionContents(); + + m_PlayerList.AddItem(pGridRow); + } + + + // Add the hit test panel. It is invisible and traps mouse clicks so we can go into squelch mode. + m_HitTestPanel.setBgColor(0,0,0,255); + m_HitTestPanel.setParent(this); + m_HitTestPanel.setBounds(0, 0, wide, tall); + m_HitTestPanel.addInputSignal(this); + + m_pCloseButton = new CommandButton( "x", wide-XRES(12 + 4), YRES(2), XRES( 12 ) , YRES( 12 ) ); + m_pCloseButton->setParent( this ); + m_pCloseButton->addActionSignal( new CMenuHandler_StringCommandWatch( "-showscores", true ) ); + m_pCloseButton->setBgColor(0,0,0,255); + m_pCloseButton->setFgColor( 255, 255, 255, 0 ); + m_pCloseButton->setFont(tfont); + m_pCloseButton->setBoundKey( (char)255 ); + m_pCloseButton->setContentAlignment(Label::a_center); + + + Initialize(); +} + + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void ScorePanel::Initialize( void ) +{ + // Clear out scoreboard data + m_iLastKilledBy = 0; + m_fLastKillTime = 0; + m_iPlayerNum = 0; + m_iNumTeams = 0; + memset( g_PlayerExtraInfo, 0, sizeof g_PlayerExtraInfo ); + memset( g_TeamInfo, 0, sizeof g_TeamInfo ); +} + +bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ) +{ + return !!gEngfuncs.GetPlayerUniqueID( iPlayer, playerID ); +} + +//----------------------------------------------------------------------------- +// Purpose: Recalculate the internal scoreboard data +//----------------------------------------------------------------------------- +void ScorePanel::Update() +{ + // Set the title + if (gViewPort->m_szServerName) + { + char sz[MAX_SERVERNAME_LENGTH + 16]; + sprintf(sz, "%s", gViewPort->m_szServerName ); + m_TitleLabel.setText(sz); + } + + m_iRows = 0; + gViewPort->GetAllPlayersInfo(); + + // Clear out sorts + for (int i = 0; i < NUM_ROWS; i++) + { + m_iSortedRows[i] = 0; + m_iIsATeam[i] = TEAM_NO; + m_bHasBeenSorted[i] = false; + } + + // If it's not teamplay, sort all the players. Otherwise, sort the teams. + if ( !gHUD.m_Teamplay ) + SortPlayers( 0, NULL ); + else + SortTeams(); + + // set scrollbar range + m_PlayerList.SetScrollRange(m_iRows); + + FillGrid(); + + if ( gViewPort->m_pSpectatorPanel->m_menuVisible ) + { + m_pCloseButton->setVisible ( true ); + } + else + { + m_pCloseButton->setVisible ( false ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Sort all the teams +//----------------------------------------------------------------------------- +void ScorePanel::SortTeams() +{ + // clear out team scores + for ( int i = 1; i <= m_iNumTeams; i++ ) + { + if ( !g_TeamInfo[i].scores_overriden ) + g_TeamInfo[i].frags = g_TeamInfo[i].deaths = 0; + g_TeamInfo[i].ping = g_TeamInfo[i].packetloss = 0; + } + + // recalc the team scores, then draw them + for ( i = 1; i < MAX_PLAYERS; i++ ) + { + if ( g_PlayerInfoList[i].name == NULL ) + continue; // empty player slot, skip + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + // find what team this player is in + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + break; + } + if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy + continue; + + if ( !g_TeamInfo[j].scores_overriden ) + { + g_TeamInfo[j].frags += g_PlayerExtraInfo[i].frags; + g_TeamInfo[j].deaths += g_PlayerExtraInfo[i].deaths; + } + + g_TeamInfo[j].ping += g_PlayerInfoList[i].ping; + g_TeamInfo[j].packetloss += g_PlayerInfoList[i].packetloss; + + if ( g_PlayerInfoList[i].thisplayer ) + g_TeamInfo[j].ownteam = TRUE; + else + g_TeamInfo[j].ownteam = FALSE; + + // Set the team's number (used for team colors) + g_TeamInfo[j].teamnumber = g_PlayerExtraInfo[i].teamnumber; + } + + // find team ping/packetloss averages + for ( i = 1; i <= m_iNumTeams; i++ ) + { + g_TeamInfo[i].already_drawn = FALSE; + + if ( g_TeamInfo[i].players > 0 ) + { + g_TeamInfo[i].ping /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping + g_TeamInfo[i].packetloss /= g_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping + } + } + + // Draw the teams + while ( 1 ) + { + int highest_frags = -99999; int lowest_deaths = 99999; + int best_team = 0; + + for ( i = 1; i <= m_iNumTeams; i++ ) + { + if ( g_TeamInfo[i].players < 1 ) + continue; + + if ( !g_TeamInfo[i].already_drawn && g_TeamInfo[i].frags >= highest_frags ) + { + if ( g_TeamInfo[i].frags > highest_frags || g_TeamInfo[i].deaths < lowest_deaths ) + { + best_team = i; + lowest_deaths = g_TeamInfo[i].deaths; + highest_frags = g_TeamInfo[i].frags; + } + } + } + + // draw the best team on the scoreboard + if ( !best_team ) + break; + + // Put this team in the sorted list + m_iSortedRows[ m_iRows ] = best_team; + m_iIsATeam[ m_iRows ] = TEAM_YES; + g_TeamInfo[best_team].already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get sorted again + m_iRows++; + + // Now sort all the players on this team + SortPlayers( 0, g_TeamInfo[best_team].name ); + } + + // Add all the players who aren't in a team yet into spectators + SortPlayers( TEAM_SPECTATORS, NULL ); +} + +//----------------------------------------------------------------------------- +// Purpose: Sort a list of players +//----------------------------------------------------------------------------- +void ScorePanel::SortPlayers( int iTeam, char *team ) +{ + bool bCreatedTeam = false; + + // draw the players, in order, and restricted to team if set + while ( 1 ) + { + // Find the top ranking player + int highest_frags = -99999; int lowest_deaths = 99999; + int best_player; + best_player = 0; + + for ( int i = 1; i < MAX_PLAYERS; i++ ) + { + if ( m_bHasBeenSorted[i] == false && g_PlayerInfoList[i].name && g_PlayerExtraInfo[i].frags >= highest_frags ) + { + cl_entity_t *ent = gEngfuncs.GetEntityByIndex( i ); + + if ( ent && !(team && stricmp(g_PlayerExtraInfo[i].teamname, team)) ) + { + extra_player_info_t *pl_info = &g_PlayerExtraInfo[i]; + if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths ) + { + best_player = i; + lowest_deaths = pl_info->deaths; + highest_frags = pl_info->frags; + } + } + } + } + + if ( !best_player ) + break; + + // If we haven't created the Team yet, do it first + if (!bCreatedTeam && iTeam) + { + m_iIsATeam[ m_iRows ] = iTeam; + m_iRows++; + + bCreatedTeam = true; + } + + // Put this player in the sorted list + m_iSortedRows[ m_iRows ] = best_player; + m_bHasBeenSorted[ best_player ] = true; + m_iRows++; + } + + if (team) + { + m_iIsATeam[m_iRows++] = TEAM_BLANK; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Recalculate the existing teams in the match +//----------------------------------------------------------------------------- +void ScorePanel::RebuildTeams() +{ + // clear out player counts from teams + for ( int i = 1; i <= m_iNumTeams; i++ ) + { + g_TeamInfo[i].players = 0; + } + + // rebuild the team list + gViewPort->GetAllPlayersInfo(); + m_iNumTeams = 0; + for ( i = 1; i < MAX_PLAYERS; i++ ) + { + if ( g_PlayerInfoList[i].name == NULL ) + continue; + + if ( g_PlayerExtraInfo[i].teamname[0] == 0 ) + continue; // skip over players who are not in a team + + // is this player in an existing team? + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( g_TeamInfo[j].name[0] == '\0' ) + break; + + if ( !stricmp( g_PlayerExtraInfo[i].teamname, g_TeamInfo[j].name ) ) + break; + } + + if ( j > m_iNumTeams ) + { // they aren't in a listed team, so make a new one + // search through for an empty team slot + for ( int j = 1; j <= m_iNumTeams; j++ ) + { + if ( g_TeamInfo[j].name[0] == '\0' ) + break; + } + m_iNumTeams = max( j, m_iNumTeams ); + + strncpy( g_TeamInfo[j].name, g_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); + g_TeamInfo[j].players = 0; + } + + g_TeamInfo[j].players++; + } + + // clear out any empty teams + for ( i = 1; i <= m_iNumTeams; i++ ) + { + if ( g_TeamInfo[i].players < 1 ) + memset( &g_TeamInfo[i], 0, sizeof(team_info_t) ); + } + + // Update the scoreboard + Update(); +} + + +void ScorePanel::FillGrid() +{ + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + SchemeHandle_t hScheme = pSchemes->getSchemeHandle("Scoreboard Text"); + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle("Scoreboard Title Text"); + SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle("Scoreboard Small Text"); + + Font *sfont = pSchemes->getFont(hScheme); + Font *tfont = pSchemes->getFont(hTitleScheme); + Font *smallfont = pSchemes->getFont(hSmallScheme); + + // update highlight position + int x, y; + getApp()->getCursorPos(x, y); + cursorMoved(x, y, this); + + // remove highlight row if we're not in squelch mode + if (!GetClientVoiceMgr()->IsInSquelchMode()) + { + m_iHighlightRow = -1; + } + + bool bNextRowIsGap = false; + + for(int row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + pGridRow->SetRowUnderline(0, false, 0, 0, 0, 0, 0); + + if(row >= m_iRows) + { + for(int col=0; col < NUM_COLUMNS; col++) + m_PlayerEntries[col][row].setVisible(false); + + continue; + } + + bool bRowIsGap = false; + if (bNextRowIsGap) + { + bNextRowIsGap = false; + bRowIsGap = true; + } + + for(int col=0; col < NUM_COLUMNS; col++) + { + CLabelHeader *pLabel = &m_PlayerEntries[col][row]; + + pLabel->setVisible(true); + pLabel->setText2(""); + pLabel->setImage(NULL); + pLabel->setFont(sfont); + pLabel->setTextOffset(0, 0); + + int rowheight = 13; + if (ScreenHeight > 480) + { + rowheight = YRES(rowheight); + } + else + { + // more tweaking, make sure icons fit at low res + rowheight = 15; + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setBgColor(0, 0, 0, 255); + + char sz[128]; + hud_player_info_t *pl_info = NULL; + team_info_t *team_info = NULL; + + if (m_iIsATeam[row] == TEAM_BLANK) + { + pLabel->setText(" "); + continue; + } + else if ( m_iIsATeam[row] == TEAM_YES ) + { + // Get the team's data + team_info = &g_TeamInfo[ m_iSortedRows[row] ]; + + // team color text for team names + pLabel->setFgColor( iTeamColors[team_info->teamnumber % iNumberOfTeamColors][0], + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][1], + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][2], + 0 ); + + // different height for team header rows + rowheight = 20; + if (ScreenHeight >= 480) + { + rowheight = YRES(rowheight); + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setFont(tfont); + + pGridRow->SetRowUnderline( 0, + true, + YRES(3), + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][0], + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][1], + iTeamColors[team_info->teamnumber % iNumberOfTeamColors][2], + 0 ); + } + else if ( m_iIsATeam[row] == TEAM_SPECTATORS ) + { + // grey text for spectators + pLabel->setFgColor(100, 100, 100, 0); + + // different height for team header rows + rowheight = 20; + if (ScreenHeight >= 480) + { + rowheight = YRES(rowheight); + } + pLabel->setSize(pLabel->getWide(), rowheight); + pLabel->setFont(tfont); + + pGridRow->SetRowUnderline(0, true, YRES(3), 100, 100, 100, 0); + } + else + { + // team color text for player names + pLabel->setFgColor( iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][0], + iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][1], + iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][2], + 0 ); + + // Get the player's data + pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; + + // Set background color + if ( pl_info->thisplayer ) // if it is their name, draw it a different color + { + // Highlight this player + pLabel->setFgColor(Scheme::sc_white); + pLabel->setBgColor( iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][0], + iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][1], + iTeamColors[ g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber % iNumberOfTeamColors ][2], + 196 ); + } + else if ( m_iSortedRows[row] == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) + { + // Killer's name + pLabel->setBgColor( 255,0,0, 255 - ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); + } + } + + // Align + if (col == COLUMN_NAME || col == COLUMN_CLASS) + { + pLabel->setContentAlignment( vgui::Label::a_west ); + } + else if (col == COLUMN_TRACKER) + { + pLabel->setContentAlignment( vgui::Label::a_center ); + } + else + { + pLabel->setContentAlignment( vgui::Label::a_east ); + } + + // Fill out with the correct data + strcpy(sz, ""); + if ( m_iIsATeam[row] ) + { + char sz2[128]; + + switch (col) + { + case COLUMN_NAME: + if ( m_iIsATeam[row] == TEAM_SPECTATORS ) + { + sprintf( sz2, CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ) ); + } + else + { + sprintf( sz2, gViewPort->GetTeamName(team_info->teamnumber) ); + } + + strcpy(sz, sz2); + + // Append the number of players + if ( m_iIsATeam[row] == TEAM_YES ) + { + if (team_info->players == 1) + { + sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player" ) ); + } + else + { + sprintf(sz2, "(%d %s)", team_info->players, CHudTextMessage::BufferedLocaliseTextString( "#Player_plural" ) ); + } + + pLabel->setText2(sz2); + pLabel->setFont2(smallfont); + } + break; + case COLUMN_VOICE: + break; + case COLUMN_CLASS: + break; + case COLUMN_KILLS: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->frags ); + break; + case COLUMN_DEATHS: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->deaths ); + break; + case COLUMN_LATENCY: + if ( m_iIsATeam[row] == TEAM_YES ) + sprintf(sz, "%d", team_info->ping ); + break; + default: + break; + } + } + else + { + bool bShowClass = false; + + switch (col) + { + case COLUMN_NAME: + sprintf(sz, "%s ", pl_info->name); + break; + case COLUMN_VOICE: + sz[0] = 0; + // in HLTV mode allow spectator to turn on/off commentator voice + if (!pl_info->thisplayer || gEngfuncs.IsSpectateOnly() ) + { + GetClientVoiceMgr()->UpdateSpeakerImage(pLabel, m_iSortedRows[row]); + } + break; + case COLUMN_CLASS: + // No class for other team's members (unless allied or spectator) + if ( gViewPort && EV_TFC_IsAllyTeam( g_iTeamNumber, g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ) ) + bShowClass = true; + // Don't show classes if this client hasnt picked a team yet + if ( g_iTeamNumber == 0 ) + bShowClass = false; + + if (bShowClass) + { + // Only print Civilian if this team are all civilians + bool bNoClass = false; + if ( g_PlayerExtraInfo[ m_iSortedRows[row] ].playerclass == 0 ) + { + if ( gViewPort->GetValidClasses( g_PlayerExtraInfo[ m_iSortedRows[row] ].teamnumber ) != -1 ) + bNoClass = true; + } + + if (bNoClass) + sprintf(sz, ""); + else + sprintf( sz, "%s", CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[ g_PlayerExtraInfo[ m_iSortedRows[row] ].playerclass ] ) ); + } + else + { + strcpy(sz, ""); + } + break; + + case COLUMN_TRACKER: + break; + case COLUMN_KILLS: + sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].frags ); + break; + case COLUMN_DEATHS: + sprintf(sz, "%d", g_PlayerExtraInfo[ m_iSortedRows[row] ].deaths ); + break; + case COLUMN_LATENCY: + sprintf(sz, "%d", g_PlayerInfoList[ m_iSortedRows[row] ].ping ); + break; + default: + break; + } + } + + pLabel->setText(sz); + } + } + + for(row=0; row < NUM_ROWS; row++) + { + CGrid *pGridRow = &m_PlayerGrids[row]; + + pGridRow->AutoSetRowHeights(); + pGridRow->setSize(PanelWidth(pGridRow), pGridRow->CalcDrawHeight()); + pGridRow->RepositionContents(); + } + + // hack, for the thing to resize + m_PlayerList.getSize(x, y); + m_PlayerList.setSize(x, y); +} + + +//----------------------------------------------------------------------------- +// Purpose: Setup highlights for player names in scoreboard +//----------------------------------------------------------------------------- +void ScorePanel::DeathMsg( int killer, int victim ) +{ + // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide + if ( victim == m_iPlayerNum || killer == 0 ) + { + m_iLastKilledBy = killer ? killer : m_iPlayerNum; + m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds + + if ( killer == m_iPlayerNum ) + m_iLastKilledBy = m_iPlayerNum; + } +} + + +void ScorePanel::Open( void ) +{ + RebuildTeams(); + setVisible(true); + m_HitTestPanel.setVisible(true); +} + + +void ScorePanel::mousePressed(MouseCode code, Panel* panel) +{ + if(gHUD.m_iIntermission) + return; + + if (!GetClientVoiceMgr()->IsInSquelchMode()) + { + GetClientVoiceMgr()->StartSquelchMode(); + m_HitTestPanel.setVisible(false); + } + else if (m_iHighlightRow >= 0) + { + // mouse has been pressed, toggle mute state + int iPlayer = m_iSortedRows[m_iHighlightRow]; + if (iPlayer > 0) + { + // print text message + hud_player_info_t *pl_info = &g_PlayerInfoList[iPlayer]; + + if (pl_info && pl_info->name && pl_info->name[0]) + { + char string[256]; + if (GetClientVoiceMgr()->IsPlayerBlocked(iPlayer)) + { + char string1[1024]; + + // remove mute + GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, false); + + sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Unmuted" ), pl_info->name ); + sprintf( string, "%c** %s\n", HUD_PRINTTALK, string1 ); + + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + else + { + char string1[1024]; + char string2[1024]; + + // mute the player + GetClientVoiceMgr()->SetPlayerBlockedState(iPlayer, true); + + sprintf( string1, CHudTextMessage::BufferedLocaliseTextString( "#Muted" ), pl_info->name ); + sprintf( string2, CHudTextMessage::BufferedLocaliseTextString( "#No_longer_hear_that_player" ) ); + sprintf( string, "%c** %s %s\n", HUD_PRINTTALK, string1, string2 ); + + gHUD.m_TextMessage.MsgFunc_TextMsg(NULL, strlen(string)+1, string ); + } + } + } + } +} + +void ScorePanel::cursorMoved(int x, int y, Panel *panel) +{ + if (GetClientVoiceMgr()->IsInSquelchMode()) + { + // look for which cell the mouse is currently over + for (int i = 0; i < NUM_ROWS; i++) + { + int row, col; + if (m_PlayerGrids[i].getCellAtPoint(x, y, row, col)) + { + MouseOverCell(i, col); + return; + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handles mouse movement over a cell +// Input : row - +// col - +//----------------------------------------------------------------------------- +void ScorePanel::MouseOverCell(int row, int col) +{ + CLabelHeader *label = &m_PlayerEntries[col][row]; + + // clear the previously highlighted label + if (m_pCurrentHighlightLabel != label) + { + m_pCurrentHighlightLabel = NULL; + m_iHighlightRow = -1; + } + if (!label) + return; + + // don't act on teams + if (m_iIsATeam[row] != TEAM_NO) + return; + + // don't act on disconnected players or ourselves + hud_player_info_t *pl_info = &g_PlayerInfoList[ m_iSortedRows[row] ]; + if (!pl_info->name || !pl_info->name[0]) + return; + + if (pl_info->thisplayer && !gEngfuncs.IsSpectateOnly() ) + return; + + // setup the new highlight + m_pCurrentHighlightLabel = label; + m_iHighlightRow = row; +} + +//----------------------------------------------------------------------------- +// Purpose: Label paint functions - take into account current highligh status +//----------------------------------------------------------------------------- +void CLabelHeader::paintBackground() +{ + Color oldBg; + getBgColor(oldBg); + + if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) + { + setBgColor(134, 91, 19, 0); + } + + Panel::paintBackground(); + + setBgColor(oldBg); +} + + +//----------------------------------------------------------------------------- +// Purpose: Label paint functions - take into account current highligh status +//----------------------------------------------------------------------------- +void CLabelHeader::paint() +{ + Color oldFg; + getFgColor(oldFg); + + if (gViewPort->GetScoreBoard()->m_iHighlightRow == _row) + { + setFgColor(255, 255, 255, 0); + } + + // draw text + int x, y, iwide, itall; + getTextSize(iwide, itall); + calcAlignment(iwide, itall, x, y); + _dualImage->setPos(x, y); + + int x1, y1; + _dualImage->GetImage(1)->getPos(x1, y1); + _dualImage->GetImage(1)->setPos(_gap, y1); + + _dualImage->doPaint(this); + + // get size of the panel and the image + if (_image) + { + Color imgColor; + getFgColor( imgColor ); + if( _useFgColorAsImageColor ) + { + _image->setColor( imgColor ); + } + + _image->getSize(iwide, itall); + calcAlignment(iwide, itall, x, y); + _image->setPos(x, y); + _image->doPaint(this); + } + + setFgColor(oldFg[0], oldFg[1], oldFg[2], oldFg[3]); +} + + +void CLabelHeader::calcAlignment(int iwide, int itall, int &x, int &y) +{ + // calculate alignment ourselves, since vgui is so broken + int wide, tall; + getSize(wide, tall); + + x = 0, y = 0; + + // align left/right + switch (_contentAlignment) + { + // left + case Label::a_northwest: + case Label::a_west: + case Label::a_southwest: + { + x = 0; + break; + } + + // center + case Label::a_north: + case Label::a_center: + case Label::a_south: + { + x = (wide - iwide) / 2; + break; + } + + // right + case Label::a_northeast: + case Label::a_east: + case Label::a_southeast: + { + x = wide - iwide; + break; + } + } + + // top/down + switch (_contentAlignment) + { + // top + case Label::a_northwest: + case Label::a_north: + case Label::a_northeast: + { + y = 0; + break; + } + + // center + case Label::a_west: + case Label::a_center: + case Label::a_east: + { + y = (tall - itall) / 2; + break; + } + + // south + case Label::a_southwest: + case Label::a_south: + case Label::a_southeast: + { + y = tall - itall; + break; + } + } + +// don't clip to Y +// if (y < 0) +// { +// y = 0; +// } + if (x < 0) + { + x = 0; + } + + x += _offset[0]; + y += _offset[1]; +} diff --git a/cl_dll/vgui_ScorePanel.h b/cl_dll/vgui_ScorePanel.h new file mode 100644 index 00000000..f7a8543a --- /dev/null +++ b/cl_dll/vgui_ScorePanel.h @@ -0,0 +1,310 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef SCOREPANEL_H +#define SCOREPANEL_H + +#include +#include +#include +#include +#include +#include +#include "..\game_shared\vgui_listbox.h" + +#include + +#define MAX_SCORES 10 +#define MAX_SCOREBOARD_TEAMS 5 + +// Scoreboard cells +#define COLUMN_TRACKER 0 +#define COLUMN_NAME 1 +#define COLUMN_CLASS 2 +#define COLUMN_KILLS 3 +#define COLUMN_DEATHS 4 +#define COLUMN_LATENCY 5 +#define COLUMN_VOICE 6 +#define COLUMN_BLANK 7 +#define NUM_COLUMNS 8 +#define NUM_ROWS (MAX_PLAYERS + (MAX_SCOREBOARD_TEAMS * 2)) + +using namespace vgui; + +class CTextImage2 : public Image +{ +public: + CTextImage2() + { + _image[0] = new TextImage(""); + _image[1] = new TextImage(""); + } + + ~CTextImage2() + { + delete _image[0]; + delete _image[1]; + } + + TextImage *GetImage(int image) + { + return _image[image]; + } + + void getSize(int &wide, int &tall) + { + int w1, w2, t1, t2; + _image[0]->getTextSize(w1, t1); + _image[1]->getTextSize(w2, t2); + + wide = w1 + w2; + tall = max(t1, t2); + setSize(wide, tall); + } + + void doPaint(Panel *panel) + { + _image[0]->doPaint(panel); + _image[1]->doPaint(panel); + } + + void setPos(int x, int y) + { + _image[0]->setPos(x, y); + + int swide, stall; + _image[0]->getSize(swide, stall); + + int wide, tall; + _image[1]->getSize(wide, tall); + _image[1]->setPos(x + wide, y + (stall * 0.9) - tall); + } + + void setColor(Color color) + { + _image[0]->setColor(color); + } + + void setColor2(Color color) + { + _image[1]->setColor(color); + } + +private: + TextImage *_image[2]; + +}; + +//----------------------------------------------------------------------------- +// Purpose: Custom label for cells in the Scoreboard's Table Header +//----------------------------------------------------------------------------- +class CLabelHeader : public Label +{ +public: + CLabelHeader() : Label("") + { + _dualImage = new CTextImage2(); + _dualImage->setColor2(Color(255, 170, 0, 0)); + _row = -2; + _useFgColorAsImageColor = true; + _offset[0] = 0; + _offset[1] = 0; + } + + ~CLabelHeader() + { + delete _dualImage; + } + + void setRow(int row) + { + _row = row; + } + + void setFgColorAsImageColor(bool state) + { + _useFgColorAsImageColor = state; + } + + virtual void setText(int textBufferLen, const char* text) + { + _dualImage->GetImage(0)->setText(text); + + // calculate the text size + Font *font = _dualImage->GetImage(0)->getFont(); + _gap = 0; + for (const char *ch = text; *ch != 0; ch++) + { + int a, b, c; + font->getCharABCwide(*ch, a, b, c); + _gap += (a + b + c); + } + + _gap += XRES(5); + } + + virtual void setText(const char* text) + { + // strip any non-alnum characters from the end + char buf[512]; + strcpy(buf, text); + + int len = strlen(buf); + while (len && isspace(buf[--len])) + { + buf[len] = 0; + } + + CLabelHeader::setText(0, buf); + } + + void setText2(const char *text) + { + _dualImage->GetImage(1)->setText(text); + } + + void getTextSize(int &wide, int &tall) + { + _dualImage->getSize(wide, tall); + } + + void setFgColor(int r,int g,int b,int a) + { + Label::setFgColor(r,g,b,a); + Color color(r,g,b,a); + _dualImage->setColor(color); + _dualImage->setColor2(color); + repaint(); + } + + void setFgColor(Scheme::SchemeColor sc) + { + int r, g, b, a; + Label::setFgColor(sc); + Label::getFgColor( r, g, b, a ); + + // Call the r,g,b,a version so it sets the color in the dualImage.. + setFgColor( r, g, b, a ); + } + + void setFont(Font *font) + { + _dualImage->GetImage(0)->setFont(font); + } + + void setFont2(Font *font) + { + _dualImage->GetImage(1)->setFont(font); + } + + // this adjust the absolute position of the text after alignment is calculated + void setTextOffset(int x, int y) + { + _offset[0] = x; + _offset[1] = y; + } + + void paint(); + void paintBackground(); + void calcAlignment(int iwide, int itall, int &x, int &y); + +private: + CTextImage2 *_dualImage; + int _row; + int _gap; + int _offset[2]; + bool _useFgColorAsImageColor; +}; + +class ScoreTablePanel; + +#include "..\game_shared\vgui_grid.h" +#include "..\game_shared\vgui_defaultinputsignal.h" + +//----------------------------------------------------------------------------- +// Purpose: Scoreboard back panel +//----------------------------------------------------------------------------- +class ScorePanel : public Panel, public vgui::CDefaultInputSignal +{ +private: + // Default panel implementation doesn't forward mouse messages when there is no cursor and we need them. + class HitTestPanel : public Panel + { + public: + virtual void internalMousePressed(MouseCode code); + }; + + +private: + + Label m_TitleLabel; + + // Here is how these controls are arranged hierarchically. + // m_HeaderGrid + // m_HeaderLabels + + // m_PlayerGridScroll + // m_PlayerGrid + // m_PlayerEntries + + CGrid m_HeaderGrid; + CLabelHeader m_HeaderLabels[NUM_COLUMNS]; // Labels above the + CLabelHeader *m_pCurrentHighlightLabel; + int m_iHighlightRow; + + vgui::CListBox m_PlayerList; + CGrid m_PlayerGrids[NUM_ROWS]; // The grid with player and team info. + CLabelHeader m_PlayerEntries[NUM_COLUMNS][NUM_ROWS]; // Labels for the grid entries. + + ScorePanel::HitTestPanel m_HitTestPanel; + CommandButton *m_pCloseButton; + CLabelHeader* GetPlayerEntry(int x, int y) {return &m_PlayerEntries[x][y];} + +public: + + int m_iNumTeams; + int m_iPlayerNum; + int m_iShowscoresHeld; + + int m_iRows; + int m_iSortedRows[NUM_ROWS]; + int m_iIsATeam[NUM_ROWS]; + bool m_bHasBeenSorted[MAX_PLAYERS]; + int m_iLastKilledBy; + int m_fLastKillTime; + + +public: + + ScorePanel(int x,int y,int wide,int tall); + + void Update( void ); + + void SortTeams( void ); + void SortPlayers( int iTeam, char *team ); + void RebuildTeams( void ); + + void FillGrid(); + + void DeathMsg( int killer, int victim ); + + void Initialize( void ); + + void Open( void ); + + void MouseOverCell(int row, int col); + +// InputSignal overrides. +public: + + virtual void mousePressed(MouseCode code, Panel* panel); + virtual void cursorMoved(int x, int y, Panel *panel); + + friend CLabelHeader; +}; + +#endif diff --git a/cl_dll/vgui_ServerBrowser.cpp b/cl_dll/vgui_ServerBrowser.cpp new file mode 100644 index 00000000..6e902594 --- /dev/null +++ b/cl_dll/vgui_ServerBrowser.cpp @@ -0,0 +1,623 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include +#include +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include "hud_servers.h" +#include "net_api.h" + +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" + +using namespace vgui; + +namespace +{ + +#define MAX_SB_ROWS 24 + +#define NUM_COLUMNS 5 + +#define HEADER_SIZE_Y YRES(18) + +// Column sizes +#define CSIZE_ADDRESS XRES(200) +#define CSIZE_SERVER XRES(400) +#define CSIZE_MAP XRES(500) +#define CSIZE_CURRENT XRES(570) +#define CSIZE_PING XRES(640) + +#define CELL_HEIGHT YRES(15) + +class ServerBrowserTablePanel; + +class CBrowser_InputSignal : public InputSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; +public: + CBrowser_InputSignal( ServerBrowserTablePanel *pBrowser ) + { + m_pBrowser = pBrowser; + } + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void cursorEntered(Panel* panel){}; + virtual void cursorExited(Panel* Panel) {}; + + virtual void mousePressed(MouseCode code,Panel* panel); + + virtual void mouseDoublePressed(MouseCode code,Panel* panel); + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class ServerBrowserTablePanel : public TablePanel +{ +private: + Label *m_pLabel; + int m_nMouseOverRow; + +public: + + ServerBrowserTablePanel( int x,int y,int wide,int tall,int columnCount) : TablePanel( x,y,wide,tall,columnCount) + { + m_pLabel = new Label( "", 0, 0 /*,wide, tall*/ ); + + m_nMouseOverRow = 0; + } + +public: + void setMouseOverRow( int row ) + { + m_nMouseOverRow = row; + } + + void DoSort( char *sortkey ) + { + // Request server list and refresh servers... + SortServers( sortkey ); + } + + void DoRefresh( void ) + { + // Request server list and refresh servers... + ServersList(); + BroadcastServersList( 0 ); + } + + void DoBroadcastRefresh( void ) + { + // Request server list and refresh servers... + BroadcastServersList( 1 ); + } + + void DoStop( void ) + { + // Stop requesting + ServersCancel(); + } + + void DoCancel( void ) + { + ClientCmd( "togglebrowser\n" ); + } + + void DoConnect( void ) + { + const char *info; + const char *address; + char sz[ 256 ]; + + info = ServersGetInfo( m_nMouseOverRow ); + if ( !info ) + return; + + address = gEngfuncs.pNetAPI->ValueForKey( info, "address" ); + //gEngfuncs.Con_Printf( "Connecting to %s\n", address ); + + sprintf( sz, "connect %s\n", address ); + + ClientCmd( sz ); + + DoCancel(); + } + + void DoPing( void ) + { + ServerPing( 0 ); + ServerRules( 0 ); + ServerPlayers( 0 ); + } + + virtual int getRowCount() + { + int rowcount; + int height, width; + + getSize( width, height ); + + // Space for buttons + height -= YRES(20); + height = max( 0, height ); + + rowcount = height / CELL_HEIGHT; + + return rowcount; + } + + virtual int getCellTall(int row) + { + return CELL_HEIGHT - 2; + } + + virtual Panel* getCellRenderer(int column,int row,bool columnSelected,bool rowSelected,bool cellSelected) + { + const char *info; + const char *val, *val2; + char sz[ 32 ]; + + info = ServersGetInfo( row ); + + if ( row == m_nMouseOverRow ) + { + m_pLabel->setFgColor( 200, 240, 63, 100 ); + } + else + { + m_pLabel->setFgColor( 255, 255, 255, 0 ); + } + m_pLabel->setBgColor( 0, 0, 0, 200 ); + m_pLabel->setContentAlignment( vgui::Label::a_west ); + m_pLabel->setFont( Scheme::sf_primary2 ); + + if ( info ) + { + // Fill out with the correct data + switch ( column ) + { + case 0: + val = gEngfuncs.pNetAPI->ValueForKey( info, "address" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + case 1: + val = gEngfuncs.pNetAPI->ValueForKey( info, "hostname" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Map; + m_pLabel->setText( sz ); + } + break; + case 2: + val = gEngfuncs.pNetAPI->ValueForKey( info, "map" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + case 3: + val = gEngfuncs.pNetAPI->ValueForKey( info, "current" ); + val2 = gEngfuncs.pNetAPI->ValueForKey( info, "max" ); + if ( val && val2 ) + { + sprintf( sz, "%s/%s", val, val2 ); + sz[ 31 ] = '\0'; + // Server Map; + m_pLabel->setText( sz ); + } + break; + case 4: + val = gEngfuncs.pNetAPI->ValueForKey( info, "ping" ); + if ( val ) + { + strncpy( sz, val, 31 ); + sz[ 31 ] = '\0'; + // Server Name; + m_pLabel->setText( sz ); + } + break; + default: + break; + } + } + else + { + if ( !row && !column ) + { + if ( ServersIsQuerying() ) + { + m_pLabel->setText( "Waiting for servers to respond..." ); + } + else + { + m_pLabel->setText( "Press 'Refresh' to search for servers..." ); + } + } + else + { + m_pLabel->setText( "" ); + } + } + + return m_pLabel; + } + + virtual Panel* startCellEditing(int column,int row) + { + return null; + } + +}; + +class ConnectHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + ConnectHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoConnect(); + } +}; + +class RefreshHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + RefreshHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoRefresh(); + } +}; + +class BroadcastRefreshHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + BroadcastRefreshHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoBroadcastRefresh(); + } +}; + +class StopHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + StopHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoStop(); + } +}; + +class CancelHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + CancelHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoCancel(); + } +}; + +class PingHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + PingHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoPing(); + } +}; + +class SortHandler : public ActionSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + +public: + SortHandler( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + } + + virtual void actionPerformed( Panel *panel ) + { + m_pBrowser->DoSort( "map" ); + } +}; + +} + +class LabelSortInputHandler : public InputSignal +{ +private: + ServerBrowserTablePanel *m_pBrowser; + char m_szSortKey[ 64 ]; + +public: + LabelSortInputHandler( ServerBrowserTablePanel *pBrowser, char *name ) + { + m_pBrowser = pBrowser; + strcpy( m_szSortKey, name ); + } + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void cursorEntered(Panel* panel){}; + virtual void cursorExited(Panel* Panel) {}; + + virtual void mousePressed(MouseCode code,Panel* panel) + { + m_pBrowser->DoSort( m_szSortKey ); + } + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) + { + m_pBrowser->DoSort( m_szSortKey ); + } + + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class CSBLabel : public Label +{ + +private: + char m_szSortKey[ 64 ]; + ServerBrowserTablePanel *m_pBrowser; + +public: + CSBLabel( char *name, char *sortkey ) : Label( name ) + { + m_pBrowser = NULL; + + strcpy( m_szSortKey, sortkey ); + + int label_bg_r = 120, + label_bg_g = 75, + label_bg_b = 32, + label_bg_a = 200; + + int label_fg_r = 255, + label_fg_g = 0, + label_fg_b = 0, + label_fg_a = 0; + + setContentAlignment( vgui::Label::a_west ); + setFgColor( label_fg_r, label_fg_g, label_fg_b, label_fg_a ); + setBgColor( label_bg_r, label_bg_g, label_bg_b, label_bg_a ); + setFont( Scheme::sf_primary2 ); + + } + + void setTable( ServerBrowserTablePanel *browser ) + { + m_pBrowser = browser; + + addInputSignal( new LabelSortInputHandler( (ServerBrowserTablePanel * )m_pBrowser, m_szSortKey ) ); + } +}; + +ServerBrowser::ServerBrowser(int x,int y,int wide,int tall) : CTransparentPanel( 100, x,y,wide,tall ) +{ + int i; + + _headerPanel = new HeaderPanel(0,0,wide,HEADER_SIZE_Y); + _headerPanel->setParent(this); + _headerPanel->setFgColor( 100,100,100, 100 ); + _headerPanel->setBgColor( 0, 0, 0, 100 ); + + CSBLabel *pLabel[5]; + + pLabel[0] = new CSBLabel( "Address", "address" ); + pLabel[1] = new CSBLabel( "Server", "hostname" ); + pLabel[2] = new CSBLabel( "Map", "map" ); + pLabel[3] = new CSBLabel( "Current", "current" ); + pLabel[4] = new CSBLabel( "Latency", "ping" ); + + for ( i = 0; i < 5; i++ ) + { + _headerPanel->addSectionPanel( pLabel[i] ); + } + + // _headerPanel->setFont( Scheme::sf_primary1 ); + + _headerPanel->setSliderPos( 0, CSIZE_ADDRESS ); + _headerPanel->setSliderPos( 1, CSIZE_SERVER ); + _headerPanel->setSliderPos( 2, CSIZE_MAP ); + _headerPanel->setSliderPos( 3, CSIZE_CURRENT ); + _headerPanel->setSliderPos( 4, CSIZE_PING ); + + _tablePanel = new ServerBrowserTablePanel( 0, HEADER_SIZE_Y, wide, tall - HEADER_SIZE_Y, NUM_COLUMNS ); + _tablePanel->setParent(this); + _tablePanel->setHeaderPanel(_headerPanel); + _tablePanel->setFgColor( 100,100,100, 100 ); + _tablePanel->setBgColor( 0, 0, 0, 100 ); + + _tablePanel->addInputSignal( new CBrowser_InputSignal( (ServerBrowserTablePanel *)_tablePanel ) ); + + for ( i = 0; i < 5; i++ ) + { + pLabel[i]->setTable( (ServerBrowserTablePanel * )_tablePanel ); + } + + int bw = 80, bh = 15; + int by = tall - HEADER_SIZE_Y; + + int btnx = 10; + + _connectButton = new CommandButton( "Connect", btnx, by, bw, bh ); + _connectButton->setParent( this ); + _connectButton->addActionSignal( new ConnectHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + btnx += bw; + + _refreshButton = new CommandButton( "Refresh", btnx, by, bw, bh ); + _refreshButton->setParent( this ); + _refreshButton->addActionSignal( new RefreshHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + /* + btnx += bw; + + _broadcastRefreshButton = new CommandButton( "LAN", btnx, by, bw, bh ); + _broadcastRefreshButton->setParent( this ); + _broadcastRefreshButton->addActionSignal( new BroadcastRefreshHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + */ + + btnx += bw; + + _stopButton = new CommandButton( "Stop", btnx, by, bw, bh ); + _stopButton->setParent( this ); + _stopButton->addActionSignal( new StopHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + /* + btnx += bw; + + _pingButton = new CommandButton( "Test", btnx, by, bw, bh ); + _pingButton->setParent( this ); + _pingButton->addActionSignal( new PingHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + btnx += bw; + + _sortButton = new CommandButton( "Sort", btnx, by, bw, bh ); + _sortButton->setParent( this ); + _sortButton->addActionSignal( new SortHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + */ + + btnx += bw; + + _cancelButton = new CommandButton( "Close", btnx, by, bw, bh ); + _cancelButton->setParent( this ); + _cancelButton->addActionSignal( new CancelHandler( (ServerBrowserTablePanel * )_tablePanel ) ); + + setPaintBorderEnabled(false); + setPaintBackgroundEnabled(false); + setPaintEnabled(false); + +} + +void ServerBrowser::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + _headerPanel->setBounds(0,0,wide,HEADER_SIZE_Y); + _tablePanel->setBounds(0,HEADER_SIZE_Y,wide,tall - HEADER_SIZE_Y); + + _connectButton->setBounds( 5, tall - HEADER_SIZE_Y, 75, 15 ); + _refreshButton->setBounds( 85, tall - HEADER_SIZE_Y, 75, 15 ); + /* + _broadcastRefreshButton->setBounds( 165, tall - HEADER_SIZE_Y, 75, 15 ); + */ + _stopButton->setBounds( 165, tall - HEADER_SIZE_Y, 75, 15 ); + /* + _pingButton->setBounds( 325, tall - HEADER_SIZE_Y, 75, 15 ); + */ + _cancelButton->setBounds( 245, tall - HEADER_SIZE_Y, 75, 15 ); +} + +void CBrowser_InputSignal::mousePressed(MouseCode code,Panel* panel) +{ + int x, y; + int therow = 2; + + if ( code != MOUSE_LEFT ) + return; + + panel->getApp()->getCursorPos(x,y); + panel->screenToLocal( x, y ); + + therow = y / CELL_HEIGHT; + + // Figure out which row it's on + m_pBrowser->setMouseOverRow( therow ); +} + +void CBrowser_InputSignal::mouseDoublePressed(MouseCode code,Panel* panel) +{ + int x, y; + int therow = 2; + + if ( code != MOUSE_LEFT ) + return; + + panel->getApp()->getCursorPos(x,y); + panel->screenToLocal( x, y ); + + therow = y / CELL_HEIGHT; + + // Figure out which row it's on + m_pBrowser->setMouseOverRow( therow ); + m_pBrowser->DoConnect(); +} diff --git a/cl_dll/vgui_ServerBrowser.h b/cl_dll/vgui_ServerBrowser.h new file mode 100644 index 00000000..43da4f4e --- /dev/null +++ b/cl_dll/vgui_ServerBrowser.h @@ -0,0 +1,50 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef ServerBrowser_H +#define ServerBrowser_H + +#include + +namespace vgui +{ +class Button; +class TablePanel; +class HeaderPanel; +} + +class CTransparentPanel; +class CommandButton; + +// Scoreboard positions +#define SB_X_INDENT (20 * ((float)ScreenHeight / 640)) +#define SB_Y_INDENT (20 * ((float)ScreenHeight / 480)) + +class ServerBrowser : public CTransparentPanel +{ +private: + HeaderPanel * _headerPanel; + TablePanel* _tablePanel; + + CommandButton* _connectButton; + CommandButton* _refreshButton; + CommandButton* _broadcastRefreshButton; + CommandButton* _stopButton; + CommandButton* _sortButton; + CommandButton* _cancelButton; + + CommandButton* _pingButton; + +public: + ServerBrowser(int x,int y,int wide,int tall); +public: + virtual void setSize(int wide,int tall); +}; + + + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_SpectatorPanel.cpp b/cl_dll/vgui_SpectatorPanel.cpp new file mode 100644 index 00000000..582a319e --- /dev/null +++ b/cl_dll/vgui_SpectatorPanel.cpp @@ -0,0 +1,383 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// vgui_SpectatorPanel.cpp: implementation of the SpectatorPanel class. +// +////////////////////////////////////////////////////////////////////// + +#include "hud.h" +#include "cl_util.h" +#include "const.h" +#include "entity_state.h" +#include "cl_entity.h" +#include "pm_shared.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_SpectatorPanel.h" +#include "vgui_scorepanel.h" + +#define PANEL_HEIGHT 32 + + +#define BANNER_WIDTH 256 +#define BANNER_HEIGHT 64 + + +#define OPTIONS_BUTTON_X 96 +#define CAMOPTIONS_BUTTON_X 200 + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +SpectatorPanel::SpectatorPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) +{ +} + +SpectatorPanel::~SpectatorPanel() +{ + +} + +void SpectatorPanel::ActionSignal(int cmd) +{ + switch (cmd) + { + case SPECTATOR_PANEL_CMD_NONE : break; + + case SPECTATOR_PANEL_CMD_OPTIONS : gViewPort->ShowCommandMenu( gViewPort->m_SpectatorOptionsMenu ); + break; + + case SPECTATOR_PANEL_CMD_NEXTPLAYER : gHUD.m_Spectator.FindNextPlayer(true); + break; + + case SPECTATOR_PANEL_CMD_PREVPLAYER : gHUD.m_Spectator.FindNextPlayer(false); + break; + + case SPECTATOR_PANEL_CMD_HIDEMENU : ShowMenu(false); + break; + + case SPECTATOR_PANEL_CMD_CAMERA : gViewPort->ShowCommandMenu( gViewPort->m_SpectatorCameraMenu ); + break; + + case SPECTATOR_PANEL_CMD_TOGGLE_INSET : gHUD.m_Spectator.SetModes( -1, + gHUD.m_Spectator.ToggleInset(false) ); + break; + + + default : gEngfuncs.Con_DPrintf("Unknown SpectatorPanel ActionSingal %i.\n",cmd); break; + } + +} + + +void SpectatorPanel::Initialize() +{ + int x,y,wide,tall; + + getBounds(x,y,wide,tall); + + CSchemeManager * pSchemes = gViewPort->GetSchemeManager(); + + SchemeHandle_t hSmallScheme = pSchemes->getSchemeHandle( "Team Info Text" ); + + m_TopBorder = new CTransparentPanel(64, 0, 0, ScreenWidth, YRES(PANEL_HEIGHT)); + m_TopBorder->setParent(this); + + m_BottomBorder = new CTransparentPanel(64, 0, ScreenHeight - YRES(32), ScreenWidth, YRES(PANEL_HEIGHT)); + m_BottomBorder->setParent(this); + + setPaintBackgroundEnabled(false); + + m_ExtraInfo = new Label( "Extra Info", 0, 0, wide, YRES(PANEL_HEIGHT) ); + m_ExtraInfo->setParent(m_TopBorder); + m_ExtraInfo->setFont( pSchemes->getFont(hSmallScheme) ); + + m_ExtraInfo->setPaintBackgroundEnabled(false); + m_ExtraInfo->setFgColor( 143, 143, 54, 0 ); + m_ExtraInfo->setContentAlignment( vgui::Label::a_west ); + + + + m_TimerImage = new CImageLabel( "timer", 0, 0, 14, 14 ); + m_TimerImage->setParent(m_TopBorder); + + m_TopBanner = new CImageLabel( "banner", 0, 0, XRES(BANNER_WIDTH), YRES(BANNER_HEIGHT) ); + m_TopBanner->setParent(this); + + m_CurrentTime = new Label( "00:00", 0, 0, wide, YRES(PANEL_HEIGHT) ); + m_CurrentTime->setParent(m_TopBorder); + m_CurrentTime->setFont( pSchemes->getFont(hSmallScheme) ); + m_CurrentTime->setPaintBackgroundEnabled(false); + m_CurrentTime->setFgColor( 143, 143, 54, 0 ); + m_CurrentTime->setContentAlignment( vgui::Label::a_west ); + + m_Separator = new Panel( 0, 0, XRES( 64 ), YRES( 96 )); + m_Separator->setParent( m_TopBorder ); + m_Separator->setFgColor( 59, 58, 34, 48 ); + m_Separator->setBgColor( 59, 58, 34, 48 ); + + for ( int j= 0; j < TEAM_NUMBER; j++ ) + { + m_TeamScores[j] = new Label( " ", 0, 0, wide, YRES(PANEL_HEIGHT) ); + m_TeamScores[j]->setParent( m_TopBorder ); + m_TeamScores[j]->setFont( pSchemes->getFont(hSmallScheme) ); + m_TeamScores[j]->setPaintBackgroundEnabled(false); + m_TeamScores[j]->setFgColor( 143, 143, 54, 0 ); + m_TeamScores[j]->setContentAlignment( vgui::Label::a_west ); + m_TeamScores[j]->setVisible ( false ); + } + + + // Initialize command buttons. + m_OptionButton = new ColorButton( CHudTextMessage::BufferedLocaliseTextString( "#SPECT_OPTIONS" ), XRES(15), YRES(6), XRES(OPTIONS_BUTTON_X), YRES(20), false, false ); + m_OptionButton->setParent( m_BottomBorder ); + m_OptionButton->setContentAlignment( vgui::Label::a_center ); + m_OptionButton->setBoundKey( (char)255 ); // special no bound to avoid leading spaces in name + m_OptionButton->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_OPTIONS) ); + m_OptionButton->setUnArmedBorderColor ( 59, 58, 34, 48 ); + m_OptionButton->setArmedBorderColor ( 194, 202, 54, 0 ); + m_OptionButton->setUnArmedColor ( 143, 143, 54, 0 ); + m_OptionButton->setArmedColor ( 194, 202, 54, 0 ); + + m_CamButton = new ColorButton( CHudTextMessage::BufferedLocaliseTextString( "#CAM_OPTIONS" ), ScreenWidth - ( XRES ( CAMOPTIONS_BUTTON_X ) + 15 ), YRES(6), XRES ( CAMOPTIONS_BUTTON_X ), YRES(20), false, false ); + m_CamButton->setParent( m_BottomBorder ); + m_CamButton->setContentAlignment( vgui::Label::a_center ); + m_CamButton->setBoundKey( (char)255 ); // special no bound to avoid leading spaces in name + m_CamButton->addActionSignal( new CSpectatorHandler_Command( this, SPECTATOR_PANEL_CMD_CAMERA ) ); + m_CamButton->setUnArmedBorderColor ( 59, 58, 34, 48 ); + m_CamButton->setArmedBorderColor ( 194, 202, 54, 0 ); + m_CamButton->setUnArmedColor ( 143, 143, 54, 0 ); + m_CamButton->setArmedColor ( 194, 202, 54, 0 ); + + m_PrevPlayerButton= new ColorButton("<", XRES( 15 + OPTIONS_BUTTON_X + 15 ), YRES(6), XRES(24), YRES(20), false, false ); + m_PrevPlayerButton->setParent( m_BottomBorder ); + m_PrevPlayerButton->setContentAlignment( vgui::Label::a_center ); + m_PrevPlayerButton->setBoundKey( (char)255 ); // special no bound to avoid leading spaces in name + m_PrevPlayerButton->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_PREVPLAYER) ); + m_PrevPlayerButton->setUnArmedBorderColor ( 59, 58, 34, 48 ); + m_PrevPlayerButton->setArmedBorderColor ( 194, 202, 54, 0 ); + m_PrevPlayerButton->setUnArmedColor ( 143, 143, 54, 0 ); + m_PrevPlayerButton->setArmedColor ( 194, 202, 54, 0 ); + + m_NextPlayerButton= new ColorButton(">", (ScreenWidth - (XRES ( CAMOPTIONS_BUTTON_X ) + 15)) - XRES ( 24 + 15 ), YRES(6), XRES(24), YRES(20),false, false ); + m_NextPlayerButton->setParent( m_BottomBorder ); + m_NextPlayerButton->setContentAlignment( vgui::Label::a_center ); + m_NextPlayerButton->setBoundKey( (char)255 ); // special no bound to avoid leading spaces in name + m_NextPlayerButton->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_NEXTPLAYER) ); + m_NextPlayerButton->setUnArmedBorderColor ( 59, 58, 34, 48 ); + m_NextPlayerButton->setArmedBorderColor ( 194, 202, 54, 0 ); + m_NextPlayerButton->setUnArmedColor ( 143, 143, 54, 0 ); + m_NextPlayerButton->setArmedColor ( 194, 202, 54, 0 ); + + // Initialize the bottom title. + + float flLabelSize = ( (ScreenWidth - (XRES ( CAMOPTIONS_BUTTON_X ) + 15)) - XRES ( 24 + 15 ) ) - XRES( (15 + OPTIONS_BUTTON_X + 15) + 38 ); + + m_BottomMainLabel = new Label( "Spectator Bottom", XRES( ( 15 + OPTIONS_BUTTON_X + 15 ) + 31 ), YRES(6), flLabelSize, YRES(20) ); + m_BottomMainLabel->setParent(m_BottomBorder); + m_BottomMainLabel->setPaintBackgroundEnabled(false); + m_BottomMainLabel->setFgColor( Scheme::sc_primary1 ); + m_BottomMainLabel->setContentAlignment( vgui::Label::a_center ); + m_BottomMainLabel->setBorder( new LineBorder( Color( 59, 58, 34, 48 ) ) ); + + m_InsetViewButton = new ColorButton("", XRES(2), YRES(2), XRES(240), YRES(180), false, false ); + m_InsetViewButton->setParent( this ); + m_InsetViewButton->setBoundKey( (char)255 ); + m_InsetViewButton->addActionSignal( new CSpectatorHandler_Command(this,SPECTATOR_PANEL_CMD_TOGGLE_INSET) ); + m_InsetViewButton->setUnArmedBorderColor ( 59, 58, 34, 48 ); + m_InsetViewButton->setArmedBorderColor ( 194, 202, 54, 0 ); + m_InsetViewButton->setUnArmedColor ( 143, 143, 54, 0 ); + m_InsetViewButton->setArmedColor ( 194, 202, 54, 0 ); + + + m_menuVisible = false; + m_insetVisible = false; +// m_HideButton->setVisible(false); + m_CamButton->setVisible(false); + m_OptionButton->setVisible(false); + m_NextPlayerButton->setVisible(false); + m_PrevPlayerButton->setVisible(false); + m_TopBanner->setVisible( false ); + m_ExtraInfo->setVisible( false ); + m_Separator->setVisible( false ); + m_TimerImage->setVisible( false ); + +} + +void SpectatorPanel::ShowMenu(bool isVisible) +{ +// m_HideButton->setVisible(isVisible); m_HideButton->setArmed( false ); + m_OptionButton->setVisible(isVisible); m_OptionButton->setArmed( false ); + m_CamButton->setVisible(isVisible); m_CamButton->setArmed( false ); + m_NextPlayerButton->setVisible(isVisible); m_NextPlayerButton->setArmed( false ); + m_PrevPlayerButton->setVisible(isVisible); m_PrevPlayerButton->setArmed( false ); + + if ( !isVisible ) + { + int iLabelSizeX, iLabelSizeY; + m_BottomMainLabel->getSize( iLabelSizeX, iLabelSizeY ); + m_BottomMainLabel->setPos( ( ScreenWidth / 2 ) - (iLabelSizeX/2), YRES(6) ); + } + else + m_BottomMainLabel->setPos( XRES( ( 15 + OPTIONS_BUTTON_X + 15 ) + 31 ), YRES(6) ); + + if ( !isVisible ) + { + gViewPort->HideCommandMenu(); + + // if switching from visible menu to invisible menu, show help text + if ( m_menuVisible && this->isVisible() ) + { + char string[ 64 ]; + + _snprintf( string, sizeof( string ) - 1, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( "#Spec_Duck" ) ); + string[ sizeof( string ) - 1 ] = '\0'; + + gHUD.m_TextMessage.MsgFunc_TextMsg( NULL, strlen( string ) + 1, string ); + } + } + + m_menuVisible = isVisible; + + gViewPort->UpdateCursorState(); +} + + +const char *GetSpectatorLabel ( int iMode ) +{ + switch ( iMode ) + { + case OBS_CHASE_LOCKED: + return "#OBS_CHASE_LOCKED"; + + case OBS_CHASE_FREE: + return "#OBS_CHASE_FREE"; + + case OBS_ROAMING: + return "#OBS_ROAMING"; + + case OBS_IN_EYE: + return "#OBS_IN_EYE"; + + case OBS_MAP_FREE: + return "#OBS_MAP_FREE"; + + case OBS_MAP_CHASE: + return "#OBS_MAP_CHASE"; + + case OBS_NONE: + default: + return "#OBS_NONE"; + } + + return ""; +} + +void SpectatorPanel::EnableInsetView(bool isEnabled) +{ + int x = gHUD.m_Spectator.m_OverviewData.insetWindowX; + int y = gHUD.m_Spectator.m_OverviewData.insetWindowY; + int wide = gHUD.m_Spectator.m_OverviewData.insetWindowWidth; + int tall = gHUD.m_Spectator.m_OverviewData.insetWindowHeight; + int offset = x + wide + 2; + + if ( isEnabled ) + { + // short black bar to see full inset + m_TopBorder->setBounds( XRES(offset), 0, XRES(640 - offset ), YRES(PANEL_HEIGHT) ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + m_TopBanner->setVisible( true ); + m_TopBanner->setPos( XRES(offset), 0 ); + } + else + m_TopBanner->setVisible( false ); + + m_InsetViewButton->setBounds( XRES( x ), YRES( y ), + XRES( wide ), YRES( tall ) ); + m_InsetViewButton->setVisible(true); + } + else + { + // full black bar, no inset border + // show banner only in real HLTV mode + if ( gEngfuncs.IsSpectateOnly() ) + { + m_TopBanner->setVisible( true ); + m_TopBanner->setPos( 0,0 ); + } + else + m_TopBanner->setVisible( false ); + + m_TopBorder->setBounds( 0, 0, ScreenWidth, YRES(PANEL_HEIGHT) ); + + m_InsetViewButton->setVisible(false); + } + + m_insetVisible = isEnabled; + + Update(); + + m_CamButton->setText( CHudTextMessage::BufferedLocaliseTextString( GetSpectatorLabel( g_iUser1 ) ) ); +} + + + + +void SpectatorPanel::Update() +{ + int iTextWidth, iTextHeight; + int iTimeHeight, iTimeWidth; + int offset,j; + + if ( m_insetVisible ) + offset = gHUD.m_Spectator.m_OverviewData.insetWindowX + gHUD.m_Spectator.m_OverviewData.insetWindowWidth + 2; + else + offset = 0; + + bool visible = gHUD.m_Spectator.m_drawstatus->value != 0; + + m_ExtraInfo->setVisible( visible ); + m_TimerImage->setVisible( visible ); + m_CurrentTime->setVisible( visible ); + m_Separator->setVisible( visible ); + + for ( j= 0; j < TEAM_NUMBER; j++ ) + m_TeamScores[j]->setVisible( visible ); + + if ( !visible ) + return; + + m_ExtraInfo->getTextSize( iTextWidth, iTextHeight ); + m_CurrentTime->getTextSize( iTimeWidth, iTimeHeight ); + + iTimeWidth += XRES ( 14 ); // +timer icon + iTimeWidth += ( 4-(iTimeWidth%4) ); + + if ( iTimeWidth > iTextWidth ) + iTextWidth = iTimeWidth; + + int xPos = ScreenWidth - ( iTextWidth + XRES ( 4 + offset ) ); + + m_ExtraInfo->setBounds( xPos, YRES( 1 ), iTextWidth, iTextHeight ); + + m_TimerImage->setBounds( xPos, YRES( 2 ) + iTextHeight , XRES(14), YRES(14) ); + + m_CurrentTime->setBounds( xPos + XRES ( 14 + 1 ), YRES( 2 ) + iTextHeight , iTimeWidth, iTimeHeight ); + + m_Separator->setPos( ScreenWidth - ( iTextWidth + XRES ( 4+2+4+offset ) ) , YRES( 1 ) ); + m_Separator->setSize( XRES( 4 ), YRES( PANEL_HEIGHT - 2 ) ); + + for ( j= 0; j < TEAM_NUMBER; j++ ) + { + int iwidth, iheight; + + m_TeamScores[j]->getTextSize( iwidth, iheight ); + m_TeamScores[j]->setBounds( ScreenWidth - ( iTextWidth + XRES ( 4+2+4+2+offset ) + iwidth ), YRES( 1 ) + ( iheight * j ), iwidth, iheight ); + } +} diff --git a/cl_dll/vgui_SpectatorPanel.h b/cl_dll/vgui_SpectatorPanel.h new file mode 100644 index 00000000..d77e9003 --- /dev/null +++ b/cl_dll/vgui_SpectatorPanel.h @@ -0,0 +1,102 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// vgui_SpectatorPanel.h: interface for the SpectatorPanel class. +// +////////////////////////////////////////////////////////////////////// + +#ifndef SPECTATORPANEL_H +#define SPECTATORPANEL_H + +#include +#include +#include + +using namespace vgui; + +#define SPECTATOR_PANEL_CMD_NONE 0 + +#define SPECTATOR_PANEL_CMD_OPTIONS 1 +#define SPECTATOR_PANEL_CMD_PREVPLAYER 2 +#define SPECTATOR_PANEL_CMD_NEXTPLAYER 3 +#define SPECTATOR_PANEL_CMD_HIDEMENU 4 +#define SPECTATOR_PANEL_CMD_TOGGLE_INSET 5 +#define SPECTATOR_PANEL_CMD_CAMERA 6 + +#define TEAM_NUMBER 2 + +class SpectatorPanel : public Panel //, public vgui::CDefaultInputSignal +{ + +public: + SpectatorPanel(int x,int y,int wide,int tall); + virtual ~SpectatorPanel(); + + void ActionSignal(int cmd); + + // InputSignal overrides. +public: + void Initialize(); + void Update(); + + + +public: + + void EnableInsetView(bool isEnabled); + void ShowMenu(bool isVisible); + + + ColorButton * m_OptionButton; +// CommandButton * m_HideButton; + ColorButton * m_PrevPlayerButton; + ColorButton * m_NextPlayerButton; + ColorButton * m_CamButton; + + CTransparentPanel * m_TopBorder; + CTransparentPanel * m_BottomBorder; + + ColorButton *m_InsetViewButton; + + Label *m_BottomMainLabel; + CImageLabel *m_TimerImage; + Label *m_CurrentTime; + Label *m_ExtraInfo; + Panel *m_Separator; + + Label *m_TeamScores[TEAM_NUMBER]; + + CImageLabel *m_TopBanner; + + bool m_menuVisible; + bool m_insetVisible; +}; + + + +class CSpectatorHandler_Command : public ActionSignal +{ + +private: + SpectatorPanel * m_pFather; + int m_cmd; + +public: + CSpectatorHandler_Command( SpectatorPanel * panel, int cmd ) + { + m_pFather = panel; + m_cmd = cmd; + } + + virtual void actionPerformed( Panel * panel ) + { + m_pFather->ActionSignal(m_cmd); + } +}; + + +#endif // !defined SPECTATORPANEL_H diff --git a/cl_dll/vgui_TeamFortressViewport.cpp b/cl_dll/vgui_TeamFortressViewport.cpp new file mode 100644 index 00000000..20331c2a --- /dev/null +++ b/cl_dll/vgui_TeamFortressViewport.cpp @@ -0,0 +1,2369 @@ +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: Client DLL VGUI Viewport +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "parsemsg.h" +#include "pm_shared.h" +#include "../engine/keydefs.h" +#include "demo.h" +#include "demo_api.h" + +#include "vgui_int.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ServerBrowser.h" +#include "vgui_ScorePanel.h" +#include "vgui_SpectatorPanel.h" + +extern int g_iVisibleMouse; +class CCommandMenu; +int g_iPlayerClass; +int g_iTeamNumber; +int g_iUser1; +int g_iUser2; +int g_iUser3; + +// Scoreboard positions +#define SBOARD_INDENT_X XRES(104) +#define SBOARD_INDENT_Y YRES(40) + +// low-res scoreboard indents +#define SBOARD_INDENT_X_512 30 +#define SBOARD_INDENT_Y_512 30 + +#define SBOARD_INDENT_X_400 0 +#define SBOARD_INDENT_Y_400 20 + +void IN_ResetMouse( void ); +extern CMenuPanel *CMessageWindowPanel_Create( const char *szMOTD, const char *szTitle, int iShadeFullscreen, int iRemoveMe, int x, int y, int wide, int tall ); +extern float * GetClientColor( int clientIndex ); + +using namespace vgui; + +// Team Colors +int iNumberOfTeamColors = 5; +int iTeamColors[5][3] = +{ + { 255, 170, 0 }, // HL orange (default) + { 125, 165, 210 }, // Blue + { 200, 90, 70 }, // Red + { 225, 205, 45 }, // Yellow + { 145, 215, 140 }, // Green +}; + + +// Used for Class specific buttons +char *sTFClasses[] = +{ + "", + "SCOUT", + "SNIPER", + "SOLDIER", + "DEMOMAN", + "MEDIC", + "HWGUY", + "PYRO", + "SPY", + "ENGINEER", + "CIVILIAN", +}; + +char *sLocalisedClasses[] = +{ + "#Civilian", + "#Scout", + "#Sniper", + "#Soldier", + "#Demoman", + "#Medic", + "#HWGuy", + "#Pyro", + "#Spy", + "#Engineer", + "#Random", + "#Civilian", +}; + +char *sTFClassSelection[] = +{ + "civilian", + "scout", + "sniper", + "soldier", + "demoman", + "medic", + "hwguy", + "pyro", + "spy", + "engineer", + "randompc", + "civilian", +}; + +int iBuildingCosts[] = +{ + BUILD_COST_DISPENSER, + BUILD_COST_SENTRYGUN +}; + +// This maps class numbers to the Invalid Class bit. +// This is needed for backwards compatability in maps that were finished before +// all the classes were in TF. Hence the wacky sequence. +int sTFValidClassInts[] = +{ + 0, + TF_ILL_SCOUT, + TF_ILL_SNIPER, + TF_ILL_SOLDIER, + TF_ILL_DEMOMAN, + TF_ILL_MEDIC, + TF_ILL_HVYWEP, + TF_ILL_PYRO, + TF_ILL_SPY, + TF_ILL_ENGINEER, + TF_ILL_RANDOMPC, +}; + +// Get the name of TGA file, based on GameDir +char* GetVGUITGAName(const char *pszName) +{ + int i; + char sz[256]; + static char gd[256]; + const char *gamedir; + + if (ScreenWidth < 640) + i = 320; + else + i = 640; + sprintf(sz, pszName, i); + + gamedir = gEngfuncs.pfnGetGameDirectory(); + sprintf(gd, "%s/gfx/vgui/%s.tga",gamedir,sz); + + return gd; +} + +//================================================================ +// COMMAND MENU +//================================================================ +void CCommandMenu::AddButton( CommandButton *pButton ) +{ + if (m_iButtons >= MAX_BUTTONS) + return; + + m_aButtons[m_iButtons] = pButton; + m_iButtons++; + pButton->setParent( this ); + pButton->setFont( Scheme::sf_primary3 ); + + // give the button a default key binding + if ( m_iButtons < 10 ) + { + pButton->setBoundKey( m_iButtons + '0' ); + } + else if ( m_iButtons == 10 ) + { + pButton->setBoundKey( '0' ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Tries to find a button that has a key bound to the input, and +// presses the button if found +// Input : keyNum - the character number of the input key +// Output : Returns true if the command menu should close, false otherwise +//----------------------------------------------------------------------------- +bool CCommandMenu::KeyInput( int keyNum ) +{ + // loop through all our buttons looking for one bound to keyNum + for ( int i = 0; i < m_iButtons; i++ ) + { + if ( !m_aButtons[i]->IsNotValid() ) + { + if ( m_aButtons[i]->getBoundKey() == keyNum ) + { + // hit the button + if ( m_aButtons[i]->GetSubMenu() ) + { + // open the sub menu + gViewPort->SetCurrentCommandMenu( m_aButtons[i]->GetSubMenu() ); + return false; + } + else + { + // run the bound command + m_aButtons[i]->fireActionSignal(); + return true; + } + } + } + } + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: clears the current menus buttons of any armed (highlighted) +// state, and all their sub buttons +//----------------------------------------------------------------------------- +void CCommandMenu::ClearButtonsOfArmedState( void ) +{ + for ( int i = 0; i < GetNumButtons(); i++ ) + { + m_aButtons[i]->setArmed( false ); + + if ( m_aButtons[i]->GetSubMenu() ) + { + m_aButtons[i]->GetSubMenu()->ClearButtonsOfArmedState(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pSubMenu - +// Output : CommandButton +//----------------------------------------------------------------------------- +CommandButton *CCommandMenu::FindButtonWithSubmenu( CCommandMenu *pSubMenu ) +{ + for ( int i = 0; i < GetNumButtons(); i++ ) + { + if ( m_aButtons[i]->GetSubMenu() == pSubMenu ) + return m_aButtons[i]; + } + + return NULL; +} + +// Recalculate the visible buttons +bool CCommandMenu::RecalculateVisibles( int iYOffset, bool bHideAll ) +{ + int i, iCurrentY = 0; + int iVisibleButtons = 0; + + // Cycle through all the buttons in this menu, and see which will be visible + for (i = 0; i < m_iButtons; i++) + { + int iClass = m_aButtons[i]->GetPlayerClass(); + + if ( (iClass && iClass != g_iPlayerClass ) || ( m_aButtons[i]->IsNotValid() ) || bHideAll ) + { + m_aButtons[i]->setVisible( false ); + if ( m_aButtons[i]->GetSubMenu() != NULL ) + { + (m_aButtons[i]->GetSubMenu())->RecalculateVisibles( 0, true ); + } + } + else + { + // If it's got a submenu, force it to check visibilities + if ( m_aButtons[i]->GetSubMenu() != NULL ) + { + if ( !(m_aButtons[i]->GetSubMenu())->RecalculateVisibles( 0 , false ) ) + { + // The submenu had no visible buttons, so don't display this button + m_aButtons[i]->setVisible( false ); + continue; + } + } + + m_aButtons[i]->setVisible( true ); + iVisibleButtons++; + } + } + + // Set Size + setSize( _size[0], (iVisibleButtons * (m_flButtonSizeY-1)) + 1 ); + + if ( iYOffset ) + { + m_iYOffset = iYOffset; + } + + for (i = 0; i < m_iButtons; i++) + { + if ( m_aButtons[i]->isVisible() ) + { + if ( m_aButtons[i]->GetSubMenu() != NULL ) + (m_aButtons[i]->GetSubMenu())->RecalculateVisibles( iCurrentY + m_iYOffset, false ); + + + // Make sure it's at the right Y position + // m_aButtons[i]->getPos( iXPos, iYPos ); + + if ( m_iDirection ) + { + m_aButtons[i]->setPos( 0, (iVisibleButtons-1) * (m_flButtonSizeY-1) - iCurrentY ); + } + else + { + m_aButtons[i]->setPos( 0, iCurrentY ); + } + + iCurrentY += (m_flButtonSizeY-1); + } + } + + return iVisibleButtons?true:false; +} + +// Make sure all submenus can fit on the screen +void CCommandMenu::RecalculatePositions( int iYOffset ) +{ + int iTop; + int iAdjust = 0; + + m_iYOffset+= iYOffset; + + if ( m_iDirection ) + iTop = ScreenHeight - (m_iYOffset + _size[1] ); + else + iTop = m_iYOffset; + + if ( iTop < 0 ) + iTop = 0; + + // Calculate if this is going to fit onscreen, and shuffle it up if it won't + int iBottom = iTop + _size[1]; + + if ( iBottom > ScreenHeight ) + { + // Move in increments of button sizes + while (iAdjust < (iBottom - ScreenHeight)) + { + iAdjust += m_flButtonSizeY - 1; + } + + iTop -= iAdjust; + + // Make sure it doesn't move off the top of the screen (the menu's too big to fit it all) + if ( iTop < 0 ) + { + iAdjust -= (0 - iTop); + iTop = 0; + } + } + + setPos( _pos[0], iTop ); + + // We need to force all menus below this one to update their positions now, because they + // might have submenus riding off buttons in this menu that have just shifted. + for (int i = 0; i < m_iButtons; i++) + m_aButtons[i]->UpdateSubMenus( iAdjust ); +} + + +// Make this menu and all menus above it in the chain visible +void CCommandMenu::MakeVisible( CCommandMenu *pChildMenu ) +{ +/* + // Push down the button leading to the child menu + for (int i = 0; i < m_iButtons; i++) + { + if ( (pChildMenu != NULL) && (m_aButtons[i]->GetSubMenu() == pChildMenu) ) + { + m_aButtons[i]->setArmed( true ); + } + else + { + m_aButtons[i]->setArmed( false ); + } + } +*/ + + setVisible(true); + if (m_pParentMenu) + m_pParentMenu->MakeVisible( this ); +} + +//================================================================ +// CreateSubMenu +CCommandMenu *TeamFortressViewport::CreateSubMenu( CommandButton *pButton, CCommandMenu *pParentMenu, int iYOffset, int iXOffset ) +{ + int iXPos = 0; + int iYPos = 0; + int iWide = CMENU_SIZE_X; + int iTall = 0; + int iDirection = 0; + + if (pParentMenu) + { + iXPos = m_pCurrentCommandMenu->GetXOffset() + (CMENU_SIZE_X - 1) + iXOffset; + iYPos = m_pCurrentCommandMenu->GetYOffset() + iYOffset; + iDirection = pParentMenu->GetDirection(); + } + + CCommandMenu *pMenu = new CCommandMenu(pParentMenu, iDirection, iXPos, iYPos, iWide, iTall ); + pMenu->setParent(this); + pButton->AddSubMenu( pMenu ); + pButton->setFont( Scheme::sf_primary3 ); + pMenu->m_flButtonSizeY = m_pCurrentCommandMenu->m_flButtonSizeY; + + // Create the Submenu-open signal + InputSignal *pISignal = new CMenuHandler_PopupSubMenuInput(pButton, pMenu); + pButton->addInputSignal(pISignal); + + // Put a > to show it's a submenu + CImageLabel *pLabel = new CImageLabel( "arrow", CMENU_SIZE_X - SUBMENU_SIZE_X, SUBMENU_SIZE_Y ); + pLabel->setParent(pButton); + pLabel->addInputSignal(pISignal); + + // Reposition + pLabel->getPos( iXPos, iYPos ); + pLabel->setPos( CMENU_SIZE_X - pLabel->getImageWide(), (BUTTON_SIZE_Y - pLabel->getImageTall()) / 2 ); + + // Create the mouse off signal for the Label too + if (!pButton->m_bNoHighlight) + pLabel->addInputSignal( new CHandler_CommandButtonHighlight(pButton) ); + + return pMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: Makes sure the memory allocated for TeamFortressViewport is nulled out +// Input : stAllocateBlock - +// Output : void * +//----------------------------------------------------------------------------- +void *TeamFortressViewport::operator new( size_t stAllocateBlock ) +{ +// void *mem = Panel::operator new( stAllocateBlock ); + void *mem = ::operator new( stAllocateBlock ); + memset( mem, 0, stAllocateBlock ); + return mem; +} + +//----------------------------------------------------------------------------- +// Purpose: InputSignal handler for the main viewport +//----------------------------------------------------------------------------- +class CViewPortInputHandler : public InputSignal +{ +public: + bool bPressed; + + CViewPortInputHandler() + { + } + + virtual void cursorMoved(int x,int y,Panel* panel) {} + virtual void cursorEntered(Panel* panel) {} + virtual void cursorExited(Panel* panel) {} + virtual void mousePressed(MouseCode code,Panel* panel) + { + if ( code != MOUSE_LEFT ) + { + // send a message to close the command menu + // this needs to be a message, since a direct call screws the timing + gEngfuncs.pfnClientCmd( "ForceCloseCommandMenu\n" ); + } + } + virtual void mouseReleased(MouseCode code,Panel* panel) + { + } + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} + virtual void mouseWheeled(int delta,Panel* panel) {} + virtual void keyPressed(KeyCode code,Panel* panel) {} + virtual void keyTyped(KeyCode code,Panel* panel) {} + virtual void keyReleased(KeyCode code,Panel* panel) {} + virtual void keyFocusTicked(Panel* panel) {} +}; + + +//================================================================ +TeamFortressViewport::TeamFortressViewport(int x,int y,int wide,int tall) : Panel(x,y,wide,tall), m_SchemeManager(wide,tall) +{ + gViewPort = this; + m_iInitialized = false; + m_pTeamMenu = NULL; + m_pClassMenu = NULL; + m_pScoreBoard = NULL; + m_pSpectatorPanel = NULL; + m_pCurrentMenu = NULL; + m_pCurrentCommandMenu = NULL; + + Initialize(); + addInputSignal( new CViewPortInputHandler ); + + int r, g, b, a; + + Scheme* pScheme = App::getInstance()->getScheme(); + + // primary text color + // Get the colors + //!! two different types of scheme here, need to integrate + SchemeHandle_t hPrimaryScheme = m_SchemeManager.getSchemeHandle( "Primary Button Text" ); + { + // font + pScheme->setFont( Scheme::sf_primary1, m_SchemeManager.getFont(hPrimaryScheme) ); + + // text color + m_SchemeManager.getFgColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary1, r, g, b, a ); // sc_primary1 is non-transparent orange + + // background color (transparent black) + m_SchemeManager.getBgColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary3, r, g, b, a ); + + // armed foreground color + m_SchemeManager.getFgArmedColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_secondary2, r, g, b, a ); + + // armed background color + m_SchemeManager.getBgArmedColor( hPrimaryScheme, r, g, b, a ); + pScheme->setColor(Scheme::sc_primary2, r, g, b, a ); + + //!! need to get this color from scheme file + // used for orange borders around buttons + m_SchemeManager.getBorderColor( hPrimaryScheme, r, g, b, a ); + // pScheme->setColor(Scheme::sc_secondary1, r, g, b, a ); + pScheme->setColor(Scheme::sc_secondary1, 255*0.7, 170*0.7, 0, 0); + } + + // Change the second primary font (used in the scoreboard) + SchemeHandle_t hScoreboardScheme = m_SchemeManager.getSchemeHandle( "Scoreboard Text" ); + { + pScheme->setFont(Scheme::sf_primary2, m_SchemeManager.getFont(hScoreboardScheme) ); + } + + // Change the third primary font (used in command menu) + SchemeHandle_t hCommandMenuScheme = m_SchemeManager.getSchemeHandle( "CommandMenu Text" ); + { + pScheme->setFont(Scheme::sf_primary3, m_SchemeManager.getFont(hCommandMenuScheme) ); + } + + App::getInstance()->setScheme(pScheme); + + // VGUI MENUS + CreateTeamMenu(); + CreateClassMenu(); + CreateSpectatorMenu(); + CreateScoreBoard(); + // Init command menus + m_iNumMenus = 0; + m_iCurrentTeamNumber = m_iUser1 = m_iUser2 = m_iUser3 = 0; + + m_StandardMenu = CreateCommandMenu("commandmenu.txt", 0, CMENU_TOP, false, CMENU_SIZE_X, BUTTON_SIZE_Y, 0 ); + m_SpectatorOptionsMenu = CreateCommandMenu("spectatormenu.txt", 1, YRES(32), true, CMENU_SIZE_X, BUTTON_SIZE_Y / 2, 0 ); // above bottom bar, flat design + m_SpectatorCameraMenu = CreateCommandMenu("spectcammenu.txt", 1, YRES(32), true, XRES( 200 ), BUTTON_SIZE_Y / 2, ScreenWidth - ( XRES ( 200 ) + 15 ) ); // above bottom bar, flat design + CreateServerBrowser(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called everytime a new level is started. Viewport clears out it's data. +//----------------------------------------------------------------------------- +void TeamFortressViewport::Initialize( void ) +{ + // Force each menu to Initialize + if (m_pTeamMenu) + { + m_pTeamMenu->Initialize(); + } + if (m_pClassMenu) + { + m_pClassMenu->Initialize(); + } + if (m_pScoreBoard) + { + m_pScoreBoard->Initialize(); + HideScoreBoard(); + } + if (m_pSpectatorPanel) + { + // Spectator menu doesn't need initializing + m_pSpectatorPanel->setVisible( false ); + } + + // Make sure all menus are hidden + HideVGUIMenu(); + HideCommandMenu(); + + // Clear out some data + m_iGotAllMOTD = true; + m_iRandomPC = false; + m_flScoreBoardLastUpdated = 0; + m_flSpectatorPanelLastUpdated = 0; + + // reset player info + g_iPlayerClass = 0; + g_iTeamNumber = 0; + + strcpy(m_sMapName, ""); + strcpy(m_szServerName, ""); + for (int i = 0; i < 5; i++) + { + m_iValidClasses[i] = 0; + strcpy(m_sTeamNames[i], ""); + } + + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_none) ); +} + +class CException; +//----------------------------------------------------------------------------- +// Purpose: Read the Command Menu structure from the txt file and create the menu. +// Returns Index of menu in m_pCommandMenus +//----------------------------------------------------------------------------- +int TeamFortressViewport::CreateCommandMenu( char * menuFile, int direction, int yOffset, bool flatDesign, float flButtonSizeX, float flButtonSizeY, int xOffset ) +{ + // COMMAND MENU + // Create the root of this new Command Menu + + int newIndex = m_iNumMenus; + + m_pCommandMenus[newIndex] = new CCommandMenu(NULL, direction, xOffset, yOffset, flButtonSizeX, 300); // This will be resized once we know how many items are in it + m_pCommandMenus[newIndex]->setParent(this); + m_pCommandMenus[newIndex]->setVisible(false); + m_pCommandMenus[newIndex]->m_flButtonSizeY = flButtonSizeY; + m_pCommandMenus[newIndex]->m_iSpectCmdMenu = direction; + + m_iNumMenus++; + + // Read Command Menu from the txt file + char token[1024]; + char *pfile = (char*)gEngfuncs.COM_LoadFile( menuFile, 5, NULL); + if (!pfile) + { + gEngfuncs.Con_DPrintf( "Unable to open %s\n", menuFile); + SetCurrentCommandMenu( NULL ); + return newIndex; + } + +try +{ + // First, read in the localisation strings + + // Detpack strings + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For5Seconds", m_sDetpackStrings[0], MAX_BUTTON_SIZE ); + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For20Seconds", m_sDetpackStrings[1], MAX_BUTTON_SIZE ); + gHUD.m_TextMessage.LocaliseTextString( "#DetpackSet_For50Seconds", m_sDetpackStrings[2], MAX_BUTTON_SIZE ); + + // Now start parsing the menu structure + m_pCurrentCommandMenu = m_pCommandMenus[newIndex]; + char szLastButtonText[32] = "file start"; + pfile = gEngfuncs.COM_ParseFile(pfile, token); + while ( ( strlen ( token ) > 0 ) && ( m_iNumMenus < MAX_MENUS ) ) + { + // Keep looping until we hit the end of this menu + while ( token[0] != '}' && ( strlen( token ) > 0 ) ) + { + char cText[32] = ""; + char cBoundKey[32] = ""; + char cCustom[32] = ""; + static const int cCommandLength = 128; + char cCommand[cCommandLength] = ""; + char szMap[MAX_MAPNAME] = ""; + int iPlayerClass = 0; + int iCustom = false; + int iTeamOnly = -1; + int iToggle = 0; + int iButtonY; + bool bGetExtraToken = true; + CommandButton *pButton = NULL; + + // We should never be here without a Command Menu + if (!m_pCurrentCommandMenu) + { + gEngfuncs.Con_Printf("Error in %s file after '%s'.\n",menuFile, szLastButtonText ); + m_iInitialized = false; + return newIndex; + } + + // token should already be the bound key, or the custom name + strncpy( cCustom, token, 32 ); + cCustom[31] = '\0'; + + // See if it's a custom button + if (!strcmp(cCustom, "CUSTOM") ) + { + iCustom = true; + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + // See if it's a map + else if (!strcmp(cCustom, "MAP") ) + { + // Get the mapname + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( szMap, token, MAX_MAPNAME ); + szMap[MAX_MAPNAME-1] = '\0'; + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + else if ( !strncmp(cCustom, "TEAM", 4) ) // TEAM1, TEAM2, TEAM3, TEAM4 + { + // make it a team only button + iTeamOnly = atoi( cCustom + 4 ); + + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + else if ( !strncmp(cCustom, "TOGGLE", 6) ) + { + iToggle = true; + // Get the next token + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + else + { + // See if it's a Class + for (int i = 1; i <= PC_ENGINEER; i++) + { + if ( !strcmp(token, sTFClasses[i]) ) + { + // Save it off + iPlayerClass = i; + + // Get the button text + pfile = gEngfuncs.COM_ParseFile(pfile, token); + break; + } + } + } + + // Get the button bound key + strncpy( cBoundKey, token, 32 ); + cText[31] = '\0'; + + // Get the button text + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( cText, token, 32 ); + cText[31] = '\0'; + + // save off the last button text we've come across (for error reporting) + strcpy( szLastButtonText, cText ); + + // Get the button command + pfile = gEngfuncs.COM_ParseFile(pfile, token); + strncpy( cCommand, token, cCommandLength ); + cCommand[cCommandLength - 1] = '\0'; + + iButtonY = (BUTTON_SIZE_Y-1) * m_pCurrentCommandMenu->GetNumButtons(); + + // Custom button handling + if ( iCustom ) + { + pButton = CreateCustomButton( cText, cCommand, iButtonY ); + + // Get the next token to see if we're a menu + pfile = gEngfuncs.COM_ParseFile(pfile, token); + + if ( token[0] == '{' ) + { + strcpy( cCommand, token ); + } + else + { + bGetExtraToken = false; + } + } + else if ( szMap[0] != '\0' ) + { + // create a map button + pButton = new MapButton(szMap, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY ); + } + else if ( iTeamOnly != -1) + { + // button that only shows up if the player is on team iTeamOnly + pButton = new TeamOnlyCommandButton( iTeamOnly, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); + } + else if ( iToggle && direction == 0 ) + { + pButton = new ToggleCommandButton( cCommand, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); + } + else if ( direction == 1 ) + { + if ( iToggle ) + pButton = new SpectToggleButton( cCommand, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); + else + pButton = new SpectButton( iPlayerClass, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY ); + } + else + { + // normal button + pButton = new CommandButton( iPlayerClass, cText, xOffset, iButtonY, flButtonSizeX, flButtonSizeY, flatDesign ); + } + + // add the button into the command menu + if ( pButton ) + { + m_pCurrentCommandMenu->AddButton( pButton ); + pButton->setBoundKey( cBoundKey[0] ); + pButton->setParentMenu( m_pCurrentCommandMenu ); + + // Override font in CommandMenu + pButton->setFont( Scheme::sf_primary3 ); + } + + // Find out if it's a submenu or a button we're dealing with + if ( cCommand[0] == '{' ) + { + if ( m_iNumMenus >= MAX_MENUS ) + { + gEngfuncs.Con_Printf( "Too many menus in %s past '%s'\n",menuFile, szLastButtonText ); + } + else + { + // Create the menu + m_pCommandMenus[m_iNumMenus] = CreateSubMenu(pButton, m_pCurrentCommandMenu, iButtonY ); + m_pCurrentCommandMenu = m_pCommandMenus[m_iNumMenus]; + m_iNumMenus++; + } + } + else if ( !iCustom ) + { + // Create the button and attach it to the current menu + if ( iToggle ) + pButton->addActionSignal(new CMenuHandler_ToggleCvar(cCommand)); + else + pButton->addActionSignal(new CMenuHandler_StringCommand(cCommand)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + + // Get the next token + if ( bGetExtraToken ) + { + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } + } + + // Move back up a menu + m_pCurrentCommandMenu = m_pCurrentCommandMenu->GetParentMenu(); + + pfile = gEngfuncs.COM_ParseFile(pfile, token); + } +} +catch( CException *e ) +{ + e; + //e->Delete(); + e = NULL; + m_iInitialized = false; + return newIndex; +} + + SetCurrentMenu( NULL ); + SetCurrentCommandMenu( NULL ); + gEngfuncs.COM_FreeFile( pfile ); + + m_iInitialized = true; + return newIndex; +} + +//----------------------------------------------------------------------------- +// Purpose: Creates all the class choices under a spy's disguise menus, and +// maps a command to them +// Output : CCommandMenu +//----------------------------------------------------------------------------- +CCommandMenu *TeamFortressViewport::CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText, int iYOffset, int iXOffset ) +{ + // create the submenu, under which the class choices will be listed + CCommandMenu *pMenu = CreateSubMenu( pButton, pParentMenu, iYOffset, iXOffset ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // create the class choice buttons + for ( int i = PC_SCOUT; i <= PC_ENGINEER; i++ ) + { + CommandButton *pDisguiseButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( sLocalisedClasses[i] ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y ); + + char sz[256]; + sprintf(sz, "%s %d", commandText, i ); + pDisguiseButton->addActionSignal(new CMenuHandler_StringCommand(sz)); + + pMenu->AddButton( pDisguiseButton ); + } + + return pMenu; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pButtonText - +// *pButtonName - +// Output : CommandButton +//----------------------------------------------------------------------------- +CommandButton *TeamFortressViewport::CreateCustomButton( char *pButtonText, char *pButtonName, int iYOffset ) +{ + CommandButton *pButton = NULL; + CCommandMenu *pMenu = NULL; + + // ChangeTeam + if ( !strcmp( pButtonName, "!CHANGETEAM" ) ) + { + // ChangeTeam Submenu + pButton = new CommandButton(pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + + // Create the submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // ChangeTeam buttons + for (int i = 0; i < 4; i++) + { + char sz[256]; + sprintf(sz, "jointeam %d", i+1); + m_pTeamButtons[i] = new TeamButton(i+1, "teamname", 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + m_pTeamButtons[i]->addActionSignal(new CMenuHandler_StringCommandWatch( sz )); + pMenu->AddButton( m_pTeamButtons[i] ); + } + + // Auto Assign button + m_pTeamButtons[4] = new TeamButton(5, gHUD.m_TextMessage.BufferedLocaliseTextString( "#Team_AutoAssign" ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + m_pTeamButtons[4]->addActionSignal(new CMenuHandler_StringCommand( "jointeam 5" )); + pMenu->AddButton( m_pTeamButtons[4] ); + + // Spectate button + m_pTeamButtons[5] = new SpectateButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Spectate" ), 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + m_pTeamButtons[5]->addActionSignal(new CMenuHandler_StringCommand( "spectate" )); + pMenu->AddButton( m_pTeamButtons[5] ); + } + // ChangeClass + else if ( !strcmp( pButtonName, "!CHANGECLASS" ) ) + { + // Create the Change class menu + pButton = new ClassButton(-1, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + + // ChangeClass Submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + for (int i = PC_SCOUT; i <= PC_RANDOM; i++ ) + { + char sz[256]; + + // ChangeClass buttons + CHudTextMessage::LocaliseTextString( sLocalisedClasses[i], sz, 256 ); + ClassButton *pClassButton = new ClassButton( i, sz, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y, false); + + sprintf(sz, "%s", sTFClassSelection[i]); + pClassButton->addActionSignal(new CMenuHandler_StringCommandClassSelect(sz)); + pMenu->AddButton( pClassButton ); + } + } + // Map Briefing + else if ( !strcmp( pButtonName, "!MAPBRIEFING" ) ) + { + pButton = new CommandButton(pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_MAPBRIEFING)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Class Descriptions + else if ( !strcmp( pButtonName, "!CLASSDESC" ) ) + { + pButton = new ClassButton(0, pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y, false); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_CLASSHELP)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!SERVERINFO" ) ) + { + pButton = new ClassButton(0, pButtonText, 0, BUTTON_SIZE_Y * m_pCurrentCommandMenu->GetNumButtons(), CMENU_SIZE_X, BUTTON_SIZE_Y, false); + pButton->addActionSignal(new CMenuHandler_TextWindow(MENU_INTRO)); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Spy abilities + else if ( !strcmp( pButtonName, "!SPY" ) ) + { + pButton = new DisguiseButton( 0, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y ); + } + // Feign + else if ( !strcmp( pButtonName, "!FEIGN" ) ) + { + pButton = new FeignButton(FALSE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "feign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Feign Silently + else if ( !strcmp( pButtonName, "!FEIGNSILENT" ) ) + { + pButton = new FeignButton(FALSE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "sfeign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Stop Feigning + else if ( !strcmp( pButtonName, "!FEIGNSTOP" ) ) + { + pButton = new FeignButton(TRUE, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "feign" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Disguise + else if ( !strcmp( pButtonName, "!DISGUISEENEMY" ) ) + { + // Create the disguise enemy button, which active only if there are 2 teams + pButton = new DisguiseButton(DISGUISE_TEAM2, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CreateDisguiseSubmenu( pButton, m_pCurrentCommandMenu, "disguise_enemy", iYOffset); + } + else if ( !strcmp( pButtonName, "!DISGUISEFRIENDLY" ) ) + { + // Create the disguise friendly button, which active only if there are 1 or 2 teams + pButton = new DisguiseButton(DISGUISE_TEAM1 | DISGUISE_TEAM2, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CreateDisguiseSubmenu( pButton, m_pCurrentCommandMenu, "disguise_friendly", iYOffset ); + } + else if ( !strcmp( pButtonName, "!DISGUISE" ) ) + { + // Create the Disguise button + pButton = new DisguiseButton( DISGUISE_TEAM3 | DISGUISE_TEAM4, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + CCommandMenu *pDisguiseMenu = CreateSubMenu( pButton, m_pCurrentCommandMenu, iYOffset ); + m_pCommandMenus[m_iNumMenus] = pDisguiseMenu; + m_iNumMenus++; + + // Disguise Enemy submenu buttons + for ( int i = 1; i <= 4; i++ ) + { + // only show the 4th disguise button if we have 4 teams + m_pDisguiseButtons[i] = new DisguiseButton( ((i < 4) ? DISGUISE_TEAM3 : 0) | DISGUISE_TEAM4, "Disguise", 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + + pDisguiseMenu->AddButton( m_pDisguiseButtons[i] ); + m_pDisguiseButtons[i]->setParentMenu( pDisguiseMenu ); + + char sz[256]; + sprintf( sz, "disguise %d", i ); + CreateDisguiseSubmenu( m_pDisguiseButtons[i], pDisguiseMenu, sz, iYOffset, CMENU_SIZE_X - 1 ); + } + } + // Start setting a Detpack + else if ( !strcmp( pButtonName, "!DETPACKSTART" ) ) + { + // Detpack Submenu + pButton = new DetpackButton(2, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + + // Create the submenu + pMenu = CreateSubMenu(pButton, m_pCurrentCommandMenu, iYOffset ); + m_pCommandMenus[m_iNumMenus] = pMenu; + m_iNumMenus++; + + // Set detpack buttons + CommandButton *pDetButton; + pDetButton = new CommandButton(m_sDetpackStrings[0], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 5")); + pMenu->AddButton( pDetButton ); + pDetButton = new CommandButton(m_sDetpackStrings[1], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 20")); + pMenu->AddButton( pDetButton ); + pDetButton = new CommandButton(m_sDetpackStrings[2], 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pDetButton->addActionSignal(new CMenuHandler_StringCommand("detstart 50")); + pMenu->AddButton( pDetButton ); + } + // Stop setting a Detpack + else if ( !strcmp( pButtonName, "!DETPACKSTOP" ) ) + { + pButton = new DetpackButton(1, pButtonText, 0, BUTTON_SIZE_Y, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand( "detstop" )); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Engineer building + else if ( !strcmp( pButtonName, "!BUILD" ) ) + { + // only appears if the player is an engineer, and either they have built something or have enough metal to build + pButton = new BuildButton( BUILDSTATE_BASE, 0, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + } + else if ( !strcmp( pButtonName, "!BUILDSENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_CANBUILD, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build 2")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!BUILDDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_CANBUILD, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build 1")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!ROTATESENTRY180" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("rotatesentry180")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!ROTATESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("rotatesentry")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DISMANTLEDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("dismantle 1")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DISMANTLESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("dismantle 2")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DETONATEDISPENSER" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::DISPENSER, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("detdispenser")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + else if ( !strcmp( pButtonName, "!DETONATESENTRY" ) ) + { + pButton = new BuildButton( BUILDSTATE_HASBUILDING, BuildButton::SENTRYGUN, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("detsentry")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + // Stop building + else if ( !strcmp( pButtonName, "!BUILDSTOP" ) ) + { + pButton = new BuildButton( BUILDSTATE_BUILDING, 0, pButtonText, 0, BUTTON_SIZE_Y * 2, CMENU_SIZE_X, BUTTON_SIZE_Y); + pButton->addActionSignal(new CMenuHandler_StringCommand("build")); + // Create an input signal that'll popup the current menu + pButton->addInputSignal( new CMenuHandler_PopupSubMenuInput(pButton, m_pCurrentCommandMenu) ); + } + + return pButton; +} + +void TeamFortressViewport::ToggleServerBrowser() +{ + if (!m_iInitialized) + return; + + if ( !m_pServerBrowser ) + return; + + if ( m_pServerBrowser->isVisible() ) + { + m_pServerBrowser->setVisible( false ); + } + else + { + m_pServerBrowser->setVisible( true ); + } + + UpdateCursorState(); +} + +//======================================================================= +void TeamFortressViewport::ShowCommandMenu(int menuIndex) +{ + if (!m_iInitialized) + return; + + //Already have a menu open. + if ( m_pCurrentMenu ) + return; + + // is the command menu open? + if ( m_pCurrentCommandMenu == m_pCommandMenus[menuIndex] ) + { + HideCommandMenu(); + return; + } + + // Not visible while in intermission + if ( gHUD.m_iIntermission ) + return; + + // Recalculate visible menus + UpdateCommandMenu( menuIndex ); + HideVGUIMenu(); + + SetCurrentCommandMenu( m_pCommandMenus[menuIndex] ); + m_flMenuOpenTime = gHUD.m_flTime; + UpdateCursorState(); + + // get command menu parameters + for ( int i = 2; i < gEngfuncs.Cmd_Argc(); i++ ) + { + const char *param = gEngfuncs.Cmd_Argv( i - 1 ); + if ( param ) + { + if ( m_pCurrentCommandMenu->KeyInput(param[0]) ) + { + // kill the menu open time, since the key input is final + HideCommandMenu(); + } + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Handles the key input of "-commandmenu" +// Input : +//----------------------------------------------------------------------------- +void TeamFortressViewport::InputSignalHideCommandMenu() +{ + if (!m_iInitialized) + return; + + // if they've just tapped the command menu key, leave it open + if ( (m_flMenuOpenTime + 0.3) > gHUD.m_flTime ) + return; + + HideCommandMenu(); +} + +//----------------------------------------------------------------------------- +// Purpose: Hides the command menu +//----------------------------------------------------------------------------- +void TeamFortressViewport::HideCommandMenu() +{ + if (!m_iInitialized) + return; + + if ( m_pCommandMenus[m_StandardMenu] ) + { + m_pCommandMenus[m_StandardMenu]->ClearButtonsOfArmedState(); + } + + if ( m_pCommandMenus[m_SpectatorOptionsMenu] ) + { + m_pCommandMenus[m_SpectatorOptionsMenu]->ClearButtonsOfArmedState(); + } + + if ( m_pCommandMenus[m_SpectatorCameraMenu] ) + { + m_pCommandMenus[m_SpectatorCameraMenu]->ClearButtonsOfArmedState(); + } + + m_flMenuOpenTime = 0.0f; + SetCurrentCommandMenu( NULL ); + UpdateCursorState(); +} + +//----------------------------------------------------------------------------- +// Purpose: Bring up the scoreboard +//----------------------------------------------------------------------------- +void TeamFortressViewport::ShowScoreBoard( void ) +{ + if (m_pScoreBoard) + { + // No Scoreboard in single-player + if ( gEngfuncs.GetMaxClients() > 1 ) + { + m_pScoreBoard->Open(); + UpdateCursorState(); + } + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if the scoreboard is up +//----------------------------------------------------------------------------- +bool TeamFortressViewport::IsScoreBoardVisible( void ) +{ + if (m_pScoreBoard) + return m_pScoreBoard->isVisible(); + + return false; +} + +//----------------------------------------------------------------------------- +// Purpose: Hide the scoreboard +//----------------------------------------------------------------------------- +void TeamFortressViewport::HideScoreBoard( void ) +{ + // Prevent removal of scoreboard during intermission + if ( gHUD.m_iIntermission ) + return; + + if (m_pScoreBoard) + { + m_pScoreBoard->setVisible(false); + + GetClientVoiceMgr()->StopSquelchMode(); + + UpdateCursorState(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Activate's the player special ability +// called when the player hits their "special" key +//----------------------------------------------------------------------------- +void TeamFortressViewport::InputPlayerSpecial( void ) +{ + if (!m_iInitialized) + return; + + if ( g_iPlayerClass == PC_ENGINEER || g_iPlayerClass == PC_SPY ) + { + ShowCommandMenu( gViewPort->m_StandardMenu ); + + if ( m_pCurrentCommandMenu ) + { + m_pCurrentCommandMenu->KeyInput( '7' ); + } + } + else + { + // if it's any other class, just send the command down to the server + ClientCmd( "_special" ); + } +} + +// Set the submenu of the Command Menu +void TeamFortressViewport::SetCurrentCommandMenu( CCommandMenu *pNewMenu ) +{ + for (int i = 0; i < m_iNumMenus; i++) + m_pCommandMenus[i]->setVisible(false); + + m_pCurrentCommandMenu = pNewMenu; + + if (m_pCurrentCommandMenu) + m_pCurrentCommandMenu->MakeVisible( NULL ); +} + +void TeamFortressViewport::UpdateCommandMenu(int menuIndex) +{ + m_pCommandMenus[menuIndex]->RecalculateVisibles( 0, false ); + m_pCommandMenus[menuIndex]->RecalculatePositions( 0 ); +} + +void COM_FileBase ( const char *in, char *out); + +void TeamFortressViewport::UpdateSpectatorPanel() +{ + m_iUser1 = g_iUser1; + m_iUser2 = g_iUser2; + m_iUser3 = g_iUser3; + + if (!m_pSpectatorPanel) + return; + + if ( g_iUser1 && gHUD.m_pCvarDraw->value && !gHUD.m_iIntermission) // don't draw in dev_overview mode + { + char bottomText[128]; + char helpString2[128]; + char tempString[128]; + char * name; + int player = 0; + + // check if spectator combinations are still valid + gHUD.m_Spectator.CheckSettings(); + + if ( !m_pSpectatorPanel->isVisible() ) + { + m_pSpectatorPanel->setVisible( true ); // show spectator panel, but + m_pSpectatorPanel->ShowMenu( false ); // dsiable all menus/buttons + + _snprintf( tempString, sizeof( tempString ) - 1, "%c%s", HUD_PRINTCENTER, CHudTextMessage::BufferedLocaliseTextString( "#Spec_Duck" ) ); + tempString[ sizeof( tempString ) - 1 ] = '\0'; + + gHUD.m_TextMessage.MsgFunc_TextMsg( NULL, strlen( tempString ) + 1, tempString ); + } + + sprintf(bottomText,"#Spec_Mode%d", g_iUser1 ); + sprintf(helpString2,"#Spec_Mode%d", g_iUser1 ); + + if ( gEngfuncs.IsSpectateOnly() ) + strcat(helpString2, " - HLTV"); + + // check if we're locked onto a target, show the player's name + if ( (g_iUser2 > 0) && (g_iUser2 <= gEngfuncs.GetMaxClients()) && (g_iUser1 != OBS_ROAMING) ) + { + player = g_iUser2; + } + + // special case in free map and inset off, don't show names + if ( (g_iUser1 == OBS_MAP_FREE) && !gHUD.m_Spectator.m_pip->value ) + name = NULL; + else + name = g_PlayerInfoList[player].name; + + // create player & health string + if ( player && name ) + { + strcpy( bottomText, name ); + } + + // in first person mode colorize player names + if ( (g_iUser1 == OBS_IN_EYE) && player ) + { + float * color = GetClientColor( player ); + int r = color[0]*255; + int g = color[1]*255; + int b = color[2]*255; + + // set team color, a bit transparent + m_pSpectatorPanel->m_BottomMainLabel->setFgColor(r,g,b,0); + } + else + { // restore GUI color + m_pSpectatorPanel->m_BottomMainLabel->setFgColor( 143, 143, 54, 0 ); + } + + // add sting auto if we are in auto directed mode + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + char tempString[128]; + sprintf(tempString, "#Spec_Auto %s", helpString2); + strcpy( helpString2, tempString ); + } + + m_pSpectatorPanel->m_BottomMainLabel->setText( CHudTextMessage::BufferedLocaliseTextString( bottomText ) ); + + + // update extra info field + char szText[64]; + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in HLTV mode show number of spectators + _snprintf( szText, 63, "%s: %d", CHudTextMessage::BufferedLocaliseTextString( "#Spectators" ), gHUD.m_Spectator.m_iSpectatorNumber ); + } + else + { + // otherwise show map name + char szMapName[64]; + COM_FileBase( gEngfuncs.pfnGetLevelName(), szMapName ); + + _snprintf ( szText, 63, "%s: %s",CHudTextMessage::BufferedLocaliseTextString( "#Spec_Map" ), szMapName ); + } + + szText[63] = 0; + + m_pSpectatorPanel->m_ExtraInfo->setText ( szText ); + + /* + int timer = (int)( gHUD.m_roundTimer.m_flTimeEnd - gHUD.m_flTime ); + + if ( timer < 0 ) + timer = 0; + + _snprintf ( szText, 63, "%d:%02d\n", (timer / 60), (timer % 60) ); + + szText[63] = 0; + + m_pSpectatorPanel->m_CurrentTime->setText( szText ); */ + + // update spectator panel + gViewPort->m_pSpectatorPanel->Update(); + } + else + { + if ( m_pSpectatorPanel->isVisible() ) + { + m_pSpectatorPanel->setVisible( false ); + m_pSpectatorPanel->ShowMenu( false ); // dsiable all menus/buttons + } + } + + m_flSpectatorPanelLastUpdated = gHUD.m_flTime + 1.0; // update every seconds +} + +//====================================================================== +void TeamFortressViewport::CreateScoreBoard( void ) +{ + int xdent = SBOARD_INDENT_X, ydent = SBOARD_INDENT_Y; + if (ScreenWidth == 512) + { + xdent = SBOARD_INDENT_X_512; + ydent = SBOARD_INDENT_Y_512; + } + else if (ScreenWidth == 400) + { + xdent = SBOARD_INDENT_X_400; + ydent = SBOARD_INDENT_Y_400; + } + + m_pScoreBoard = new ScorePanel(xdent, ydent, ScreenWidth - (xdent * 2), ScreenHeight - (ydent * 2)); + m_pScoreBoard->setParent(this); + m_pScoreBoard->setVisible(false); +} + +void TeamFortressViewport::CreateServerBrowser( void ) +{ + m_pServerBrowser = new ServerBrowser( 0, 0, ScreenWidth, ScreenHeight ); + m_pServerBrowser->setParent(this); + m_pServerBrowser->setVisible(false); +} + + +//====================================================================== +// Set the VGUI Menu +void TeamFortressViewport::SetCurrentMenu( CMenuPanel *pMenu ) +{ + m_pCurrentMenu = pMenu; + if ( m_pCurrentMenu ) + { + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return; + + m_pCurrentMenu->Open(); + } +} + +//================================================================ +// Text Window +CMenuPanel* TeamFortressViewport::CreateTextWindow( int iTextToShow ) +{ + char sz[256]; + char *cText; + char *pfile = NULL; + static const int MAX_TITLE_LENGTH = 32; + char cTitle[MAX_TITLE_LENGTH]; + + if ( iTextToShow == SHOW_MOTD ) + { + if (!m_szServerName || !m_szServerName[0]) + strcpy( cTitle, "Half-Life" ); + else + strncpy( cTitle, m_szServerName, MAX_TITLE_LENGTH ); + cTitle[MAX_TITLE_LENGTH-1] = 0; + cText = m_szMOTD; + } + else if ( iTextToShow == SHOW_MAPBRIEFING ) + { + // Get the current mapname, and open it's map briefing text + if (m_sMapName && m_sMapName[0]) + { + strcpy( sz, "maps/"); + strcat( sz, m_sMapName ); + strcat( sz, ".txt" ); + } + else + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (!level) + return NULL; + + strcpy( sz, level ); + char *ch = strchr( sz, '.' ); + *ch = '\0'; + strcat( sz, ".txt" ); + + // pull out the map name + strcpy( m_sMapName, level ); + ch = strchr( m_sMapName, '.' ); + if ( ch ) + { + *ch = 0; + } + + ch = strchr( m_sMapName, '/' ); + if ( ch ) + { + // move the string back over the '/' + memmove( m_sMapName, ch+1, strlen(ch)+1 ); + } + } + + pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + + if (!pfile) + return NULL; + + cText = pfile; + + strncpy( cTitle, m_sMapName, MAX_TITLE_LENGTH ); + cTitle[MAX_TITLE_LENGTH-1] = 0; + } + else if ( iTextToShow == SHOW_CLASSDESC ) + { + switch ( g_iPlayerClass ) + { + case PC_SCOUT: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_scout" ); + CHudTextMessage::LocaliseTextString( "#Title_scout", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SNIPER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_sniper" ); + CHudTextMessage::LocaliseTextString( "#Title_sniper", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SOLDIER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_soldier" ); + CHudTextMessage::LocaliseTextString( "#Title_soldier", cTitle, MAX_TITLE_LENGTH ); break; + case PC_DEMOMAN: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_demoman" ); + CHudTextMessage::LocaliseTextString( "#Title_demoman", cTitle, MAX_TITLE_LENGTH ); break; + case PC_MEDIC: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_medic" ); + CHudTextMessage::LocaliseTextString( "#Title_medic", cTitle, MAX_TITLE_LENGTH ); break; + case PC_HVYWEAP: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_hwguy" ); + CHudTextMessage::LocaliseTextString( "#Title_hwguy", cTitle, MAX_TITLE_LENGTH ); break; + case PC_PYRO: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_pyro" ); + CHudTextMessage::LocaliseTextString( "#Title_pyro", cTitle, MAX_TITLE_LENGTH ); break; + case PC_SPY: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_spy" ); + CHudTextMessage::LocaliseTextString( "#Title_spy", cTitle, MAX_TITLE_LENGTH ); break; + case PC_ENGINEER: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_engineer" ); + CHudTextMessage::LocaliseTextString( "#Title_engineer", cTitle, MAX_TITLE_LENGTH ); break; + case PC_CIVILIAN: cText = CHudTextMessage::BufferedLocaliseTextString( "#Help_civilian" ); + CHudTextMessage::LocaliseTextString( "#Title_civilian", cTitle, MAX_TITLE_LENGTH ); break; + default: + return NULL; + } + + if ( g_iPlayerClass == PC_CIVILIAN ) + { + sprintf(sz, "classes/long_civilian.txt"); + } + else + { + sprintf(sz, "classes/long_%s.txt", sTFClassSelection[ g_iPlayerClass ]); + } + char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + { + cText = pfile; + } + } + else if ( iTextToShow == SHOW_SPECHELP ) + { + CHudTextMessage::LocaliseTextString( "#Spec_Help_Title", cTitle, MAX_TITLE_LENGTH ); + cTitle[MAX_TITLE_LENGTH-1] = 0; + + char *pfile = CHudTextMessage::BufferedLocaliseTextString( "#Spec_Help_Text" ); + if ( pfile ) + { + cText = pfile; + } + } + + // if we're in the game (ie. have selected a class), flag the menu to be only grayed in the dialog box, instead of full screen + CMenuPanel *pMOTDPanel = CMessageWindowPanel_Create( cText, cTitle, g_iPlayerClass == PC_UNDEFINED, false, 0, 0, ScreenWidth, ScreenHeight ); + pMOTDPanel->setParent( this ); + + if ( pfile ) + gEngfuncs.COM_FreeFile( pfile ); + + return pMOTDPanel; +} + +//================================================================ +// VGUI Menus +void TeamFortressViewport::ShowVGUIMenu( int iMenu ) +{ + CMenuPanel *pNewMenu = NULL; + + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return; + + // Don't open any menus except the MOTD during intermission + // MOTD needs to be accepted because it's sent down to the client + // after map change, before intermission's turned off + if ( gHUD.m_iIntermission && iMenu != MENU_INTRO ) + return; + + // Don't create one if it's already in the list + if (m_pCurrentMenu) + { + CMenuPanel *pMenu = m_pCurrentMenu; + while (pMenu != NULL) + { + if (pMenu->GetMenuID() == iMenu) + return; + pMenu = pMenu->GetNextMenu(); + } + } + + switch ( iMenu ) + { + case MENU_TEAM: + pNewMenu = ShowTeamMenu(); + break; + + // Map Briefing removed now that it appears in the team menu + case MENU_MAPBRIEFING: + pNewMenu = CreateTextWindow( SHOW_MAPBRIEFING ); + break; + + case MENU_INTRO: + pNewMenu = CreateTextWindow( SHOW_MOTD ); + break; + + case MENU_CLASSHELP: + pNewMenu = CreateTextWindow( SHOW_CLASSDESC ); + break; + + case MENU_SPECHELP: + pNewMenu = CreateTextWindow( SHOW_SPECHELP ); + break; + case MENU_CLASS: + pNewMenu = ShowClassMenu(); + break; + + default: + break; + } + + if (!pNewMenu) + return; + + // Close the Command Menu if it's open + HideCommandMenu(); + + pNewMenu->SetMenuID( iMenu ); + pNewMenu->SetActive( true ); + pNewMenu->setParent(this); + + // See if another menu is visible, and if so, cache this one for display once the other one's finished + if (m_pCurrentMenu) + { + if ( m_pCurrentMenu->GetMenuID() == MENU_CLASS && iMenu == MENU_TEAM ) + { + CMenuPanel *temp = m_pCurrentMenu; + m_pCurrentMenu->Close(); + m_pCurrentMenu = pNewMenu; + m_pCurrentMenu->SetNextMenu( temp ); + m_pCurrentMenu->Open(); + UpdateCursorState(); + } + else + { + m_pCurrentMenu->SetNextMenu( pNewMenu ); + } + } + else + { + m_pCurrentMenu = pNewMenu; + m_pCurrentMenu->Open(); + UpdateCursorState(); + } +} + +// Removes all VGUI Menu's onscreen +void TeamFortressViewport::HideVGUIMenu() +{ + while (m_pCurrentMenu) + { + HideTopMenu(); + } +} + +// Remove the top VGUI menu, and bring up the next one +void TeamFortressViewport::HideTopMenu() +{ + if (m_pCurrentMenu) + { + // Close the top one + m_pCurrentMenu->Close(); + + // Bring up the next one + gViewPort->SetCurrentMenu( m_pCurrentMenu->GetNextMenu() ); + } + + UpdateCursorState(); +} + +// Return TRUE if the HUD's allowed to print text messages +bool TeamFortressViewport::AllowedToPrintText( void ) +{ + // Prevent text messages when fullscreen menus are up + if ( m_pCurrentMenu && g_iPlayerClass == 0 ) + { + int iId = m_pCurrentMenu->GetMenuID(); + if ( iId == MENU_TEAM || iId == MENU_CLASS || iId == MENU_INTRO || iId == MENU_CLASSHELP ) + return FALSE; + } + + return TRUE; +} + +//====================================================================================== +// TEAM MENU +//====================================================================================== +// Bring up the Team selection Menu +CMenuPanel* TeamFortressViewport::ShowTeamMenu() +{ + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return NULL; + + m_pTeamMenu->Reset(); + return m_pTeamMenu; +} + +void TeamFortressViewport::CreateTeamMenu() +{ + // Create the panel + m_pTeamMenu = new CTeamMenuPanel(100, false, 0, 0, ScreenWidth, ScreenHeight); + m_pTeamMenu->setParent( this ); + m_pTeamMenu->setVisible( false ); +} + +//====================================================================================== +// CLASS MENU +//====================================================================================== +// Bring up the Class selection Menu +CMenuPanel* TeamFortressViewport::ShowClassMenu() +{ + // Don't open menus in demo playback + if ( gEngfuncs.pDemoAPI->IsPlayingback() ) + return NULL; + + m_pClassMenu->Reset(); + return m_pClassMenu; +} + +void TeamFortressViewport::CreateClassMenu() +{ + // Create the panel + m_pClassMenu = new CClassMenuPanel(100, false, 0, 0, ScreenWidth, ScreenHeight); + m_pClassMenu->setParent(this); + m_pClassMenu->setVisible( false ); +} + +//====================================================================================== +//====================================================================================== +// SPECTATOR MENU +//====================================================================================== +// Spectator "Menu" explaining the Spectator buttons +void TeamFortressViewport::CreateSpectatorMenu() +{ + // Create the Panel + m_pSpectatorPanel = new SpectatorPanel(0, 0, ScreenWidth, ScreenHeight); + m_pSpectatorPanel->setParent(this); + m_pSpectatorPanel->setVisible(false); + m_pSpectatorPanel->Initialize(); +} + +//====================================================================================== +// UPDATE HUD SECTIONS +//====================================================================================== +// We've got an update on player info +// Recalculate any menus that use it. +void TeamFortressViewport::UpdateOnPlayerInfo() +{ + if (m_pTeamMenu) + m_pTeamMenu->Update(); + if (m_pClassMenu) + m_pClassMenu->Update(); + if (m_pScoreBoard) + m_pScoreBoard->Update(); +} + +void TeamFortressViewport::UpdateCursorState() +{ + // Need cursor if any VGUI window is up + if ( m_pSpectatorPanel->m_menuVisible || m_pCurrentMenu || m_pTeamMenu->isVisible() || m_pServerBrowser->isVisible() || GetClientVoiceMgr()->IsInSquelchMode() ) + { + g_iVisibleMouse = true; + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); + return; + } + else if ( m_pCurrentCommandMenu ) + { + // commandmenu doesn't have cursor if hud_capturemouse is turned off + if ( gHUD.m_pCvarStealMouse->value != 0.0f ) + { + g_iVisibleMouse = true; + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_arrow) ); + return; + } + } + + // Don't reset mouse in demo playback + if ( !gEngfuncs.pDemoAPI->IsPlayingback() ) + { + IN_ResetMouse(); + } + + g_iVisibleMouse = false; + App::getInstance()->setCursorOveride( App::getInstance()->getScheme()->getCursor(Scheme::SchemeCursor::scu_none) ); +} + +void TeamFortressViewport::UpdateHighlights() +{ + if (m_pCurrentCommandMenu) + m_pCurrentCommandMenu->MakeVisible( NULL ); +} + +void TeamFortressViewport::GetAllPlayersInfo( void ) +{ + for ( int i = 1; i < MAX_PLAYERS; i++ ) + { + GetPlayerInfo( i, &g_PlayerInfoList[i] ); + + if ( g_PlayerInfoList[i].thisplayer ) + m_pScoreBoard->m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine + } +} + +void TeamFortressViewport::paintBackground() +{ + if (m_pScoreBoard) + { + int x, y; + getApp()->getCursorPos(x, y); + m_pScoreBoard->cursorMoved(x, y, m_pScoreBoard); + } + + // See if the command menu is visible and needs recalculating due to some external change + if ( g_iTeamNumber != m_iCurrentTeamNumber ) + { + UpdateCommandMenu( m_StandardMenu ); + + if ( m_pClassMenu ) + { + m_pClassMenu->Update(); + } + + m_iCurrentTeamNumber = g_iTeamNumber; + } + + if ( g_iPlayerClass != m_iCurrentPlayerClass ) + { + UpdateCommandMenu( m_StandardMenu ); + + m_iCurrentPlayerClass = g_iPlayerClass; + } + + // See if the Spectator Menu needs to be update + if ( ( g_iUser1 != m_iUser1 || g_iUser2 != m_iUser2 ) || + ( m_flSpectatorPanelLastUpdated < gHUD.m_flTime ) ) + { + UpdateSpectatorPanel(); + } + + // Update the Scoreboard, if it's visible + if ( m_pScoreBoard->isVisible() && (m_flScoreBoardLastUpdated < gHUD.m_flTime) ) + { + m_pScoreBoard->Update(); + m_flScoreBoardLastUpdated = gHUD.m_flTime + 0.5; + } + + int extents[4]; + getAbsExtents(extents[0],extents[1],extents[2],extents[3]); + VGui_ViewportPaintBackground(extents); +} + +//================================================================ +// Input Handler for Drag N Drop panels +void CDragNDropHandler::cursorMoved(int x,int y,Panel* panel) +{ + if(m_bDragging) + { + App::getInstance()->getCursorPos(x,y); + m_pPanel->setPos(m_iaDragOrgPos[0]+(x-m_iaDragStart[0]),m_iaDragOrgPos[1]+(y-m_iaDragStart[1])); + + if(m_pPanel->getParent()!=null) + { + m_pPanel->getParent()->repaint(); + } + } +} + +void CDragNDropHandler::mousePressed(MouseCode code,Panel* panel) +{ + int x,y; + App::getInstance()->getCursorPos(x,y); + m_bDragging=true; + m_iaDragStart[0]=x; + m_iaDragStart[1]=y; + m_pPanel->getPos(m_iaDragOrgPos[0],m_iaDragOrgPos[1]); + App::getInstance()->setMouseCapture(panel); + + m_pPanel->setDragged(m_bDragging); + m_pPanel->requestFocus(); +} + +void CDragNDropHandler::mouseReleased(MouseCode code,Panel* panel) +{ + m_bDragging=false; + m_pPanel->setDragged(m_bDragging); + App::getInstance()->setMouseCapture(null); +} + +//================================================================ +// Number Key Input +bool TeamFortressViewport::SlotInput( int iSlot ) +{ + // If there's a menu up, give it the input + if ( m_pCurrentMenu ) + return m_pCurrentMenu->SlotInput( iSlot ); + + return FALSE; +} + +// Direct Key Input +int TeamFortressViewport::KeyInput( int down, int keynum, const char *pszCurrentBinding ) +{ + // Enter gets out of Spectator Mode by bringing up the Team Menu + if (m_iUser1 && gEngfuncs.Con_IsVisible() == false ) + { + if ( down && (keynum == K_ENTER || keynum == K_KP_ENTER) ) + ShowVGUIMenu( MENU_TEAM ); + } + + // Open Text Window? + if (m_pCurrentMenu && gEngfuncs.Con_IsVisible() == false) + { + int iMenuID = m_pCurrentMenu->GetMenuID(); + + // Get number keys as Input for Team/Class menus + if (iMenuID == MENU_TEAM || iMenuID == MENU_CLASS) + { + // Escape gets you out of Team/Class menus if the Cancel button is visible + if ( keynum == K_ESCAPE ) + { + if ( (iMenuID == MENU_TEAM && g_iTeamNumber) || (iMenuID == MENU_CLASS && g_iPlayerClass) ) + { + HideTopMenu(); + return 0; + } + } + + for (int i = '0'; i <= '9'; i++) + { + if ( down && (keynum == i) ) + { + SlotInput( i - '0' ); + return 0; + } + } + } + + // Grab enter keys to close TextWindows + if ( down && (keynum == K_ENTER || keynum == K_KP_ENTER || keynum == K_SPACE || keynum == K_ESCAPE) ) + { + if ( iMenuID == MENU_MAPBRIEFING || iMenuID == MENU_INTRO || iMenuID == MENU_CLASSHELP ) + { + HideTopMenu(); + return 0; + } + } + + // Grab jump key on Team Menu as autoassign + if ( pszCurrentBinding && down && !strcmp(pszCurrentBinding, "+jump") ) + { + if (iMenuID == MENU_TEAM) + { + m_pTeamMenu->SlotInput(5); + return 0; + } + } + + } + + // if we're in a command menu, try hit one of it's buttons + if ( down && m_pCurrentCommandMenu ) + { + // Escape hides the command menu + if ( keynum == K_ESCAPE ) + { + HideCommandMenu(); + return 0; + } + + // only trap the number keys + if ( keynum >= '0' && keynum <= '9' ) + { + if ( m_pCurrentCommandMenu->KeyInput(keynum) ) + { + // a final command has been issued, so close the command menu + HideCommandMenu(); + } + + return 0; + } + } + + return 1; +} + +//================================================================ +// Message Handlers +int TeamFortressViewport::MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + for (int i = 0; i < 5; i++) + m_iValidClasses[i] = READ_SHORT(); + + // Force the menu to update + UpdateCommandMenu( m_StandardMenu ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iNumberOfTeams = READ_BYTE(); + + for (int i = 0; i < m_iNumberOfTeams; i++) + { + int teamNum = i + 1; + + gHUD.m_TextMessage.LocaliseTextString( READ_STRING(), m_sTeamNames[teamNum], MAX_TEAMNAME_SIZE ); + + // Set the team name buttons + if (m_pTeamButtons[i]) + m_pTeamButtons[i]->setText( m_sTeamNames[teamNum] ); + + // range check this value...m_pDisguiseButtons[5]; + if ( teamNum < 5 ) + { + // Set the disguise buttons + if ( m_pDisguiseButtons[teamNum] ) + m_pDisguiseButtons[teamNum]->setText( m_sTeamNames[teamNum] ); + } + } + + // Update the Team Menu + if (m_pTeamMenu) + m_pTeamMenu->Update(); + + return 1; +} + +int TeamFortressViewport::MsgFunc_Feign(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iIsFeigning = READ_BYTE(); + + // Force the menu to update + UpdateCommandMenu( m_StandardMenu ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iIsSettingDetpack = READ_BYTE(); + + // Force the menu to update + UpdateCommandMenu( m_StandardMenu ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + int iMenu = READ_BYTE(); + + // Map briefing includes the name of the map (because it's sent down before the client knows what map it is) + if (iMenu == MENU_MAPBRIEFING) + { + strncpy( m_sMapName, READ_STRING(), sizeof(m_sMapName) ); + m_sMapName[ sizeof(m_sMapName) - 1 ] = '\0'; + } + + // Bring up the menu6 + ShowVGUIMenu( iMenu ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) +{ + if (m_iGotAllMOTD) + m_szMOTD[0] = 0; + + BEGIN_READ( pbuf, iSize ); + + m_iGotAllMOTD = READ_BYTE(); + + int roomInArray = sizeof(m_szMOTD) - strlen(m_szMOTD) - 1; + + strncat( m_szMOTD, READ_STRING(), roomInArray >= 0 ? roomInArray : 0 ); + m_szMOTD[ sizeof(m_szMOTD)-1 ] = '\0'; + + // don't show MOTD for HLTV spectators + if ( m_iGotAllMOTD && !gEngfuncs.IsSpectateOnly() ) + { + ShowVGUIMenu( MENU_INTRO ); + } + + return 1; +} + +int TeamFortressViewport::MsgFunc_BuildSt( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iBuildState = READ_BYTE(); + + // Force the menu to update + UpdateCommandMenu( m_StandardMenu ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_RandomPC( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iRandomPC = READ_BYTE(); + + return 1; +} + +int TeamFortressViewport::MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + strncpy( m_szServerName, READ_STRING(), MAX_SERVERNAME_LENGTH ); + + return 1; +} + +int TeamFortressViewport::MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + short cl = READ_BYTE(); + short frags = READ_SHORT(); + short deaths = READ_SHORT(); + short playerclass = READ_SHORT(); + short teamnumber = READ_SHORT(); + + if ( cl > 0 && cl <= MAX_PLAYERS ) + { + g_PlayerExtraInfo[cl].frags = frags; + g_PlayerExtraInfo[cl].deaths = deaths; + g_PlayerExtraInfo[cl].playerclass = playerclass; + g_PlayerExtraInfo[cl].teamnumber = teamnumber; + + //Dont go bellow 0! + if ( g_PlayerExtraInfo[cl].teamnumber < 0 ) + g_PlayerExtraInfo[cl].teamnumber = 0; + + UpdateOnPlayerInfo(); + } + + return 1; +} + +// Message handler for TeamScore message +// accepts three values: +// string: team name +// short: teams kills +// short: teams deaths +// if this message is never received, then scores will simply be the combined totals of the players. +int TeamFortressViewport::MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + char *TeamName = READ_STRING(); + + // find the team matching the name + for ( int i = 1; i <= m_pScoreBoard->m_iNumTeams; i++ ) + { + if ( !stricmp( TeamName, g_TeamInfo[i].name ) ) + break; + } + + if ( i > m_pScoreBoard->m_iNumTeams ) + return 1; + + // use this new score data instead of combined player scoresw + g_TeamInfo[i].scores_overriden = TRUE; + g_TeamInfo[i].frags = READ_SHORT(); + g_TeamInfo[i].deaths = READ_SHORT(); + + return 1; +} + +// Message handler for TeamInfo message +// accepts two values: +// byte: client number +// string: client team name +int TeamFortressViewport::MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) +{ + if (!m_pScoreBoard) + return 1; + + BEGIN_READ( pbuf, iSize ); + short cl = READ_BYTE(); + + if ( cl > 0 && cl <= MAX_PLAYERS ) + { + // set the players team + strncpy( g_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME ); + } + + // rebuild the list of teams + m_pScoreBoard->RebuildTeams(); + + return 1; +} + +void TeamFortressViewport::DeathMsg( int killer, int victim ) +{ + m_pScoreBoard->DeathMsg(killer,victim); +} + +int TeamFortressViewport::MsgFunc_Spectator( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + short cl = READ_BYTE(); + if ( cl > 0 && cl <= MAX_PLAYERS ) + { + g_IsSpectator[cl] = READ_BYTE(); + } + + return 1; +} + +int TeamFortressViewport::MsgFunc_AllowSpec( const char *pszName, int iSize, void *pbuf ) +{ + BEGIN_READ( pbuf, iSize ); + + m_iAllowSpectators = READ_BYTE(); + + // Force the menu to update + UpdateCommandMenu( m_StandardMenu ); + + // If the team menu is up, update it too + if (m_pTeamMenu) + m_pTeamMenu->Update(); + + return 1; +} diff --git a/cl_dll/vgui_TeamFortressViewport.h b/cl_dll/vgui_TeamFortressViewport.h new file mode 100644 index 00000000..c87258a6 --- /dev/null +++ b/cl_dll/vgui_TeamFortressViewport.h @@ -0,0 +1,1715 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef TEAMFORTRESSVIEWPORT_H +#define TEAMFORTRESSVIEWPORT_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// custom scheme handling +#include "vgui_SchemeManager.h" + +#define TF_DEFS_ONLY +#include "tf_defs.h" + +using namespace vgui; + +class Cursor; +class ScorePanel; +class SpectatorPanel; +class CCommandMenu; +class CommandLabel; +class CommandButton; +class BuildButton; +class ClassButton; +class CMenuPanel; +class ServerBrowser; +class DragNDropPanel; +class CTransparentPanel; +class CClassMenuPanel; +class CTeamMenuPanel; + +char* GetVGUITGAName(const char *pszName); +BitmapTGA *LoadTGAForRes(const char* pImageName); +void ScaleColors( int &r, int &g, int &b, int a ); +extern char *sTFClassSelection[]; +extern int sTFValidClassInts[]; +extern char *sLocalisedClasses[]; +extern int iTeamColors[5][3]; +extern int iNumberOfTeamColors; + +#define MAX_SERVERNAME_LENGTH 32 + +// Command Menu positions +#define MAX_MENUS 80 +#define MAX_BUTTONS 100 + +#define BUTTON_SIZE_Y YRES(30) +#define CMENU_SIZE_X XRES(160) + +#define SUBMENU_SIZE_X (CMENU_SIZE_X / 8) +#define SUBMENU_SIZE_Y (BUTTON_SIZE_Y / 6) + +#define CMENU_TOP (BUTTON_SIZE_Y * 4) + +#define MAX_TEAMNAME_SIZE 64 +#define MAX_BUTTON_SIZE 32 + +// Map Briefing Window +#define MAPBRIEF_INDENT 30 + +// Team Menu +#define TMENU_INDENT_X (30 * ((float)ScreenHeight / 640)) +#define TMENU_HEADER 100 +#define TMENU_SIZE_X (ScreenWidth - (TMENU_INDENT_X * 2)) +#define TMENU_SIZE_Y (TMENU_HEADER + BUTTON_SIZE_Y * 7) +#define TMENU_PLAYER_INDENT (((float)TMENU_SIZE_X / 3) * 2) +#define TMENU_INDENT_Y (((float)ScreenHeight - TMENU_SIZE_Y) / 2) + +// Class Menu +#define CLMENU_INDENT_X (30 * ((float)ScreenHeight / 640)) +#define CLMENU_HEADER 100 +#define CLMENU_SIZE_X (ScreenWidth - (CLMENU_INDENT_X * 2)) +#define CLMENU_SIZE_Y (CLMENU_HEADER + BUTTON_SIZE_Y * 11) +#define CLMENU_PLAYER_INDENT (((float)CLMENU_SIZE_X / 3) * 2) +#define CLMENU_INDENT_Y (((float)ScreenHeight - CLMENU_SIZE_Y) / 2) + +// Arrows +enum +{ + ARROW_UP, + ARROW_DOWN, + ARROW_LEFT, + ARROW_RIGHT, +}; + +//============================================================================== +// VIEWPORT PIECES +//============================================================ +// Wrapper for an Image Label without a background +class CImageLabel : public Label +{ +public: + BitmapTGA *m_pTGA; + +public: + void LoadImage(const char * pImageName); + CImageLabel( const char* pImageName,int x,int y ); + CImageLabel( const char* pImageName,int x,int y,int wide,int tall ); + + virtual int getImageTall(); + virtual int getImageWide(); + + virtual void paintBackground() + { + // Do nothing, so the background's left transparent. + } +}; + +// Command Label +// Overridden label so we can darken it when submenus open +class CommandLabel : public Label +{ +private: + int m_iState; + +public: + CommandLabel(const char* text,int x,int y,int wide,int tall) : Label(text,x,y,wide,tall) + { + m_iState = false; + } + + void PushUp() + { + m_iState = false; + repaint(); + } + + void PushDown() + { + m_iState = true; + repaint(); + } +}; + +//============================================================ +// Command Buttons +class CommandButton : public Button +{ +private: + int m_iPlayerClass; + bool m_bFlat; + + // Submenus under this button + CCommandMenu *m_pSubMenu; + CCommandMenu *m_pParentMenu; + CommandLabel *m_pSubLabel; + + char m_sMainText[MAX_BUTTON_SIZE]; + char m_cBoundKey; + + SchemeHandle_t m_hTextScheme; + + void RecalculateText( void ); + +public: + bool m_bNoHighlight; + +public: + CommandButton(const char* text,int x,int y,int wide,int tall, bool bNoHighlight, bool bFlat); + // Constructors + CommandButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight = false); + CommandButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall, bool bFlat ); + + void Init( void ); + + // Menu Handling + void AddSubMenu( CCommandMenu *pNewMenu ); + void AddSubLabel( CommandLabel *pSubLabel ) + { + m_pSubLabel = pSubLabel; + } + + virtual int IsNotValid( void ) + { + return false; + } + + void UpdateSubMenus( int iAdjustment ); + int GetPlayerClass() { return m_iPlayerClass; }; + CCommandMenu *GetSubMenu() { return m_pSubMenu; }; + + CCommandMenu *getParentMenu( void ); + void setParentMenu( CCommandMenu *pParentMenu ); + + // Overloaded vgui functions + virtual void paint(); + virtual void setText( const char *text ); + virtual void paintBackground(); + + void cursorEntered( void ); + void cursorExited( void ); + + void setBoundKey( char boundKey ); + char getBoundKey( void ); +}; + +class ColorButton : public CommandButton +{ +private: + + Color *ArmedColor; + Color *UnArmedColor; + + Color *ArmedBorderColor; + Color *UnArmedBorderColor; + +public: + ColorButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight, bool bFlat ) : + CommandButton( text, x, y, wide, tall, bNoHighlight, bFlat ) + { + ArmedColor = NULL; + UnArmedColor = NULL; + ArmedBorderColor = NULL; + UnArmedBorderColor = NULL; + } + + + virtual void paintBackground() + { + int r, g, b, a; + Color bgcolor; + + if ( isArmed() ) + { + // Highlight background + /* getBgColor(bgcolor); + bgcolor.getColor(r, g, b, a); + drawSetColor( r,g,b,a ); + drawFilledRect(0,0,_size[0],_size[1]);*/ + + if ( ArmedBorderColor ) + { + ArmedBorderColor->getColor( r, g, b, a); + drawSetColor( r, g, b, a ); + drawOutlinedRect(0,0,_size[0],_size[1]); + } + } + else + { + if ( UnArmedBorderColor ) + { + UnArmedBorderColor->getColor( r, g, b, a); + drawSetColor( r, g, b, a ); + drawOutlinedRect(0,0,_size[0],_size[1]); + } + } + } + void paint() + { + int r, g, b, a; + if ( isArmed() ) + { + if (ArmedColor) + { + ArmedColor->getColor(r, g, b, a); + setFgColor(r, g, b, a); + } + else + setFgColor( Scheme::sc_secondary2 ); + } + else + { + if (UnArmedColor) + { + UnArmedColor->getColor(r, g, b, a); + setFgColor(r, g, b, a); + } + else + setFgColor( Scheme::sc_primary1 ); + } + + Button::paint(); + } + + void setArmedColor ( int r, int g, int b, int a ) + { + ArmedColor = new Color( r, g, b, a ); + } + + void setUnArmedColor ( int r, int g, int b, int a ) + { + UnArmedColor = new Color( r, g, b, a ); + } + + void setArmedBorderColor ( int r, int g, int b, int a ) + { + ArmedBorderColor = new Color( r, g, b, a ); + } + + void setUnArmedBorderColor ( int r, int g, int b, int a ) + { + UnArmedBorderColor = new Color( r, g, b, a ); + } +}; + +class SpectButton : public CommandButton +{ +private: + +public: + SpectButton( int iPlayerClass, const char* text,int x,int y,int wide,int tall ) : + CommandButton( text, x, y, wide, tall, false) + { + Init(); + + setText( text ); + } + + virtual void paintBackground() + { + if ( isArmed()) + { + drawSetColor( 143,143, 54, 125 ); + drawFilledRect( 5, 0,_size[0] - 5,_size[1]); + } + } + + virtual void paint() + { + + if ( isArmed() ) + { + setFgColor( 194, 202, 54, 0 ); + } + else + { + setFgColor( 143, 143, 54, 15 ); + } + + Button::paint(); + } +}; +//============================================================ +// Command Menus +class CCommandMenu : public Panel +{ +private: + CCommandMenu *m_pParentMenu; + int m_iXOffset; + int m_iYOffset; + + // Buttons in this menu + CommandButton *m_aButtons[ MAX_BUTTONS ]; + int m_iButtons; + + // opens menu from top to bottom (0 = default), or from bottom to top (1)? + int m_iDirection; +public: + CCommandMenu( CCommandMenu *pParentMenu, int x,int y,int wide,int tall ) : Panel(x,y,wide,tall) + { + m_pParentMenu = pParentMenu; + m_iXOffset = x; + m_iYOffset = y; + m_iButtons = 0; + m_iDirection = 0; + } + + CCommandMenu( CCommandMenu *pParentMenu, int direction, int x,int y,int wide,int tall ) : Panel(x,y,wide,tall) + { + m_pParentMenu = pParentMenu; + m_iXOffset = x; + m_iYOffset = y; + m_iButtons = 0; + m_iDirection = direction; + } + + float m_flButtonSizeY; + int m_iSpectCmdMenu; + void AddButton( CommandButton *pButton ); + bool RecalculateVisibles( int iNewYPos, bool bHideAll ); + void RecalculatePositions( int iYOffset ); + void MakeVisible( CCommandMenu *pChildMenu ); + + CCommandMenu *GetParentMenu() { return m_pParentMenu; }; + int GetXOffset() { return m_iXOffset; }; + int GetYOffset() { return m_iYOffset; }; + int GetDirection() { return m_iDirection; }; + int GetNumButtons() { return m_iButtons; }; + CommandButton *FindButtonWithSubmenu( CCommandMenu *pSubMenu ); + + void ClearButtonsOfArmedState( void ); + + + bool KeyInput( int keyNum ); + + virtual void paintBackground(); +}; + +//============================================================================== +class TeamFortressViewport : public Panel +{ +private: + vgui::Cursor* _cursorNone; + vgui::Cursor* _cursorArrow; + + int m_iInitialized; + + CCommandMenu *m_pCommandMenus[ MAX_MENUS ]; + CCommandMenu *m_pCurrentCommandMenu; + float m_flMenuOpenTime; + float m_flScoreBoardLastUpdated; + float m_flSpectatorPanelLastUpdated; + int m_iNumMenus; + int m_iCurrentTeamNumber; + int m_iCurrentPlayerClass; + int m_iUser1; + int m_iUser2; + int m_iUser3; + + // VGUI Menus + void CreateTeamMenu( void ); + CMenuPanel* ShowTeamMenu( void ); + void CreateClassMenu( void ); + CMenuPanel* ShowClassMenu( void ); + void CreateSpectatorMenu( void ); + + // Scheme handler + CSchemeManager m_SchemeManager; + + // MOTD + int m_iGotAllMOTD; + char m_szMOTD[ MAX_MOTD_LENGTH ]; + + // Command Menu Team buttons + CommandButton *m_pTeamButtons[6]; + CommandButton *m_pDisguiseButtons[5]; + BuildButton *m_pBuildButtons[3]; + BuildButton *m_pBuildActiveButtons[3]; + + // Server Browser + ServerBrowser *m_pServerBrowser; + + int m_iAllowSpectators; + + // Data for specific sections of the Command Menu + int m_iValidClasses[5]; + int m_iIsFeigning; + int m_iIsSettingDetpack; + int m_iNumberOfTeams; + int m_iBuildState; + int m_iRandomPC; + char m_sTeamNames[5][MAX_TEAMNAME_SIZE]; + + // Localisation strings + char m_sDetpackStrings[3][MAX_BUTTON_SIZE]; + + char m_sMapName[64]; +public: + TeamFortressViewport(int x,int y,int wide,int tall); + void Initialize( void ); + + int CreateCommandMenu( char * menuFile, int direction, int yOffset, bool flatDesign, float flButtonSizeX, float flButtonSizeY, int xOffset ); + void CreateScoreBoard( void ); + void CreateServerBrowser( void ); + CommandButton * CreateCustomButton( char *pButtonText, char * pButtonName, int iYOffset ); + CCommandMenu * CreateDisguiseSubmenu( CommandButton *pButton, CCommandMenu *pParentMenu, const char *commandText, int iYOffset, int iXOffset = 0 ); + + void UpdateCursorState( void ); + void UpdateCommandMenu(int menuIndex); + void UpdateOnPlayerInfo( void ); + void UpdateHighlights( void ); + void UpdateSpectatorPanel( void ); + + int KeyInput( int down, int keynum, const char *pszCurrentBinding ); + void InputPlayerSpecial( void ); + void GetAllPlayersInfo( void ); + void DeathMsg( int killer, int victim ); + + void ShowCommandMenu(int menuIndex); + void InputSignalHideCommandMenu( void ); + void HideCommandMenu( void ); + void SetCurrentCommandMenu( CCommandMenu *pNewMenu ); + void SetCurrentMenu( CMenuPanel *pMenu ); + + void ShowScoreBoard( void ); + void HideScoreBoard( void ); + bool IsScoreBoardVisible( void ); + + bool AllowedToPrintText( void ); + + void ShowVGUIMenu( int iMenu ); + void HideVGUIMenu( void ); + void HideTopMenu( void ); + + void ToggleServerBrowser( void ); + + CMenuPanel* CreateTextWindow( int iTextToShow ); + + CCommandMenu *CreateSubMenu( CommandButton *pButton, CCommandMenu *pParentMenu, int iYOffset, int iXOffset = 0 ); + + // Data Handlers + int GetValidClasses(int iTeam) { return m_iValidClasses[iTeam]; }; + int GetNumberOfTeams() { return m_iNumberOfTeams; }; + int GetIsFeigning() { return m_iIsFeigning; }; + int GetIsSettingDetpack() { return m_iIsSettingDetpack; }; + int GetBuildState() { return m_iBuildState; }; + int IsRandomPC() { return m_iRandomPC; }; + char *GetTeamName( int iTeam ) { return m_sTeamNames[iTeam]; }; + int GetAllowSpectators() { return m_iAllowSpectators; }; + + // Message Handlers + int MsgFunc_ValClass(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamNames(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Feign(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Detpack(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_VGUIMenu(const char *pszName, int iSize, void *pbuf ); + int MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_BuildSt( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_RandomPC( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_Spectator( const char *pszName, int iSize, void *pbuf ); + int MsgFunc_AllowSpec( const char *pszName, int iSize, void *pbuf ); + + // Input + bool SlotInput( int iSlot ); + + virtual void paintBackground(); + + CSchemeManager *GetSchemeManager( void ) { return &m_SchemeManager; } + ScorePanel *GetScoreBoard( void ) { return m_pScoreBoard; } + + void *operator new( size_t stAllocateBlock ); + +public: + // VGUI Menus + CMenuPanel *m_pCurrentMenu; + CTeamMenuPanel *m_pTeamMenu; + int m_StandardMenu; // indexs in m_pCommandMenus + int m_SpectatorOptionsMenu; + int m_SpectatorCameraMenu; + CClassMenuPanel *m_pClassMenu; + ScorePanel *m_pScoreBoard; + SpectatorPanel * m_pSpectatorPanel; + char m_szServerName[ MAX_SERVERNAME_LENGTH ]; +}; + +//============================================================ +// Command Menu Button Handlers +#define MAX_COMMAND_SIZE 256 + +class CMenuHandler_StringCommand : public ActionSignal +{ +protected: + char m_pszCommand[MAX_COMMAND_SIZE]; + int m_iCloseVGUIMenu; +public: + CMenuHandler_StringCommand( char *pszCommand ) + { + strncpy( m_pszCommand, pszCommand, MAX_COMMAND_SIZE); + m_pszCommand[MAX_COMMAND_SIZE-1] = '\0'; + m_iCloseVGUIMenu = false; + } + + CMenuHandler_StringCommand( char *pszCommand, int iClose ) + { + strncpy( m_pszCommand, pszCommand, MAX_COMMAND_SIZE); + m_pszCommand[MAX_COMMAND_SIZE-1] = '\0'; + m_iCloseVGUIMenu = true; + } + + virtual void actionPerformed(Panel* panel) + { + gEngfuncs.pfnClientCmd(m_pszCommand); + + if (m_iCloseVGUIMenu) + gViewPort->HideTopMenu(); + else + gViewPort->HideCommandMenu(); + } +}; + +// This works the same as CMenuHandler_StringCommand, except it watches the string command +// for specific commands, and modifies client vars based upon them. +class CMenuHandler_StringCommandWatch : public CMenuHandler_StringCommand +{ +private: +public: + CMenuHandler_StringCommandWatch( char *pszCommand ) : CMenuHandler_StringCommand( pszCommand ) + { + } + + CMenuHandler_StringCommandWatch( char *pszCommand, int iClose ) : CMenuHandler_StringCommand( pszCommand, iClose ) + { + } + + virtual void actionPerformed(Panel* panel) + { + CMenuHandler_StringCommand::actionPerformed( panel ); + + // Try to guess the player's new team (it'll be corrected if it's wrong) + if ( !strcmp( m_pszCommand, "jointeam 1" ) ) + g_iTeamNumber = 1; + else if ( !strcmp( m_pszCommand, "jointeam 2" ) ) + g_iTeamNumber = 2; + else if ( !strcmp( m_pszCommand, "jointeam 3" ) ) + g_iTeamNumber = 3; + else if ( !strcmp( m_pszCommand, "jointeam 4" ) ) + g_iTeamNumber = 4; + } +}; + +// Used instead of CMenuHandler_StringCommand for Class Selection buttons. +// Checks the state of hud_classautokill and kills the player if set +class CMenuHandler_StringCommandClassSelect : public CMenuHandler_StringCommand +{ +private: +public: + CMenuHandler_StringCommandClassSelect( char *pszCommand ) : CMenuHandler_StringCommand( pszCommand ) + { + } + + CMenuHandler_StringCommandClassSelect( char *pszCommand, int iClose ) : CMenuHandler_StringCommand( pszCommand, iClose ) + { + } + + virtual void actionPerformed(Panel* panel); +}; + +class CMenuHandler_PopupSubMenuInput : public InputSignal +{ +private: + CCommandMenu *m_pSubMenu; + Button *m_pButton; +public: + CMenuHandler_PopupSubMenuInput( Button *pButton, CCommandMenu *pSubMenu ) + { + m_pSubMenu = pSubMenu; + m_pButton = pButton; + } + + virtual void cursorMoved(int x,int y,Panel* panel) + { + //gViewPort->SetCurrentCommandMenu( m_pSubMenu ); + } + + virtual void cursorEntered(Panel* panel) + { + gViewPort->SetCurrentCommandMenu( m_pSubMenu ); + + if (m_pButton) + m_pButton->setArmed(true); + }; + virtual void cursorExited(Panel* Panel) {}; + virtual void mousePressed(MouseCode code,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +class CMenuHandler_LabelInput : public InputSignal +{ +private: + ActionSignal *m_pActionSignal; +public: + CMenuHandler_LabelInput( ActionSignal *pSignal ) + { + m_pActionSignal = pSignal; + } + + virtual void mousePressed(MouseCode code,Panel* panel) + { + m_pActionSignal->actionPerformed( panel ); + } + + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void cursorEntered(Panel* panel) {}; + virtual void cursorExited(Panel* Panel) {}; + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +#define HIDE_TEXTWINDOW 0 +#define SHOW_MAPBRIEFING 1 +#define SHOW_CLASSDESC 2 +#define SHOW_MOTD 3 +#define SHOW_SPECHELP 4 + +class CMenuHandler_TextWindow : public ActionSignal +{ +private: + int m_iState; +public: + CMenuHandler_TextWindow( int iState ) + { + m_iState = iState; + } + + virtual void actionPerformed(Panel* panel) + { + if (m_iState == HIDE_TEXTWINDOW) + { + gViewPort->HideTopMenu(); + } + else + { + gViewPort->HideCommandMenu(); + gViewPort->ShowVGUIMenu( m_iState ); + } + } +}; + +class CMenuHandler_ToggleCvar : public ActionSignal +{ +private: + struct cvar_s * m_cvar; + +public: + CMenuHandler_ToggleCvar( char * cvarname ) + { + m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); + } + + virtual void actionPerformed(Panel* panel) + { + if ( m_cvar->value ) + m_cvar->value = 0.0f; + else + m_cvar->value = 1.0f; + + gViewPort->UpdateSpectatorPanel(); + } + + +}; +class CDragNDropHandler : public InputSignal +{ +private: + DragNDropPanel* m_pPanel; + bool m_bDragging; + int m_iaDragOrgPos[2]; + int m_iaDragStart[2]; + +public: + CDragNDropHandler(DragNDropPanel* pPanel) + { + m_pPanel = pPanel; + m_bDragging = false; + } + + void cursorMoved(int x,int y,Panel* panel); + void mousePressed(MouseCode code,Panel* panel); + void mouseReleased(MouseCode code,Panel* panel); + + void mouseDoublePressed(MouseCode code,Panel* panel) {}; + void cursorEntered(Panel* panel) {}; + void cursorExited(Panel* panel) {}; + void mouseWheeled(int delta,Panel* panel) {}; + void keyPressed(KeyCode code,Panel* panel) {}; + void keyTyped(KeyCode code,Panel* panel) {}; + void keyReleased(KeyCode code,Panel* panel) {}; + void keyFocusTicked(Panel* panel) {}; +}; + +class CHandler_MenuButtonOver : public InputSignal +{ +private: + int m_iButton; + CMenuPanel *m_pMenuPanel; +public: + CHandler_MenuButtonOver( CMenuPanel *pPanel, int iButton ) + { + m_iButton = iButton; + m_pMenuPanel = pPanel; + } + + void cursorEntered(Panel *panel); + + void cursorMoved(int x,int y,Panel* panel) {}; + void mousePressed(MouseCode code,Panel* panel) {}; + void mouseReleased(MouseCode code,Panel* panel) {}; + void mouseDoublePressed(MouseCode code,Panel* panel) {}; + void cursorExited(Panel* panel) {}; + void mouseWheeled(int delta,Panel* panel) {}; + void keyPressed(KeyCode code,Panel* panel) {}; + void keyTyped(KeyCode code,Panel* panel) {}; + void keyReleased(KeyCode code,Panel* panel) {}; + void keyFocusTicked(Panel* panel) {}; +}; + +class CHandler_ButtonHighlight : public InputSignal +{ +private: + Button *m_pButton; +public: + CHandler_ButtonHighlight( Button *pButton ) + { + m_pButton = pButton; + } + + virtual void cursorEntered(Panel* panel) + { + m_pButton->setArmed(true); + }; + virtual void cursorExited(Panel* Panel) + { + m_pButton->setArmed(false); + }; + virtual void mousePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void cursorMoved(int x,int y,Panel* panel) {}; + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; +}; + +//----------------------------------------------------------------------------- +// Purpose: Special handler for highlighting of command menu buttons +//----------------------------------------------------------------------------- +class CHandler_CommandButtonHighlight : public CHandler_ButtonHighlight +{ +private: + CommandButton *m_pCommandButton; +public: + CHandler_CommandButtonHighlight( CommandButton *pButton ) : CHandler_ButtonHighlight( pButton ) + { + m_pCommandButton = pButton; + } + + virtual void cursorEntered( Panel *panel ) + { + m_pCommandButton->cursorEntered(); + } + + virtual void cursorExited( Panel *panel ) + { + m_pCommandButton->cursorExited(); + } +}; + + +//================================================================ +// Overidden Command Buttons for special visibilities +class ClassButton : public CommandButton +{ +protected: + int m_iPlayerClass; + +public: + ClassButton( int iClass, const char* text,int x,int y,int wide,int tall, bool bNoHighlight ) : CommandButton( text,x,y,wide,tall, bNoHighlight) + { + m_iPlayerClass = iClass; + } + + virtual int IsNotValid(); +}; + +class TeamButton : public CommandButton +{ +private: + int m_iTeamNumber; +public: + TeamButton( int iTeam, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iTeamNumber = iTeam; + } + + virtual int IsNotValid() + { + int iTeams = gViewPort->GetNumberOfTeams(); + // Never valid if there's only 1 team + if (iTeams == 1) + return true; + + // Auto Team's always visible + if (m_iTeamNumber == 5) + return false; + + if (iTeams >= m_iTeamNumber && m_iTeamNumber != g_iTeamNumber) + return false; + + return true; + } +}; + +class FeignButton : public CommandButton +{ +private: + int m_iFeignState; +public: + FeignButton( int iState, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iFeignState = iState; + } + + virtual int IsNotValid() + { + // Only visible for spies + if (g_iPlayerClass != PC_SPY) + return true; + + if (m_iFeignState == gViewPort->GetIsFeigning()) + return false; + + return true; + } +}; + +class SpectateButton : public CommandButton +{ +public: + SpectateButton( const char* text,int x,int y,int wide,int tall, bool bNoHighlight ) : CommandButton( text,x,y,wide,tall, bNoHighlight) + { + } + + virtual int IsNotValid() + { + // Only visible if the server allows it + if ( gViewPort->GetAllowSpectators() != 0 ) + return false; + + return true; + } +}; + +#define DISGUISE_TEAM1 (1<<0) +#define DISGUISE_TEAM2 (1<<1) +#define DISGUISE_TEAM3 (1<<2) +#define DISGUISE_TEAM4 (1<<3) + +class DisguiseButton : public CommandButton +{ +private: + int m_iValidTeamsBits; + int m_iThisTeam; +public: + DisguiseButton( int iValidTeamNumsBits, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall,false ) + { + m_iValidTeamsBits = iValidTeamNumsBits; + } + + virtual int IsNotValid() + { + // Only visible for spies + if ( g_iPlayerClass != PC_SPY ) + return true; + + // if it's not tied to a specific team, then always show (for spies) + if ( !m_iValidTeamsBits ) + return false; + + // if we're tied to a team make sure we can change to that team + int iTmp = 1 << (gViewPort->GetNumberOfTeams() - 1); + if ( m_iValidTeamsBits & iTmp ) + return false; + + return true; + } +}; + +class DetpackButton : public CommandButton +{ +private: + int m_iDetpackState; +public: + DetpackButton( int iState, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iDetpackState = iState; + } + + virtual int IsNotValid() + { + // Only visible for demomen + if (g_iPlayerClass != PC_DEMOMAN) + return true; + + if (m_iDetpackState == gViewPort->GetIsSettingDetpack()) + return false; + + return true; + } +}; + +extern int iBuildingCosts[]; +#define BUILDSTATE_HASBUILDING (1<<0) // Data is building ID (1 = Dispenser, 2 = Sentry) +#define BUILDSTATE_BUILDING (1<<1) +#define BUILDSTATE_BASE (1<<2) +#define BUILDSTATE_CANBUILD (1<<3) // Data is building ID (0 = Dispenser, 1 = Sentry) + +class BuildButton : public CommandButton +{ +private: + int m_iBuildState; + int m_iBuildData; + +public: + enum Buildings + { + DISPENSER = 0, + SENTRYGUN = 1, + }; + + BuildButton( int iState, int iData, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + m_iBuildState = iState; + m_iBuildData = iData; + } + + virtual int IsNotValid() + { + // Only visible for engineers + if (g_iPlayerClass != PC_ENGINEER) + return true; + + // If this isn't set, it's only active when they're not building + if (m_iBuildState & BUILDSTATE_BUILDING) + { + // Make sure the player's building + if ( !(gViewPort->GetBuildState() & BS_BUILDING) ) + return true; + } + else + { + // Make sure the player's not building + if ( gViewPort->GetBuildState() & BS_BUILDING ) + return true; + } + + if (m_iBuildState & BUILDSTATE_BASE) + { + // Only appear if we've got enough metal to build something, or something already built + if ( gViewPort->GetBuildState() & (BS_HAS_SENTRYGUN | BS_HAS_DISPENSER | BS_CANB_SENTRYGUN | BS_CANB_DISPENSER) ) + return false; + + return true; + } + + // Must have a building + if (m_iBuildState & BUILDSTATE_HASBUILDING) + { + if ( m_iBuildData == BuildButton::DISPENSER && !(gViewPort->GetBuildState() & BS_HAS_DISPENSER) ) + return true; + if ( m_iBuildData == BuildButton::SENTRYGUN && !(gViewPort->GetBuildState() & BS_HAS_SENTRYGUN) ) + return true; + } + + // Can build something + if (m_iBuildState & BUILDSTATE_CANBUILD) + { + // Make sure they've got the ammo and don't have one already + if ( m_iBuildData == BuildButton::DISPENSER && (gViewPort->GetBuildState() & BS_CANB_DISPENSER) ) + return false; + if ( m_iBuildData == BuildButton::SENTRYGUN && (gViewPort->GetBuildState() & BS_CANB_SENTRYGUN) ) + return false; + + return true; + } + + return false; + } +}; + +#define MAX_MAPNAME 256 + +class MapButton : public CommandButton +{ +private: + char m_szMapName[ MAX_MAPNAME ]; + +public: + MapButton( const char *pMapName, const char* text,int x,int y,int wide,int tall ) : CommandButton( text,x,y,wide,tall) + { + sprintf( m_szMapName, "maps/%s.bsp", pMapName ); + } + + virtual int IsNotValid() + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (!level) + return true; + + // Does it match the current map name? + if ( strcmp(m_szMapName, level) ) + return true; + + return false; + } +}; + +//----------------------------------------------------------------------------- +// Purpose: CommandButton which is only displayed if the player is on team X +//----------------------------------------------------------------------------- +class TeamOnlyCommandButton : public CommandButton +{ +private: + int m_iTeamNum; + +public: + TeamOnlyCommandButton( int iTeamNum, const char* text,int x,int y,int wide,int tall, bool flat ) : + CommandButton( text, x, y, wide, tall, false, flat ), m_iTeamNum(iTeamNum) {} + + virtual int IsNotValid() + { + if ( g_iTeamNumber != m_iTeamNum ) + return true; + + return CommandButton::IsNotValid(); + } + + virtual void paintBackground() + { + if ( isArmed() ) + { + drawSetColor( 143,143, 54, 125 ); + drawFilledRect( 5, 0,_size[0] - 5,_size[1]); + } + } + + virtual void paint( void ) + { + if ( isArmed() ) + { + setFgColor( 194, 202, 54, 0 ); + } + else + { + setFgColor( 143, 143, 54, 15 ); + } + + Button::paint(); + } +}; + +//----------------------------------------------------------------------------- +// Purpose: CommandButton which is only displayed if the player is on team X +//----------------------------------------------------------------------------- +class ToggleCommandButton : public CommandButton, public InputSignal +{ +private: + struct cvar_s * m_cvar; + CImageLabel * pLabelOn; + CImageLabel * pLabelOff; + + +public: + ToggleCommandButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : + CommandButton( text, x, y, wide, tall, false, flat ) + { + m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); + + // Put a > to show it's a submenu + pLabelOn = new CImageLabel( "checked", 0, 0 ); + pLabelOn->setParent(this); + pLabelOn->addInputSignal(this); + + pLabelOff = new CImageLabel( "unchecked", 0, 0 ); + pLabelOff->setParent(this); + pLabelOff->setEnabled(true); + pLabelOff->addInputSignal(this); + + int textwide, texttall; + getTextSize( textwide, texttall); + + // Reposition + pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); + + pLabelOff->setPos( textwide, (tall - pLabelOff->getTall()) / 2 ); + + // Set text color to orange + setFgColor(Scheme::sc_primary1); + } + + virtual void cursorEntered(Panel* panel) + { + CommandButton::cursorEntered(); + } + + virtual void cursorExited(Panel* panel) + { + CommandButton::cursorExited(); + } + + virtual void mousePressed(MouseCode code,Panel* panel) + { + doClick(); + }; + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; + + virtual void paint( void ) + { + if ( !m_cvar ) + { + pLabelOff->setVisible(false); + pLabelOn->setVisible(false); + } + else if ( m_cvar->value ) + { + pLabelOff->setVisible(false); + pLabelOn->setVisible(true); + } + else + { + pLabelOff->setVisible(true); + pLabelOn->setVisible(false); + } + + CommandButton::paint(); + + } +}; +class SpectToggleButton : public CommandButton, public InputSignal +{ +private: + struct cvar_s * m_cvar; + CImageLabel * pLabelOn; + +public: + SpectToggleButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : + CommandButton( text, x, y, wide, tall, false, flat ) + { + m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); + + // Put a > to show it's a submenu + pLabelOn = new CImageLabel( "checked", 0, 0 ); + pLabelOn->setParent(this); + pLabelOn->addInputSignal(this); + + + int textwide, texttall; + getTextSize( textwide, texttall); + + // Reposition + pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); + } + + virtual void cursorEntered(Panel* panel) + { + CommandButton::cursorEntered(); + } + + virtual void cursorExited(Panel* panel) + { + CommandButton::cursorExited(); + } + + virtual void mousePressed(MouseCode code,Panel* panel) + { + doClick(); + }; + + virtual void cursorMoved(int x,int y,Panel* panel) {}; + + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {}; + virtual void mouseReleased(MouseCode code,Panel* panel) {}; + virtual void mouseWheeled(int delta,Panel* panel) {}; + virtual void keyPressed(KeyCode code,Panel* panel) {}; + virtual void keyTyped(KeyCode code,Panel* panel) {}; + virtual void keyReleased(KeyCode code,Panel* panel) {}; + virtual void keyFocusTicked(Panel* panel) {}; + + virtual void paintBackground() + { + if ( isArmed() ) + { + drawSetColor( 143,143, 54, 125 ); + drawFilledRect( 5, 0,_size[0] - 5,_size[1]); + } + } + + virtual void paint( void ) + { + if ( isArmed() ) + { + setFgColor( 194, 202, 54, 0 ); + } + else + { + setFgColor( 143, 143, 54, 15 ); + } + + if ( !m_cvar ) + { + pLabelOn->setVisible(false); + } + else if ( m_cvar->value ) + { + pLabelOn->setVisible(true); + } + else + { + pLabelOn->setVisible(false); + } + + Button::paint(); + } +}; + +/* +class SpectToggleButton : public ToggleCommandButton +{ +private: + struct cvar_s * m_cvar; + CImageLabel * pLabelOn; + CImageLabel * pLabelOff; + +public: + + SpectToggleButton( const char* cvarname, const char* text,int x,int y,int wide,int tall, bool flat ) : + ToggleCommandButton( cvarname, text, x, y, wide, tall, flat, TRUE ) + { + m_cvar = gEngfuncs.pfnGetCvarPointer( cvarname ); + + // Put a > to show it's a submenu + pLabelOn = new CImageLabel( "checked", 0, 0 ); + pLabelOn->setParent(this); + pLabelOn->addInputSignal(this); + + pLabelOff = new CImageLabel( "unchecked", 0, 0 ); + pLabelOff->setParent(this); + pLabelOff->setEnabled(true); + pLabelOff->addInputSignal(this); + + int textwide, texttall; + getTextSize( textwide, texttall); + + // Reposition + pLabelOn->setPos( textwide, (tall - pLabelOn->getTall()) / 2 ); + + pLabelOff->setPos( textwide, (tall - pLabelOff->getTall()) / 2 ); + + // Set text color to orange + setFgColor(Scheme::sc_primary1); + } + + virtual void paintBackground() + { + if ( isArmed()) + { + drawSetColor( 143,143, 54, 125 ); + drawFilledRect( 5, 0,_size[0] - 5,_size[1]); + } + } + + virtual void paint() + { + + if ( isArmed() ) + { + setFgColor( 194, 202, 54, 0 ); + } + else + { + setFgColor( 143, 143, 54, 15 ); + } + + if ( !m_cvar ) + { + pLabelOff->setVisible(false); + pLabelOn->setVisible(false); + } + else if ( m_cvar->value ) + { + pLabelOff->setVisible(false); + pLabelOn->setVisible(true); + } + else + { + pLabelOff->setVisible(true); + pLabelOn->setVisible(false); + } + + Button::paint(); + } +}; +*/ +//============================================================ +// Panel that can be dragged around +class DragNDropPanel : public Panel +{ +private: + bool m_bBeingDragged; + LineBorder *m_pBorder; +public: + DragNDropPanel(int x,int y,int wide,int tall) : Panel(x,y,wide,tall) + { + m_bBeingDragged = false; + + // Create the Drag Handler + addInputSignal( new CDragNDropHandler(this) ); + + // Create the border (for dragging) + m_pBorder = new LineBorder(); + } + + virtual void setDragged( bool bState ) + { + m_bBeingDragged = bState; + + if (m_bBeingDragged) + setBorder(m_pBorder); + else + setBorder(NULL); + } +}; + +//================================================================ +// Panel that draws itself with a transparent black background +class CTransparentPanel : public Panel +{ +private: + int m_iTransparency; +public: + CTransparentPanel(int iTrans, int x,int y,int wide,int tall) : Panel(x,y,wide,tall) + { + m_iTransparency = iTrans; + } + + virtual void paintBackground() + { + if (m_iTransparency) + { + // Transparent black background + drawSetColor( 0,0,0, m_iTransparency ); + drawFilledRect(0,0,_size[0],_size[1]); + } + } +}; + +//================================================================ +// Menu Panel that supports buffering of menus +class CMenuPanel : public CTransparentPanel +{ +private: + CMenuPanel *m_pNextMenu; + int m_iMenuID; + int m_iRemoveMe; + int m_iIsActive; + float m_flOpenTime; +public: + CMenuPanel(int iRemoveMe, int x,int y,int wide,int tall) : CTransparentPanel(100, x,y,wide,tall) + { + Reset(); + m_iRemoveMe = iRemoveMe; + } + + CMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CTransparentPanel(iTrans, x,y,wide,tall) + { + Reset(); + m_iRemoveMe = iRemoveMe; + } + + virtual void Reset( void ) + { + m_pNextMenu = NULL; + m_iIsActive = false; + m_flOpenTime = 0; + } + + void SetNextMenu( CMenuPanel *pNextPanel ) + { + if (m_pNextMenu) + m_pNextMenu->SetNextMenu( pNextPanel ); + else + m_pNextMenu = pNextPanel; + } + + void SetMenuID( int iID ) + { + m_iMenuID = iID; + } + + void SetActive( int iState ) + { + m_iIsActive = iState; + } + + virtual void Open( void ) + { + setVisible( true ); + + // Note the open time, so we can delay input for a bit + m_flOpenTime = gHUD.m_flTime; + } + + virtual void Close( void ) + { + setVisible( false ); + m_iIsActive = false; + + if ( m_iRemoveMe ) + gViewPort->removeChild( this ); + + // This MenuPanel has now been deleted. Don't append code here. + } + + int ShouldBeRemoved() { return m_iRemoveMe; }; + CMenuPanel* GetNextMenu() { return m_pNextMenu; }; + int GetMenuID() { return m_iMenuID; }; + int IsActive() { return m_iIsActive; }; + float GetOpenTime() { return m_flOpenTime; }; + + // Numeric input + virtual bool SlotInput( int iSlot ) { return false; }; + virtual void SetActiveInfo( int iInput ) {}; +}; + +//================================================================ +// Custom drawn scroll bars +class CTFScrollButton : public CommandButton +{ +private: + BitmapTGA *m_pTGA; + +public: + CTFScrollButton(int iArrow, const char* text,int x,int y,int wide,int tall); + + virtual void paint( void ); + virtual void paintBackground( void ); +}; + +// Custom drawn slider bar +class CTFSlider : public Slider +{ +public: + CTFSlider(int x,int y,int wide,int tall,bool vertical) : Slider(x,y,wide,tall,vertical) + { + }; + + virtual void paintBackground( void ); +}; + +// Custom drawn scrollpanel +class CTFScrollPanel : public ScrollPanel +{ +public: + CTFScrollPanel(int x,int y,int wide,int tall); +}; + +//================================================================ +// Menu Panels that take key input +//============================================================ +class CClassMenuPanel : public CMenuPanel +{ +private: + CTransparentPanel *m_pClassInfoPanel[PC_LASTCLASS]; + Label *m_pPlayers[PC_LASTCLASS]; + ClassButton *m_pButtons[PC_LASTCLASS]; + CommandButton *m_pCancelButton; + ScrollPanel *m_pScrollPanel; + + CImageLabel *m_pClassImages[MAX_TEAMS][PC_LASTCLASS]; + + int m_iCurrentInfo; + + enum { STRLENMAX_PLAYERSONTEAM = 128 }; + char m_sPlayersOnTeamString[STRLENMAX_PLAYERSONTEAM]; + +public: + CClassMenuPanel(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 SetActiveInfo( int iInput ); + virtual void Initialize( void ); + + virtual void Reset( void ) + { + CMenuPanel::Reset(); + m_iCurrentInfo = 0; + } +}; + +class CTeamMenuPanel : public CMenuPanel +{ +public: + ScrollPanel *m_pScrollPanel; + CTransparentPanel *m_pTeamWindow; + Label *m_pMapTitle; + TextPanel *m_pBriefing; + TextPanel *m_pTeamInfoPanel[6]; + CommandButton *m_pButtons[6]; + bool m_bUpdatedMapName; + CommandButton *m_pCancelButton; + CommandButton *m_pSpectateButton; + + int m_iCurrentInfo; + +public: + CTeamMenuPanel(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 SetActiveInfo( int iInput ); + virtual void paintBackground( void ); + + virtual void Initialize( void ); + + virtual void Reset( void ) + { + CMenuPanel::Reset(); + m_iCurrentInfo = 0; + } +}; + +//========================================================= +// Specific Menus to handle old HUD sections +class CHealthPanel : public DragNDropPanel +{ +private: + BitmapTGA *m_pHealthTGA; + Label *m_pHealthLabel; +public: + CHealthPanel(int x,int y,int wide,int tall) : DragNDropPanel(x,y,wide,tall) + { + // Load the Health icon + FileInputStream* fis = new FileInputStream( GetVGUITGAName("%d_hud_health"), false); + m_pHealthTGA = new BitmapTGA(fis,true); + fis->close(); + + // Create the Health Label + int iXSize,iYSize; + m_pHealthTGA->getSize(iXSize,iYSize); + m_pHealthLabel = new Label("",0,0,iXSize,iYSize); + m_pHealthLabel->setImage(m_pHealthTGA); + m_pHealthLabel->setParent(this); + + // Set panel dimension + // Shouldn't be needed once Billy's fized setImage not recalculating the size + //setSize( iXSize + 100, gHUD.m_iFontHeight + 10 ); + //m_pHealthLabel->setPos( 10, (getTall() - iYSize) / 2 ); + } + + virtual void paintBackground() + { + } + + void paint() + { + // Get the paint color + int r,g,b,a; + // Has health changed? Flash the health # + if (gHUD.m_Health.m_fFade) + { + gHUD.m_Health.m_fFade -= (gHUD.m_flTimeDelta * 20); + if (gHUD.m_Health.m_fFade <= 0) + { + a = MIN_ALPHA; + gHUD.m_Health.m_fFade = 0; + } + + // Fade the health number back to dim + a = MIN_ALPHA + (gHUD.m_Health.m_fFade/FADE_TIME) * 128; + } + else + a = MIN_ALPHA; + + gHUD.m_Health.GetPainColor( r, g, b ); + ScaleColors(r, g, b, a ); + + // If health is getting low, make it bright red + if (gHUD.m_Health.m_iHealth <= 15) + a = 255; + + int iXSize,iYSize, iXPos, iYPos; + m_pHealthTGA->getSize(iXSize,iYSize); + m_pHealthTGA->getPos(iXPos, iYPos); + + // Paint the player's health + int x = gHUD.DrawHudNumber( iXPos + iXSize + 5, iYPos + 5, DHN_3DIGITS | DHN_DRAWZERO, gHUD.m_Health.m_iHealth, r, g, b); + + // Draw the vertical line + int HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; + x += HealthWidth / 2; + FillRGBA(x, iYPos + 5, HealthWidth / 10, gHUD.m_iFontHeight, 255, 160, 0, a); + } +}; + +#endif diff --git a/cl_dll/vgui_int.cpp b/cl_dll/vgui_int.cpp new file mode 100644 index 00000000..7d7bdaa4 --- /dev/null +++ b/cl_dll/vgui_int.cpp @@ -0,0 +1,128 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include"vgui_int.h" +#include +#include +#include +#include +#include +#include +#include +#include "hud.h" +#include "cl_util.h" +#include "camera.h" +#include "kbutton.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" +#include "camera.h" +#include "in_defs.h" +#include "vgui_TeamFortressViewport.h" +#include "vgui_ControlConfigPanel.h" + +namespace +{ + +class TexturePanel : public Panel , public ActionSignal +{ +private: + int _bindIndex; + TextEntry* _textEntry; +public: + TexturePanel() : Panel(0,0,256,276) + { + _bindIndex=2700; + _textEntry=new TextEntry("2700",0,0,128,20); + _textEntry->setParent(this); + _textEntry->addActionSignal(this); + } +public: + virtual bool isWithin(int x,int y) + { + return _textEntry->isWithin(x,y); + } +public: + virtual void actionPerformed(Panel* panel) + { + char buf[256]; + _textEntry->getText(0,buf,256); + sscanf(buf,"%d",&_bindIndex); + } +protected: + virtual void paintBackground() + { + Panel::paintBackground(); + + int wide,tall; + getPaintSize(wide,tall); + + drawSetColor(0,0,255,0); + drawSetTexture(_bindIndex); + drawTexturedRect(0,19,257,257); + } + +}; + +} + +using namespace vgui; + +void VGui_ViewportPaintBackground(int extents[4]) +{ + gEngfuncs.VGui_ViewportPaintBackground(extents); +} + +void* VGui_GetPanel() +{ + return (Panel*)gEngfuncs.VGui_GetPanel(); +} + +void VGui_Startup() +{ + Panel* root=(Panel*)VGui_GetPanel(); + root->setBgColor(128,128,0,0); + //root->setNonPainted(false); + //root->setBorder(new LineBorder()); + root->setLayout(new BorderLayout(0)); + + + //root->getSurfaceBase()->setEmulatedCursorVisible(true); + + if (gViewPort != NULL) + { +// root->removeChild(gViewPort); + + // free the memory +// delete gViewPort; +// gViewPort = NULL; + + gViewPort->Initialize(); + } + else + { + gViewPort = new TeamFortressViewport(0,0,root->getWide(),root->getTall()); + gViewPort->setParent(root); + } + + /* + TexturePanel* texturePanel=new TexturePanel(); + texturePanel->setParent(gViewPort); + */ + +} + +void VGui_Shutdown() +{ + delete gViewPort; + gViewPort = NULL; +} + + + + + diff --git a/cl_dll/vgui_int.h b/cl_dll/vgui_int.h new file mode 100644 index 00000000..b5302b28 --- /dev/null +++ b/cl_dll/vgui_int.h @@ -0,0 +1,21 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_INT_H +#define VGUI_INT_H + +extern "C" +{ +void VGui_Startup(); +void VGui_Shutdown(); + +//Only safe to call from inside subclass of Panel::paintBackground +void VGui_ViewportPaintBackground(int extents[4]); +} + + +#endif \ No newline at end of file diff --git a/cl_dll/vgui_teammenu.cpp b/cl_dll/vgui_teammenu.cpp new file mode 100644 index 00000000..a1370791 --- /dev/null +++ b/cl_dll/vgui_teammenu.cpp @@ -0,0 +1,393 @@ +//=========== (C) Copyright 1996-2002 Valve, L.L.C. All rights reserved. =========== +// +// The copyright to the contents herein is the property of Valve, L.L.C. +// The contents may be used and/or copied only with the written permission of +// Valve, L.L.C., or in accordance with the terms and conditions stipulated in +// the agreement/contract under which the contents have been supplied. +// +// Purpose: TFC Team Menu +// +// $Workfile: $ +// $Date: $ +// +//----------------------------------------------------------------------------- +// $Log: $ +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_int.h" +#include "VGUI_Font.h" +#include "VGUI_ScrollPanel.h" +#include "VGUI_TextImage.h" + +#include "hud.h" +#include "cl_util.h" +#include "vgui_TeamFortressViewport.h" + +// Team Menu Dimensions +#define TEAMMENU_TITLE_X XRES(40) +#define TEAMMENU_TITLE_Y YRES(32) +#define TEAMMENU_TOPLEFT_BUTTON_X XRES(40) +#define TEAMMENU_TOPLEFT_BUTTON_Y YRES(80) +#define TEAMMENU_BUTTON_SIZE_X XRES(124) +#define TEAMMENU_BUTTON_SIZE_Y YRES(24) +#define TEAMMENU_BUTTON_SPACER_Y YRES(8) +#define TEAMMENU_WINDOW_X XRES(176) +#define TEAMMENU_WINDOW_Y YRES(80) +#define TEAMMENU_WINDOW_SIZE_X XRES(424) +#define TEAMMENU_WINDOW_SIZE_Y YRES(312) +#define TEAMMENU_WINDOW_TITLE_X XRES(16) +#define TEAMMENU_WINDOW_TITLE_Y YRES(16) +#define TEAMMENU_WINDOW_TEXT_X XRES(16) +#define TEAMMENU_WINDOW_TEXT_Y YRES(48) +#define TEAMMENU_WINDOW_TEXT_SIZE_Y YRES(178) +#define TEAMMENU_WINDOW_INFO_X XRES(16) +#define TEAMMENU_WINDOW_INFO_Y YRES(234) + +// Creation +CTeamMenuPanel::CTeamMenuPanel(int iTrans, int iRemoveMe, int x,int y,int wide,int tall) : CMenuPanel(iTrans, iRemoveMe, x,y,wide,tall) +{ + // Get the scheme used for the Titles + CSchemeManager *pSchemes = gViewPort->GetSchemeManager(); + + // schemes + SchemeHandle_t hTitleScheme = pSchemes->getSchemeHandle( "Title Font" ); + SchemeHandle_t hTeamWindowText = pSchemes->getSchemeHandle( "Briefing Text" ); + SchemeHandle_t hTeamInfoText = pSchemes->getSchemeHandle( "Team Info Text" ); + + // get the Font used for the Titles + Font *pTitleFont = pSchemes->getFont( hTitleScheme ); + int r, g, b, a; + + // Create the title + Label *pLabel = new Label( "", TEAMMENU_TITLE_X, TEAMMENU_TITLE_Y ); + pLabel->setParent( this ); + pLabel->setFont( pTitleFont ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + pLabel->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + pLabel->setBgColor( r, g, b, a ); + pLabel->setContentAlignment( vgui::Label::a_west ); + pLabel->setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Title_SelectYourTeam")); + + // Create the Info Window + m_pTeamWindow = new CTransparentPanel( 255, TEAMMENU_WINDOW_X, TEAMMENU_WINDOW_Y, TEAMMENU_WINDOW_SIZE_X, TEAMMENU_WINDOW_SIZE_Y ); + m_pTeamWindow->setParent( this ); + m_pTeamWindow->setBorder( new LineBorder( Color(255*0.7,170*0.7,0,0 )) ); + + // Create the Map Name Label + m_pMapTitle = new Label( "", TEAMMENU_WINDOW_TITLE_X, TEAMMENU_WINDOW_TITLE_Y ); + m_pMapTitle->setFont( pTitleFont ); + m_pMapTitle->setParent( m_pTeamWindow ); + pSchemes->getFgColor( hTitleScheme, r, g, b, a ); + m_pMapTitle->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTitleScheme, r, g, b, a ); + m_pMapTitle->setBgColor( r, g, b, a ); + m_pMapTitle->setContentAlignment( vgui::Label::a_west ); + + // Create the Scroll panel + m_pScrollPanel = new CTFScrollPanel( TEAMMENU_WINDOW_TEXT_X, TEAMMENU_WINDOW_TEXT_Y, TEAMMENU_WINDOW_SIZE_X - (TEAMMENU_WINDOW_TEXT_X * 2), TEAMMENU_WINDOW_TEXT_SIZE_Y ); + m_pScrollPanel->setParent(m_pTeamWindow); + m_pScrollPanel->setScrollBarVisible(false, false); + + // Create the Map Briefing panel + m_pBriefing = new TextPanel("", 0,0, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_TEXT_X, TEAMMENU_WINDOW_TEXT_SIZE_Y ); + m_pBriefing->setParent( m_pScrollPanel->getClient() ); + m_pBriefing->setFont( pSchemes->getFont(hTeamWindowText) ); + pSchemes->getFgColor( hTeamWindowText, r, g, b, a ); + m_pBriefing->setFgColor( r, g, b, a ); + pSchemes->getBgColor( hTeamWindowText, r, g, b, a ); + m_pBriefing->setBgColor( r, g, b, a ); + + m_pBriefing->setText( gHUD.m_TextMessage.BufferedLocaliseTextString("#Map_Description_not_available") ); + + // Team Menu buttons + for (int i = 1; i <= 5; i++) + { + char sz[256]; + + int iYPos = TEAMMENU_TOPLEFT_BUTTON_Y + ( (TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y) * i ); + + // Team button + m_pButtons[i] = new CommandButton( "", TEAMMENU_TOPLEFT_BUTTON_X, iYPos, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y, true); + m_pButtons[i]->setParent( this ); + m_pButtons[i]->setContentAlignment( vgui::Label::a_west ); + m_pButtons[i]->setVisible( false ); + + // AutoAssign button uses special case + if (i == 5) + { + m_pButtons[5]->setBoundKey( '5' ); + m_pButtons[5]->setText( gHUD.m_TextMessage.BufferedLocaliseTextString("#Team_AutoAssign") ); + m_pButtons[5]->setVisible( true ); + } + + // Create the Signals + sprintf(sz, "jointeam %d", i); + m_pButtons[i]->addActionSignal( new CMenuHandler_StringCommandWatch( sz, true ) ); + m_pButtons[i]->addInputSignal( new CHandler_MenuButtonOver(this, i) ); + + // Create the Team Info panel + m_pTeamInfoPanel[i] = new TextPanel("", TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_INFO_Y, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_X, TEAMMENU_WINDOW_SIZE_X - TEAMMENU_WINDOW_INFO_Y ); + m_pTeamInfoPanel[i]->setParent( m_pTeamWindow ); + m_pTeamInfoPanel[i]->setFont( pSchemes->getFont(hTeamInfoText) ); + m_pTeamInfoPanel[i]->setFgColor( iTeamColors[i % iNumberOfTeamColors][0], + iTeamColors[i % iNumberOfTeamColors][1], + iTeamColors[i % iNumberOfTeamColors][2], + 0 ); + m_pTeamInfoPanel[i]->setBgColor( 0,0,0, 255 ); + } + + // Create the Cancel button + m_pCancelButton = new CommandButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Cancel" ), TEAMMENU_TOPLEFT_BUTTON_X, 0, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y); + m_pCancelButton->setParent( this ); + m_pCancelButton->addActionSignal( new CMenuHandler_TextWindow(HIDE_TEXTWINDOW) ); + + // Create the Spectate button + m_pSpectateButton = new SpectateButton( CHudTextMessage::BufferedLocaliseTextString( "#Menu_Spectate" ), TEAMMENU_TOPLEFT_BUTTON_X, 0, TEAMMENU_BUTTON_SIZE_X, TEAMMENU_BUTTON_SIZE_Y, true); + m_pSpectateButton->setParent( this ); + m_pSpectateButton->addActionSignal( new CMenuHandler_StringCommand( "spectate", true ) ); + m_pSpectateButton->setBoundKey( '6' ); + m_pSpectateButton->addInputSignal( new CHandler_MenuButtonOver(this, 6) ); + + Initialize(); +} + +//----------------------------------------------------------------------------- +// Purpose: Called each time a new level is started. +//----------------------------------------------------------------------------- +void CTeamMenuPanel::Initialize( void ) +{ + m_bUpdatedMapName = false; + m_iCurrentInfo = 0; + m_pScrollPanel->setScrollValue( 0, 0 ); +} + +//----------------------------------------------------------------------------- +// Purpose: Called everytime the Team Menu is displayed +//----------------------------------------------------------------------------- +void CTeamMenuPanel::Update( void ) +{ + int iYPos = TEAMMENU_TOPLEFT_BUTTON_Y; + + // Set the team buttons + for (int i = 1; i <= 4; i++) + { + if (m_pButtons[i]) + { + if ( i <= gViewPort->GetNumberOfTeams() ) + { + m_pButtons[i]->setText( gViewPort->GetTeamName(i) ); + + // bound key replacement + char sz[32]; + sprintf( sz, "%d", i ); + m_pButtons[i]->setBoundKey( sz[0] ); + + m_pButtons[i]->setVisible( true ); + m_pButtons[i]->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + + // Start with the first option up + if (!m_iCurrentInfo) + SetActiveInfo( i ); + + char szPlayerList[ (MAX_PLAYER_NAME_LENGTH + 3) * 31 ]; // name + ", " + strcpy(szPlayerList, "\n"); + // Update the Team Info + // Now count the number of teammembers of this class + int iTotal = 0; + for ( int j = 1; j < MAX_PLAYERS; j++ ) + { + if ( g_PlayerInfoList[j].name == NULL ) + continue; // empty player slot, skip + if ( g_PlayerInfoList[j].thisplayer ) + continue; // skip this player + if ( g_PlayerExtraInfo[j].teamnumber != i ) + continue; // skip over players in other teams + + iTotal++; + if (iTotal > 1) + strncat( szPlayerList, ", ", sizeof(szPlayerList) - strlen(szPlayerList) ); + strncat( szPlayerList, g_PlayerInfoList[j].name, sizeof(szPlayerList) - strlen(szPlayerList) ); + szPlayerList[ sizeof(szPlayerList) - 1 ] = '\0'; + } + + if (iTotal > 0) + { + // Set the text of the info Panel + char szText[ ((MAX_PLAYER_NAME_LENGTH + 3) * 31) + 256 ]; + if (iTotal == 1) + sprintf(szText, "%s: %d Player (%d points)", gViewPort->GetTeamName(i), iTotal, g_TeamInfo[i].frags ); + else + sprintf(szText, "%s: %d Players (%d points)", gViewPort->GetTeamName(i), iTotal, g_TeamInfo[i].frags ); + strncat( szText, szPlayerList, sizeof(szText) - strlen(szText) ); + szText[ sizeof(szText) - 1 ] = '\0'; + + m_pTeamInfoPanel[i]->setText( szText ); + } + else + { + m_pTeamInfoPanel[i]->setText( "" ); + } + } + else + { + // Hide the button (may be visible from previous maps) + m_pButtons[i]->setVisible( false ); + } + } + } + + // Move the AutoAssign button into place + m_pButtons[5]->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + + // Spectate button + if (m_pSpectateButton->IsNotValid()) + { + m_pSpectateButton->setVisible( false ); + } + else + { + m_pSpectateButton->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + m_pSpectateButton->setVisible( true ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + } + + // If the player is already in a team, make the cancel button visible + if ( g_iTeamNumber ) + { + m_pCancelButton->setPos( TEAMMENU_TOPLEFT_BUTTON_X, iYPos ); + iYPos += TEAMMENU_BUTTON_SIZE_Y + TEAMMENU_BUTTON_SPACER_Y; + m_pCancelButton->setVisible( true ); + } + else + { + m_pCancelButton->setVisible( false ); + } + + // Set the Map Title + if (!m_bUpdatedMapName) + { + const char *level = gEngfuncs.pfnGetLevelName(); + if (level && level[0]) + { + char sz[256]; + char szTitle[256]; + char *ch; + + // Update the level name + strcpy( sz, level ); + ch = strchr( sz, '/' ); + if (!ch) + ch = strchr( sz, '\\' ); + strcpy( szTitle, ch+1 ); + ch = strchr( szTitle, '.' ); + *ch = '\0'; + m_pMapTitle->setText( szTitle ); + *ch = '.'; + + // Update the map briefing + strcpy( sz, level ); + ch = strchr( sz, '.' ); + *ch = '\0'; + strcat( sz, ".txt" ); + char *pfile = (char*)gEngfuncs.COM_LoadFile( sz, 5, NULL ); + if (pfile) + { + m_pBriefing->setText( pfile ); + + // Get the total size of the Briefing text and resize the text panel + int iXSize, iYSize; + m_pBriefing->getTextImage()->getTextSize( iXSize, iYSize ); + m_pBriefing->setSize( iXSize, iYSize ); + gEngfuncs.COM_FreeFile( pfile ); + } + + m_bUpdatedMapName = true; + } + } + + m_pScrollPanel->validate(); +} + +//===================================== +// Key inputs +bool CTeamMenuPanel::SlotInput( int iSlot ) +{ + // Check for AutoAssign + if ( iSlot == 5) + { + m_pButtons[5]->fireActionSignal(); + return true; + } + + // Spectate + if ( iSlot == 6) + { + m_pSpectateButton->fireActionSignal(); + return true; + } + + // Otherwise, see if a particular team is selectable + if ( (iSlot < 1) || (iSlot > gViewPort->GetNumberOfTeams()) ) + return false; + if ( !m_pButtons[ iSlot ] ) + return false; + + // Is the button pushable? + if ( m_pButtons[ iSlot ]->isVisible() ) + { + m_pButtons[ iSlot ]->fireActionSignal(); + return true; + } + + return false; +} + +//====================================== +// Update the Team menu before opening it +void CTeamMenuPanel::Open( void ) +{ + Update(); + CMenuPanel::Open(); +} + +void CTeamMenuPanel::paintBackground() +{ + // make sure we get the map briefing up + if ( !m_bUpdatedMapName ) + Update(); + + CMenuPanel::paintBackground(); +} + +//====================================== +// Mouse is over a team button, bring up the class info +void CTeamMenuPanel::SetActiveInfo( int iInput ) +{ + // Remove all the Info panels and bring up the specified one + m_pSpectateButton->setArmed( false ); + for (int i = 1; i <= 5; i++) + { + m_pButtons[i]->setArmed( false ); + m_pTeamInfoPanel[i]->setVisible( false ); + } + + // 6 is Spectate + if (iInput == 6) + { + m_pSpectateButton->setArmed( true ); + } + else + { + m_pButtons[iInput]->setArmed( true ); + m_pTeamInfoPanel[iInput]->setVisible( true ); + } + + m_iCurrentInfo = iInput; + + m_pScrollPanel->validate(); +} diff --git a/cl_dll/view.cpp b/cl_dll/view.cpp new file mode 100644 index 00000000..02af24a3 --- /dev/null +++ b/cl_dll/view.cpp @@ -0,0 +1,1773 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// view/refresh setup functions + +#include "hud.h" +#include "cl_util.h" +#include "cvardef.h" +#include "usercmd.h" +#include "const.h" + +#include "entity_state.h" +#include "cl_entity.h" +#include "ref_params.h" +#include "in_defs.h" // PITCH YAW ROLL +#include "pm_movevars.h" +#include "pm_shared.h" +#include "pm_defs.h" +#include "event_api.h" +#include "pmtrace.h" +#include "screenfade.h" +#include "shake.h" +#include "hltv.h" + +// Spectator Mode +extern "C" +{ + float vecNewViewAngles[3]; + int iHasNewViewAngles; + float vecNewViewOrigin[3]; + int iHasNewViewOrigin; + int iIsSpectator; +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h +#endif + +extern "C" +{ + int CL_IsThirdPerson( void ); + void CL_CameraOffset( float *ofs ); + + void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ); + + void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); + int PM_GetVisEntInfo( int ent ); + int PM_GetPhysEntInfo( int ent ); + void InterpolateAngles( float * start, float * end, float * output, float frac ); + void NormalizeAngles( float * angles ); + float Distance(const float * v1, const float * v2); + float AngleBetweenVectors( const float * v1, const float * v2 ); + + float vJumpOrigin[3]; + float vJumpAngles[3]; +} + +void V_DropPunchAngle ( float frametime, float *ev_punchangle ); +void VectorAngles( const float *forward, float *angles ); + +#include "r_studioint.h" +#include "com_model.h" + +extern engine_studio_api_t IEngineStudio; + +/* +The view is allowed to move slightly from it's true position for bobbing, +but if it exceeds 8 pixels linear distance (spherical, not box), the list of +entities sent from the server may not include everything in the pvs, especially +when crossing a water boudnary. +*/ + +extern cvar_t *cl_forwardspeed; +extern cvar_t *chase_active; +extern cvar_t *scr_ofsx, *scr_ofsy, *scr_ofsz; +extern cvar_t *cl_vsmoothing; + +#define CAM_MODE_RELAX 1 +#define CAM_MODE_FOCUS 2 + +vec3_t v_origin, v_angles, v_cl_angles, v_sim_org, v_lastAngles; +float v_frametime, v_lastDistance; +float v_cameraRelaxAngle = 5.0f; +float v_cameraFocusAngle = 35.0f; +int v_cameraMode = CAM_MODE_FOCUS; +qboolean v_resetCamera = 1; + +vec3_t ev_punchangle; + +cvar_t *scr_ofsx; +cvar_t *scr_ofsy; +cvar_t *scr_ofsz; + +cvar_t *v_centermove; +cvar_t *v_centerspeed; + +cvar_t *cl_bobcycle; +cvar_t *cl_bob; +cvar_t *cl_bobup; +cvar_t *cl_waterdist; +cvar_t *cl_chasedist; + +// These cvars are not registered (so users can't cheat), so set the ->value field directly +// Register these cvars in V_Init() if needed for easy tweaking +cvar_t v_iyaw_cycle = {"v_iyaw_cycle", "2", 0, 2}; +cvar_t v_iroll_cycle = {"v_iroll_cycle", "0.5", 0, 0.5}; +cvar_t v_ipitch_cycle = {"v_ipitch_cycle", "1", 0, 1}; +cvar_t v_iyaw_level = {"v_iyaw_level", "0.3", 0, 0.3}; +cvar_t v_iroll_level = {"v_iroll_level", "0.1", 0, 0.1}; +cvar_t v_ipitch_level = {"v_ipitch_level", "0.3", 0, 0.3}; + +float v_idlescale; // used by TFC for concussion grenade effect + +//============================================================================= +/* +void V_NormalizeAngles( float *angles ) +{ + int i; + // Normalize angles + for ( i = 0; i < 3; i++ ) + { + if ( angles[i] > 180.0 ) + { + angles[i] -= 360.0; + } + else if ( angles[i] < -180.0 ) + { + angles[i] += 360.0; + } + } +} + +/* +=================== +V_InterpolateAngles + +Interpolate Euler angles. +FIXME: Use Quaternions to avoid discontinuities +Frac is 0.0 to 1.0 ( i.e., should probably be clamped, but doesn't have to be ) +=================== + +void V_InterpolateAngles( float *start, float *end, float *output, float frac ) +{ + int i; + float ang1, ang2; + float d; + + V_NormalizeAngles( start ); + V_NormalizeAngles( end ); + + for ( i = 0 ; i < 3 ; i++ ) + { + ang1 = start[i]; + ang2 = end[i]; + + d = ang2 - ang1; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + output[i] = ang1 + d * frac; + } + + V_NormalizeAngles( output ); +} */ + +// Quakeworld bob code, this fixes jitters in the mutliplayer since the clock (pparams->time) isn't quite linear +float V_CalcBob ( struct ref_params_s *pparams ) +{ + static double bobtime; + static float bob; + float cycle; + static float lasttime; + vec3_t vel; + + + if ( pparams->onground == -1 || + pparams->time == lasttime ) + { + // just use old value + return bob; + } + + lasttime = pparams->time; + + bobtime += pparams->frametime; + cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; + cycle /= cl_bobcycle->value; + + if ( cycle < cl_bobup->value ) + { + cycle = M_PI * cycle / cl_bobup->value; + } + else + { + cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value ); + } + + // bob is proportional to simulated velocity in the xy plane + // (don't count Z, or jumping messes it up) + VectorCopy( pparams->simvel, vel ); + vel[2] = 0; + + bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value; + bob = bob * 0.3 + bob * 0.7 * sin(cycle); + bob = min( bob, 4 ); + bob = max( bob, -7 ); + return bob; + +} + +/* +=============== +V_CalcRoll +Used by view and sv_user +=============== +*/ +float V_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) +{ + float sign; + float side; + float value; + vec3_t forward, right, up; + + AngleVectors ( angles, forward, right, up ); + + side = DotProduct (velocity, right); + sign = side < 0 ? -1 : 1; + side = fabs( side ); + + value = rollangle; + if (side < rollspeed) + { + side = side * value / rollspeed; + } + else + { + side = value; + } + return side * sign; +} + +typedef struct pitchdrift_s +{ + float pitchvel; + int nodrift; + float driftmove; + double laststop; +} pitchdrift_t; + +static pitchdrift_t pd; + +void V_StartPitchDrift( void ) +{ + if ( pd.laststop == gEngfuncs.GetClientTime() ) + { + return; // something else is keeping it from drifting + } + + if ( pd.nodrift || !pd.pitchvel ) + { + pd.pitchvel = v_centerspeed->value; + pd.nodrift = 0; + pd.driftmove = 0; + } +} + +void V_StopPitchDrift ( void ) +{ + pd.laststop = gEngfuncs.GetClientTime(); + pd.nodrift = 1; + pd.pitchvel = 0; +} + +/* +=============== +V_DriftPitch + +Moves the client pitch angle towards idealpitch sent by the server. + +If the user is adjusting pitch manually, either with lookup/lookdown, +mlook and mouse, or klook and keyboard, pitch drifting is constantly stopped. +=============== +*/ +void V_DriftPitch ( struct ref_params_s *pparams ) +{ + float delta, move; + + if ( gEngfuncs.IsNoClipping() || !pparams->onground || pparams->demoplayback || pparams->spectator ) + { + pd.driftmove = 0; + pd.pitchvel = 0; + return; + } + + // don't count small mouse motion + if (pd.nodrift) + { + if ( fabs( pparams->cmd->forwardmove ) < cl_forwardspeed->value ) + pd.driftmove = 0; + else + pd.driftmove += pparams->frametime; + + if ( pd.driftmove > v_centermove->value) + { + V_StartPitchDrift (); + } + return; + } + + delta = pparams->idealpitch - pparams->cl_viewangles[PITCH]; + + if (!delta) + { + pd.pitchvel = 0; + return; + } + + move = pparams->frametime * pd.pitchvel; + pd.pitchvel += pparams->frametime * v_centerspeed->value; + + if (delta > 0) + { + if (move > delta) + { + pd.pitchvel = 0; + move = delta; + } + pparams->cl_viewangles[PITCH] += move; + } + else if (delta < 0) + { + if (move > -delta) + { + pd.pitchvel = 0; + move = -delta; + } + pparams->cl_viewangles[PITCH] -= move; + } +} + +/* +============================================================================== + VIEW RENDERING +============================================================================== +*/ + +/* +================== +V_CalcGunAngle +================== +*/ +void V_CalcGunAngle ( struct ref_params_s *pparams ) +{ + cl_entity_t *viewent; + + viewent = gEngfuncs.GetViewModel(); + if ( !viewent ) + return; + + viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; + viewent->angles[PITCH] = -pparams->viewangles[PITCH] + pparams->crosshairangle[PITCH] * 0.25; + viewent->angles[ROLL] -= v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + + // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. + viewent->angles[PITCH] -= v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * (v_ipitch_level.value * 0.5); + viewent->angles[YAW] -= v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; + + VectorCopy( viewent->angles, viewent->curstate.angles ); + VectorCopy( viewent->angles, viewent->latched.prevangles ); +} + +/* +============== +V_AddIdle + +Idle swaying +============== +*/ +void V_AddIdle ( struct ref_params_s *pparams ) +{ + pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle.value) * v_iroll_level.value; + pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle.value) * v_ipitch_level.value; + pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle.value) * v_iyaw_level.value; +} + + +/* +============== +V_CalcViewRoll + +Roll is induced by movement and damage +============== +*/ +void V_CalcViewRoll ( struct ref_params_s *pparams ) +{ + float side; + cl_entity_t *viewentity; + + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( !viewentity ) + return; + + side = V_CalcRoll ( viewentity->angles, pparams->simvel, pparams->movevars->rollangle, pparams->movevars->rollspeed ); + + pparams->viewangles[ROLL] += side; + + if ( pparams->health <= 0 && ( pparams->viewheight[2] != 0 ) ) + { + // only roll the view if the player is dead and the viewheight[2] is nonzero + // this is so deadcam in multiplayer will work. + pparams->viewangles[ROLL] = 80; // dead view angle + return; + } +} + + +/* +================== +V_CalcIntermissionRefdef + +================== +*/ +void V_CalcIntermissionRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + float old; + + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + VectorCopy ( pparams->simorg, pparams->vieworg ); + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + view->model = NULL; + + // allways idle in intermission + old = v_idlescale; + v_idlescale = 1; + + V_AddIdle ( pparams ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + // in HLTV we must go to 'intermission' position by ourself + VectorCopy( gHUD.m_Spectator.m_cameraOrigin, pparams->vieworg ); + VectorCopy( gHUD.m_Spectator.m_cameraAngles, pparams->viewangles ); + } + + v_idlescale = old; + + v_cl_angles = pparams->cl_viewangles; + v_origin = pparams->vieworg; + v_angles = pparams->viewangles; +} + +#define ORIGIN_BACKUP 64 +#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 ) + +typedef struct +{ + float Origins[ ORIGIN_BACKUP ][3]; + float OriginTime[ ORIGIN_BACKUP ]; + + float Angles[ ORIGIN_BACKUP ][3]; + float AngleTime[ ORIGIN_BACKUP ]; + + int CurrentOrigin; + int CurrentAngle; +} viewinterp_t; + +/* +================== +V_CalcRefdef + +================== +*/ +void V_CalcNormalRefdef ( struct ref_params_s *pparams ) +{ + cl_entity_t *ent, *view; + int i; + vec3_t angles; + float bob, waterOffset; + static viewinterp_t ViewInterp; + + static float oldz = 0; + static float lasttime; + + vec3_t camAngles, camForward, camRight, camUp; + cl_entity_t *pwater; + + V_DriftPitch ( pparams ); + + if ( gEngfuncs.IsSpectateOnly() ) + { + ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + } + else + { + // ent is the player model ( visible when out of body ) + ent = gEngfuncs.GetLocalPlayer(); + } + + // view is the weapon model (only visible from inside body ) + view = gEngfuncs.GetViewModel(); + + // transform the view offset by the model's matrix to get the offset from + // model origin for the view + bob = V_CalcBob ( pparams ); + + // refresh position + VectorCopy ( pparams->simorg, pparams->vieworg ); + pparams->vieworg[2] += ( bob ); + VectorAdd( pparams->vieworg, pparams->viewheight, pparams->vieworg ); + + VectorCopy ( pparams->cl_viewangles, pparams->viewangles ); + + gEngfuncs.V_CalcShake(); + gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); + + // never let view origin sit exactly on a node line, because a water plane can + // dissapear when viewed with the eye exactly on it. + // FIXME, we send origin at 1/128 now, change this? + // the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis + + pparams->vieworg[0] += 1.0/32; + pparams->vieworg[1] += 1.0/32; + pparams->vieworg[2] += 1.0/32; + + // Check for problems around water, move the viewer artificially if necessary + // -- this prevents drawing errors in GL due to waves + + waterOffset = 0; + if ( pparams->waterlevel >= 2 ) + { + int i, contents, waterDist, waterEntity; + vec3_t point; + waterDist = cl_waterdist->value; + + if ( pparams->hardware ) + { + waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); + if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) + { + pwater = gEngfuncs.GetEntityByIndex( waterEntity ); + if ( pwater && ( pwater->model != NULL ) ) + { + waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height + } + } + } + else + { + waterEntity = 0; // Don't need this in software + } + + VectorCopy( pparams->vieworg, point ); + + // Eyes are above water, make sure we're above the waves + if ( pparams->waterlevel == 2 ) + { + point[2] -= waterDist; + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents > CONTENTS_WATER ) + break; + point[2] += 1; + } + waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; + } + else + { + // eyes are under water. Make sure we're far enough under + point[2] += waterDist; + + for ( i = 0; i < waterDist; i++ ) + { + contents = gEngfuncs.PM_PointContents( point, NULL ); + if ( contents <= CONTENTS_WATER ) + break; + point[2] -= 1; + } + waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; + } + } + + pparams->vieworg[2] += waterOffset; + + V_CalcViewRoll ( pparams ); + + V_AddIdle ( pparams ); + + // offsets + VectorCopy( pparams->cl_viewangles, angles ); + + AngleVectors ( angles, pparams->forward, pparams->right, pparams->up ); + + // don't allow cheats in multiplayer + if ( pparams->maxclients <= 1 ) + { + for ( i=0 ; i<3 ; i++ ) + { + pparams->vieworg[i] += scr_ofsx->value*pparams->forward[i] + scr_ofsy->value*pparams->right[i] + scr_ofsz->value*pparams->up[i]; + } + } + + // Treating cam_ofs[2] as the distance + if( CL_IsThirdPerson() ) + { + vec3_t ofs; + + ofs[0] = ofs[1] = ofs[2] = 0.0; + + CL_CameraOffset( (float *)&ofs ); + + VectorCopy( ofs, camAngles ); + camAngles[ ROLL ] = 0; + + AngleVectors( camAngles, camForward, camRight, camUp ); + + for ( i = 0; i < 3; i++ ) + { + pparams->vieworg[ i ] += -ofs[2] * camForward[ i ]; + } + } + + // Give gun our viewangles + VectorCopy ( pparams->cl_viewangles, view->angles ); + + // set up gun position + V_CalcGunAngle ( pparams ); + + // Use predicted origin as view origin. + VectorCopy ( pparams->simorg, view->origin ); + view->origin[2] += ( waterOffset ); + VectorAdd( view->origin, pparams->viewheight, view->origin ); + + // Let the viewmodel shake at about 10% of the amplitude + gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); + + for ( i = 0; i < 3; i++ ) + { + view->origin[ i ] += bob * 0.4 * pparams->forward[ i ]; + } + view->origin[2] += bob; + + // throw in a little tilt. + view->angles[YAW] -= bob * 0.5; + view->angles[ROLL] -= bob * 1; + view->angles[PITCH] -= bob * 0.3; + + // pushing the view origin down off of the same X/Z plane as the ent's origin will give the + // gun a very nice 'shifting' effect when the player looks up/down. If there is a problem + // with view model distortion, this may be a cause. (SJB). + view->origin[2] -= 1; + + // fudge position around to keep amount of weapon visible + // roughly equal with different FOV + if (pparams->viewsize == 110) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 100) + { + view->origin[2] += 2; + } + else if (pparams->viewsize == 90) + { + view->origin[2] += 1; + } + else if (pparams->viewsize == 80) + { + view->origin[2] += 0.5; + } + + // Add in the punchangle, if any + VectorAdd ( pparams->viewangles, pparams->punchangle, pparams->viewangles ); + + // Include client side punch, too + VectorAdd ( pparams->viewangles, (float *)&ev_punchangle, pparams->viewangles); + + V_DropPunchAngle ( pparams->frametime, (float *)&ev_punchangle ); + + // smooth out stair step ups +#if 1 + if ( !pparams->smoothing && pparams->onground && pparams->simorg[2] - oldz > 0) + { + float steptime; + + steptime = pparams->time - lasttime; + if (steptime < 0) + //FIXME I_Error ("steptime < 0"); + steptime = 0; + + oldz += steptime * 150; + if (oldz > pparams->simorg[2]) + oldz = pparams->simorg[2]; + if (pparams->simorg[2] - oldz > 18) + oldz = pparams->simorg[2]- 18; + pparams->vieworg[2] += oldz - pparams->simorg[2]; + view->origin[2] += oldz - pparams->simorg[2]; + } + else + { + oldz = pparams->simorg[2]; + } +#endif + + { + static float lastorg[3]; + vec3_t delta; + + VectorSubtract( pparams->simorg, lastorg, delta ); + + if ( Length( delta ) != 0.0 ) + { + VectorCopy( pparams->simorg, ViewInterp.Origins[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] ); + ViewInterp.OriginTime[ ViewInterp.CurrentOrigin & ORIGIN_MASK ] = pparams->time; + ViewInterp.CurrentOrigin++; + + VectorCopy( pparams->simorg, lastorg ); + } + } + + // Smooth out whole view in multiplayer when on trains, lifts + if ( cl_vsmoothing && cl_vsmoothing->value && + ( pparams->smoothing && ( pparams->maxclients > 1 ) ) ) + { + int foundidx; + int i; + float t; + + if ( cl_vsmoothing->value < 0.0 ) + { + gEngfuncs.Cvar_SetValue( "cl_vsmoothing", 0.0 ); + } + + t = pparams->time - cl_vsmoothing->value; + + for ( i = 1; i < ORIGIN_MASK; i++ ) + { + foundidx = ViewInterp.CurrentOrigin - 1 - i; + if ( ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] <= t ) + break; + } + + if ( i < ORIGIN_MASK && ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ] != 0.0 ) + { + // Interpolate + vec3_t delta; + double frac; + double dt; + vec3_t neworg; + + dt = ViewInterp.OriginTime[ (foundidx + 1) & ORIGIN_MASK ] - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK ]; + if ( dt > 0.0 ) + { + frac = ( t - ViewInterp.OriginTime[ foundidx & ORIGIN_MASK] ) / dt; + frac = min( 1.0, frac ); + VectorSubtract( ViewInterp.Origins[ ( foundidx + 1 ) & ORIGIN_MASK ], ViewInterp.Origins[ foundidx & ORIGIN_MASK ], delta ); + VectorMA( ViewInterp.Origins[ foundidx & ORIGIN_MASK ], frac, delta, neworg ); + + // Dont interpolate large changes + if ( Length( delta ) < 64 ) + { + VectorSubtract( neworg, pparams->simorg, delta ); + + VectorAdd( pparams->simorg, delta, pparams->simorg ); + VectorAdd( pparams->vieworg, delta, pparams->vieworg ); + VectorAdd( view->origin, delta, view->origin ); + + } + } + } + } + + // Store off v_angles before munging for third person + v_angles = pparams->viewangles; + v_lastAngles = pparams->viewangles; +// v_cl_angles = pparams->cl_viewangles; // keep old user mouse angles ! + if ( CL_IsThirdPerson() ) + { + VectorCopy( camAngles, pparams->viewangles); + float pitch = camAngles[ 0 ]; + + // Normalize angles + if ( pitch > 180 ) + pitch -= 360.0; + else if ( pitch < -180 ) + pitch += 360; + + // Player pitch is inverted + pitch /= -3.0; + + // Slam local player's pitch value + ent->angles[ 0 ] = pitch; + ent->curstate.angles[ 0 ] = pitch; + ent->prevstate.angles[ 0 ] = pitch; + ent->latched.prevangles[ 0 ] = pitch; + } + + // override all previous settings if the viewent isn't the client + if ( pparams->viewentity > pparams->maxclients ) + { + cl_entity_t *viewentity; + viewentity = gEngfuncs.GetEntityByIndex( pparams->viewentity ); + if ( viewentity ) + { + VectorCopy( viewentity->origin, pparams->vieworg ); + VectorCopy( viewentity->angles, pparams->viewangles ); + + // Store off overridden viewangles + v_angles = pparams->viewangles; + } + } + + lasttime = pparams->time; + + v_origin = pparams->vieworg; +} + +void V_SmoothInterpolateAngles( float * startAngle, float * endAngle, float * finalAngle, float degreesPerSec ) +{ + float absd,frac,d,threshhold; + + NormalizeAngles( startAngle ); + NormalizeAngles( endAngle ); + + for ( int i = 0 ; i < 3 ; i++ ) + { + d = endAngle[i] - startAngle[i]; + + if ( d > 180.0f ) + { + d -= 360.0f; + } + else if ( d < -180.0f ) + { + d += 360.0f; + } + + absd = fabs(d); + + if ( absd > 0.01f ) + { + frac = degreesPerSec * v_frametime; + + threshhold= degreesPerSec / 4; + + if ( absd < threshhold ) + { + float h = absd / threshhold; + h *= h; + frac*= h; // slow down last degrees + } + + if ( frac > absd ) + { + finalAngle[i] = endAngle[i]; + } + else + { + if ( d>0) + finalAngle[i] = startAngle[i] + frac; + else + finalAngle[i] = startAngle[i] - frac; + } + } + else + { + finalAngle[i] = endAngle[i]; + } + + } + + NormalizeAngles( finalAngle ); +} + +// Get the origin of the Observer based around the target's position and angles +void V_GetChaseOrigin( float * angles, float * origin, float distance, float * returnvec ) +{ + vec3_t vecEnd; + vec3_t forward; + vec3_t vecStart; + pmtrace_t * trace; + int maxLoops = 8; + + int ignoreent = -1; // first, ignore no entity + + cl_entity_t * ent = NULL; + + // Trace back from the target using the player's view angles + AngleVectors(angles, forward, NULL, NULL); + + VectorScale(forward,-1,forward); + + VectorCopy( origin, vecStart ); + + VectorMA(vecStart, distance , forward, vecEnd); + + while ( maxLoops > 0) + { + trace = gEngfuncs.PM_TraceLine( vecStart, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignoreent ); + + // WARNING! trace->ent is is the number in physent list not the normal entity number + + if ( trace->ent <= 0) + break; // we hit the world or nothing, stop trace + + ent = gEngfuncs.GetEntityByIndex( PM_GetPhysEntInfo( trace->ent ) ); + + if ( ent == NULL ) + break; + + // hit non-player solid BSP , stop here + if ( ent->curstate.solid == SOLID_BSP && !ent->player ) + break; + + // if close enought to end pos, stop, otherwise continue trace + if( Distance(trace->endpos, vecEnd ) < 1.0f ) + { + break; + } + else + { + ignoreent = trace->ent; // ignore last hit entity + VectorCopy( trace->endpos, vecStart); + } + + maxLoops--; + } + +/* if ( ent ) + { + gEngfuncs.Con_Printf("Trace loops %i , entity %i, model %s, solid %i\n",(8-maxLoops),ent->curstate.number, ent->model->name , ent->curstate.solid ); + } */ + + VectorMA( trace->endpos, 4, trace->plane.normal, returnvec ); + + v_lastDistance = Distance(trace->endpos, origin); // real distance without offset +} + +/*void V_GetDeathCam(cl_entity_t * ent1, cl_entity_t * ent2, float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; + + float distance = 168.0f; + + v_lastDistance+= v_frametime * 96.0f; // move unit per seconds back + + if ( v_resetCamera ) + v_lastDistance = 64.0f; + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + + // get new angle towards second target + if ( ent2 ) + { + VectorSubtract( ent2->origin, ent1->origin, newAngle ); + VectorAngles( newAngle, newAngle ); + newAngle[0] = -newAngle[0]; + } + else + { + // if no second target is given, look down to dead player + newAngle[0] = 90.0f; + newAngle[1] = 0.0f; + newAngle[2] = 0; + } + + // and smooth view + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); + + V_GetChaseOrigin( angle, newOrigin, distance, origin ); + + VectorCopy(angle, v_lastAngles); +}*/ + +void V_GetSingleTargetCam(cl_entity_t * ent1, float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + // see is target is a dead player + qboolean deadPlayer = ent1->player && (ent1->curstate.solid == SOLID_NOT); + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + else if ( deadPlayer ) + distance*=1.5f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + { + if ( deadPlayer ) + newOrigin[2]+= 2; //laying on ground + else + newOrigin[2]+= 17; // head level of living player + + } + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + // we have no second target, choose view direction based on + // show front of primary target + VectorCopy(ent1->angles, newAngle); + + // show dead players from front, normal players back + if ( flags & DRC_FLAG_FACEPLAYER ) + newAngle[1]+= 180.0f; + + + newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + + // if final scene (bomb), show from real high pos + if ( flags & DRC_FLAG_FINAL ) + newAngle[0] = 22.5f; + + // choose side of object/player + if ( flags & DRC_FLAG_SIDE ) + newAngle[1]+=22.5f; + else + newAngle[1]-=22.5f; + + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 120.0f ); + + // HACK, if player is dead don't clip against his dead body, can't check this + V_GetChaseOrigin( angle, newOrigin, distance, origin ); +} + +float MaxAngleBetweenAngles( float * a1, float * a2 ) +{ + float d, maxd = 0.0f; + + NormalizeAngles( a1 ); + NormalizeAngles( a2 ); + + for ( int i = 0 ; i < 3 ; i++ ) + { + d = a2[i] - a1[i]; + if ( d > 180 ) + { + d -= 360; + } + else if ( d < -180 ) + { + d += 360; + } + + d = fabs(d); + + if ( d > maxd ) + maxd=d; + } + + return maxd; +} + +void V_GetDoubleTargetsCam(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) +{ + float newAngle[3]; float newOrigin[3]; float tempVec[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + // get new angle towards second target + VectorSubtract( ent2->origin, ent1->origin, newAngle ); + + VectorAngles( newAngle, newAngle ); + newAngle[0] = -newAngle[0]; + + // set angle diffrent in Dramtaic scenes + newAngle[0]+= 12.5f * dfactor; // lower angle if dramatic + + if ( flags & DRC_FLAG_SIDE ) + newAngle[1]+=22.5f; + else + newAngle[1]-=22.5f; + + float d = MaxAngleBetweenAngles( v_lastAngles, newAngle ); + + if ( ( d < v_cameraFocusAngle) && ( v_cameraMode == CAM_MODE_RELAX ) ) + { + // difference is to small and we are in relax camera mode, keep viewangles + VectorCopy(v_lastAngles, newAngle ); + } + else if ( (d < v_cameraRelaxAngle) && (v_cameraMode == CAM_MODE_FOCUS) ) + { + // we catched up with our target, relax again + v_cameraMode = CAM_MODE_RELAX; + } + else + { + // target move too far away, focus camera again + v_cameraMode = CAM_MODE_FOCUS; + } + + // and smooth view, if not a scene cut + if ( v_resetCamera || (v_cameraMode == CAM_MODE_RELAX) ) + { + VectorCopy( newAngle, angle ); + } + else + { + V_SmoothInterpolateAngles( v_lastAngles, newAngle, angle, 180.0f ); + } + + V_GetChaseOrigin( newAngle, newOrigin, distance, origin ); + + // move position up, if very close at target + if ( v_lastDistance < 64.0f ) + origin[2]+= 16.0f*( 1.0f - (v_lastDistance / 64.0f ) ); + + // calculate angle to second target + VectorSubtract( ent2->origin, origin, tempVec ); + VectorAngles( tempVec, tempVec ); + tempVec[0] = -tempVec[0]; + + /* take middle between two viewangles + InterpolateAngles( newAngle, tempVec, newAngle, 0.5f); */ + + + +} + +void V_GetDirectedChasePosition(cl_entity_t * ent1, cl_entity_t * ent2,float * angle, float * origin) +{ + + if ( v_resetCamera ) + { + v_lastDistance = 4096.0f; + // v_cameraMode = CAM_MODE_FOCUS; + } + + if ( ( ent2 == (cl_entity_t*)0xFFFFFFFF ) || ( ent1->player && (ent1->curstate.solid == SOLID_NOT) ) ) + { + // we have no second target or player just died + V_GetSingleTargetCam(ent1, angle, origin); + } + else if ( ent2 ) + { + // keep both target in view + V_GetDoubleTargetsCam( ent1, ent2, angle, origin ); + } + else + { + // second target disappeard somehow (dead) + + // keep last good viewangle + float newOrigin[3]; + + int flags = gHUD.m_Spectator.m_iObserverFlags; + + float dfactor = ( flags & DRC_FLAG_DRAMATIC )? -1.0f : 1.0f; + + float distance = 112.0f + ( 16.0f * dfactor ); // get close if dramatic; + + // go away in final scenes or if player just died + if ( flags & DRC_FLAG_FINAL ) + distance*=2.0f; + + // let v_lastDistance float smoothly away + v_lastDistance+= v_frametime * 32.0f; // move unit per seconds back + + if ( distance > v_lastDistance ) + distance = v_lastDistance; + + VectorCopy(ent1->origin, newOrigin); + + if ( ent1->player ) + newOrigin[2]+= 17; // head level of living player + else + newOrigin[2]+= 8; // object, tricky, must be above bomb in CS + + V_GetChaseOrigin( angle, newOrigin, distance, origin ); + } + + VectorCopy(angle, v_lastAngles); +} + +void V_GetChasePos(int target, float * cl_angles, float * origin, float * angles) +{ + cl_entity_t * ent = NULL; + + if ( target ) + { + ent = gEngfuncs.GetEntityByIndex( target ); + }; + + if (!ent) + { + // just copy a save in-map position + VectorCopy ( vJumpAngles, angles ); + VectorCopy ( vJumpOrigin, origin ); + return; + } + + + + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + if ( g_iUser3 ) + V_GetDirectedChasePosition( ent, gEngfuncs.GetEntityByIndex( g_iUser3 ), + angles, origin ); + else + V_GetDirectedChasePosition( ent, ( cl_entity_t*)0xFFFFFFFF, + angles, origin ); + } + else + { + if ( cl_angles == NULL ) // no mouse angles given, use entity angles ( locked mode ) + { + VectorCopy ( ent->angles, angles); + angles[0]*=-1; + } + else + VectorCopy ( cl_angles, angles); + + + VectorCopy ( ent->origin, origin); + + origin[2]+= 28; // DEFAULT_VIEWHEIGHT - some offset + + V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); + } + + v_resetCamera = false; +} + +void V_ResetChaseCam() +{ + v_resetCamera = true; +} + + +void V_GetInEyePos(int target, float * origin, float * angles ) +{ + if ( !target) + { + // just copy a save in-map position + VectorCopy ( vJumpAngles, angles ); + VectorCopy ( vJumpOrigin, origin ); + return; + }; + + + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + + if ( !ent ) + return; + + VectorCopy ( ent->origin, origin ); + VectorCopy ( ent->angles, angles ); + + angles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + + if ( ent->curstate.solid == SOLID_NOT ) + { + angles[ROLL] = 80; // dead view angle + origin[2]+= -8 ; // PM_DEAD_VIEWHEIGHT + } + else if (ent->curstate.usehull == 1 ) + origin[2]+= 12; // VEC_DUCK_VIEW; + else + // exacty eye position can't be caluculated since it depends on + // client values like cl_bobcycle, this offset matches the default values + origin[2]+= 28; // DEFAULT_VIEWHEIGHT +} + +void V_GetMapFreePosition( float * cl_angles, float * origin, float * angles ) +{ + vec3_t forward; + vec3_t zScaledTarget; + + VectorCopy(cl_angles, angles); + + // modify angles since we don't wanna see map's bottom + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + + zScaledTarget[0] = gHUD.m_Spectator.m_mapOrigin[0]; + zScaledTarget[1] = gHUD.m_Spectator.m_mapOrigin[1]; + zScaledTarget[2] = gHUD.m_Spectator.m_mapOrigin[2] * (( 90.0f - angles[0] ) / 90.0f ); + + + AngleVectors(angles, forward, NULL, NULL); + + VectorNormalize(forward); + + VectorMA(zScaledTarget, -( 4096.0f / gHUD.m_Spectator.m_mapZoom ), forward , origin); +} + +void V_GetMapChasePosition(int target, float * cl_angles, float * origin, float * angles) +{ + vec3_t forward; + + if ( target ) + { + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( target ); + + if ( gHUD.m_Spectator.m_autoDirector->value ) + { + // this is done to get the angles made by director mode + V_GetChasePos(target, cl_angles, origin, angles); + VectorCopy(ent->origin, origin); + + // keep fix chase angle horizontal + angles[0] = 45.0f; + } + else + { + VectorCopy(cl_angles, angles); + VectorCopy(ent->origin, origin); + + // modify angles since we don't wanna see map's bottom + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + } + } + else + { + // keep out roaming position, but modify angles + VectorCopy(cl_angles, angles); + angles[0] = 51.25f + 38.75f*(angles[0]/90.0f); + } + + origin[2] *= (( 90.0f - angles[0] ) / 90.0f ); + angles[2] = 0.0f; // don't roll angle (if chased player is dead) + + AngleVectors(angles, forward, NULL, NULL); + + VectorNormalize(forward); + + VectorMA(origin, -1536, forward, origin); +} + +int V_FindViewModelByWeaponModel(int weaponindex) +{ + + static char * modelmap[][2] = { + { "models/p_crossbow.mdl", "models/v_crossbow.mdl" }, + { "models/p_crowbar.mdl", "models/v_crowbar.mdl" }, + { "models/p_egon.mdl", "models/v_egon.mdl" }, + { "models/p_gauss.mdl", "models/v_gauss.mdl" }, + { "models/p_9mmhandgun.mdl", "models/v_9mmhandgun.mdl" }, + { "models/p_grenade.mdl", "models/v_grenade.mdl" }, + { "models/p_hgun.mdl", "models/v_hgun.mdl" }, + { "models/p_9mmAR.mdl", "models/v_9mmAR.mdl" }, + { "models/p_357.mdl", "models/v_357.mdl" }, + { "models/p_rpg.mdl", "models/v_rpg.mdl" }, + { "models/p_shotgun.mdl", "models/v_shotgun.mdl" }, + { "models/p_squeak.mdl", "models/v_squeak.mdl" }, + { "models/p_tripmine.mdl", "models/v_tripmine.mdl" }, + { "models/p_satchel_radio.mdl", "models/v_satchel_radio.mdl"}, + { "models/p_satchel.mdl", "models/v_satchel.mdl" }, + { NULL, NULL } }; + + struct model_s * weaponModel = IEngineStudio.GetModelByIndex( weaponindex ); + + if ( weaponModel ) + { + int len = strlen( weaponModel->name ); + int i = 0; + + while ( modelmap[i] != NULL ) + { + if ( !strnicmp( weaponModel->name, modelmap[i][0], len ) ) + { + return gEngfuncs.pEventAPI->EV_FindModelIndex( modelmap[i][1] ); + } + i++; + } + + return 0; + } + else + return 0; + +} + + +/* +================== +V_CalcSpectatorRefdef + +================== +*/ +void V_CalcSpectatorRefdef ( struct ref_params_s * pparams ) +{ + static vec3_t velocity ( 0.0f, 0.0f, 0.0f); + + static int lastWeaponModelIndex = 0; + static int lastViewModelIndex = 0; + + cl_entity_t * ent = gEngfuncs.GetEntityByIndex( g_iUser2 ); + + pparams->onlyClientDraw = false; + + // refresh position + VectorCopy ( pparams->simorg, v_sim_org ); + + // get old values + VectorCopy ( pparams->cl_viewangles, v_cl_angles ); + VectorCopy ( pparams->viewangles, v_angles ); + VectorCopy ( pparams->vieworg, v_origin ); + + if ( ( g_iUser1 == OBS_IN_EYE || gHUD.m_Spectator.m_pip->value == INSET_IN_EYE ) && ent ) + { + // calculate player velocity + float timeDiff = ent->curstate.msg_time - ent->prevstate.msg_time; + + if ( timeDiff > 0 ) + { + vec3_t distance; + VectorSubtract(ent->prevstate.origin, ent->curstate.origin, distance); + VectorScale(distance, 1/timeDiff, distance ); + + velocity[0] = velocity[0]*0.9f + distance[0]*0.1f; + velocity[1] = velocity[1]*0.9f + distance[1]*0.1f; + velocity[2] = velocity[2]*0.9f + distance[2]*0.1f; + + VectorCopy(velocity, pparams->simvel); + } + + // predict missing client data and set weapon model ( in HLTV mode or inset in eye mode ) + if ( gEngfuncs.IsSpectateOnly() ) + { + V_GetInEyePos( g_iUser2, pparams->simorg, pparams->cl_viewangles ); + + pparams->health = 1; + + cl_entity_t * gunModel = gEngfuncs.GetViewModel(); + + if ( lastWeaponModelIndex != ent->curstate.weaponmodel ) + { + // weapon model changed + + lastWeaponModelIndex = ent->curstate.weaponmodel; + lastViewModelIndex = V_FindViewModelByWeaponModel( lastWeaponModelIndex ); + if ( lastViewModelIndex ) + { + gEngfuncs.pfnWeaponAnim(0,0); // reset weapon animation + } + else + { + // model not found + gunModel->model = NULL; // disable weapon model + lastWeaponModelIndex = lastViewModelIndex = 0; + } + } + + if ( lastViewModelIndex ) + { + gunModel->model = IEngineStudio.GetModelByIndex( lastViewModelIndex ); + gunModel->curstate.modelindex = lastViewModelIndex; + gunModel->curstate.frame = 0; + gunModel->curstate.colormap = 0; + gunModel->index = g_iUser2; + } + else + { + gunModel->model = NULL; // disable weaopn model + } + } + else + { + // only get viewangles from entity + VectorCopy ( ent->angles, pparams->cl_viewangles ); + pparams->cl_viewangles[PITCH]*=-3.0f; // see CL_ProcessEntityUpdate() + } + } + + v_frametime = pparams->frametime; + + if ( pparams->nextView == 0 ) + { + // first renderer cycle, full screen + + switch ( g_iUser1 ) + { + case OBS_CHASE_LOCKED: V_GetChasePos( g_iUser2, NULL, v_origin, v_angles ); + break; + + case OBS_CHASE_FREE: V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case OBS_ROAMING : VectorCopy (v_cl_angles, v_angles); + VectorCopy (v_sim_org, v_origin); + break; + + case OBS_IN_EYE : V_CalcNormalRefdef ( pparams ); + break; + + case OBS_MAP_FREE : pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + + case OBS_MAP_CHASE : pparams->onlyClientDraw = true; + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + } + + if ( gHUD.m_Spectator.m_pip->value ) + pparams->nextView = 1; // force a second renderer view + + gHUD.m_Spectator.m_iDrawCycle = 0; + + } + else + { + // second renderer cycle, inset window + + // set inset parameters + pparams->viewport[0] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowX); // change viewport to inset window + pparams->viewport[1] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowY); + pparams->viewport[2] = XRES(gHUD.m_Spectator.m_OverviewData.insetWindowWidth); + pparams->viewport[3] = YRES(gHUD.m_Spectator.m_OverviewData.insetWindowHeight); + pparams->nextView = 0; // on further view + + // override some settings in certain modes + switch ( (int)gHUD.m_Spectator.m_pip->value ) + { + case INSET_CHASE_FREE : V_GetChasePos( g_iUser2, v_cl_angles, v_origin, v_angles ); + break; + + case INSET_IN_EYE : V_CalcNormalRefdef ( pparams ); + break; + + case INSET_MAP_FREE : pparams->onlyClientDraw = true; + V_GetMapFreePosition( v_cl_angles, v_origin, v_angles ); + break; + + case INSET_MAP_CHASE : pparams->onlyClientDraw = true; + + if ( g_iUser1 == OBS_ROAMING ) + V_GetMapChasePosition( 0, v_cl_angles, v_origin, v_angles ); + else + V_GetMapChasePosition( g_iUser2, v_cl_angles, v_origin, v_angles ); + + break; + } + + gHUD.m_Spectator.m_iDrawCycle = 1; + } + + // write back new values into pparams + VectorCopy ( v_cl_angles, pparams->cl_viewangles ); + VectorCopy ( v_angles, pparams->viewangles ) + VectorCopy ( v_origin, pparams->vieworg ); + +} + + + +void DLLEXPORT V_CalcRefdef( struct ref_params_s *pparams ) +{ + // intermission / finale rendering + if ( pparams->intermission ) + { + V_CalcIntermissionRefdef ( pparams ); + } + else if ( pparams->spectator || g_iUser1 ) // g_iUser true if in spectator mode + { + V_CalcSpectatorRefdef ( pparams ); + } + else if ( !pparams->paused ) + { + V_CalcNormalRefdef ( pparams ); + } + +/* +// Example of how to overlay the whole screen with red at 50 % alpha +#define SF_TEST +#if defined SF_TEST + { + screenfade_t sf; + gEngfuncs.pfnGetScreenFade( &sf ); + + sf.fader = 255; + sf.fadeg = 0; + sf.fadeb = 0; + sf.fadealpha = 128; + sf.fadeFlags = FFADE_STAYOUT | FFADE_OUT; + + gEngfuncs.pfnSetScreenFade( &sf ); + } +#endif +*/ +} + +/* +============= +V_DropPunchAngle + +============= +*/ +void V_DropPunchAngle ( float frametime, float *ev_punchangle ) +{ + float len; + + len = VectorNormalize ( ev_punchangle ); + len -= (10.0 + len * 0.5) * frametime; + len = max( len, 0.0 ); + VectorScale ( ev_punchangle, len, ev_punchangle ); +} + +/* +============= +V_PunchAxis + +Client side punch effect +============= +*/ +void V_PunchAxis( int axis, float punch ) +{ + ev_punchangle[ axis ] = punch; +} + +/* +============= +V_Init +============= +*/ +void V_Init (void) +{ + gEngfuncs.pfnAddCommand ("centerview", V_StartPitchDrift ); + + scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx","0", 0 ); + scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy","0", 0 ); + scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz","0", 0 ); + + v_centermove = gEngfuncs.pfnRegisterVariable( "v_centermove", "0.15", 0 ); + v_centerspeed = gEngfuncs.pfnRegisterVariable( "v_centerspeed","500", 0 ); + + cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 );// best default for my experimental gun wag (sjb) + cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob","0.01", 0 );// best default for my experimental gun wag (sjb) + cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup","0.5", 0 ); + cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist","4", 0 ); + cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist","112", 0 ); +} + + +//#define TRACE_TEST +#if defined( TRACE_TEST ) + +extern float in_fov; +/* +==================== +CalcFov +==================== +*/ +float CalcFov (float fov_x, float width, float height) +{ + float a; + float x; + + if (fov_x < 1 || fov_x > 179) + fov_x = 90; // error, set to 90 + + x = width/tan(fov_x/360*M_PI); + + a = atan (height/x); + + a = a*360/M_PI; + + return a; +} + +int hitent = -1; + +void V_Move( int mx, int my ) +{ + float fov; + float fx, fy; + float dx, dy; + float c_x, c_y; + float dX, dY; + vec3_t forward, up, right; + vec3_t newangles; + + vec3_t farpoint; + pmtrace_t tr; + + fov = CalcFov( in_fov, (float)ScreenWidth, (float)ScreenHeight ); + + c_x = (float)ScreenWidth / 2.0; + c_y = (float)ScreenHeight / 2.0; + + dx = (float)mx - c_x; + dy = (float)my - c_y; + + // Proportion we moved in each direction + fx = dx / c_x; + fy = dy / c_y; + + dX = fx * in_fov / 2.0 ; + dY = fy * fov / 2.0; + + newangles = v_angles; + + newangles[ YAW ] -= dX; + newangles[ PITCH ] += dY; + + // Now rotate v_forward around that point + AngleVectors ( newangles, forward, right, up ); + + farpoint = v_origin + 8192 * forward; + + // Trace + tr = *(gEngfuncs.PM_TraceLine( (float *)&v_origin, (float *)&farpoint, PM_TRACELINE_PHYSENTSONLY, 2 /*point sized hull*/, -1 )); + + if ( tr.fraction != 1.0 && tr.ent != 0 ) + { + hitent = PM_GetPhysEntInfo( tr.ent ); + PM_ParticleLine( (float *)&v_origin, (float *)&tr.endpos, 5, 1.0, 0.0 ); + } + else + { + hitent = -1; + } +} + +#endif diff --git a/cl_dll/view.h b/cl_dll/view.h new file mode 100644 index 00000000..acd0bfb0 --- /dev/null +++ b/cl_dll/view.h @@ -0,0 +1,15 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined ( VIEWH ) +#define VIEWH +#pragma once + +void V_StartPitchDrift( void ); +void V_StopPitchDrift( void ); + +#endif // !VIEWH \ No newline at end of file diff --git a/cl_dll/wrect.h b/cl_dll/wrect.h new file mode 100644 index 00000000..620b8163 --- /dev/null +++ b/cl_dll/wrect.h @@ -0,0 +1,16 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#if !defined( WRECTH ) +#define WRECTH + +typedef struct rect_s +{ + int left, right, top, bottom; +} wrect_t; + +#endif \ No newline at end of file diff --git a/client/client.def b/client/client.def deleted file mode 100644 index ec19fdc4..00000000 --- a/client/client.def +++ /dev/null @@ -1,5 +0,0 @@ -LIBRARY client -EXPORTS - CreateAPI @1 -SECTIONS - .data READ WRITE diff --git a/client/client.dsp b/client/client.dsp deleted file mode 100644 index a8a1bef0..00000000 --- a/client/client.dsp +++ /dev/null @@ -1,424 +0,0 @@ -# Microsoft Developer Studio Project File - Name="client" - Package Owner=<4> -# Microsoft Developer Studio Generated Build File, Format Version 6.00 -# ** DO NOT EDIT ** - -# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 - -CFG=client - Win32 Release -!MESSAGE This is not a valid makefile. To build this project using NMAKE, -!MESSAGE use the Export Makefile command and run -!MESSAGE -!MESSAGE NMAKE /f "client.mak". -!MESSAGE -!MESSAGE You can specify a configuration when running NMAKE -!MESSAGE by defining the macro CFG on the command line. For example: -!MESSAGE -!MESSAGE NMAKE /f "client.mak" CFG="client - Win32 Release" -!MESSAGE -!MESSAGE Possible choices for configuration are: -!MESSAGE -!MESSAGE "client - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "client - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE - -# Begin Project -# PROP AllowPerConfigDependencies 0 -# PROP Scc_ProjName ""$/GoldSrc/client", HGEBAAAA" -# PROP Scc_LocalPath "." -CPP=cl.exe -MTL=midl.exe -RSC=rc.exe - -!IF "$(CFG)" == "client - Win32 Release" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir ".\!Release" -# PROP BASE Intermediate_Dir ".\!Release" -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\client\!release" -# PROP Intermediate_Dir "..\temp\client\!release" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /W3 /GX /O2 /I "./" /I "../common" /I "global" /I "hud" /I "../game_shared" /I "../dlls" /I "../engine" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /Fr /YX -# ADD BASE MTL /nologo /D "NDEBUG" /win32 -# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "NDEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 -# ADD LINK32 msvcrt.lib user32.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib:"libc.lib" /def:".\client.def" /libpath:"..\common\libs" -# SUBTRACT LINK32 /map -# Begin Custom Build -TargetDir=\Xash3D\src_main\temp\client\!release -InputPath=\Xash3D\src_main\temp\client\!release\client.dll -SOURCE="$(InputPath)" - -"D:\Xash3D\valve\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\client.dll "D:\Xash3D\valve\bin\client.dll" - -# End Custom Build - -!ELSEIF "$(CFG)" == "client - Win32 Debug" - -# PROP BASE Use_MFC 0 -# PROP BASE Use_Debug_Libraries 0 -# PROP BASE Output_Dir "Debug" -# PROP BASE Intermediate_Dir "Debug" -# PROP BASE Ignore_Export_Lib 0 -# PROP BASE Target_Dir "" -# PROP Use_MFC 0 -# PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\client\!debug" -# PROP Intermediate_Dir "..\temp\client\!debug" -# PROP Ignore_Export_Lib 1 -# PROP Target_Dir "" -# ADD BASE CPP /nologo /MT /W3 /GX /Zi /O2 /I "..\common\vgui" /I "..\client" /I "..\client\render" /I ".\hud" /I "..\common\engine" /I "..\common" /I "..\server" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "CLIENT_DLL" /YX /FD /c -# SUBTRACT BASE CPP /Fr -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../common" /I "global" /I "hud" /I "../game_shared" /I "../dlls" /I "../engine" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c -# SUBTRACT CPP /YX -# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 -# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 -# ADD BASE RSC /l 0x409 /d "NDEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" -BSC32=bscmake.exe -# ADD BASE BSC32 /nologo -# ADD BSC32 /nologo -LINK32=link.exe -# ADD BASE LINK32 kernel32.lib opengl32.lib glu32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib winmm.lib vgui.lib wsock32.lib cvaLib.lib /nologo /subsystem:windows /dll /machine:I386 /nodefaultlib:"libc" /def:".\client.def" /libpath:"..\common\libs" -# SUBTRACT BASE LINK32 /map -# ADD LINK32 msvcrtd.lib user32.lib /nologo /subsystem:windows /dll /incremental:yes /debug /machine:I386 /nodefaultlib:"libc.lib" /def:".\client.def" /pdbtype:sept /libpath:"..\common\libs" -# SUBTRACT LINK32 /map -# Begin Custom Build -TargetDir=\Xash3D\src_main\temp\client\!debug -InputPath=\Xash3D\src_main\temp\client\!debug\client.dll -SOURCE="$(InputPath)" - -"D:\Xash3D\valve\bin\client.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\client.dll "D:\Xash3D\valve\bin\client.dll" - -# End Custom Build - -!ENDIF - -# Begin Target - -# Name "client - Win32 Release" -# Name "client - Win32 Debug" -# Begin Group "Source Files" - -# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" -# Begin Source File - -SOURCE=.\global\aurora.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\cl_tent.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\dll_int.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\ev_common.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\ev_hldm.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_ammo.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_ammohistory.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_battery.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_death.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_flashlight.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_geiger.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_health.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_icons.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_menu.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_message.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_motd.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_msg.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_saytext.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_scoreboard.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_statusbar.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_text.cpp -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_train.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\input.cpp -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_debug.cpp -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_math.cpp -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_shared.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\r_beams.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\r_particle.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\r_tempents.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\r_tracer.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\r_weather.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\studio.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\triapi.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\utils.cpp -# End Source File -# Begin Source File - -SOURCE=.\global\view.cpp -# End Source File -# End Group -# Begin Group "Header Files" - -# PROP Default_Filter "h;hpp;hxx;hm;inl" -# Begin Source File - -SOURCE=..\common\anorms.h -# End Source File -# Begin Source File - -SOURCE=.\global\aurora.h -# End Source File -# Begin Source File - -SOURCE=..\common\basetypes.h -# End Source File -# Begin Source File - -SOURCE=..\common\beam_def.h -# End Source File -# Begin Source File - -SOURCE=..\common\bullets.h -# End Source File -# Begin Source File - -SOURCE=..\common\cdll_int.h -# End Source File -# Begin Source File - -SOURCE=..\common\const.h -# End Source File -# Begin Source File - -SOURCE=..\common\cvardef.h -# End Source File -# Begin Source File - -SOURCE=..\common\effects_api.h -# End Source File -# Begin Source File - -SOURCE=.\global\enginecallback.h -# End Source File -# Begin Source File - -SOURCE=..\common\entity_def.h -# End Source File -# Begin Source File - -SOURCE=..\common\entity_state.h -# End Source File -# Begin Source File - -SOURCE=..\common\event_api.h -# End Source File -# Begin Source File - -SOURCE=.\global\extdll.h -# End Source File -# Begin Source File - -SOURCE=..\common\game_shared.h -# End Source File -# Begin Source File - -SOURCE=.\hud\hud.h -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_ammo.h -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_ammohistory.h -# End Source File -# Begin Source File - -SOURCE=.\hud\hud_health.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_defs.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_info.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_materials.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_movevars.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\pm_shared.h -# End Source File -# Begin Source File - -SOURCE=.\global\r_beams.h -# End Source File -# Begin Source File - -SOURCE=.\global\r_particle.h -# End Source File -# Begin Source File - -SOURCE=.\global\r_weather.h -# End Source File -# Begin Source File - -SOURCE=..\common\ref_params.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\shake.h -# End Source File -# Begin Source File - -SOURCE=..\common\studio_event.h -# End Source File -# Begin Source File - -SOURCE=..\common\studio_ref.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\te_shared.h -# End Source File -# Begin Source File - -SOURCE=..\common\tmpent_def.h -# End Source File -# Begin Source File - -SOURCE=..\common\trace_def.h -# End Source File -# Begin Source File - -SOURCE=..\common\triangle_api.h -# End Source File -# Begin Source File - -SOURCE=..\common\usercmd.h -# End Source File -# Begin Source File - -SOURCE=.\global\utils.h -# End Source File -# Begin Source File - -SOURCE=.\game_shared\vector.h -# End Source File -# Begin Source File - -SOURCE=..\game_shared\vector.h -# End Source File -# End Group -# End Target -# End Project diff --git a/client/global/aurora.cpp b/client/global/aurora.cpp deleted file mode 100644 index 773b9bba..00000000 --- a/client/global/aurora.cpp +++ /dev/null @@ -1,1021 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// aurora.cpp - famous Laurie Cheers Aurora system -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "triangleapi.h" -#include "hud.h" -#include "aurora.h" -#include "pm_defs.h" - -ParticleSystemManager* g_pParticleSystems = NULL; - -void CreateAurora( int idx, char *file ) -{ - ParticleSystem *pSystem = new ParticleSystem( idx, file ); - g_pParticleSystems->AddSystem( pSystem ); -} - - -ParticleSystemManager::ParticleSystemManager( void ) -{ - m_pFirstSystem = NULL; -} - -ParticleSystemManager::~ParticleSystemManager( void ) -{ - ClearSystems(); -} - -void ParticleSystemManager::AddSystem( ParticleSystem* pNewSystem ) -{ - pNewSystem->m_pNextSystem = m_pFirstSystem; - m_pFirstSystem = pNewSystem; -} - -ParticleSystem *ParticleSystemManager::FindSystem( cl_entity_t* pEntity ) -{ - for( ParticleSystem *pSys = m_pFirstSystem; pSys; pSys = pSys->m_pNextSystem ) - { - if( pEntity->index == pSys->m_iEntIndex ) - return pSys; - } - return NULL; -} - -// blended particles don't use the z-buffer, so we need to sort them before drawing. -// for efficiency, only the systems are sorted - individual particles just get drawn in order of creation. -// (this should actually make things look better - no ugly popping when one particle passes through another.) -void ParticleSystemManager::SortSystems( void ) -{ - ParticleSystem* pSystem; - ParticleSystem* pLast; - ParticleSystem* pBeforeCompare, *pCompare; - - if (!m_pFirstSystem) return; - - // calculate how far away each system is from the viewer - for( pSystem = m_pFirstSystem; pSystem; pSystem = pSystem->m_pNextSystem ) - pSystem->CalculateDistance(); - - // do an insertion sort on the systems - pLast = m_pFirstSystem; - pSystem = pLast->m_pNextSystem; - while ( pSystem ) - { - if ( pLast->m_fViewerDist < pSystem->m_fViewerDist ) - { - // pSystem is in the wrong place! First, let's unlink it from the list - pLast->m_pNextSystem = pSystem->m_pNextSystem; - - // then find somewhere to insert it - if (m_pFirstSystem == pLast || m_pFirstSystem->m_fViewerDist < pSystem->m_fViewerDist) - { - // pSystem comes before the first system, insert it there - pSystem->m_pNextSystem = m_pFirstSystem; - m_pFirstSystem = pSystem; - } - else - { - // insert pSystem somewhere within the sorted part of the list - pBeforeCompare = m_pFirstSystem; - pCompare = pBeforeCompare->m_pNextSystem; - while (pCompare != pLast) - { - if (pCompare->m_fViewerDist < pSystem->m_fViewerDist) - { - // pSystem comes before pCompare. We've found where it belongs. - break; - } - - pBeforeCompare = pCompare; - pCompare = pBeforeCompare->m_pNextSystem; - } - - // we've found where pSystem belongs. Insert it between pBeforeCompare and pCompare. - pBeforeCompare->m_pNextSystem = pSystem; - pSystem->m_pNextSystem = pCompare; - } - } - else - { - //pSystem is in the right place, move on - pLast = pSystem; - } - pSystem = pLast->m_pNextSystem; - } -} - -void ParticleSystemManager::UpdateSystems( void ) -{ - static float fOldTime, fTime; - fOldTime = fTime; - fTime = GetClientTime(); - float frametime = fTime - fOldTime; - - ParticleSystem* pSystem; - ParticleSystem* pLast = NULL; - ParticleSystem*pLastSorted = NULL; - - SortSystems(); - - pSystem = m_pFirstSystem; - while( pSystem ) - { - if( pSystem->UpdateSystem( frametime )) - { - pSystem->DrawSystem(); - pLast = pSystem; - pSystem = pSystem->m_pNextSystem; - } - else // delete this system - { - if (pLast) - { - pLast->m_pNextSystem = pSystem->m_pNextSystem; - delete pSystem; - pSystem = pLast->m_pNextSystem; - } - else // deleting the first system - { - m_pFirstSystem = pSystem->m_pNextSystem; - delete pSystem; - pSystem = m_pFirstSystem; - } - } - } - gEngfuncs.pTriAPI->RenderMode(kRenderNormal); -} - -void ParticleSystemManager::ClearSystems( void ) -{ - ParticleSystem* pSystem = m_pFirstSystem; - ParticleSystem* pTemp; - - while( pSystem ) - { - pTemp = pSystem->m_pNextSystem; - delete pSystem; - pSystem = pTemp; - } - - m_pFirstSystem = NULL; -} - -float ParticleSystem::c_fCosTable[360 + 90]; -bool ParticleSystem::c_bCosTableInit = false; - -ParticleType::ParticleType( ParticleType *pNext ) -{ - m_pSprayType = m_pOverlayType = NULL; - m_StartAngle = RandomRange(45); - m_SpriteIndex = 0; - m_pNext = pNext; - m_szName[0] = 0; - m_StartRed = m_StartGreen = m_StartBlue = m_StartAlpha = RandomRange(1); - m_EndRed = m_EndGreen = m_EndBlue = m_EndAlpha = RandomRange(1); - m_iRenderMode = kRenderTransAdd; - m_iDrawCond = 0; - m_bEndFrame = false; - - m_bIsDefined = false; - m_iCollision = 0; -} - -particle* ParticleType::CreateParticle(ParticleSystem *pSys)//particle *pPart) -{ - if (!pSys) return NULL; - - particle *pPart = pSys->ActivateParticle(); - if (!pPart) return NULL; - - pPart->age = 0.0; - pPart->age_death = m_Life.GetInstance(); - - InitParticle(pPart, pSys); - - return pPart; -} - -void ParticleType::InitParticle(particle *pPart, ParticleSystem *pSys) -{ - float fLifeRecip = 1/pPart->age_death; - - particle *pOverlay = NULL; - if (m_pOverlayType) - { - // create an overlay for this particle - pOverlay = pSys->ActivateParticle(); - if (pOverlay) - { - pOverlay->age = pPart->age; - pOverlay->age_death = pPart->age_death; - m_pOverlayType->InitParticle(pOverlay, pSys); - } - } - - pPart->m_pOverlay = pOverlay; - - pPart->pType = this; - pPart->velocity[0] = pPart->velocity[1] = pPart->velocity[2] = 0; - pPart->accel[0] = pPart->accel[1] = 0; - pPart->accel[2] = m_Gravity.GetInstance(); - pPart->m_iEntIndex = 0; - - if (m_pSprayType) - { - pPart->age_spray = 1/m_SprayRate.GetInstance(); - } - else - { - pPart->age_spray = 0.0f; - } - - pPart->m_fSize = m_StartSize.GetInstance(); - - if (m_EndSize.IsDefined()) - pPart->m_fSizeStep = m_EndSize.GetOffset(pPart->m_fSize) * fLifeRecip; - else - pPart->m_fSizeStep = m_SizeDelta.GetInstance(); - //pPart->m_fSizeStep = m_EndSize.GetOffset(pPart->m_fSize) * fLifeRecip; - - pPart->frame = m_StartFrame.GetInstance(); - if (m_EndFrame.IsDefined( )) - pPart->m_fFrameStep = m_EndFrame.GetOffset( pPart->frame ) * fLifeRecip; - else pPart->m_fFrameStep = m_FrameRate.GetInstance(); - - pPart->m_fAlpha = m_StartAlpha.GetInstance(); - pPart->m_fAlphaStep = m_EndAlpha.GetOffset(pPart->m_fAlpha) * fLifeRecip; - pPart->m_fRed = m_StartRed.GetInstance(); - pPart->m_fRedStep = m_EndRed.GetOffset(pPart->m_fRed) * fLifeRecip; - pPart->m_fGreen = m_StartGreen.GetInstance(); - pPart->m_fGreenStep = m_EndGreen.GetOffset(pPart->m_fGreen) * fLifeRecip; - pPart->m_fBlue = m_StartBlue.GetInstance(); - pPart->m_fBlueStep = m_EndBlue.GetOffset(pPart->m_fBlue) * fLifeRecip; - - pPart->m_fAngle = m_StartAngle.GetInstance(); - pPart->m_fAngleStep = m_AngleDelta.GetInstance(); - - pPart->m_fDrag = m_Drag.GetInstance(); - - float fWindStrength = m_WindStrength.GetInstance(); - float fWindYaw = m_WindYaw.GetInstance(); - pPart->m_vecWind.x = fWindStrength*ParticleSystem::CosLookup(fWindYaw); - pPart->m_vecWind.y = fWindStrength*ParticleSystem::SinLookup(fWindYaw); - pPart->m_vecWind.z = 0; -} - -//============================================ - - -RandomRange::RandomRange( char *szToken ) -{ - char *cOneDot = NULL; - m_bDefined = true; - - for( char *c = szToken; *c; c++ ) - { - if (*c == '.') - { - if (cOneDot != NULL) - { - // found two dots in a row - it's a range - - *cOneDot = 0; // null terminate the first number - m_fMin = atof( szToken ); // parse the first number - *cOneDot = '.'; // change it back, just in case - c++; - m_fMax = atof( c ); // parse the second number - return; - } - else - { - cOneDot = c; - } - } - else - { - cOneDot = NULL; - } - } - - // no range, just record the number - m_fMin = m_fMax = atof( szToken ); -} - -//============================================ - -ParticleSystem::ParticleSystem( int iEntIndex, char *szFilename ) -{ - int iParticles = 100; // default - - m_iEntIndex = iEntIndex; - m_pNextSystem = NULL; - m_pFirstType = NULL; - if (!c_bCosTableInit) - { - for (int i = 0; i < 360+90; i++) - { - c_fCosTable[i] = cos(i*M_PI/180.0); - } - c_bCosTableInit = true; - } - - char *szFile = (char *)gEngfuncs.COM_LoadFile( szFilename, 5, NULL); - char szToken[1024]; - - if (!szFile) - { - gEngfuncs.Con_DPrintf( "Particle %s not found.\n", szFilename ); - return; - } - else - { - szFile = gEngfuncs.COM_ParseFile(szFile, szToken); - - while (szFile) - { - if ( !stricmp( szToken, "particles" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - iParticles = atof(szToken); - } - else if ( !stricmp( szToken, "maintype" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - m_pMainType = AddPlaceholderType(szToken); - } - else if ( !stricmp( szToken, "attachment" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - m_iEntAttachment = atof(szToken); - } - else if ( !stricmp( szToken, "killcondition" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - if ( !stricmp( szToken, "empty" ) ) - { - m_iKillCondition = CONTENTS_EMPTY; - } - else if ( !stricmp( szToken, "water" ) ) - { - m_iKillCondition = CONTENTS_WATER; - } - else if ( !stricmp( szToken, "solid" ) ) - { - m_iKillCondition = CONTENTS_SOLID; - } - } - else if ( !stricmp( szToken, "{" ) ) - { - // parse new type - this->ParseType( szFile ); // parses the type, moves the file pointer - } - - szFile = gEngfuncs.COM_ParseFile(szFile, szToken); - } - } - - gEngfuncs.COM_FreeFile( szFile ); - AllocateParticles(iParticles); -} - -void ParticleSystem::AllocateParticles( int iParticles ) -{ - m_pAllParticles = new particle[iParticles]; - m_pFreeParticle = m_pAllParticles; - m_pActiveParticle = NULL; - m_pMainParticle = NULL; - - // initialise the linked list - particle *pLast = m_pAllParticles; - particle *pParticle = pLast+1; - - for( int i = 1; i < iParticles; i++ ) - { - pLast->nextpart = pParticle; - - pLast = pParticle; - pParticle++; - } - pLast->nextpart = NULL; -} - -ParticleSystem::~ParticleSystem( void ) -{ - delete[] m_pAllParticles; - - ParticleType *pType = m_pFirstType; - ParticleType *pNext; - while (pType) - { - pNext = pType->m_pNext; - delete pType; - pType = pNext; - } -} - - - -// returns the ParticleType with the given name, if there is one -ParticleType *ParticleSystem::GetType( const char *szName ) -{ - for (ParticleType *pType = m_pFirstType; pType; pType = pType->m_pNext) - { - if (!stricmp(pType->m_szName, szName)) - return pType; - } - return NULL; -} - -ParticleType *ParticleSystem::AddPlaceholderType( const char *szName ) -{ - m_pFirstType = new ParticleType( m_pFirstType ); - strncpy(m_pFirstType->m_szName, szName, sizeof(m_pFirstType->m_szName) ); - return m_pFirstType; -} - -// creates a new particletype from the given file -// NB: this changes the value of szFile. -ParticleType *ParticleSystem::ParseType( char *&szFile ) -{ - ParticleType *pType = new ParticleType(); - - // parse the .aur file - char szToken[1024]; - - szFile = gEngfuncs.COM_ParseFile(szFile, szToken); - while ( stricmp( szToken, "}" ) ) - { - if (!szFile) - break; - - if ( !stricmp( szToken, "name" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - strncpy(pType->m_szName, szToken, sizeof(pType->m_szName) ); - - ParticleType *pTemp = GetType(szToken); - if (pTemp) - { - // there's already a type with this name - if (pTemp->m_bIsDefined) - gEngfuncs.Con_DPrintf( "Warning: Particle type %s is defined more than once!\n", szToken); - - // copy all our data into the existing type, throw away the type we were making - *pTemp = *pType; - delete pType; - pType = pTemp; - pType->m_bIsDefined = true; // record the fact that it's defined, so we won't need to add it to the list - } - } - else if ( !stricmp( szToken, "gravity" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_Gravity = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "windyaw" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_WindYaw = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "windstrength" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_WindStrength = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "sprite" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_SpriteIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( szToken ); - } - else if ( !stricmp( szToken, "startalpha" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_StartAlpha = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "endalpha" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_EndAlpha = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "startred" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_StartRed = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "endred" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_EndRed = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "startgreen" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_StartGreen = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "endgreen" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_EndGreen = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "startblue" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_StartBlue = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "endblue" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_EndBlue = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "startsize" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_StartSize = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "sizedelta" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_SizeDelta = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "endsize" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_EndSize = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "startangle" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_StartAngle = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "angledelta" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_AngleDelta = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "startframe" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_StartFrame = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "endframe" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_EndFrame = RandomRange( szToken ); - pType->m_bEndFrame = true; - } - else if ( !stricmp( szToken, "framerate" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_FrameRate = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "lifetime" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_Life = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "spraytype" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - ParticleType *pTemp = GetType(szToken); - - if (pTemp) pType->m_pSprayType = pTemp; - else pType->m_pSprayType = AddPlaceholderType(szToken); - } - else if ( !stricmp( szToken, "overlaytype" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - ParticleType *pTemp = GetType(szToken); - - if (pTemp) pType->m_pOverlayType = pTemp; - else pType->m_pOverlayType = AddPlaceholderType(szToken); - } - else if ( !stricmp( szToken, "sprayrate" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_SprayRate = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "sprayforce" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_SprayForce = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "spraypitch" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_SprayPitch = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "sprayyaw" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_SprayYaw = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "drag" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_Drag = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "bounce" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_Bounce = RandomRange( szToken ); - if (pType->m_Bounce.m_fMin != 0 || pType->m_Bounce.m_fMax != 0) - pType->m_bBouncing = true; - } - else if ( !stricmp( szToken, "bouncefriction" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - pType->m_BounceFriction = RandomRange( szToken ); - } - else if ( !stricmp( szToken, "rendermode" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - if ( !stricmp( szToken, "additive" ) ) - { - pType->m_iRenderMode = kRenderTransAdd; - } - else if ( !stricmp( szToken, "solid" ) ) - { - pType->m_iRenderMode = kRenderTransAlpha; - } - else if ( !stricmp( szToken, "texture" ) ) - { - pType->m_iRenderMode = kRenderTransTexture; - } - else if ( !stricmp( szToken, "color" ) ) - { - pType->m_iRenderMode = kRenderTransColor; - } - } - else if ( !stricmp( szToken, "drawcondition" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - if ( !stricmp( szToken, "empty" ) ) - { - pType->m_iDrawCond = CONTENTS_EMPTY; - } - else if ( !stricmp( szToken, "water" ) ) - { - pType->m_iDrawCond = CONTENTS_WATER; - } - else if ( !stricmp( szToken, "solid" ) ) - { - pType->m_iDrawCond = CONTENTS_SOLID; - } - else if ( !stricmp( szToken, "special" ) || !stricmp( szToken, "special1" ) ) - { - pType->m_iDrawCond = -20; - } - else if ( !stricmp( szToken, "special2" ) ) - { - pType->m_iDrawCond = -21; - } - else if ( !stricmp( szToken, "special3" ) ) - { - pType->m_iDrawCond = -22; - } - } - else if ( !stricmp( szToken, "collision" ) ) - { - szFile = gEngfuncs.COM_ParseFile(szFile,szToken); - if ( !stricmp( szToken, "none" ) ) - { - pType->m_iCollision = COLLISION_NONE; - } - else if ( !stricmp( szToken, "die" ) ) - { - pType->m_iCollision = COLLISION_DIE; - } - else if ( !stricmp( szToken, "bounce" ) ) - { - pType->m_iCollision = COLLISION_BOUNCE; - } - } - // get the next token - szFile = gEngfuncs.COM_ParseFile(szFile, szToken); - } - - if (!pType->m_bIsDefined) - { - // if this is a newly-defined type, we need to add it to the list - pType->m_pNext = m_pFirstType; - m_pFirstType = pType; - pType->m_bIsDefined = true; - } - - return pType; -} - -particle *ParticleSystem::ActivateParticle() -{ - particle* pActivated = m_pFreeParticle; - if (pActivated) - { - m_pFreeParticle = pActivated->nextpart; - pActivated->nextpart = m_pActiveParticle; - m_pActiveParticle = pActivated; - } - return pActivated; -} - -extern Vector v_origin; - -void ParticleSystem::CalculateDistance() -{ - if (!m_pActiveParticle) - return; - - Vector offset = v_origin - m_pActiveParticle->origin; // just pick one - m_fViewerDist = offset[0]*offset[0] + offset[1]*offset[1] + offset[2]*offset[2]; -} - - -bool ParticleSystem::UpdateSystem( float frametime ) -{ - // the entity emitting this system - cl_entity_t *source = GetEntityByIndex( m_iEntIndex ); - - if( !source ) return false; - - // Don't update if the system is outside the player's PVS. - enable = (source->curstate.renderfx == 21); - - // check for contents to remove - if( POINT_CONTENTS( source->origin ) == m_iKillCondition ) - { - enable = 0; - } - - if ( m_pMainParticle == NULL ) - { - if ( enable ) - { - ParticleType *pType = m_pMainType; - if ( pType ) - { - m_pMainParticle = pType->CreateParticle( this ); - if ( m_pMainParticle ) - { - m_pMainParticle->m_iEntIndex = m_iEntIndex; - m_pMainParticle->age_death = -1; // never die - } - } - } - } - else if ( !enable ) - { - m_pMainParticle->age_death = 0; // die now - m_pMainParticle = NULL; - } - - particle* pParticle = m_pActiveParticle; - particle* pLast = NULL; - - while( pParticle ) - { - if ( UpdateParticle( pParticle, frametime )) - { - pLast = pParticle; - pParticle = pParticle->nextpart; - } - else // deactivate it - { - if ( pLast ) - { - pLast->nextpart = pParticle->nextpart; - pParticle->nextpart = m_pFreeParticle; - m_pFreeParticle = pParticle; - pParticle = pLast->nextpart; - } - else // deactivate the first particle in the list - { - m_pActiveParticle = pParticle->nextpart; - pParticle->nextpart = m_pFreeParticle; - m_pFreeParticle = pParticle; - pParticle = m_pActiveParticle; - } - } - } - return true; -} - -void ParticleSystem :: DrawSystem( void ) -{ - Vector normal, forward, right, up; - - GetViewAngles( normal ); - AngleVectors( normal, forward, right, up ); - - particle* pParticle = m_pActiveParticle; - for( pParticle = m_pActiveParticle; pParticle; pParticle = pParticle->nextpart ) - { - DrawParticle( pParticle, right, up ); - } -} - -bool ParticleSystem::ParticleIsVisible( particle* part ) -{ - vec3_t normal, forward, right, up; - - GetViewAngles( normal ); - AngleVectors( normal, forward, right, up ); - - Vector vec = ( part->origin - v_origin ); - Vector vecDir = vec.Normalize( ); - float distance = vec.Length(); - - if ( DotProduct ( vecDir, forward ) < 0.0f ) - return false; - return true; -} - -bool ParticleSystem::UpdateParticle( particle *part, float frametime ) -{ - if( frametime == 0 ) return true; - part->age += frametime; - - cl_entity_t *source = GetEntityByIndex( m_iEntIndex ); - if( !source ) return false; // total paranoia :) - - // is this particle bound to an entity? - if( part->m_iEntIndex ) - { - if ( enable ) - { - if( m_iEntAttachment ) - { - Vector pos = source->origin + source->attachment[m_iEntAttachment - 1]; - - part->velocity = (pos - part->origin) / frametime; - part->origin = pos; - } - else - { - part->velocity = ( source->origin - part->origin ) / frametime; - part->origin = source->origin; - } - } - else - { - // entity is switched off, die - return false; - } - } - else - { - // not tied to an entity, check whether it's time to die - if( part->age_death >= 0 && part->age > part->age_death ) - return false; - - // apply acceleration and velocity - Vector vecOldPos = part->origin; - - if ( part->m_fDrag ) - part->velocity = part->velocity + (-part->m_fDrag * frametime) * ( part->velocity - part->m_vecWind ); - part->velocity = part->velocity + frametime * part->accel; - part->origin = part->origin + frametime * part->velocity; - - if( part->pType->m_bBouncing ) - { - Vector vecTarget = part->origin + frametime * part->velocity; - pmtrace_t *tr = gEngfuncs.PM_TraceLine( part->origin, vecTarget, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); - - if( tr->fraction < 1.0f ) - { - part->origin = tr->endpos; - float bounceforce = DotProduct( tr->plane.normal, part->velocity ); - float newspeed = (1.0f - part->pType->m_BounceFriction.GetInstance()); - part->velocity = part->velocity * newspeed; - part->velocity = part->velocity + (-bounceforce * ( newspeed + part->pType->m_Bounce.GetInstance())) * tr->plane.normal; - } - } - } - - - // spray children - if ( part->age_spray && part->age > part->age_spray ) - { - part->age_spray = part->age + 1/part->pType->m_SprayRate.GetInstance(); - - // particle *pChild = ActivateParticle(); - if (part->pType->m_pSprayType) - { - particle *pChild = part->pType->m_pSprayType->CreateParticle(this); - if (pChild) - { - pChild->origin = part->origin; - float fSprayForce = part->pType->m_SprayForce.GetInstance(); - pChild->velocity = part->velocity; - if (fSprayForce) - { - float fSprayPitch = part->pType->m_SprayPitch.GetInstance() - source->angles.x; - float fSprayYaw = part->pType->m_SprayYaw.GetInstance() - source->angles.y; - float fSprayRoll = source->angles.z; - float fForceCosPitch = fSprayForce*CosLookup(fSprayPitch); - pChild->velocity.x += CosLookup(fSprayYaw) * fForceCosPitch; - pChild->velocity.y += SinLookup(fSprayYaw) * fForceCosPitch + SinLookup(fSprayYaw) * fSprayForce * SinLookup(fSprayRoll); - pChild->velocity.z -= SinLookup(fSprayPitch) * fSprayForce * CosLookup(fSprayRoll); - } - } - } - } - - part->m_fSize += part->m_fSizeStep * frametime; - part->m_fAlpha += part->m_fAlphaStep * frametime; - part->m_fRed += part->m_fRedStep * frametime; - part->m_fGreen += part->m_fGreenStep * frametime; - part->m_fBlue += part->m_fBlueStep * frametime; - part->frame += part->m_fFrameStep * frametime; - if ( part->m_fAngleStep ) - { - part->m_fAngle += part->m_fAngleStep * frametime; - while ( part->m_fAngle < 0 ) part->m_fAngle += 360; - while ( part->m_fAngle > 360 ) part->m_fAngle -= 360; - } - return true; -} - -void ParticleSystem::DrawParticle( particle *part, Vector &right, Vector &up ) -{ - float fSize = part->m_fSize; - Vector point1, point2, point3, point4; - Vector origin = part->origin; - - // nothing to draw? - if ( fSize == 0 ) return; - - // frustrum visible check - if( !ParticleIsVisible( part )) return; - - float fCosSize = CosLookup( part->m_fAngle ) * fSize; - float fSinSize = SinLookup( part->m_fAngle ) * fSize; - - // calculate the four corners of the sprite - point1 = origin + fSinSize * up; - point1 = point1 + (-fCosSize) * right; - - point2 = origin + fCosSize * up; - point2 = point2 + fSinSize * right; - - point3 = origin + (-fSinSize) * up; - point3 = point3 + fCosSize * right; - - point4 = origin + (-fCosSize) * up; - point4 = point4 + (-fSinSize) * right; - - int iContents = 0; - - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - - for ( particle *pDraw = part; pDraw; pDraw = pDraw->m_pOverlay ) - { - if( pDraw->pType->m_SpriteIndex == 0 ) - continue; - - if ( pDraw->pType->m_iDrawCond ) - { - if ( iContents == 0 ) - iContents = POINT_CONTENTS( origin ); - - if ( iContents != pDraw->pType->m_iDrawCond ) - continue; - } - - int numFrames = Mod_GetFrames( pDraw->pType->m_SpriteIndex ); - - // gEngfuncs.Con_Printf( "UpdParticle %d: age %f, life %f, R:%f G:%f, B, %f \n", pDraw->pType->m_hSprite, part->age, part->age_death, pDraw->m_fRed, pDraw->m_fGreen, pDraw->m_fBlue); - - // if we've reached the end of the sprite's frames, loop back - while ( pDraw->frame > numFrames ) - pDraw->frame -= numFrames; - - while ( pDraw->frame < 0 ) - pDraw->frame += numFrames; - - HSPRITE m_hSprite; - - m_hSprite = gEngfuncs.pTriAPI->GetSpriteTexture( pDraw->pType->m_SpriteIndex, int( pDraw->frame )); - gEngfuncs.pTriAPI->RenderMode( pDraw->pType->m_iRenderMode ); - gEngfuncs.pTriAPI->Color4f( pDraw->m_fRed, pDraw->m_fGreen, pDraw->m_fBlue, pDraw->m_fAlpha ); - - gEngfuncs.pTriAPI->Bind( m_hSprite, int( pDraw->frame )); - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f ( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3fv( point1 ); - - gEngfuncs.pTriAPI->TexCoord2f ( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3fv ( point2 ); - - gEngfuncs.pTriAPI->TexCoord2f ( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3fv ( point3 ); - - gEngfuncs.pTriAPI->TexCoord2f ( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3fv ( point4 ); - gEngfuncs.pTriAPI->End(); - } - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} \ No newline at end of file diff --git a/client/global/aurora.h b/client/global/aurora.h deleted file mode 100644 index 66132c67..00000000 --- a/client/global/aurora.h +++ /dev/null @@ -1,212 +0,0 @@ -// 02/08/02 November235: Particle System -#pragma once - -class ParticleType; -class ParticleSystem; -void CreateAurora( int idx, char *file ); //make new partsystem - -#define COLLISION_NONE 0 -#define COLLISION_DIE 1 -#define COLLISION_BOUNCE 2 - -struct particle -{ - particle *nextpart; - particle *m_pOverlay; // for making multi-layered particles - ParticleType *pType; - - Vector origin; - Vector velocity; - Vector accel; - Vector m_vecWind; - - int m_iEntIndex; // if non-zero, this particle is tied to the given entity - - float m_fRed; - float m_fGreen; - float m_fBlue; - float m_fRedStep; - float m_fGreenStep; - float m_fBlueStep; - - float m_fAlpha; - float m_fAlphaStep; - - float frame; - float m_fFrameStep; - - float m_fAngle; - float m_fAngleStep; - - float m_fSize; - float m_fSizeStep; - - float m_fDrag; - - float age; - float age_death; - float age_spray; -}; - - -class RandomRange -{ -public: - RandomRange() { m_fMin = m_fMax = 0; m_bDefined = false; } - RandomRange(float fValue) { m_fMin = m_fMax = fValue; m_bDefined = true; } - RandomRange(float fMin, float fMax) { m_fMin = fMin; m_fMax = fMax; m_bDefined = true; } - RandomRange( char *szToken ); - - float m_fMax; - float m_fMin; - bool m_bDefined; - - float GetInstance() - { - return RANDOM_FLOAT( m_fMin, m_fMax ); - } - - float GetOffset( float fBasis ) - { - return GetInstance() - fBasis; - } - - bool IsDefined( void ) - { - return m_bDefined; - } -}; - -#define MAX_TYPENAME 256 - -class ParticleType -{ -public: - ParticleType( ParticleType *pNext = NULL ); - ParticleType( char *szFilename ); - - bool m_bIsDefined; // is this ParticleType just a placeholder? - int m_iRenderMode; - int m_iDrawCond; - int m_iCollision; - RandomRange m_Bounce; - RandomRange m_BounceFriction; - bool m_bBouncing; - - RandomRange m_Life; - - RandomRange m_StartAlpha; - RandomRange m_EndAlpha; - RandomRange m_StartRed; - RandomRange m_EndRed; - RandomRange m_StartGreen; - RandomRange m_EndGreen; - RandomRange m_StartBlue; - RandomRange m_EndBlue; - - RandomRange m_StartSize; - RandomRange m_SizeDelta; - RandomRange m_EndSize; - - RandomRange m_StartFrame; - RandomRange m_EndFrame; - RandomRange m_FrameRate; // incompatible with EndFrame - bool m_bEndFrame; - - RandomRange m_StartAngle; - RandomRange m_AngleDelta; - - RandomRange m_SprayRate; - RandomRange m_SprayForce; - RandomRange m_SprayPitch; - RandomRange m_SprayYaw; - RandomRange m_SprayRoll; - ParticleType *m_pSprayType; - - RandomRange m_Gravity; - RandomRange m_WindStrength; - RandomRange m_WindYaw; - - int m_SpriteIndex; - ParticleType *m_pOverlayType; - - RandomRange m_Drag; - - ParticleType *m_pNext; - - char m_szName[MAX_TYPENAME]; - - // here is a particle system. Add a (set of) particles according to this type, and initialise their values. - particle* CreateParticle(ParticleSystem *pSys);//particle *pPart); - - // initialise this particle. Does not define velocity or age. - void InitParticle(particle *pPart, ParticleSystem *pSys); -}; - -class ParticleSystem -{ -public: - ParticleSystem( int entindex, char *szFilename ); - ~ParticleSystem( void ); - void AllocateParticles( int iParticles ); - void CalculateDistance(); - - ParticleType *GetType( const char *szName ); - ParticleType *AddPlaceholderType( const char *szName ); - ParticleType *ParseType( char *&szFile ); - - cl_entity_t *GetEntity() { return GetEntityByIndex( m_iEntIndex ); } - - static float c_fCosTable[360 + 90]; - static bool c_bCosTableInit; - - // General functions - bool UpdateSystem( float frametime ); //If this function returns false, the manager deletes the system - void DrawSystem(); - particle *ActivateParticle(); // adds one of the free particles to the active list, and returns it for initialisation. - - static float CosLookup(int angle) { return angle < 0? c_fCosTable[angle+360]: c_fCosTable[angle]; } - static float SinLookup(int angle) { return angle < -90? c_fCosTable[angle+450]: c_fCosTable[angle+90]; } - - // returns false if the particle has died - bool UpdateParticle( particle *part, float frametime ); - void DrawParticle( particle* part, Vector &right, Vector &up ); - - // Utility functions that have to be public - bool ParticleIsVisible( particle* part ); - - // Pointer to next system for linked list structure - ParticleSystem* m_pNextSystem; - - particle* m_pActiveParticle; - float m_fViewerDist; - int m_iEntIndex; - int m_iEntAttachment; - int m_iKillCondition; - int enable; -private: - // the block of allocated particles - particle* m_pAllParticles; - // First particles in the linked list for the active particles and the dead particles - particle* m_pFreeParticle; - particle* m_pMainParticle; // the "source" particle. - - ParticleType *m_pFirstType; - ParticleType *m_pMainType; -}; - -class ParticleSystemManager -{ -public: - ParticleSystemManager( void ); - ~ParticleSystemManager( void ); - - ParticleSystem *FindSystem( cl_entity_t* pEntity ); - void SortSystems( void ); - void AddSystem( ParticleSystem* ); - void UpdateSystems( void ); - void ClearSystems( void ); - ParticleSystem *m_pFirstSystem; -}; - -extern ParticleSystemManager* g_pParticleSystems; \ No newline at end of file diff --git a/client/global/cl_tent.cpp b/client/global/cl_tent.cpp deleted file mode 100644 index 18e58e95..00000000 --- a/client/global/cl_tent.cpp +++ /dev/null @@ -1,1342 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// tempents.cpp - client side entity management functions -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "studio_event.h" -#include "r_efx.h" -#include "pm_movevars.h" -#include "r_particle.h" -#include "r_tempents.h" -#include "ev_hldm.h" -#include "r_beams.h" -#include "hud.h" - -/* ---------------- -TE_ParseBeamPoints - -Creates a beam between two points ---------------- -*/ -void TE_ParseBeamPoints( void ) -{ - Vector vecStart, vecEnd, vecColor; - int modelIndex, startFrame; - float frameRate, life, width; - float brightness, noise, speed; - - // beam position - vecStart.x = READ_COORD(); - vecStart.y = READ_COORD(); - vecStart.z = READ_COORD(); - vecEnd.x = READ_COORD(); - vecEnd.y = READ_COORD(); - vecEnd.z = READ_COORD(); - - // beam info - modelIndex = READ_SHORT(); - startFrame = READ_BYTE(); - frameRate = (float)(READ_BYTE()); - life = (float)(READ_BYTE() * 0.1f); - width = (float)(READ_BYTE() * 0.1f); - noise = (float)(READ_BYTE() * 0.1f); - - // renderinfo - vecColor.x = (float)READ_BYTE(); - vecColor.y = (float)READ_BYTE(); - vecColor.z = (float)READ_BYTE(); - brightness = (float)READ_BYTE(); - speed = (float)(READ_BYTE() * 0.1f); - - g_pViewRenderBeams->CreateBeamPoints( vecStart, vecEnd, modelIndex, life, width, noise, brightness, speed, - startFrame, frameRate, vecColor.x, vecColor.y, vecColor.z ); -} - - -/* ---------------- -TE_ParseBeamEntPoint - -Creates a beam between two points ---------------- -*/ -void TE_ParseBeamEntPoint( void ) -{ - Vector vecEnd, vecColor; - int entityIndex, modelIndex, startFrame; - float frameRate, life, width; - float brightness, noise, speed; - - // beam position - entityIndex = READ_SHORT(); - vecEnd.x = READ_COORD(); - vecEnd.y = READ_COORD(); - vecEnd.z = READ_COORD(); - - // beam info - modelIndex = READ_SHORT(); - startFrame = READ_BYTE(); - frameRate = (float)(READ_BYTE()); - life = (float)(READ_BYTE() * 0.1f); - width = (float)(READ_BYTE() * 0.1f); - noise = (float)(READ_BYTE() * 0.1f); - - // renderinfo - vecColor.x = (float)READ_BYTE(); - vecColor.y = (float)READ_BYTE(); - vecColor.z = (float)READ_BYTE(); - brightness = (float)READ_BYTE(); - speed = (float)(READ_BYTE() * 0.1f); - - g_pViewRenderBeams->CreateBeamEntPoint( entityIndex, vecEnd, modelIndex, life, width, noise, brightness, - speed, startFrame, frameRate, vecColor.x, vecColor.y, vecColor.z ); -} - -/* ---------------- -TE_ParseGunShot - -Particle effect plus ricochet sound ---------------- -*/ -void TE_ParseGunShot( void ) -{ - char soundpath[32]; - Vector pos; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - g_pParticles->ParticleEffect( pos, g_vecZero, 0, 20 ); - - if( RANDOM_LONG( 0, 32 ) <= 8 ) // 25% chanse - { - int iPitch = RANDOM_LONG( 90, 105 ); - float fvol = RANDOM_FLOAT( 0.7f, 0.9f ); - sprintf( soundpath, "weapons/ric%i.wav", RANDOM_LONG( 1, 5 )); - gEngfuncs.pEventAPI->EV_PlaySound( 0, pos, CHAN_AUTO, soundpath, fvol, ATTN_NORM, 0, iPitch ); - } -} - -/* ---------------- -TE_ParseExplosion - -Creates additive sprite, 2 dynamic lights, flickering particles, explosion sound, move vertically 8 pps ---------------- -*/ -void TE_ParseExplosion( void ) -{ - Vector dir, pos, pos2; - float scale, magnitude, frameRate; - int flags, spriteIndex; - TENT *pTemp; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - spriteIndex = READ_SHORT(); - magnitude = (float)(READ_BYTE() * 0.1f); - frameRate = READ_BYTE(); - flags = READ_BYTE(); - - UTIL_GetForceDirection( pos, magnitude, &dir, &scale ); - pos2 = pos + (dir * scale); - - if( scale != 0.0f ) - { - // create explosion sprite - pTemp = g_pTempEnts->DefaultSprite( pos2, spriteIndex, frameRate ); - g_pTempEnts->Sprite_Explode( pTemp, scale, flags ); - - if( !( flags & TE_EXPLFLAG_NODLIGHTS )) - { - dlight_t *dl; - - // big flash - dl = gEngfuncs.pEfxAPI->CL_AllocDLight( 0 ); - dl->origin = pos2; - dl->radius = 200; - dl->color.r = dl->color.g = 250; - dl->color.b = 150; - dl->die = GetClientTime() + 0.01f; - dl->decay = 800; - - // red glow - dl = gEngfuncs.pEfxAPI->CL_AllocDLight( 0 ); - dl->origin = pos2; - dl->radius = 150; - dl->color.r = 255; - dl->color.g= 190; - dl->color.b = 40; - dl->die = GetClientTime() + 1.0f; - dl->decay = 200; - } - } - - if(!( flags & TE_EXPLFLAG_NOPARTICLES )) - g_pParticles->ParticleEffect( pos, g_vecZero, 224, 200 ); - - if( flags & TE_EXPLFLAG_NOSOUND ) return; - - gEngfuncs.pEventAPI->EV_PlaySound( 0, pos2, CHAN_AUTO, "weapons/explode3.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM ); -} - -/* ---------------- -TE_ParseTarExplosion - -Creates a Quake1 "tarbaby" explosion with sound ---------------- -*/ -void TE_ParseTarExplosion( void ) -{ - Vector pos; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - g_pParticles->BlobExplosion( pos ); -} - -/* ---------------- -TE_ParseSmoke - -Creates alphablend sprite, move vertically 30 pps ---------------- -*/ -void TE_ParseSmoke( void ) -{ - TENT *pTemp; - float scale, framerate; - int modelIndex; - Vector pos; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - modelIndex = READ_SHORT(); - scale = (float)(READ_BYTE() * 0.1f); - framerate = (float)READ_BYTE(); - - // create smoke sprite - pTemp = g_pTempEnts->DefaultSprite( pos, modelIndex, framerate ); - g_pTempEnts->Sprite_Smoke( pTemp, scale ); -} - -/* ---------------- -TE_ParseTracer - -Creates tracer effect from point to point ---------------- -*/ -void TE_ParseTracer( void ) -{ - Vector start, end; - - start.x = READ_COORD(); // tracer start - start.y = READ_COORD(); - start.z = READ_COORD(); - - end.x = READ_COORD(); // tracer end - end.y = READ_COORD(); - end.z = READ_COORD(); - - EV_CreateTracer( start, end ); -} - -/* ---------------- -TE_ParseLighting - -version of TE_BEAMPOINTS with simplified parameters ---------------- -*/ -void TE_ParseLighting( void ) -{ - Vector start, end; - float life, width, noise; - int modelIndex; - - start.x = READ_COORD(); - start.y = READ_COORD(); - start.z = READ_COORD(); - - end.x = READ_COORD(); - end.y = READ_COORD(); - end.z = READ_COORD(); - - life = (float)(READ_BYTE() * 0.1f); - width = (float)(READ_BYTE() * 0.1f); - noise = (float)(READ_BYTE() * 0.1f); - modelIndex = READ_SHORT(); - - g_pViewRenderBeams->CreateBeamPoints( start, end, modelIndex, life, width, noise, 255, 1.0f, 0, 0, 255, 255, 255 ); -} - -/* ---------------- -TE_ParseBeamEnts - -Creates a beam between origins of two entities ---------------- -*/ -void TE_ParseBeamEnts( void ) -{ - int modelIndex, startEntity, endEntity, startFrame; - float life, width, noise, framerate, brightness, speed; - Vector vecColor; - - startEntity = READ_SHORT(); - endEntity = READ_SHORT(); - modelIndex = READ_SHORT(); - - startFrame = READ_BYTE(); - framerate = (float)(READ_BYTE() * 0.1f); - life = (float)(READ_BYTE() * 0.1f); - width = (float)(READ_BYTE() * 0.1f); - noise = (float)(READ_BYTE() * 0.1f); - - // renderinfo - vecColor.x = (float)READ_BYTE(); - vecColor.y = (float)READ_BYTE(); - vecColor.z = (float)READ_BYTE(); - brightness = (float)READ_BYTE(); - speed = (float)(READ_BYTE() * 0.1f); - - g_pViewRenderBeams->CreateBeamEnts( startEntity, endEntity, modelIndex, life, width, noise, brightness, - speed, startFrame, framerate, vecColor.x, vecColor.y, vecColor.z ); -} - -/* ---------------- -TE_ParseSparks - -Creates a 8 random tracers with gravity, ricochet sprite ---------------- -*/ -void TE_ParseSparks( void ) -{ - Vector pos; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - g_pTempEnts->SparkShower( pos ); -} - -/* ---------------- -TE_ParseLavaSplash - -Creates a Quake1 lava splash ---------------- -*/ -void TE_ParseLavaSplash( void ) -{ - Vector pos; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - g_pParticles->LavaSplash( pos ); -} - -/* ---------------- -TE_ParseTeleport - -Creates a Quake1 teleport splash ---------------- -*/ -void TE_ParseTeleport( void ) -{ - Vector pos; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - g_pParticles->TeleportSplash( pos ); -} - -/* ---------------- -TE_ParseExplosion2 - -Creates a Quake1 colormaped (base palette) particle explosion with sound ---------------- -*/ -void TE_ParseExplosion2( void ) -{ - Vector pos; - int colorIndex, numColors; - dlight_t *dl; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - colorIndex = READ_BYTE(); - numColors = READ_BYTE(); - - g_pParticles->ParticleExplosion2( pos, colorIndex, numColors ); - - dl = gEngfuncs.pEfxAPI->CL_AllocDLight( 0 ); - dl->origin = pos; - dl->radius = 350; - dl->color.r = dl->color.g = dl->color.b = 255; - dl->die = GetClientTime() + 0.5f; - dl->decay = 300; - - gEngfuncs.pEventAPI->EV_PlaySound( 0, pos, CHAN_AUTO, "weapons/explode3.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM ); -} - -/* ---------------- -TE_ParseBSPDecal - -Creates a decal from the .BSP file ---------------- -*/ -void TE_ParseBSPDecal( void ) -{ - Vector pos; - int decalIndex, entityIndex, modelIndex; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - decalIndex = READ_SHORT(); - entityIndex = READ_SHORT(); - if( entityIndex > 0 ) - modelIndex = READ_SHORT(); - else modelIndex = 0; - - g_pTempEnts->PlaceDecal( pos, entityIndex, decalIndex ); -} - -/* ---------------- -TE_ParseImplosion - -Creates a tracers moving toward a point ---------------- -*/ -void TE_ParseImplosion( void ) -{ - Vector pos; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - // FIXME: create tracers moving toward a point - gEngfuncs.pEventAPI->EV_PlaySound( 0, pos, CHAN_AUTO, "shambler/sattck1.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM ); -} - -/* ---------------- -TE_ParseStreakSplash - -Creates a oriented shower of tracers ---------------- -*/ -void TE_ParseStreakSplash( void ) -{ - Vector pos, dir; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - dir.x = READ_COORD(); - dir.y = READ_COORD(); - dir.z = READ_COORD(); - - int color = READ_BYTE(); - int count = READ_SHORT(); - int speed = READ_SHORT(); - int velocityRange = READ_SHORT(); - - g_pTempEnts->StreakSplash( pos, dir, color, count, speed, -velocityRange, velocityRange ); -} - -/* ---------------- -TE_ParseSpriteTrail - -Creates a line of moving glow sprites with gravity, fadeout, and collisions ---------------- -*/ -void TE_ParseSpriteTrail( void ) -{ - Vector start, end; - float life, scale, vel, random; - int spriteIndex, count; - - start.x = READ_COORD(); - start.y = READ_COORD(); - start.z = READ_COORD(); - - end.x = READ_COORD(); - end.y = READ_COORD(); - end.z = READ_COORD(); - - spriteIndex = READ_SHORT(); - count = READ_BYTE(); - life = (float)(READ_BYTE() * 0.1f); - scale = (float)(READ_BYTE() * 0.1f); - vel = (float)READ_BYTE(); - random = (float)READ_BYTE(); - - g_pTempEnts->Sprite_Trail( TE_SPRITETRAIL, start, end, spriteIndex, count, life, scale, random, 255, vel ); -} - -/* ---------------- -TE_ParseSprite - -Creates a additive sprite, plays 1 cycle ---------------- -*/ -void TE_ParseSprite( void ) -{ - Vector pos; - TENT *pTemp; - float scale, brightness; - int spriteIndex; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - spriteIndex = READ_SHORT(); - scale = (float)(READ_BYTE() * 0.1f); - brightness = (float)READ_BYTE(); - - pTemp = g_pTempEnts->DefaultSprite( pos, spriteIndex, 0 ); - - if( pTemp ) - { - pTemp->entity.baseline.scale = scale; - pTemp->entity.baseline.renderamt = brightness; - pTemp->entity.curstate.renderamt = brightness; - } -} - -/* ---------------- -TE_ParseBeamRing - -Generic function to parse various beam rings ---------------- -*/ -void TE_ParseBeamRing( int type ) -{ - Vector start, end, vecColor; - float life, framerate, width, noise, speed, brightness; - int spriteIndex, startFrame; - - start.x = READ_COORD(); - start.y = READ_COORD(); - start.z = READ_COORD(); - - end.x = READ_COORD(); - end.y = READ_COORD(); - end.z = READ_COORD(); - - spriteIndex = READ_SHORT(); - startFrame = READ_BYTE(); - framerate = (float)(READ_BYTE() * 0.1f); - life = (float)(READ_BYTE() * 0.1f); - width = (float)(READ_BYTE()); - noise = (float)(READ_BYTE() * 0.1f); - - // renderinfo - vecColor.x = (float)READ_BYTE(); - vecColor.y = (float)READ_BYTE(); - vecColor.z = (float)READ_BYTE(); - brightness = (float)READ_BYTE(); - speed = (float)(READ_BYTE() * 0.1f); - - g_pViewRenderBeams->CreateBeamCirclePoints( type, start, end, spriteIndex, life, width, width, 0.0f, - noise, brightness, speed, startFrame, framerate, vecColor.x, vecColor.y, vecColor.z ); -} - -/* ---------------- -TE_ParseBeamFollow - -Create a line of decaying beam segments until entity stops moving ---------------- -*/ -void TE_ParseBeamFollow( void ) -{ - int entityIndex, modelIndex; - float life, width, brightness; - Vector color; - - entityIndex = READ_SHORT(); - modelIndex = READ_SHORT(); - life = (float)(READ_BYTE() * 0.1f); - width = (float)READ_BYTE(); - - // parse color - color.x = READ_BYTE(); - color.y = READ_BYTE(); - color.z = READ_BYTE(); - brightness = READ_BYTE(); - - g_pViewRenderBeams->CreateBeamFollow( entityIndex, modelIndex, life, width, width, 0.0f, color.x, color.y, color.z, brightness ); -} - -/* ---------------- -TE_ParseBeamRing - -Creates a beam between two points ---------------- -*/ -void TE_ParseBeamRing( void ) -{ - int startEnt, endEnt, modelIndex, startFrame; - float frameRate, life, width; - float brightness, noise, speed; - Vector vecColor; - - startEnt = READ_SHORT(); - endEnt = READ_SHORT(); - - modelIndex= READ_SHORT(); - startFrame = READ_BYTE(); - frameRate = (float)(READ_BYTE()); - life = (float)(READ_BYTE() * 0.1f); - width = (float)(READ_BYTE() * 0.1f); - noise = (float)(READ_BYTE() * 0.1f); - - // renderinfo - vecColor.x = (float)READ_BYTE(); - vecColor.y = (float)READ_BYTE(); - vecColor.z = (float)READ_BYTE(); - brightness = (float)READ_BYTE(); - speed = (float)(READ_BYTE() * 0.1f); - - g_pViewRenderBeams->CreateBeamRing( startEnt, endEnt, modelIndex, life, width, width, 0.0f, noise, - brightness, speed, startFrame, frameRate, vecColor.x, vecColor.y, vecColor.z ); -} - -/* ---------------- -TE_ParseDynamicLight - -Creates a single source light ---------------- -*/ -void TE_ParseDynamicLight( int type ) -{ - Vector pos; - int iAttachment = 0; - cl_entity_t *pEnt = NULL; - float life, radius, decay; - byte r, g, b; - dlight_t *dl; - - if( type == TE_ELIGHT ) - { - int entIndex = READ_SHORT(); - pEnt = GetEntityByIndex( BEAMENT_ENTITY( entIndex )); - iAttachment = BEAMENT_ATTACHMENT( entIndex ); - } - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - - if( type == TE_ELIGHT ) - radius = (float)READ_COORD(); - else radius = (float)(READ_BYTE() * 0.1f); - - r = READ_BYTE(); - g = READ_BYTE(); - b = READ_BYTE(); - - life = (float)(READ_BYTE() * 0.1f); - - if( type == TE_ELIGHT ) - decay = (float)READ_COORD(); - else decay = (float)(READ_BYTE() * 0.1f); - - if( type == TE_ELIGHT ) - { - dl = gEngfuncs.pEfxAPI->CL_AllocELight( 0 ); - } - else - { - dl = gEngfuncs.pEfxAPI->CL_AllocDLight( 0 ); - } - - dl->origin = pos; - dl->radius = radius; - dl->decay = decay; - dl->color.r = r; - dl->color.g = g; - dl->color.b = b; - dl->die = GetClientTime() + life; -} - -/* ---------------- -TE_AddClientMessage - -show user message form server ---------------- -*/ -void TE_AddClientMessage( void ) -{ - const int MAX_CHANNELS = 4; // hl1 network specs - static client_textmessage_t gTextMsg[MAX_CHANNELS], *msg; - static char text[MAX_CHANNELS][512]; - static int msgindex = 0; - - int channel = READ_BYTE(); // channel - - if( channel <= 0 || channel > ( MAX_CHANNELS - 1 )) - { - // invalid channel specified, use internal counter - if( channel != 0 ) gEngfuncs.Con_Printf( "ERROR: HUD_Message: invalid channel %i\n", channel ); - channel = msgindex; - msgindex = (msgindex + 1) & (MAX_CHANNELS - 1); - } - - // grab message channel - msg = &gTextMsg[channel]; - msg->pMessage = text[channel]; - - ASSERT( msg != NULL ); - - msg->pName = "Text Message"; - msg->x = (float)(READ_SHORT() / 8192.0f); - msg->y = (float)(READ_SHORT() / 8192.0f); - msg->effect = READ_BYTE(); - msg->r1 = READ_BYTE(); - msg->g1 = READ_BYTE(); - msg->b1 = READ_BYTE(); - msg->a1 = READ_BYTE(); - msg->r2 = READ_BYTE(); - msg->g2 = READ_BYTE(); - msg->b2 = READ_BYTE(); - msg->a2 = READ_BYTE(); - msg->fadein = (float)( READ_SHORT() / 256.0f ); - msg->fadeout = (float)( READ_SHORT() / 256.0f ); - msg->holdtime = (float)( READ_SHORT() / 256.0f ); - - if( msg->effect == 2 ) - msg->fxtime = (float)( READ_SHORT() / 256.0f ); - else msg->fxtime = 0.0f; - - strcpy( (char *)msg->pMessage, READ_STRING()); - gHUD.m_Message.MessageAdd( msg ); -} - -/* ---------------- -TE_ParseKillBeam - -Kill all beams attached to entity ---------------- -*/ -void TE_ParseKillBeam( void ) -{ - cl_entity_t *pEntity = GetEntityByIndex( READ_SHORT() ); - - g_pViewRenderBeams->KillDeadBeams( pEntity ); -} - -/* ---------------- -TE_ParseFunnel - -see env_funnel description for details ---------------- -*/ -void TE_ParseFunnel( void ) -{ - Vector vecPos; - - vecPos.x = READ_COORD(); - vecPos.y = READ_COORD(); - vecPos.z = READ_COORD(); - - int spriteIndex = READ_SHORT(); - int flags = READ_SHORT(); - - g_pTempEnts->Large_Funnel( vecPos, spriteIndex, flags ); -} - -/* ---------------- -TE_ParseBlood - -create a particle spray ---------------- -*/ -void TE_ParseBlood( void ) -{ - Vector pos, dir; - int color, speed; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - dir.x = READ_COORD(); - dir.y = READ_COORD(); - dir.z = READ_COORD(); - color = READ_BYTE(); - speed = READ_BYTE(); - - g_pParticles->ParticleEffect( pos, dir, color, speed ); -} - -/* ---------------- -TE_ParseDecal - -generic message for place static decal ---------------- -*/ -void TE_ParseDecal( int type ) -{ - Vector pos; - int decalIndex, entityIndex; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - decalIndex = READ_BYTE(); - - if( type == TE_DECAL || type == TE_DECALHIGH ) - entityIndex = READ_SHORT(); - else entityIndex = 0; - - if( type == TE_DECALHIGH || type == TE_WORLDDECALHIGH ) - decalIndex += 256; - - g_pTempEnts->PlaceDecal( pos, entityIndex, decalIndex ); -} - -/* ---------------- -TE_ParseFizzEffect - -Create alpha sprites inside of entity, float upwards ---------------- -*/ -void TE_ParseFizzEffect( void ) -{ - int modelIndex, density; - cl_entity_t *pEnt; - - pEnt = GetEntityByIndex( READ_SHORT()); - modelIndex = READ_SHORT(); - density = READ_BYTE(); - - g_pTempEnts->FizzEffect( pEnt, modelIndex, density ); -} - -/* ---------------- -TE_ParseTempModel - -Create a moving model that bounces and makes a sound when it hits ---------------- -*/ -void TE_ParseTempModel( void ) -{ - Vector pos, dir, rot; - int modelIndex, soundType; - float decay; - - pos.x = READ_COORD(); // pos - pos.y = READ_COORD(); - pos.z = READ_COORD(); - dir.x = READ_COORD(); // velocity - dir.y = READ_COORD(); - dir.z = READ_COORD(); - - rot = Vector( 0.0f, READ_ANGLE(), 0.0f ); // yaw - modelIndex = READ_SHORT(); - soundType = READ_BYTE(); - decay = (float)(READ_BYTE() * 0.1f); - - g_pTempEnts->TempModel( pos, dir, rot, decay, modelIndex, soundType ); -} - -/* ---------------- -TE_ParseBreakModel - -Create a box of models or sprites ---------------- -*/ -void TE_ParseBreakModel( void ) -{ - Vector pos, size, dir; - float random, decay; - int modelIndex, count, flags; - - pos.x = READ_COORD(); // breakmodel center - pos.y = READ_COORD(); - pos.z = READ_COORD(); - size.x = READ_COORD(); // bmodel size - size.y = READ_COORD(); - size.z = READ_COORD(); - dir.x = READ_COORD(); // damage direction with velocity - dir.y = READ_COORD(); - dir.z = READ_COORD(); - random = (float)(READ_BYTE()); - modelIndex = READ_SHORT(); // shard model - count = READ_BYTE(); // # of shards ( 0 - autodetect by size ) - decay = (float)(READ_BYTE() * 0.1f); - flags = READ_BYTE(); // material flags - - g_pTempEnts->BreakModel( pos, size, dir, random, decay, count, modelIndex, flags ); -} - -/* ---------------- -TE_ParseGunShotDecal - -decal and ricochet sound ---------------- -*/ -void TE_ParseGunShotDecal( void ) -{ - Vector pos; - int entityIndex, decalIndex; - char soundpath[32]; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - entityIndex = READ_SHORT(); - decalIndex = READ_BYTE(); - - g_pTempEnts->PlaceDecal( pos, entityIndex, decalIndex ); - - if( RANDOM_LONG( 0, 32 ) <= 8 ) // 25% chanse - { - int iPitch = RANDOM_LONG( 90, 105 ); - float fvol = RANDOM_FLOAT( 0.7f, 0.9f ); - sprintf( soundpath, "weapons/ric%i.wav", RANDOM_LONG( 1, 5 )); - gEngfuncs.pEventAPI->EV_PlaySound( 0, pos, CHAN_AUTO, soundpath, fvol, ATTN_NORM, 0, iPitch ); - } -} - -/* ---------------- -TE_ParseSpriteSpray - -spray of alpha sprites ---------------- -*/ -void TE_ParseSpriteSpray( int type ) -{ - Vector pos, vel; - int spriteIndex, count, speed, noise; - int renderMode; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - vel.x = READ_COORD(); - vel.y = READ_COORD(); - vel.z = READ_COORD(); - spriteIndex = READ_SHORT(); - count = READ_BYTE(); - speed = READ_BYTE(); - noise = READ_BYTE(); - - if( type == TE_SPRAY ) - { - renderMode = READ_BYTE(); - g_pTempEnts->Sprite_Spray( pos, vel, spriteIndex, count, speed, noise, renderMode ); - } - else - { - g_pTempEnts->Sprite_Spray( pos, vel, spriteIndex, count, speed, noise ); - } -} - -/* ---------------- -TE_ParseArmorRicochet - -quick spark sprite, client ricochet sound. ---------------- -*/ -void TE_ParseArmorRicochet( void ) -{ - Vector pos; - float radius; - char soundpath[32]; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - radius = (float)(READ_BYTE() * 0.1f); - - int modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/richo1.spr" ); - g_pTempEnts->RicochetSprite( pos, modelIndex, radius ); - - int iPitch = RANDOM_LONG( 90, 105 ); - float fvol = RANDOM_FLOAT( 0.7f, 0.9f ); - sprintf( soundpath, "weapons/ric%i.wav", RANDOM_LONG( 1, 5 )); - gEngfuncs.pEventAPI->EV_PlaySound( 0, pos, CHAN_AUTO, soundpath, fvol, ATTN_NORM, 0, iPitch ); -} - -/* ---------------- -TE_ParseBubblesEffect - -Create a colored decal, get settings from client ---------------- -*/ -void TE_ParsePlayerDecal( void ) -{ - int clientIndex, decalIndex, entityIndex; - byte color[4]; - Vector pos; - - clientIndex = READ_BYTE(); - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - entityIndex = READ_SHORT(); - decalIndex = READ_BYTE(); - - // FIXME: get logo color from user variable - color[0] = 255; - color[1] = 255; - color[2] = 255; - color[3] = 255; // alpha - - HSPRITE hDecal = gEngfuncs.pEfxAPI->CL_DecalIndex( decalIndex ); - gEngfuncs.pEfxAPI->R_PlayerDecal( hDecal, entityIndex, pos, 0 ); -} - -/* ---------------- -TE_ParseBubblesEffect - -Create alpha sprites inside of box, float upwards ---------------- -*/ -void TE_ParseBubblesEffect( void ) -{ - Vector mins, maxs; - int modelIndex, count; - float height, speed; - - maxs.x = READ_COORD(); - maxs.y = READ_COORD(); - maxs.z = READ_COORD(); - maxs.x = READ_COORD(); - maxs.y = READ_COORD(); - maxs.z = READ_COORD(); - height = READ_COORD(); - modelIndex = READ_SHORT(); - count = READ_BYTE(); - speed = READ_COORD(); - - g_pTempEnts->Bubbles( mins, maxs, height, modelIndex, count, speed ); -} - -/* ---------------- -TE_ParseBubbleTrail - -Create alpha sprites along a line, float upwards ---------------- -*/ -void TE_ParseBubbleTrail( void ) -{ - Vector start, end; - int modelIndex, count; - float height, speed; - - start.x = READ_COORD(); - start.y = READ_COORD(); - start.z = READ_COORD(); - end.x = READ_COORD(); - end.y = READ_COORD(); - end.z = READ_COORD(); - height = READ_COORD(); - modelIndex = READ_SHORT(); - count = READ_BYTE(); - speed = READ_COORD(); - - g_pTempEnts->BubbleTrail( start, end, height, modelIndex, count, speed ); -} - -/* ---------------- -TE_ParseBloodSprite - -Spray of opaque sprite1's that fall, single sprite2 for 1..2 secs -(this is a high-priority tent) ---------------- -*/ -void TE_ParseBloodSprite( void ) -{ - Vector pos; - int modelIndex, modelIndex2, iColor; - float scale; - - pos.x = READ_COORD(); - pos.y = READ_COORD(); - pos.z = READ_COORD(); - modelIndex = READ_SHORT(); - modelIndex2 =READ_SHORT(); - iColor = READ_BYTE(); - scale = (float)READ_BYTE(); - - g_pTempEnts->BloodSprite( pos, iColor, modelIndex, modelIndex2, scale ); -} - -/* ---------------- -TE_ParseAttachTentToPlayer - -Attaches a TENT to a player -(this is a high-priority tent) ---------------- -*/ -void TE_ParseAttachTentToPlayer( void ) -{ - int clientIndex, modelIndex; - float zoffset, life; - - clientIndex = READ_BYTE(); - zoffset = READ_COORD(); - modelIndex = READ_SHORT(); - life = (float)(READ_BYTE() * 0.1f); - - g_pTempEnts->AttachTentToPlayer( clientIndex, modelIndex, zoffset, life ); -} - -/* ---------------- -TE_KillAttachedTents - -will expire all TENTS attached to a player. ---------------- -*/ -void TE_KillAttachedTents( void ) -{ - int clientIndex = READ_BYTE(); - - g_pTempEnts->KillAttachedTents( clientIndex ); -} - -/* ---------------- -HUD_ParseTempEntity - -main switch for all tempentities ---------------- -*/ -void HUD_ParseTempEntity( void ) -{ - switch( READ_BYTE() ) - { - case TE_BEAMPOINTS: - TE_ParseBeamPoints(); - break; - case TE_BEAMENTPOINT: - TE_ParseBeamEntPoint(); - break; - case TE_GUNSHOT: - TE_ParseGunShot(); - break; - case TE_EXPLOSION: - TE_ParseExplosion(); - break; - case TE_TAREXPLOSION: - TE_ParseTarExplosion(); - break; - case TE_SMOKE: - TE_ParseSmoke(); - break; - case TE_TRACER: - TE_ParseTracer(); - break; - case TE_LIGHTNING: - TE_ParseLighting(); - break; - case TE_BEAMENTS: - TE_ParseBeamEnts(); - break; - case TE_SPARKS: - TE_ParseSparks(); - break; - case TE_LAVASPLASH: - TE_ParseLavaSplash(); - break; - case TE_TELEPORT: - TE_ParseTeleport(); - break; - case TE_EXPLOSION2: - TE_ParseExplosion2(); - break; - case TE_BSPDECAL: - TE_ParseBSPDecal(); - break; - case TE_IMPLOSION: - TE_ParseImplosion(); - break; - case TE_SPRITETRAIL: - TE_ParseSpriteTrail(); - break; - case TE_SPRITE: - TE_ParseSprite(); - break; - case TE_BEAMSPRITE: - // FIXME: implement - break; - case TE_BEAMTORUS: - TE_ParseBeamRing( TE_BEAMTORUS ); - break; - case TE_BEAMDISK: - TE_ParseBeamRing( TE_BEAMDISK ); - break; - case TE_BEAMCYLINDER: - TE_ParseBeamRing( TE_BEAMCYLINDER ); - break; - case TE_BEAMFOLLOW: - TE_ParseBeamFollow(); - break; - case TE_GLOWSPRITE: - // FIXME: implement - break; - case TE_BEAMRING: - TE_ParseBeamRing(); - break; - case TE_STREAK_SPLASH: - TE_ParseStreakSplash(); - break; - case TE_ELIGHT: - TE_ParseDynamicLight( TE_ELIGHT ); - break; - case TE_DLIGHT: - TE_ParseDynamicLight( TE_DLIGHT ); - break; - case TE_TEXTMESSAGE: - TE_AddClientMessage(); - break; - case TE_LINE: - // FIXME: implement - break; - case TE_BOX: - // FIXME: implement - break; - case TE_KILLBEAM: - TE_ParseKillBeam(); - break; - case TE_LARGEFUNNEL: - TE_ParseFunnel(); - break; - case TE_BLOODSTREAM: - // FIXME: implement - break; - case TE_SHOWLINE: - // FIXME: implement - break; - case TE_BLOOD: - TE_ParseBlood(); - break; - case TE_DECAL: - TE_ParseDecal( TE_DECAL ); - break; - case TE_FIZZ: - TE_ParseFizzEffect(); - break; - case TE_MODEL: - TE_ParseTempModel(); - break; - case TE_EXPLODEMODEL: - // FIXME: implement - break; - case TE_BREAKMODEL: - TE_ParseBreakModel(); - break; - case TE_GUNSHOTDECAL: - TE_ParseGunShotDecal(); - break; - case TE_SPRITE_SPRAY: - TE_ParseSpriteSpray( TE_SPRITE_SPRAY ); - break; - case TE_ARMOR_RICOCHET: - TE_ParseArmorRicochet(); - break; - case TE_PLAYERDECAL: - TE_ParsePlayerDecal(); - break; - case TE_BUBBLES: - TE_ParseBubblesEffect(); - break; - case TE_BUBBLETRAIL: - TE_ParseBubbleTrail(); - break; - case TE_BLOODSPRITE: - TE_ParseBloodSprite(); - break; - case TE_WORLDDECAL: - TE_ParseDecal( TE_WORLDDECAL ); - break; - case TE_WORLDDECALHIGH: - TE_ParseDecal( TE_WORLDDECALHIGH ); - break; - case TE_DECALHIGH: - TE_ParseDecal( TE_DECALHIGH ); - break; - case TE_PROJECTILE: - // FIXME: implement - break; - case TE_SPRAY: - TE_ParseSpriteSpray( TE_SPRAY ); - break; - case TE_PLAYERSPRITES: - // FIXME: implement - break; - case TE_PARTICLEBURST: - // FIXME: implement - break; - case TE_FIREFIELD: - // FIXME: implement - break; - case TE_PLAYERATTACHMENT: - TE_ParseAttachTentToPlayer(); - break; - case TE_KILLPLAYERATTACHMENTS: - TE_KillAttachedTents(); - break; - case TE_MULTIGUNSHOT: - // FIXME: implement - break; - case TE_USERTRACER: - // FIXME: implement - break; - } -} \ No newline at end of file diff --git a/client/global/dll_int.cpp b/client/global/dll_int.cpp deleted file mode 100644 index 82f30dac..00000000 --- a/client/global/dll_int.cpp +++ /dev/null @@ -1,415 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// dll_int.cpp - dll entry points -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "ref_params.h" -#include "studio.h" -#include "hud.h" -#include "aurora.h" -#include "r_efx.h" -#include "r_particle.h" -#include "r_tempents.h" -#include "r_beams.h" -#include "ev_hldm.h" -#include "r_weather.h" -#include "pm_shared.h" -#include "pm_movevars.h" -#include "entity_types.h" - -cl_enginefunc_t gEngfuncs; -int g_iPlayerClass; -int g_iTeamNumber; -int g_iUser1; -int g_iUser2; -int g_iUser3; -CHud gHUD; - -// main DLL entry point -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) -{ - return TRUE; -} - -static HUD_FUNCTIONS gFunctionTable = -{ - HUD_VidInit, - HUD_Init, - HUD_Redraw, - HUD_UpdateClientData, - HUD_GetHullBounds, - HUD_TxferLocalOverrides, - HUD_ProcessPlayerState, - HUD_UpdateOnRemove, - HUD_Reset, - HUD_StartFrame, - HUD_Frame, - HUD_Shutdown, - HUD_RenderCallback, - HUD_CreateEntities, - HUD_AddVisibleEntity, - HUD_StudioEvent, - HUD_StudioFxTransform, - V_CalcRefdef, - PM_Move, // pfnPM_Move - PM_Init, // pfnPM_Init - PM_FindTextureType, // pfnPM_FindTextureType - HUD_CmdStart, - HUD_CmdEnd, - IN_CreateMove, - IN_MouseEvent, - IN_KeyEvent, - VGui_ConsolePrint, - HUD_ParticleEffect, - HUD_TempEntityMessage, - HUD_DirectorMessage, -}; - -//======================================================================= -// GetApi -//======================================================================= -int CreateAPI( HUD_FUNCTIONS *pFunctionTable, cl_enginefunc_t* pEngfuncsFromEngine ) -{ - if( !pFunctionTable || !pEngfuncsFromEngine ) - { - return FALSE; - } - - // copy HUD_FUNCTIONS table to engine, copy engfuncs table from engine - memcpy( pFunctionTable, &gFunctionTable, sizeof( HUD_FUNCTIONS )); - memcpy( &gEngfuncs, pEngfuncsFromEngine, sizeof( cl_enginefunc_t )); - - return TRUE; -} - -int HUD_VidInit( void ) -{ - if ( g_pParticleSystems ) - g_pParticleSystems->ClearSystems(); - - if ( g_pViewRenderBeams ) - g_pViewRenderBeams->ClearBeams(); - - if ( g_pParticles ) - g_pParticles->Clear(); - - if ( g_pTempEnts ) - g_pTempEnts->Clear(); - - ResetRain (); - - gHUD.VidInit(); - - return 1; -} - -void HUD_ShutdownEffects( void ) -{ - if ( g_pParticleSystems ) - { - // init partsystem - delete g_pParticleSystems; - g_pParticleSystems = NULL; - } - - if ( g_pViewRenderBeams ) - { - // init render beams - delete g_pViewRenderBeams; - g_pViewRenderBeams = NULL; - } - - if ( g_pParticles ) - { - // init particles - delete g_pParticles; - g_pParticles = NULL; - } - - if ( g_pTempEnts ) - { - // init client tempents - delete g_pTempEnts; - g_pTempEnts = NULL; - } -} - -void HUD_Init( void ) -{ - HUD_ShutdownEffects (); - - g_pParticleSystems = new ParticleSystemManager(); - g_pViewRenderBeams = new CViewRenderBeams(); - g_pParticles = new CParticleSystem(); - g_pTempEnts = new CTempEnts(); - - InitRain(); // init weather system - - gHUD.Init(); - - IN_Init (); - - // link all events - EV_HookEvents (); -} - -/* -================================ -HUD_GetHullBounds - -Engine calls this to enumerate player collision hulls, for prediction. -Return 0 if the hullnumber doesn't exist. -================================ -*/ -int HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ) -{ - int iret = 0; - - switch( hullnumber ) - { - case 0: // Normal player - VEC_HULL_MIN.CopyToArray( mins ); - VEC_HULL_MAX.CopyToArray( maxs ); - iret = 1; - break; - case 1: // Crouched player - VEC_DUCK_HULL_MIN.CopyToArray( mins ); - VEC_DUCK_HULL_MAX.CopyToArray( maxs ); - iret = 1; - break; - case 2: // Point based hull - g_vecZero.CopyToArray( mins ); - g_vecZero.CopyToArray( maxs ); - iret = 1; - break; - } - return iret; -} - -/* -========================== - HUD_UpdateClientData - -called every time shared client -dll/engine data gets changed, -and gives the cdll a chance -to modify the data. - -returns 1 if anything has been changed, 0 otherwise. -========================== -*/ - -int HUD_UpdateClientData( client_data_t *pcldata, float flTime ) -{ - return gHUD.UpdateClientData( pcldata, flTime ); -} - -int HUD_Redraw( float flTime, int intermission ) -{ - gHUD.Redraw( flTime ); - - return 1; -} - -/* -========================= -HUD_UpdateClientVars - -The server sends us our origin with extra precision as part of the clientdata structure, not during the normal -playerstate update in entity_state_t. In order for these overrides to eventually get to the appropriate playerstate -structure, we need to copy them into the state structure at this point. -========================= -*/ -void HUD_TxferLocalOverrides( entity_state_t *state, const clientdata_t *client ) -{ - state->origin = client->origin; - - // Spectator - state->iuser1 = client->iuser1; - state->iuser2 = client->iuser2; - - // Duck prevention - state->iuser3 = client->iuser3; - - // Fire prevention - state->iuser4 = client->iuser4; - - // FIXME: move this stuff into TxferPredictionData when it will be done - - // Spectating or not dead == get control over view angles. - g_iAlive = ( client->iuser1 || ( client->deadflag == DEAD_NO ) ) ? 1 : 0; - - // FIXME: temporary hack so gaitsequence it's works properly - state->velocity = client->velocity; -} - -/* -========================= -HUD_ProcessPlayerState - -We have received entity_state_t for this player over the network. We need to copy appropriate fields to the -playerstate structure -========================= -*/ -void HUD_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ) -{ - // Copy in network data - dst->origin = src->origin; - dst->angles = src->angles; - - dst->velocity = src->velocity; - - dst->frame = src->frame; - dst->modelindex = src->modelindex; - dst->skin = src->skin; - dst->effects = src->effects; - dst->weaponmodel = src->weaponmodel; - dst->movetype = src->movetype; - dst->sequence = src->sequence; - dst->animtime = src->animtime; - - dst->solid = src->solid; - - dst->rendermode = src->rendermode; - dst->renderamt = src->renderamt; - dst->rendercolor.r = src->rendercolor.r; - dst->rendercolor.g = src->rendercolor.g; - dst->rendercolor.b = src->rendercolor.b; - dst->renderfx = src->renderfx; - - dst->framerate = src->framerate; - dst->body = src->body; - - memcpy( &dst->controller[0], &src->controller[0], 4 * sizeof( byte ) ); - memcpy( &dst->blending[0], &src->blending[0], 2 * sizeof( byte ) ); - - dst->basevelocity = src->basevelocity; - - dst->friction = src->friction; - dst->gravity = src->gravity; - dst->gaitsequence = src->gaitsequence; - dst->spectator = src->spectator; - dst->usehull = src->usehull; - dst->playerclass = src->playerclass; - dst->team = src->team; - dst->colormap = src->colormap; - - // Save off some data so other areas of the Client DLL can get to it - cl_entity_t *player = GetLocalPlayer(); // Get the local player's index - if ( dst->number == player->index ) - { - g_iPlayerClass = dst->playerclass; - g_iTeamNumber = dst->team; - - g_iUser1 = src->iuser1; - g_iUser2 = src->iuser2; - g_iUser3 = src->iuser3; - } -} - -int HUD_AddVisibleEntity( cl_entity_t *pEnt, int entityType ) -{ - int result; - - result = gEngfuncs.CL_CreateVisibleEntity( entityType, pEnt ); - - if ( pEnt->curstate.effects & EF_BRIGHTFIELD ) - { - g_pParticles->EntityParticles( pEnt ); - } - - // add in muzzleflash effect - if ( pEnt->curstate.effects & EF_MUZZLEFLASH ) - { - if( entityType == ET_VIEWENTITY ) - pEnt->curstate.effects &= ~EF_MUZZLEFLASH; - g_pTempEnts->WeaponFlash( pEnt, 1 ); - } - - // add light effect - if ( pEnt->curstate.effects & EF_LIGHT ) - { - g_pTempEnts->AllocDLight( pEnt->curstate.origin, 100, 100, 100, 200, 0.001f ); - g_pTempEnts->RocketFlare( pEnt->curstate.origin ); - } - - // add dimlight - if ( pEnt->curstate.effects & EF_DIMLIGHT ) - { - if ( entityType == ET_PLAYER ) - { - EV_UpadteFlashlight( pEnt ); - } - else - { - g_pTempEnts->AllocDLight( pEnt->curstate.origin, RANDOM_LONG( 200, 230 ), 0.001f ); - } - } - - // NOTE: Xash3D sent entities to client even if it has EF_NODRAW flags - // run simple check here to prevent lighting invisible entity - if ( pEnt->curstate.effects & EF_BRIGHTLIGHT && !( pEnt->curstate.effects & EF_NODRAW )) - { - Vector pos( pEnt->curstate.origin.x, pEnt->curstate.origin.y, pEnt->curstate.origin.z + 16 ); - g_pTempEnts->AllocDLight( pos, RANDOM_LONG( 400, 430 ), 0.001f ); - } - - return result; -} - -void HUD_CreateEntities( void ) -{ - EV_UpdateBeams (); // egon use this - EV_UpdateLaserSpot (); // predictable laserspot - - g_pTempEnts->Update(); -} - -void HUD_UpdateOnRemove( cl_entity_t *pEdict ) -{ - // move TE_BEAMTRAIL, kill other beams - g_pViewRenderBeams->KillDeadBeams( pEdict ); -} - -void HUD_Reset( void ) -{ - HUD_VidInit (); -} - -void HUD_StartFrame( void ) -{ - // clear list of server beams after each frame - g_pViewRenderBeams->ClearServerBeams( ); -} - -void HUD_ParticleEffect( const float *org, const float *dir, int color, int count ) -{ - g_pParticles->ParticleEffect( org, dir, color, count ); -} - -void HUD_TempEntityMessage( int iSize, void *pbuf ) -{ - BEGIN_READ( "TempEntity", iSize, pbuf ); - HUD_ParseTempEntity(); - END_READ(); -} - -void HUD_DirectorMessage( int iSize, void *pbuf ) -{ - // FIXME: implement -} - -void HUD_Frame( double time ) -{ - // place to call vgui_frame - // VGUI not implemented, wait for version 0.75 -} - -void HUD_Shutdown( void ) -{ - HUD_ShutdownEffects (); - - IN_Shutdown (); -} \ No newline at end of file diff --git a/client/global/enginecallback.h b/client/global/enginecallback.h deleted file mode 100644 index 875ad910..00000000 --- a/client/global/enginecallback.h +++ /dev/null @@ -1,86 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// enginecallback.h - actual engine callbacks -//======================================================================= - -#ifndef ENGINECALLBACKS_H -#define ENGINECALLBACKS_H - -// screen handlers -#define SPR_GetList (*gEngfuncs.pfnSPR_GetList) -#define SPR_Frames (*gEngfuncs.pfnSPR_Frames) -#define SPR_Width (*gEngfuncs.pfnSPR_Width) -#define SPR_Height (*gEngfuncs.pfnSPR_Height) -#define SPR_EnableScissor (*gEngfuncs.pfnSPR_EnableScissor) -#define SPR_DisableScissor (*gEngfuncs.pfnSPR_DisableScissor) -#define FillRGBA (*gEngfuncs.pfnFillRGBA) -#define GetScreenInfo (*gEngfuncs.pfnGetScreenInfo) - -#define SPR_Load (*gEngfuncs.pfnSPR_Load) -#define TEX_Load( x ) (*gEngfuncs.pTriAPI->LoadShader)( x, false ) -#define TEX_LoadNoMip( x ) (*gEngfuncs.pTriAPI->LoadShader)( x, true ) -#define SetCrosshair (*gEngfuncs.pfnSetCrosshair) - -#define SendWeaponAnim (*gEngfuncs.pEventAPI->EV_WeaponAnimation) -#define CVAR_REGISTER (*gEngfuncs.pfnRegisterVariable) -#define CVAR_SET_FLOAT (*gEngfuncs.Cvar_SetValue) -#define CVAR_GET_FLOAT (*gEngfuncs.pfnGetCvarFloat) -#define CVAR_GET_STRING (*gEngfuncs.pfnGetCvarString) -#define SERVER_COMMAND (*gEngfuncs.pfnServerCmd) -#define CLIENT_COMMAND (*gEngfuncs.pfnClientCmd) -#define GetPlayerInfo (*gEngfuncs.pfnGetPlayerInfo) -#define TextMessageGet (*gEngfuncs.pfnTextMessageGet) -#define Cmd_AddCommand (*gEngfuncs.pfnAddCommand) -#define CMD_ARGC (*gEngfuncs.Cmd_Argc) -#define CMD_ARGV (*gEngfuncs.Cmd_Argv) - -inline void SPR_Set( HSPRITE hPic, int r, int g, int b ) -{ - gEngfuncs.pfnSPR_Set( hPic, r, g, b ); -} - -inline void SPR_Draw( int frame, int x, int y, const wrect_t *prc ) -{ - gEngfuncs.pfnSPR_Draw( frame, x, y, prc ); -} - -inline void SPR_DrawHoles( int frame, int x, int y, const wrect_t *prc ) -{ - gEngfuncs.pfnSPR_DrawHoles( frame, x, y, prc ); -} - -inline void SPR_DrawAdditive( int frame, int x, int y, const wrect_t *prc ) -{ - gEngfuncs.pfnSPR_DrawAdditive( frame, x, y, prc ); -} - -// sound functions -inline void PlaySound( char *szSound, float vol ) { gEngfuncs.pfnPlaySoundByName( szSound, vol ); } -inline void PlaySound( int iSound, float vol ) { gEngfuncs.pfnPlaySoundByIndex( iSound, vol ); } - -#define TextMessageDrawChar (*gEngfuncs.pfnDrawCharacter) -#define TextMessageSetColor (*gEngfuncs.pfnDrawSetTextColor) -#define DrawConsoleString (*gEngfuncs.pfnDrawConsoleString) -#define GetConsoleStringSize (*gEngfuncs.pfnDrawConsoleStringLen) -#define AngleVectors (*gEngfuncs.pfnAngleVectors) -#define CenterPrint (*gEngfuncs.pfnCenterPrint) -#define ConsolePrint (*gEngfuncs.pfnConsolePrint) -#define GetViewAngles (*gEngfuncs.GetViewAngles) -#define SetViewAngles (*gEngfuncs.SetViewAngles) -#define GetLocalPlayer (*gEngfuncs.GetLocalPlayer) -#define GetClientMaxspeed (*gEngfuncs.GetClientMaxspeed) -#define IsSpectateOnly (*gEngfuncs.IsSpectateOnly) -#define GetClientTime (*gEngfuncs.GetClientTime) -#define GetViewModel (*gEngfuncs.GetViewModel) -#define GetModelPtr (*gEngfuncs.pfnGetModelPtr) -#define CL_GetPaletteColor (*gEngfuncs.pEfxAPI->R_GetPaletteColor) -#define POINT_CONTENTS( x ) (*gEngfuncs.PM_PointContents)( x, NULL ) -#define TRACE_LINE (*gEngfuncs.pfnTraceLine) -#define TRACE_HULL (*gEngfuncs.pfnTraceHull) -#define RANDOM_LONG (*gEngfuncs.pfnRandomLong) -#define RANDOM_FLOAT (*gEngfuncs.pfnRandomFloat) -#define HOST_ERROR (*gEngfuncs.pfnHostError) -#define MAKE_ENVSHOT( x, y ) (*gEngfuncs.R_EnvShot)( x, y, 0 ) -#define MAKE_SKYSHOT( x, y ) (*gEngfuncs.R_EnvShot)( x, y, 1 ) - -#endif//ENGINECALLBACKS_H \ No newline at end of file diff --git a/client/global/ev_common.cpp b/client/global/ev_common.cpp deleted file mode 100644 index c796d6f4..00000000 --- a/client/global/ev_common.cpp +++ /dev/null @@ -1,282 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// ev_common.cpp - events common code -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "ev_hldm.h" -#include "event_args.h" -#include "r_tempents.h" -#include "pm_defs.h" -#include "hud.h" - -void EV_FireGlock1( struct event_args_s *args ); -void EV_FireGlock2( struct event_args_s *args ); -void EV_FireShotGunSingle( struct event_args_s *args ); -void EV_FireShotGunDouble( struct event_args_s *args ); -void EV_FireMP5( struct event_args_s *args ); -void EV_FireMP52( struct event_args_s *args ); -void EV_FirePython( struct event_args_s *args ); -void EV_FireGauss( struct event_args_s *args ); -void EV_SpinGauss( struct event_args_s *args ); -void EV_Crowbar( struct event_args_s *args ); -void EV_FireCrossbow( struct event_args_s *args ); -void EV_FireCrossbow2( struct event_args_s *args ); -void EV_FireRpg( struct event_args_s *args ); -void EV_EgonFire( struct event_args_s *args ); -void EV_EgonStop( struct event_args_s *args ); -void EV_HornetGunFire( struct event_args_s *args ); -void EV_TripmineFire( struct event_args_s *args ); -void EV_SnarkFire( struct event_args_s *args ); -void EV_TrainPitchAdjust( struct event_args_s *args ); - -//====================== -// Game_HookEvents -//====================== -void EV_HookEvents( void ) -{ - gEngfuncs.pfnHookEvent( "events/glock1.sc", EV_FireGlock1 ); - gEngfuncs.pfnHookEvent( "events/glock2.sc", EV_FireGlock2 ); - gEngfuncs.pfnHookEvent( "events/shotgun1.sc", EV_FireShotGunSingle ); - gEngfuncs.pfnHookEvent( "events/shotgun2.sc", EV_FireShotGunDouble ); - gEngfuncs.pfnHookEvent( "events/mp5.sc", EV_FireMP5 ); - gEngfuncs.pfnHookEvent( "events/mp52.sc", EV_FireMP52 ); - gEngfuncs.pfnHookEvent( "events/python.sc", EV_FirePython ); - gEngfuncs.pfnHookEvent( "events/gauss.sc", EV_FireGauss ); - gEngfuncs.pfnHookEvent( "events/gaussspin.sc", EV_SpinGauss ); - gEngfuncs.pfnHookEvent( "events/train.sc", EV_TrainPitchAdjust ); - gEngfuncs.pfnHookEvent( "events/crowbar.sc", EV_Crowbar ); - gEngfuncs.pfnHookEvent( "events/crossbow1.sc", EV_FireCrossbow ); - gEngfuncs.pfnHookEvent( "events/crossbow2.sc", EV_FireCrossbow2 ); - gEngfuncs.pfnHookEvent( "events/rpg.sc", EV_FireRpg ); - gEngfuncs.pfnHookEvent( "events/egon_fire.sc", EV_EgonFire ); - gEngfuncs.pfnHookEvent( "events/egon_stop.sc", EV_EgonStop ); - gEngfuncs.pfnHookEvent( "events/firehornet.sc", EV_HornetGunFire ); - gEngfuncs.pfnHookEvent( "events/tripfire.sc", EV_TripmineFire ); - gEngfuncs.pfnHookEvent( "events/snarkfire.sc", EV_SnarkFire ); -} - -/* -================= -GetEntity - -Return's the requested cl_entity_t -================= -*/ -cl_entity_t *GetEntity( int idx ) -{ - return GetEntityByIndex( idx ); -} - -/* -================= -GetViewEntity - -Return's the current weapon/view model -================= -*/ -cl_entity_t *GetViewEntity( void ) -{ - return GetViewModel(); -} - -//================= -// EV_CreateTracer -//================= -void EV_CreateTracer( float *start, float *end ) -{ - g_pTempEnts->TracerEffect( start, end ); -} - - -//================= -// EV_IsPlayer -//================= -int EV_IsPlayer( int idx ) -{ - if ( idx >= 1 && idx <= gEngfuncs.GetMaxClients() ) - return true; - return false; -} - - -//================= -// EV_IsLocal -//================= -int EV_IsLocal( int idx ) -{ - return gEngfuncs.pEventAPI->EV_IsLocal( idx - 1 ) ? true : false; -} - - -//================= -// EV_GetGunPosition -//================= -void EV_GetGunPosition( event_args_t *args, float *pos, float *origin ) -{ - int idx; - Vector view_ofs; - - idx = args->entindex; - - view_ofs = Vector( 0, 0, 0 ); - view_ofs.z = DEFAULT_VIEWHEIGHT; - - if ( EV_IsPlayer( idx )) - { - // in spec mode use entity viewheigh, not own - if ( EV_IsLocal( idx )) - { - // Grab predicted result for local player - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - } - else if ( args->ducking == 1 ) - { - view_ofs[2] = VEC_DUCK_VIEW; - } - } - - pos[0] = origin[0] + view_ofs.x; - pos[1] = origin[1] + view_ofs.y; - pos[2] = origin[2] + view_ofs.z; -} - - -//================= -// EV_EjectBrass -//================= -void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ) -{ - Vector endpos = Vector( 0.0f, rotation, 0.0f ); - - g_pTempEnts->TempModel( origin, velocity, endpos, RANDOM_LONG( 30, 50 ), model, soundtype ); -} - - -//================= -// EV_GetDefaultShellInfo -//================= -void EV_GetDefaultShellInfo( event_args_t *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ) -{ - int idx; - Vector view_ofs; - float fR, fU; - - idx = args->entindex; - view_ofs = Vector( 0, 0, 0 ); - view_ofs.z = DEFAULT_VIEWHEIGHT; - - if ( EV_IsPlayer( idx ) ) - { - if ( EV_IsLocal( idx ) ) - { - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - } - else if ( args->ducking == 1 ) - { - view_ofs[2] = VEC_DUCK_VIEW; - } - } - - fR = RANDOM_FLOAT( 50, 70 ); - fU = RANDOM_FLOAT( 100, 150 ); - - for ( int i = 0; i < 3; i++ ) - { - ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; - ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * upScale + forward[i] * forwardScale + right[i] * rightScale; - } -} - -//================= -// EV_MuzzleFlash -//================= -void EV_MuzzleFlash( void ) -{ - // Add muzzle flash to current weapon model - cl_entity_t *ent = GetViewEntity(); - if ( !ent ) return; - - // Or in the muzzle flash - ent->curstate.effects |= EF_MUZZLEFLASH; -} - -//================= -// EV_FlashLight -//================= -void EV_UpadteFlashlight( cl_entity_t *pEnt ) -{ - Vector vecSrc, vecEnd, vecPos, forward; - float rgba[4] = { 1.0f, 1.0f, 1.0f, 1.0f }; - pmtrace_t *trace; - - if ( EV_IsLocal( pEnt->index ) ) - { - float viewangles[3]; - - // get the predicted angles - GetViewAngles( viewangles ); - AngleVectors( viewangles, forward, NULL, NULL ); - } - else - { - Vector v_angle; - - // restore viewangles from angles - v_angle[PITCH] = -pEnt->angles[PITCH] * 3; - v_angle[YAW] = pEnt->angles[YAW]; - v_angle[ROLL] = 0; // no roll - - AngleVectors( v_angle, forward, NULL, NULL ); - } - - Vector view_ofs = Vector( 0, 0, 0 ); - view_ofs.z = DEFAULT_VIEWHEIGHT; - - if ( EV_IsPlayer( pEnt->index ) ) - { - if ( EV_IsLocal( pEnt->index ) ) - { - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - } - else if ( pEnt->curstate.usehull == 1 ) // NOTE: needs changes in delta.lst - { - view_ofs[2] = VEC_DUCK_VIEW; - } - } - - vecSrc = pEnt->origin + view_ofs; - vecEnd = vecSrc + forward * 512; - int ignore = PM_FindPhysEntByIndex( pEnt->index ); - - trace = gEngfuncs.PM_TraceLine( vecSrc, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignore ); - - if( trace->fraction != 1.0f ) - vecPos = trace->endpos + (trace->plane.normal * -16.0f); - else vecPos = trace->endpos; - - // update flashlight endpos - dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDLight( pEnt->index ); - - dl->origin = vecPos; - dl->die = GetClientTime() + 0.001f; // die on next frame - dl->color.r = 255; - dl->color.g = 255; - dl->color.b = 255; - dl->radius = 96; -} - -void HUD_CmdStart( const cl_entity_t *player, int runfuncs ) -{ -} - -void HUD_CmdEnd( const cl_entity_t *player, const usercmd_t *cmd, unsigned int random_seed ) -{ - // Offset final origin by view_offset - if( cl_lw && cl_lw->value ) - { - // FIXME: probably this is not correct - previousorigin = gHUD.m_vecOrigin; - } -} \ No newline at end of file diff --git a/client/global/ev_hldm.h b/client/global/ev_hldm.h deleted file mode 100644 index 2975ac96..00000000 --- a/client/global/ev_hldm.h +++ /dev/null @@ -1,217 +0,0 @@ -//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ -// -// Purpose: -// -// $NoKeywords: $ -//============================================================================= - -#if !defined ( EV_HLDMH ) -#define EV_HLDMH - -// defaults for clientinfo messages -#define DEFAULT_VIEWHEIGHT 28 -#define VEC_DUCK_VIEW 12 -#define VEC_HULL_MIN Vector(-16, -16, -36 ) -#define VEC_HULL_MAX Vector( 16, 16, 36 ) -#define VEC_DUCK_HULL_MIN Vector(-16, -16, -18 ) -#define VEC_DUCK_HULL_MAX Vector( 16, 16, 18 ) - -// bullet types -typedef enum -{ - BULLET_NONE = 0, - BULLET_PLAYER_9MM, // glock - BULLET_PLAYER_MP5, // mp5 - BULLET_PLAYER_357, // python - BULLET_PLAYER_BUCKSHOT, // shotgun - BULLET_PLAYER_CROWBAR, // crowbar swipe - - BULLET_MONSTER_9MM, - BULLET_MONSTER_MP5, - BULLET_MONSTER_12MM, -} Bullet; - -enum glock_e -{ - GLOCK_IDLE1 = 0, - GLOCK_IDLE2, - GLOCK_IDLE3, - GLOCK_SHOOT, - GLOCK_SHOOT_EMPTY, - GLOCK_RELOAD, - GLOCK_RELOAD_NOT_EMPTY, - GLOCK_DRAW, - GLOCK_HOLSTER, - GLOCK_ADD_SILENCER -}; - -enum shotgun_e -{ - SHOTGUN_IDLE = 0, - SHOTGUN_FIRE, - SHOTGUN_FIRE2, - SHOTGUN_RELOAD, - SHOTGUN_PUMP, - SHOTGUN_START_RELOAD, - SHOTGUN_DRAW, - SHOTGUN_HOLSTER, - SHOTGUN_IDLE4, - SHOTGUN_IDLE_DEEP -}; - -enum mp5_e -{ - MP5_LONGIDLE = 0, - MP5_IDLE1, - MP5_LAUNCH, - MP5_RELOAD, - MP5_DEPLOY, - MP5_FIRE1, - MP5_FIRE2, - MP5_FIRE3, -}; - -enum python_e -{ - PYTHON_IDLE1 = 0, - PYTHON_FIDGET, - PYTHON_FIRE1, - PYTHON_RELOAD, - PYTHON_HOLSTER, - PYTHON_DRAW, - PYTHON_IDLE2, - PYTHON_IDLE3 -}; - -enum gauss_e -{ - GAUSS_IDLE = 0, - GAUSS_IDLE2, - GAUSS_FIDGET, - GAUSS_SPINUP, - GAUSS_SPIN, - GAUSS_FIRE, - GAUSS_FIRE2, - GAUSS_HOLSTER, - GAUSS_DRAW -}; - -enum crowbar_e -{ - CROWBAR_IDLE = 0, - CROWBAR_DRAW, - CROWBAR_HOLSTER, - CROWBAR_ATTACK1HIT, - CROWBAR_ATTACK1MISS, - CROWBAR_ATTACK2MISS, - CROWBAR_ATTACK2HIT, - CROWBAR_ATTACK3MISS, - CROWBAR_ATTACK3HIT -}; - -enum crossbow_e -{ - CROSSBOW_IDLE1 = 0, // full - CROSSBOW_IDLE2, // empty - CROSSBOW_FIDGET1, // full - CROSSBOW_FIDGET2, // empty - CROSSBOW_FIRE1, // full - CROSSBOW_FIRE2, // reload - CROSSBOW_FIRE3, // empty - CROSSBOW_RELOAD, // from empty - CROSSBOW_DRAW1, // full - CROSSBOW_DRAW2, // empty - CROSSBOW_HOLSTER1, // full - CROSSBOW_HOLSTER2, // empty -}; - -enum rpg_e -{ - RPG_IDLE = 0, - RPG_FIDGET, - RPG_RELOAD, // to reload - RPG_FIRE2, // to empty - RPG_HOLSTER1, // loaded - RPG_DRAW1, // loaded - RPG_HOLSTER2, // unloaded - RPG_DRAW_UL, // unloaded - RPG_IDLE_UL, // unloaded idle - RPG_FIDGET_UL, // unloaded fidget -}; - -enum egon_e -{ - EGON_IDLE1 = 0, - EGON_FIDGET1, - EGON_ALTFIREON, - EGON_ALTFIRECYCLE, - EGON_ALTFIREOFF, - EGON_FIRE1, - EGON_FIRE2, - EGON_FIRE3, - EGON_FIRE4, - EGON_DRAW, - EGON_HOLSTER -}; - -enum hgun_e -{ - HGUN_IDLE1 = 0, - HGUN_FIDGETSWAY, - HGUN_FIDGETSHAKE, - HGUN_DOWN, - HGUN_UP, - HGUN_SHOOT -}; - -enum tripmine_e -{ - TRIPMINE_IDLE1 = 0, - TRIPMINE_IDLE2, - TRIPMINE_ARM1, - TRIPMINE_ARM2, - TRIPMINE_FIDGET, - TRIPMINE_HOLSTER, - TRIPMINE_DRAW, - TRIPMINE_WORLD, - TRIPMINE_GROUND, -}; - -enum squeak_e -{ - SQUEAK_IDLE1 = 0, - SQUEAK_FIDGETFIT, - SQUEAK_FIDGETNIP, - SQUEAK_DOWN, - SQUEAK_UP, - SQUEAK_THROW -}; - -extern Vector previousorigin; - -void EV_HookEvents( void ); -extern void HUD_CmdStart( const cl_entity_t *player, int runfuncs ); -extern void HUD_CmdEnd( const cl_entity_t *player, const struct usercmd_s *cmd, unsigned int random_seed ); - -cl_entity_t *GetEntity( int idx ); -cl_entity_t *GetViewEntity( void ); -void EV_HLDM_GunshotDecalTrace( struct pmtrace_s *pTrace, char *decalName ); -void EV_HLDM_DecalGunshot( struct pmtrace_s *pTrace, int iBulletType ); -int EV_HLDM_CheckTracer( int idx, float *vecSrc, float *end, float *forward, float *right, int iBulletType, int iTracerFreq, int *tracerCount ); -void EV_HLDM_FireBullets( int idx, float *forward, float *right, float *up, int cShots, float *vecSrc, float *vecDirShooting, float flDistance, int iBulletType, int iTracerFreq, int *tracerCount, float flSpreadX, float flSpreadY ); -void EV_UpdateLaserSpot( void ); - -int EV_IsLocal( int idx ); -int EV_IsPlayer( int idx ); -void EV_MuzzleFlash( void ); -void EV_UpdateBeams ( void ); -void EV_GetGunPosition( struct event_args_s *args, float *pos, float *origin ); -void EV_CreateTracer( float *start, float *end ); -void EV_EjectBrass( float *origin, float *velocity, float rotation, int model, int soundtype ); -void EV_GetDefaultShellInfo( struct event_args_s *args, float *origin, float *velocity, float *ShellVelocity, float *ShellOrigin, float *forward, float *right, float *up, float forwardScale, float upScale, float rightScale ); -void EV_UpadteFlashlight( cl_entity_t *pEnt ); - -// misc pm stuff -extern int PM_FindPhysEntByIndex( int index ); - -#endif // EV_HLDMH \ No newline at end of file diff --git a/client/global/extdll.h b/client/global/extdll.h deleted file mode 100644 index c736b59e..00000000 --- a/client/global/extdll.h +++ /dev/null @@ -1,35 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// extdll.h - must be included into all client files -//======================================================================= - -#ifndef EXTDLL_H -#define EXTDLL_H - -// shut-up compiler warnings -#pragma warning(disable : 4305) // int or float data truncation -#pragma warning(disable : 4201) // nameless struct/union -#pragma warning(disable : 4514) // unreferenced inline function removed -#pragma warning(disable : 4100) // unreferenced formal parameter - -#include "windows.h" - -// Misc C-runtime library headers -#include -#include -#include -#include -#include - -// shared engine/DLL constants -#include "const.h" - -// Vector class -#include "vector.h" - -// Shared header describing protocol between engine and DLLs -#include "cl_entity.h" -#include "cdll_int.h" -#include "cdll_dll.h" - -#endif//EXTDLL_H \ No newline at end of file diff --git a/client/global/input.cpp b/client/global/input.cpp deleted file mode 100644 index c4ef686f..00000000 --- a/client/global/input.cpp +++ /dev/null @@ -1,734 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2009 й -// input.cpp - builds an intended movement command to send to the server -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "usercmd.h" -#include "hud.h" - -#define mlook_active ((int)freelook->value || (in_mlook.state & 1)) - -typedef struct -{ - int down[2]; // key nums holding it down - int state; -} kbutton_t; - -cvar_t *cl_run; -cvar_t *cl_upspeed; -cvar_t *cl_yawspeed; -cvar_t *cl_sidespeed; -cvar_t *cl_pitchspeed; -cvar_t *cl_forwardspeed; -cvar_t *cl_backspeed; -cvar_t *cl_anglespeedkey; -cvar_t *cl_movespeedkey; -cvar_t *cl_pitchup; -cvar_t *cl_pitchdown; -cvar_t *v_centermove; -cvar_t *v_centerspeed; -cvar_t *cl_particles; -cvar_t *cl_draw_beams; - -cvar_t *m_sensitivity; -cvar_t *m_filter; // mouse filtering -cvar_t *m_pitch; -cvar_t *m_yaw; -cvar_t *m_forward; -cvar_t *m_side; - -cvar_t *lookspring; -cvar_t *lookstrafe; -cvar_t *freelook; - -kbutton_t in_mlook, in_klook, in_left, in_right, in_forward, in_back; -kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; -kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack, in_attack2; -kbutton_t in_up, in_down, in_duck, in_reload, in_alt1, in_score, in_break; -int in_cancel = 0, in_impulse = 0; - -int g_iAlive; // indicates alive local client or not -static int mouse_x[2]; // use two values for filtering -static int mouse_y[2]; -static int mouse_step; -static float cl_viewangles[3]; // process viewangles -static float cl_oldviewangles[3]; - -/* -============ -IN_MouseEvent - -accumulate mouse move between calls -============ -*/ -void IN_MouseEvent( int mx, int my ) -{ - // accumulate mouse moves - mouse_x[mouse_step] += mx; - mouse_y[mouse_step] += my; -} - -/* -============ -IN_KeyEvent - -Return 1 to allow engine to process the key, otherwise, act on it as needed -============ -*/ -int IN_KeyEvent( int down, int keynum, const char *pszBind ) -{ - return 1; -} - -/* -=============================================================================== - -KEY BUTTONS - -Continuous button event tracking is complicated by the fact that two different -input sources (say, mouse button 1 and the control key) can both press the -same button, but the button should only be released when both of the -pressing key have been released. - -When a key event issues a button command (+forward, +attack, etc), it appends -its key number as a parameter to the command so it can be matched up with -the release. - -state bit 0 is the current state of the key -state bit 1 is edge triggered on the up to down transition -state bit 2 is edge triggered on the down to up transition - - -CL_KeyEvent( int key, bool down, uint time ); - -+mlook src time -=============================================================================== -*/ -void IN_KeyDown( kbutton_t *b ) -{ - const char *c; - int k; - - c = CMD_ARGV( 1 ); - - if( c[0] ) - { - k = atoi( c ); - } - else - { - k = -1; // typed manually at the console for continuous down - } - - if( k == b->down[0] || k == b->down[1] ) - return; // repeating key - - if ( !b->down[0] ) - { - b->down[0] = k; - } - else if ( !b->down[1] ) - { - b->down[1] = k; - } - else - { - gEngfuncs.Con_Printf( "Error: three keys down for a button '%c' '%c' '%c'!\n", b->down[0], b->down[1], c ); - return; - } - - if( b->state & 1 ) return; // still down - - b->state |= 1 + 2; // down + impulse down -} - -void IN_KeyUp( kbutton_t *b ) -{ - const char *c; - int k; - - c = CMD_ARGV( 1 ); - - if( c[0] ) - { - k = atoi( c ); - } - else - { - // typed manually at the console, assume for unsticking, so clear all - b->down[0] = b->down[1] = 0; - b->state = 4; // impulse up - return; - } - - if( b->down[0] == k ) - { - b->down[0] = 0; - } - else if( b->down[1] == k ) - { - b->down[1] = 0; - } - else return; // key up without coresponding down (menu pass through) - - if( b->down[0] || b->down[1] ) - return; // some other key is still holding it down - - if( !( b->state & 1 )) return; // still up (this should not happen) - - b->state &= ~1; // now up - b->state |= 4; // impulse up -} - -/* -=============== -CL_KeyState - -Returns 0.25 if a key was pressed and released during the frame, -0.5 if it was pressed and held -0 if held then released, and -1.0 if held for the entire time -=============== -*/ -static float CL_KeyState( kbutton_t *key ) -{ - float val = 0.0f; - int impulsedown, impulseup, down; - - impulsedown = key->state & 2; - impulseup = key->state & 4; - down = key->state & 1; - - if ( impulsedown && !impulseup ) - { - // pressed and held this frame? - val = down ? 0.5f : 0.0f; - } - - if ( impulseup && !impulsedown ) - { - // released this frame? - val = down ? 0.0f : 0.0f; - } - - if ( !impulsedown && !impulseup ) - { - // held the entire frame? - val = down ? 1.0f : 0.0f; - } - - if ( impulsedown && impulseup ) - { - if ( down ) - { - // released and re-pressed this frame - val = 0.75f; - } - else - { - // pressed and released this frame - val = 0.25f; - } - } - - key->state &= 1; // clear impulses - - return val; -} - -void IN_KLookDown( void ){ IN_KeyDown( &in_klook ); } -void IN_KLookUp( void ){ IN_KeyUp( &in_klook ); } -void IN_UpDown(void) {IN_KeyDown(&in_up);} -void IN_UpUp(void) {IN_KeyUp(&in_up);} -void IN_DownDown(void) {IN_KeyDown(&in_down);} -void IN_DownUp(void) {IN_KeyUp(&in_down);} -void IN_LeftDown(void) {IN_KeyDown(&in_left);} -void IN_LeftUp(void) {IN_KeyUp(&in_left);} -void IN_RightDown(void) {IN_KeyDown(&in_right);} -void IN_RightUp(void) {IN_KeyUp(&in_right);} -void IN_ForwardDown(void) {IN_KeyDown(&in_forward);} -void IN_ForwardUp(void) {IN_KeyUp(&in_forward);} -void IN_BackDown(void) {IN_KeyDown(&in_back);} -void IN_BackUp(void) {IN_KeyUp(&in_back);} -void IN_LookupDown(void) {IN_KeyDown(&in_lookup);} -void IN_LookupUp(void) {IN_KeyUp(&in_lookup);} -void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);} -void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);} -void IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);} -void IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);} -void IN_MoverightDown(void) {IN_KeyDown(&in_moveright);} -void IN_MoverightUp(void) {IN_KeyUp(&in_moveright);} -void IN_SpeedDown(void) {IN_KeyDown(&in_speed);} -void IN_SpeedUp(void) {IN_KeyUp(&in_speed);} -void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);} -void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);} -void IN_AttackDown(void) {IN_KeyDown(&in_attack);} -void IN_AttackUp(void) {IN_KeyUp(&in_attack); } -void IN_Attack2Down(void) {IN_KeyDown(&in_attack2);} -void IN_Attack2Up(void) {IN_KeyUp(&in_attack2);} -void IN_UseDown (void) {IN_KeyDown(&in_use);} -void IN_UseUp (void) {IN_KeyUp(&in_use);} -void IN_ReloadDown(void) {IN_KeyDown(&in_reload);} -void IN_ReloadUp(void) {IN_KeyUp(&in_reload);} -void IN_JumpDown(void) {IN_KeyDown( &in_jump ); } -void IN_JumpUp(void) {IN_KeyUp( &in_jump ); } -void IN_DuckDown(void){ IN_KeyDown( &in_duck ); } -void IN_DuckUp(void){ IN_KeyUp( &in_duck ); } -void IN_Alt1Down(void){ IN_KeyDown( &in_alt1 ); } -void IN_Alt1Up(void) {IN_KeyUp( &in_alt1 ); } -void IN_ScoreDown(void) {IN_KeyDown( &in_score ); } -void IN_ScoreUp(void) {IN_KeyUp( &in_score ); } -void IN_BreakDown(void) {IN_KeyDown( &in_break ); } -void IN_BreakUp(void) {IN_KeyUp( &in_break ); } -void IN_Cancel(void) { in_cancel = 1; } // special handling -void IN_Impulse(void) { in_impulse = atoi( CMD_ARGV( 1 )); } -void IN_MLookDown(void) {IN_KeyDown( &in_mlook ); } - -void IN_CenterView( void ) -{ - if( !mlook_active ) - { - V_StartPitchDrift (); - } - else - { - float viewangles[3]; - - // just reset pitch - GetViewAngles( viewangles ); - viewangles[PITCH] = 0.0f; - SetViewAngles( viewangles ); - } -} - -void IN_MLookUp(void) -{ - IN_KeyUp( &in_mlook ); - - if( !mlook_active && lookspring->value ) - { - V_StopPitchDrift (); - } -} - -/* -================= -CL_MouseMove -================= -*/ -void CL_MouseMove( usercmd_t *cmd ) -{ - float mx, my; - - // allow mouse smoothing - if( m_filter->value ) - { - mx = (mouse_x[0] + mouse_x[1]) * 0.5f; - my = (mouse_y[0] + mouse_y[1]) * 0.5f; - } - else - { - mx = mouse_x[mouse_step]; - my = mouse_y[mouse_step]; - } - - mouse_step ^= 1; - mouse_x[mouse_step] = 0; - mouse_y[mouse_step] = 0; - - // check for dead - if( !g_iAlive ) return; - - if ( gHUD.GetSensitivity( )) - { - mx *= gHUD.GetSensitivity(); // scale by fov - my *= gHUD.GetSensitivity(); - } - else - { - mx *= m_sensitivity->value; - my *= m_sensitivity->value; - } - - // add mouse X/Y movement to cmd - if(( in_strafe.state & 1 ) || (lookstrafe->value && mlook_active)) - cmd->sidemove += m_side->value * mx; - else cl_viewangles[YAW] -= m_yaw->value * mx; - - if( mlook_active ) V_StopPitchDrift (); - - if( mlook_active && !( in_strafe.state & 1 )) - { - cl_viewangles[PITCH] += m_pitch->value * my; - cl_viewangles[PITCH] = bound( -cl_pitchup->value, cl_viewangles[PITCH], cl_pitchdown->value ); - } - else - { - if(( in_strafe.state & 1 ) && gHUD.IsNoClipping() ) - cmd->upmove -= m_forward->value * my; - else cmd->forwardmove -= m_forward->value * my; - } -} - -/* -================ -CL_AdjustAngles - -Moves the local angle positions -================ -*/ -void CL_AdjustAngles( float frametime ) -{ - float speed; - float up, down; - - if( !g_iAlive || gHUD.m_iIntermission ) - return; - - if ( in_speed.state & 1 ) - { - speed = frametime * cl_anglespeedkey->value; - } - else - { - speed = frametime; - } - - if (!( in_strafe.state & 1 )) - { - cl_viewangles[YAW] -= speed * cl_yawspeed->value * CL_KeyState( &in_right ); - cl_viewangles[YAW] += speed * cl_yawspeed->value * CL_KeyState( &in_left ); - cl_viewangles[YAW] = anglemod( cl_viewangles[YAW] ); - } - - if( in_klook.state & 1 ) - { - V_StopPitchDrift (); - - cl_viewangles[PITCH] -= speed * cl_pitchspeed->value * CL_KeyState( &in_forward ); - cl_viewangles[PITCH] += speed * cl_pitchspeed->value * CL_KeyState( &in_back ); - } - - up = CL_KeyState( &in_lookup ); - down = CL_KeyState( &in_lookdown ); - - cl_viewangles[PITCH] -= speed * cl_pitchspeed->value * up; - cl_viewangles[PITCH] += speed * cl_pitchspeed->value * down; - - if( up || down ) V_StopPitchDrift(); - - cl_viewangles[PITCH] = bound( -89, cl_viewangles[PITCH], 89 ); - cl_viewangles[ROLL] = bound( -50, cl_viewangles[ROLL], 50 ); -} - -/* -================ -CL_BaseMove - -Send the intended movement message to the server -================ -*/ -void CL_BaseMove( usercmd_t *cmd ) -{ - if( in_strafe.state & 1 ) - { - cmd->sidemove += cl_sidespeed->value * CL_KeyState( &in_right ); - cmd->sidemove -= cl_sidespeed->value * CL_KeyState( &in_left ); - } - - cmd->sidemove += cl_sidespeed->value * CL_KeyState( &in_moveright ); - cmd->sidemove -= cl_sidespeed->value * CL_KeyState( &in_moveleft ); - - cmd->upmove += cl_upspeed->value * CL_KeyState( &in_up ); - cmd->upmove -= cl_upspeed->value * CL_KeyState( &in_down ); - - if(!( in_klook.state & 1 )) - { - cmd->forwardmove += cl_forwardspeed->value * CL_KeyState( &in_forward ); - cmd->forwardmove -= cl_backspeed->value * CL_KeyState( &in_back ); - } - - // adjust for speed key / running - if( in_speed.state & 1 ^ !(int)cl_run->value ) - { - cmd->forwardmove *= cl_movespeedkey->value; - cmd->sidemove *= cl_movespeedkey->value; - cmd->upmove *= cl_movespeedkey->value; - } - - // clip to maxspeed - float spd = GetClientMaxspeed(); - - if( spd != 0.0f ) - { - // scale the 3 speeds so that the total velocity is not > cl.maxspeed - float fmove = 0; - - fmove += (cmd->forwardmove * cmd->forwardmove); - fmove += (cmd->sidemove * cmd->sidemove); - fmove += (cmd->upmove * cmd->upmove); - fmove = sqrt( fmove ); - - if ( fmove > spd ) - { - float fratio = spd / fmove; - - cmd->forwardmove *= fratio; - cmd->sidemove *= fratio; - cmd->upmove *= fratio; - } - } -} - -void IN_CreateMove( usercmd_t *cmd, float frametime, int active ) -{ - if ( active && !gHUD.m_iIntermission ) - { - GetViewAngles( cl_viewangles ); - - CL_AdjustAngles( frametime ); - - CL_BaseMove( cmd ); - - // allow mice and other controllers to add their inputs - CL_MouseMove( cmd ); - - SetViewAngles( cl_viewangles ); - } - - cmd->impulse = in_impulse; - in_impulse = 0; - - cmd->weaponselect = g_weaponselect; - g_weaponselect = 0; - - // set button and flag bits - cmd->buttons = CL_ButtonBits( 1 ); - - GetViewAngles( cl_viewangles ); - - // set current view angles. - if ( g_iAlive ) - { - cmd->viewangles[0] = cl_oldviewangles[0] = cl_viewangles[0]; - cmd->viewangles[1] = cl_oldviewangles[1] = cl_viewangles[1]; - cmd->viewangles[2] = cl_oldviewangles[2] = cl_viewangles[2]; - - if( freelook->value ) - { - if( !mlook_active && lookspring->value ) - V_StartPitchDrift(); - } - } - else - { - cmd->viewangles[0] = cl_oldviewangles[0]; - cmd->viewangles[1] = cl_oldviewangles[1]; - cmd->viewangles[2] = cl_oldviewangles[2]; - } -} - -/* -============== -CL_ButtonBits -============== -*/ -int CL_ButtonBits( int bResetState ) -{ - int bits = 0; - - if( in_attack.state & 3 ) - bits |= IN_ATTACK; - - if( in_attack2.state & 3 ) - bits |= IN_ATTACK2; - - if( in_use.state & 3 ) - bits |= IN_USE; - - if( in_speed.state & 3 ) - bits |= IN_RUN; - - if( in_duck.state & 3 ) - bits |= IN_DUCK; - - if( in_down.state & 3 ) - bits |= IN_DUCK; - - if( in_jump.state & 3 ) - bits |= IN_JUMP; - - if( in_up.state & 3 ) - bits |= IN_JUMP; - - if( in_reload.state & 3) - bits |= IN_RELOAD; - - if( in_forward.state & 3 ) - bits |= IN_FORWARD; - - if( in_back.state & 3 ) - bits |= IN_BACK; - - if( in_left.state & 3 ) - bits |= IN_LEFT; - - if( in_right.state & 3 ) - bits |= IN_RIGHT; - - if( in_moveleft.state & 3 ) - bits |= IN_MOVELEFT; - - if( in_moveright.state & 3 ) - bits |= IN_MOVERIGHT; - - if( in_alt1.state & 3 ) - bits |= IN_ALT1; - - if( in_score.state & 3 ) - bits |= IN_SCORE; - - if( in_cancel ) - bits |= IN_CANCEL; - - if( bResetState ) - { - in_speed.state &= ~2; - in_attack.state &= ~2; - in_duck.state &= ~2; - in_jump.state &= ~2; - in_forward.state &= ~2; - in_back.state &= ~2; - in_use.state &= ~2; - in_left.state &= ~2; - in_right.state &= ~2; - in_up.state &= ~2; - in_down.state &= ~2; - in_moveleft.state &= ~2; - in_moveright.state &= ~2; - in_attack2.state &= ~2; - in_reload.state &= ~2; - in_alt1.state &= ~2; - in_score.state &= ~2; - } - return bits; -} - -/* -============ -CL_ResetButtonBits - -============ -*/ -void CL_ResetButtonBits( int bits ) -{ - int bitsNew = CL_ButtonBits( 0 ) ^ bits; - - // has the attack button been changed - if( bitsNew & IN_ATTACK ) - { - // was it pressed? or let go? - if( bits & IN_ATTACK ) - { - IN_KeyDown( &in_attack ); - } - else - { - // totally clear state - in_attack.state &= ~7; - } - } -} - -void IN_Init( void ) -{ - // mouse variables - m_filter = CVAR_REGISTER("m_filter", "0", FCVAR_ARCHIVE ); - m_sensitivity = CVAR_REGISTER( "m_sensitivity", "3", FCVAR_ARCHIVE ); - - // centering - v_centermove = CVAR_REGISTER ("v_centermove", "0.15", 0 ); - v_centerspeed = CVAR_REGISTER ("v_centerspeed", "500", 0 ); - - cl_upspeed = CVAR_REGISTER( "cl_upspeed", "400", 0 ); - cl_forwardspeed = CVAR_REGISTER( "cl_forwardspeed", "400", 0 ); - cl_backspeed = CVAR_REGISTER( "cl_backspeed", "400", 0 ); - cl_sidespeed = CVAR_REGISTER( "cl_sidespeed", "400", 0 ); - cl_yawspeed = CVAR_REGISTER( "cl_yawspeed", "140", 0 ); - cl_pitchspeed = CVAR_REGISTER( "cl_pitchspeed", "150", 0 ); - cl_anglespeedkey = CVAR_REGISTER( "cl_anglespeedkey", "1.5", 0 ); - cl_run = CVAR_REGISTER( "cl_run", "1", FCVAR_ARCHIVE ); - - cl_movespeedkey = CVAR_REGISTER ( "cl_movespeedkey", "0.3", 0 ); - cl_pitchup = CVAR_REGISTER ( "cl_pitchup", "89", 0 ); - cl_pitchdown = CVAR_REGISTER ( "cl_pitchdown", "89", 0 ); - - freelook = CVAR_REGISTER( "freelook", "1", FCVAR_ARCHIVE ); - lookspring = CVAR_REGISTER( "lookspring", "0", FCVAR_ARCHIVE ); - lookstrafe = CVAR_REGISTER( "lookstrafe", "0", FCVAR_ARCHIVE ); - - m_pitch = CVAR_REGISTER ("m_pitch", "0.022", FCVAR_ARCHIVE ); - m_yaw = CVAR_REGISTER ("m_yaw", "0.022", 0 ); - m_forward = CVAR_REGISTER ("m_forward", "1", 0 ); - m_side = CVAR_REGISTER ("m_side", "1", 0 ); - - cl_particles = CVAR_REGISTER ( "cl_particles", "1", FCVAR_ARCHIVE ); - cl_draw_beams = CVAR_REGISTER ( "cl_draw_beams", "1", FCVAR_ARCHIVE ); - - Cmd_AddCommand ("centerview", IN_CenterView ); - - // input commands - Cmd_AddCommand ("+moveup",IN_UpDown ); - Cmd_AddCommand ("-moveup",IN_UpUp ); - Cmd_AddCommand ("+movedown",IN_DownDown ); - Cmd_AddCommand ("-movedown",IN_DownUp ); - Cmd_AddCommand ("+left",IN_LeftDown ); - Cmd_AddCommand ("-left",IN_LeftUp ); - Cmd_AddCommand ("+right",IN_RightDown ); - Cmd_AddCommand ("-right",IN_RightUp ); - Cmd_AddCommand ("+forward",IN_ForwardDown ); - Cmd_AddCommand ("-forward",IN_ForwardUp ); - Cmd_AddCommand ("+back",IN_BackDown ); - Cmd_AddCommand ("-back",IN_BackUp ); - Cmd_AddCommand ("+lookup", IN_LookupDown ); - Cmd_AddCommand ("-lookup", IN_LookupUp ); - Cmd_AddCommand ("+lookdown", IN_LookdownDown ); - Cmd_AddCommand ("-lookdown", IN_LookdownUp ); - Cmd_AddCommand ("+strafe", IN_StrafeDown ); - Cmd_AddCommand ("-strafe", IN_StrafeUp ); - Cmd_AddCommand ("+moveleft", IN_MoveleftDown ); - Cmd_AddCommand ("-moveleft", IN_MoveleftUp ); - Cmd_AddCommand ("+moveright", IN_MoverightDown ); - Cmd_AddCommand ("-moveright", IN_MoverightUp ); - Cmd_AddCommand ("+speed", IN_SpeedDown ); - Cmd_AddCommand ("-speed", IN_SpeedUp ); - Cmd_AddCommand ("+attack", IN_AttackDown ); - Cmd_AddCommand ("-attack", IN_AttackUp ); - Cmd_AddCommand ("+attack2", IN_Attack2Down ); - Cmd_AddCommand ("-attack2", IN_Attack2Up ); - Cmd_AddCommand ("+use", IN_UseDown ); - Cmd_AddCommand ("-use", IN_UseUp ); - Cmd_AddCommand ("+jump", IN_JumpDown ); - Cmd_AddCommand ("-jump", IN_JumpUp ); - Cmd_AddCommand ("+duck", IN_DuckDown ); - Cmd_AddCommand ("-duck", IN_DuckUp ); - Cmd_AddCommand ("+klook", IN_KLookDown ); - Cmd_AddCommand ("-klook", IN_KLookUp ); - Cmd_AddCommand ("+reload", IN_ReloadDown ); - Cmd_AddCommand ("-reload", IN_ReloadUp ); - Cmd_AddCommand ("+mlook", IN_MLookDown ); - Cmd_AddCommand ("-mlook", IN_MLookUp ); - Cmd_AddCommand ("+alt1", IN_Alt1Down ); - Cmd_AddCommand ("-alt1", IN_Alt1Up ); - Cmd_AddCommand ("+break",IN_BreakDown ); - Cmd_AddCommand ("-break",IN_BreakUp ); - Cmd_AddCommand ( "impulse", IN_Impulse ); - - V_Init (); -} - -void IN_Shutdown( void ) -{ -} \ No newline at end of file diff --git a/client/global/r_beams.cpp b/client/global/r_beams.cpp deleted file mode 100644 index 6ff1c377..00000000 --- a/client/global/r_beams.cpp +++ /dev/null @@ -1,2432 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2010 й -// r_beams.cpp - rendering single beams and rings -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "triangleapi.h" -#include "r_efx.h" -#include "ref_params.h" -#include "ev_hldm.h" -#include "hud.h" -#include "r_beams.h" - -CViewRenderBeams *g_pViewRenderBeams = NULL; - -//----------------------------------------------------------------------------- -// Global methods -//----------------------------------------------------------------------------- - -// freq2 += step * 0.1; -// Fractal noise generator, power of 2 wavelength -static void FracNoise( float *noise, int divs, float scale ) -{ - int div2; - - div2 = divs >> 1; - - if( divs < 2 ) return; - - // noise is normalized to +/- scale - noise[div2] = (noise[0] + noise[divs]) * 0.5f + scale * RANDOM_FLOAT( -1.0f, 1.0f ); - - if( div2 > 1 ) - { - FracNoise( &noise[div2], div2, scale * 0.5f ); - FracNoise( noise, div2, scale * 0.5f ); - } -} - -static void SineNoise( float *noise, int divs ) -{ - float freq = 0; - float step = M_PI / (float)divs; - - for ( int i = 0; i < divs; i++ ) - { - noise[i] = sin( freq ); - freq += step; - } -} - -static bool ComputeBeamEntPosition( cl_entity_t *pEnt, int nAttachment, Vector& pt ) -{ - if( !pEnt ) - { - pt = g_vecZero; - return false; - } - - // get attachment - if( nAttachment > 0 ) - pt = pEnt->origin + pEnt->attachment[nAttachment - 1]; - else pt = pEnt->origin; - - return true; -} - -//----------------------------------------------------------------------------- -// Compute vectors perpendicular to the beam -//----------------------------------------------------------------------------- -static void ComputeBeamPerpendicular( const Vector &vecBeamDelta, Vector *pPerp ) -{ - // Direction in worldspace of the center of the beam - Vector vecBeamCenter = vecBeamDelta.Normalize(); - *pPerp = CrossProduct( g_pViewRenderBeams->GetViewParams()->vieworg, vecBeamCenter ).Normalize(); -} - -// ------------------------------------------------------------------------------------------ // -// CBeamSegDraw implementation. -// ------------------------------------------------------------------------------------------ // -void CBeamSegDraw::Start( int nSegs, HSPRITE m_hSprite, int nRenderMode, int frame ) -{ - m_nSegsDrawn = 0; - m_nTotalSegs = nSegs; - - ASSERT( nSegs >= 2 ); - - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - gEngfuncs.pTriAPI->RenderMode( nRenderMode ); - gEngfuncs.pTriAPI->Bind( m_hSprite, frame ); // GetSpriteTexture already set frame - - gEngfuncs.pTriAPI->Begin( TRI_TRIANGLE_STRIP ); -} - -inline void CBeamSegDraw::ComputeNormal( const Vector &vStartPos, const Vector &vNextPos, Vector *pNormal ) -{ - // vTangentY = line vector for beam - Vector vTangentY; - vTangentY = vStartPos - vNextPos; - - // vDirToBeam = vector from viewer origin to beam - Vector vDirToBeam; - vDirToBeam = vStartPos - g_pViewRenderBeams->GetViewParams()->vieworg; - - // Get a vector that is perpendicular to us and perpendicular to the beam. - // This is used to fatten the beam. - *pNormal = CrossProduct( vTangentY, vDirToBeam ); - VectorNormalizeFast( *pNormal ); -} - -inline void CBeamSegDraw::SpecifySeg( const Vector &vNormal ) -{ - // SUCKY: Need to do a fair amount more work to get the tangent owing to the averaged normal - Vector vDirToBeam, vTangentY; - - vDirToBeam = m_Seg.m_vPos - g_pViewRenderBeams->GetViewParams()->vieworg; - vTangentY = CrossProduct( vDirToBeam, vNormal ); - VectorNormalizeFast( vTangentY ); - - // Build the endpoints. - Vector vPoint1, vPoint2; - - vPoint1 = m_Seg.m_vPos + vNormal * ( m_Seg.m_flWidth * 0.5f); - vPoint2 = m_Seg.m_vPos + vNormal * (-m_Seg.m_flWidth * 0.5f); - - // Specify the points. - gEngfuncs.pTriAPI->Color4f( m_Seg.m_vColor[0], m_Seg.m_vColor[1], m_Seg.m_vColor[2], m_Seg.m_flAlpha ); - gEngfuncs.pTriAPI->TexCoord2f( 0.0f, m_Seg.m_flTexCoord ); - gEngfuncs.pTriAPI->Normal3fv( vNormal ); -// gEngfuncs.pTriAPI->Tangent3fv( vTangentY ); - gEngfuncs.pTriAPI->Vertex3fv( vPoint1 ); - - gEngfuncs.pTriAPI->Color4f( m_Seg.m_vColor[0], m_Seg.m_vColor[1], m_Seg.m_vColor[2], m_Seg.m_flAlpha ); - gEngfuncs.pTriAPI->TexCoord2f( 1.0f, m_Seg.m_flTexCoord ); - gEngfuncs.pTriAPI->Normal3fv( vNormal ); -// gEngfuncs.pTriAPI->Tangent3fv( vTangentY ); - gEngfuncs.pTriAPI->Vertex3fv( vPoint2 ); - -} - -void CBeamSegDraw::NextSeg( CBeamSeg *pSeg ) -{ - if ( m_nSegsDrawn > 0 ) - { - // Get a vector that is perpendicular to us and perpendicular to the beam. - // This is used to fatten the beam. - Vector vNormal, vAveNormal; - ComputeNormal( m_Seg.m_vPos, pSeg->m_vPos, &vNormal ); - - if ( m_nSegsDrawn > 1 ) - { - // Average this with the previous normal - vAveNormal = vNormal + m_vNormalLast; - vAveNormal *= 0.5f; - VectorNormalizeFast( vAveNormal ); - } - else - { - vAveNormal = vNormal; - } - - m_vNormalLast = vNormal; - SpecifySeg( vAveNormal ); - } - - m_Seg = *pSeg; - ++m_nSegsDrawn; - - if( m_nSegsDrawn == m_nTotalSegs ) - { - SpecifySeg( m_vNormalLast ); - } -} - -void CBeamSegDraw::End() -{ - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} - -//----------------------------------------------------------------------------- -// -// Methods of Beam_t -// -//----------------------------------------------------------------------------- -Beam_t::Beam_t( void ) -{ - Reset(); -} - -void Beam_t::Reset( void ) -{ - m_Mins.Init(); - m_Maxs.Init(); - type = 0; - flags = 0; - trail = 0; - m_bCalculatedNoise = false; -} - -void Beam_t::SetFlags( int iFlags ) -{ - if( iFlags & FBEAM_SINENOISE ) - m_bCalculatedNoise = false; - flags |= iFlags; -} - -void Beam_t::SetStartPos( const Vector pos ) -{ - attachment[0] = pos; -} - -void Beam_t::SetEndPos( const Vector pos ) -{ - attachment[1] = pos; -} - -void Beam_t::SetWidth( float flWidth ) -{ - width = endWidth = (flWidth * 0.1f); -} - -void Beam_t::SetNoise( float flAmplitude ) -{ - amplitude = (flAmplitude * 0.1f); -} - -void Beam_t::SetColor( float cR, float cG, float cB ) -{ - r = cR; - g = cG; - b = cB; -} - -void Beam_t::SetBrightness( float flBrightness ) -{ - brightness = flBrightness; -} - -const Vector& Beam_t::GetRenderOrigin( void ) -{ - if ( type == TE_BEAMRING ) - { - // return the center of the ring - static Vector org; - org = attachment[0] + delta * 0.5f; - return org; - } - return attachment[0]; -} - -void Beam_t::ComputeBounds( void ) -{ - switch( type ) - { - case TE_BEAMDISK: - case TE_BEAMCYLINDER: - { - // FIXME: This isn't quite right for the cylinder - - // Here, delta[2] is the radius - int radius = delta[2]; - m_Mins.Init( -radius, -radius, -radius ); - m_Maxs.Init( radius, radius, radius ); - } - break; - case TE_BEAMRING: - { - int radius = delta.Length() * 0.5f; - m_Mins.Init( -radius, -radius, -radius ); - m_Maxs.Init( radius, radius, radius ); - } - break; - case TE_BEAMPOINTS: - default: - { - // just use the delta - for( int i = 0; i < 3; i++ ) - { - if( delta[i] > 0.0f ) - { - m_Mins[i] = 0.0f; - m_Maxs[i] = delta[i]; - } - else - { - m_Mins[i] = delta[i]; - m_Maxs[i] = 0.0f; - } - } - } - break; - } - - // deal with beam follow - Vector org = GetRenderOrigin(); - Vector followDelta; - BeamTrail_t* pFollow = trail; - while ( pFollow ) - { - followDelta = pFollow->org - org; - - m_Mins = m_Mins.Min( followDelta ); - m_Maxs = m_Maxs.Max( followDelta ); - - pFollow = pFollow->next; - } -} - -//----------------------------------------------------------------------------- -// Constructor, destructor: -//----------------------------------------------------------------------------- - -CViewRenderBeams::CViewRenderBeams( void ) : m_pBeamTrails(0) -{ - m_pBeamTrails = (BeamTrail_t *)new BeamTrail_t[MAX_BEAMTRAILS]; - - ASSERT( m_pBeamTrails != NULL ); - - // invalidate ref_params ptr - pViewParams = NULL; - - // Clear them out - ClearBeams(); -} - -CViewRenderBeams::~CViewRenderBeams( void ) -{ - if ( m_pBeamTrails ) - delete[] m_pBeamTrails; -} - -//----------------------------------------------------------------------------- -// Purpose: Clear out all beams -//----------------------------------------------------------------------------- -void CViewRenderBeams::ClearBeams( void ) -{ - int i; - - m_pFreeBeams = &m_Beams[ 0 ]; - m_pActiveBeams = NULL; - - for ( i = 0; i < MAX_BEAMS; i++ ) - { - m_Beams[i].Reset(); - m_Beams[i].next = &m_Beams[i+1]; - } - - m_Beams[MAX_BEAMS-1].next = NULL; - - // Also clear any particles used by beams - m_pFreeTrails = &m_pBeamTrails[0]; - m_pActiveTrails = NULL; - - for ( i = 0; i < MAX_BEAMTRAILS; i++ ) - m_pBeamTrails[i].next = &m_pBeamTrails[i+1]; - m_pBeamTrails[MAX_BEAMTRAILS-1].next = NULL; - - ClearServerBeams(); -} - -//----------------------------------------------------------------------------- -// Purpose: Try and allocate a free beam -// Output : Beam_t -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::BeamAlloc( void ) -{ - if ( !m_pFreeBeams ) - return NULL; - - Beam_t *pBeam = m_pFreeBeams; - m_pFreeBeams = pBeam->next; - pBeam->next = m_pActiveBeams; - m_pActiveBeams = pBeam; - - return pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Free the beam. -//----------------------------------------------------------------------------- -void CViewRenderBeams::BeamFree( Beam_t* pBeam ) -{ - // Free particles that have died off. - FreeDeadTrails( &pBeam->trail ); - - // Clear us out - pBeam->Reset(); - - // Now link into free list; - pBeam->next = m_pFreeBeams; - m_pFreeBeams = pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Iterates through active list and kills beams associated with deadEntity -// Input : deadEntity - -//----------------------------------------------------------------------------- -void CViewRenderBeams::KillDeadBeams( cl_entity_t *pDeadEntity ) -{ - Beam_t *pbeam; - Beam_t *pnewlist; - Beam_t *pnext; - BeamTrail_t *pHead; // Build a new list to replace m_pActiveBeams. - - pbeam = m_pActiveBeams; // Old list. - pnewlist = NULL; // New list. - - while (pbeam) - { - pnext = pbeam->next; - if ( pbeam->entity[0] != pDeadEntity ) // Link into new list. - { - pbeam->next = pnewlist; - pnewlist = pbeam; - - pbeam = pnext; - continue; - } - - pbeam->flags &= ~(FBEAM_STARTENTITY | FBEAM_ENDENTITY); - if ( pbeam->type != TE_BEAMFOLLOW ) - { - // Die Die Die! - pbeam->die = GetClientTime() - 0.1f; - - // Kill off particles - pHead = pbeam->trail; - while (pHead) - { - pHead->die = GetClientTime() - 0.1f; - pHead = pHead->next; - } - - // Free the beam - BeamFree( pbeam ); - } - else - { - // Stay active - pbeam->next = pnewlist; - pnewlist = pbeam; - } - pbeam = pnext; - } - - // We now have a new list with the bogus stuff released. - m_pActiveBeams = pnewlist; -} - -//----------------------------------------------------------------------------- -// Purpose: Fill in values to beam structure. -// Input: pBeam - -// beamInfo - -//----------------------------------------------------------------------------- -void CViewRenderBeams::SetupBeam( Beam_t *pBeam, const BeamInfo_t &beamInfo ) -{ - if( Mod_GetModelType( beamInfo.m_nModelIndex ) != mod_sprite ) - return; - - pBeam->type = ( beamInfo.m_nType < 0 ) ? TE_BEAMPOINTS : beamInfo.m_nType; - pBeam->modelIndex = beamInfo.m_nModelIndex; - pBeam->frame = 0; - pBeam->frameRate = 0; - pBeam->frameCount = Mod_GetFrames( beamInfo.m_nModelIndex ); - pBeam->freq = GetClientTime() * beamInfo.m_flSpeed; - pBeam->die = GetClientTime() + beamInfo.m_flLife; - pBeam->width = beamInfo.m_flWidth; - pBeam->endWidth = beamInfo.m_flEndWidth; - pBeam->fadeLength = beamInfo.m_flFadeLength; - pBeam->amplitude = beamInfo.m_flAmplitude; - pBeam->brightness = beamInfo.m_flBrightness; - pBeam->speed = beamInfo.m_flSpeed; - pBeam->life = beamInfo.m_flLife; - pBeam->flags = 0; - - pBeam->attachment[0] = beamInfo.m_vecStart; - pBeam->attachment[1] = beamInfo.m_vecEnd; - -// ASSERT( beamInfo.m_vecStart != g_vecZero ); -// ASSERT( beamInfo.m_vecEnd != g_vecZero ); - - pBeam->delta = beamInfo.m_vecEnd - beamInfo.m_vecStart; - - ASSERT( pBeam->delta.IsValid() ); - - if ( beamInfo.m_nSegments == -1 ) - { - if ( pBeam->amplitude >= 0.50 ) - { - pBeam->segments = pBeam->delta.Length() * 0.25f + 3; // one per 4 pixels - } - else - { - pBeam->segments = pBeam->delta.Length() * 0.075f + 3; // one per 16 pixels - } - } - else - { - pBeam->segments = beamInfo.m_nSegments; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Set beam color and frame data. -// Input: pBeam - -// beamInfo - -//----------------------------------------------------------------------------- -void CViewRenderBeams::SetBeamAttributes( Beam_t *pBeam, const BeamInfo_t &beamInfo ) -{ - pBeam->frame = ( float )beamInfo.m_nStartFrame; - pBeam->frameRate = beamInfo.m_flFrameRate; - pBeam->flags |= beamInfo.m_nFlags; - - pBeam->r = beamInfo.m_flRed; - pBeam->g = beamInfo.m_flGreen; - pBeam->b = beamInfo.m_flBlue; -} - -//----------------------------------------------------------------------------- -// Purpose: Cull beam by bbox -// Input : *start - -// *end - -// pvsOnly - -// Output : int -//----------------------------------------------------------------------------- - -int CViewRenderBeams::CullBeam( const Vector &start, const Vector &end, int pvsOnly ) -{ - Vector mins, maxs; - - for ( int i = 0; i < 3; i++ ) - { - if ( start[i] < end[i] ) - { - mins[i] = start[i]; - maxs[i] = end[i]; - } - else - { - mins[i] = end[i]; - maxs[i] = start[i]; - } - - // Don't let it be zero sized - if ( mins[i] == maxs[i] ) - { - maxs[i] += 1; - } - } - - // check bbox - if( gEngfuncs.pEfxAPI->CL_IsBoxVisible( mins, maxs )) - { - if ( pvsOnly || !gEngfuncs.pEfxAPI->R_CullBox( mins, maxs ) ) - { - // Beam is visible - return 1; - } - } - - // Beam is not visible - return 0; -} - -//----------------------------------------------------------------------------- -// Purpose: Allocate and setup a generic beam. -// Input: beamInfo - -// Output: Beam_t -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateGenericBeam( BeamInfo_t &beamInfo ) -{ - Beam_t *pBeam = BeamAlloc(); - if ( !pBeam ) - return NULL; - - // In case we fail. - pBeam->die = GetClientTime(); - - // Need a valid model. - if ( Mod_GetModelType( beamInfo.m_nModelIndex ) == mod_bad ) - return NULL; - - // Set it up - SetupBeam( pBeam, beamInfo ); - - return pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Create a beam between two ents -// Input : startEnt - -// endEnt - -// modelIndex - -// life - -// width - -// amplitude - -// brightness - -// speed - -// startFrame - -// framerate - -// BEAMENT_ENTITY(startEnt - -// Output : Beam_t -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamEnts( int startEnt, int endEnt, int modelIndex, float life, - float width, float endWidth, float fadeLength, float amplitude, float brightness, - float speed, int startFrame, float framerate, float r, float g, float b, int type ) -{ - BeamInfo_t beamInfo; - - beamInfo.m_nType = type; - beamInfo.m_pStartEnt = GetEntityByIndex( BEAMENT_ENTITY( startEnt )); - beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt ); - beamInfo.m_pEndEnt = GetEntityByIndex( BEAMENT_ENTITY( endEnt )); - beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( endEnt ); - beamInfo.m_nModelIndex = modelIndex; - beamInfo.m_flLife = life; - beamInfo.m_flWidth = width; - beamInfo.m_flEndWidth = endWidth; - beamInfo.m_flFadeLength = fadeLength; - beamInfo.m_flAmplitude = amplitude; - beamInfo.m_flBrightness = brightness; - beamInfo.m_flSpeed = speed; - beamInfo.m_nStartFrame = startFrame; - beamInfo.m_flFrameRate = framerate; - beamInfo.m_flRed = r; - beamInfo.m_flGreen = g; - beamInfo.m_flBlue = b; - - return CreateBeamEnts( beamInfo ); -} - -//----------------------------------------------------------------------------- -// Purpose: Create a beam between two entities. -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamEnts( BeamInfo_t &beamInfo ) -{ - // Don't start temporary beams out of the PVS - if ( beamInfo.m_flLife != 0 && ( !beamInfo.m_pStartEnt || beamInfo.m_pStartEnt->curstate.modelindex == 0 || - !beamInfo.m_pEndEnt || beamInfo.m_pEndEnt->curstate.modelindex == 0 )) - { - return NULL; - } - - beamInfo.m_vecStart = g_vecZero; - beamInfo.m_vecEnd = g_vecZero; - - Beam_t *pBeam = CreateGenericBeam( beamInfo ); - if ( !pBeam ) - return NULL; - - pBeam->type = ( beamInfo.m_nType < 0 ) ? TE_BEAMPOINTS : beamInfo.m_nType; - pBeam->flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY; - - pBeam->entity[0] = beamInfo.m_pStartEnt; - pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment; - pBeam->entity[1] = beamInfo.m_pEndEnt; - pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment; - - // Attributes. - SetBeamAttributes( pBeam, beamInfo ); - if ( beamInfo.m_flLife == 0 ) - { - pBeam->flags |= FBEAM_FOREVER; - } - - UpdateBeam( pBeam, 0 ); - - return pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Creates a beam between an entity and a point -// Input : startEnt - -// *end - -// modelIndex - -// life - -// width - -// amplitude - -// brightness - -// speed - -// startFrame - -// framerate - -// r - -// g - -// b - -// Output : Beam_t -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamEntPoint( int nStartEntity, const Vector *pStart, int nEndEntity, - const Vector* pEnd, int modelIndex, float life, float width, float endWidth, float fadeLength, - float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ) -{ - BeamInfo_t beamInfo; - - if ( nStartEntity <= 0 ) - { - beamInfo.m_vecStart = pStart ? *pStart : g_vecZero; - beamInfo.m_pStartEnt = NULL; - } - else - { - beamInfo.m_pStartEnt = LinkWithViewModel( BEAMENT_ENTITY( nStartEntity ) ); - beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( nStartEntity ); - - // don't start beams out of the PVS - if ( !beamInfo.m_pStartEnt ) - return NULL; - } - - if ( nEndEntity <= 0 ) - { - beamInfo.m_vecEnd = pEnd ? *pEnd : g_vecZero; - beamInfo.m_pEndEnt = NULL; - } - else - { - beamInfo.m_pEndEnt = LinkWithViewModel( BEAMENT_ENTITY( nEndEntity ) ); - beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( nEndEntity ); - - // Don't start beams out of the PVS - if ( !beamInfo.m_pEndEnt ) - return NULL; - } - - beamInfo.m_nModelIndex = modelIndex; - beamInfo.m_flLife = life; - beamInfo.m_flWidth = width; - beamInfo.m_flEndWidth = endWidth; - beamInfo.m_flFadeLength = fadeLength; - beamInfo.m_flAmplitude = amplitude; - beamInfo.m_flBrightness = brightness; - beamInfo.m_flSpeed = speed; - beamInfo.m_nStartFrame = startFrame; - beamInfo.m_flFrameRate = framerate; - beamInfo.m_flRed = r; - beamInfo.m_flGreen = g; - beamInfo.m_flBlue = b; - - return CreateBeamEntPoint( beamInfo ); -} - -Beam_t *CViewRenderBeams::CreateBeamEntPoint( int startEnt, Vector end, int modelIndex, float life, float width, - float amplitude, float brightness, float speed, int startFrame, float framerate, - float r, float g, float b ) -{ - return CreateBeamEntPoint( startEnt, NULL, 0, &end, modelIndex, life, width, width, 0.0f, amplitude, - brightness, speed, startFrame, framerate, r, g, b ); -} - -Beam_t *CViewRenderBeams::CreateBeamEnts( int startEnt, int endEnt, int modelIndex, float life, float width, - float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ) -{ - return CreateBeamEnts( startEnt, endEnt, modelIndex, life, width, width, 0.0f, amplitude, brightness, speed, - startFrame, framerate, r, g, b ); -} - -Beam_t *CViewRenderBeams::CreateBeamPoints( Vector start, Vector end, int modelIndex, float life, float width, - float amplitude, float brightness, float speed, int startFrame, float framerate, float r, float g, float b ) -{ - return CreateBeamPoints( start, end, modelIndex, life, width, width, 0.0f, amplitude, brightness, speed, - startFrame, framerate, r, g, b ); -} - -//----------------------------------------------------------------------------- -// Purpose: Creates a beam between an entity and a point. -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamEntPoint( BeamInfo_t &beamInfo ) -{ - if ( beamInfo.m_flLife != 0 ) - { - if ( beamInfo.m_pStartEnt && !beamInfo.m_pStartEnt->curstate.modelindex ) - return NULL; - - if ( beamInfo.m_pEndEnt && !beamInfo.m_pEndEnt->curstate.modelindex ) - return NULL; - } - - Beam_t *pBeam = CreateGenericBeam( beamInfo ); - if ( !pBeam ) - return NULL; - - pBeam->type = TE_BEAMPOINTS; - pBeam->flags = 0; - - if ( beamInfo.m_pStartEnt ) - { - pBeam->flags |= FBEAM_STARTENTITY; - pBeam->entity[0] = beamInfo.m_pStartEnt; - pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment; - beamInfo.m_vecStart = g_vecZero; - } - if ( beamInfo.m_pEndEnt ) - { - pBeam->flags |= FBEAM_ENDENTITY; - pBeam->entity[1] = beamInfo.m_pEndEnt; - pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment; - beamInfo.m_vecEnd = g_vecZero; - } - - SetBeamAttributes( pBeam, beamInfo ); - if ( beamInfo.m_flLife == 0 ) - { - pBeam->flags |= FBEAM_FOREVER; - } - - UpdateBeam( pBeam, 0 ); - - return pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Creates a beam between two points -// Input : *start - -// *end - -// modelIndex - -// life - -// width - -// amplitude - -// brightness - -// speed - -// startFrame - -// framerate - -// r - -// g - -// b - -// Output : Beam_t -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamPoints( Vector& start, Vector& end, int modelIndex, float life, float width, - float endWidth, float fadeLength,float amplitude, float brightness, float speed, int startFrame, - float framerate, float r, float g, float b ) -{ - BeamInfo_t beamInfo; - - beamInfo.m_vecStart = start; - beamInfo.m_vecEnd = end; - beamInfo.m_nModelIndex = modelIndex; - beamInfo.m_flLife = life; - beamInfo.m_flWidth = width; - beamInfo.m_flEndWidth = endWidth; - beamInfo.m_flFadeLength = fadeLength; - beamInfo.m_flAmplitude = amplitude; - beamInfo.m_flBrightness = brightness; - beamInfo.m_flSpeed = speed; - beamInfo.m_nStartFrame = startFrame; - beamInfo.m_flFrameRate = framerate; - beamInfo.m_flRed = r; - beamInfo.m_flGreen = g; - beamInfo.m_flBlue = b; - - return CreateBeamPoints( beamInfo ); -} - -//----------------------------------------------------------------------------- -// Purpose: Creates a beam between two points. -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamPoints( BeamInfo_t &beamInfo ) -{ - // don't start temporary beams out of the PVS - if ( beamInfo.m_flLife != 0 && !CullBeam( beamInfo.m_vecStart, beamInfo.m_vecEnd, 1 )) - return NULL; - - // Model index. - if (( beamInfo.m_pszModelName ) && ( beamInfo.m_nModelIndex == -1 ) ) - { - beamInfo.m_nModelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( beamInfo.m_pszModelName ); - } - - // Create the new beam. - Beam_t *pBeam = CreateGenericBeam( beamInfo ); - if ( !pBeam ) - return NULL; - - // Set beam initial state. - SetBeamAttributes( pBeam, beamInfo ); - if ( beamInfo.m_flLife == 0 ) - { - pBeam->flags |= FBEAM_FOREVER; - } - - return pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Creates a circular beam between two points -// Input : type - -// *start - -// *end - -// modelIndex - -// life - -// width - -// amplitude - -// brightness - -// speed - -// startFrame - -// framerate - -// r - -// g - -// b - -// Output : Beam_t -//----------------------------------------------------------------------------- -void CViewRenderBeams::CreateBeamCirclePoints( int type, Vector& start, Vector& end, int modelIndex, float life, - float width, float endWidth, float fadeLength,float amplitude, float brightness, float speed, - int startFrame, float framerate, float r, float g, float b ) -{ - BeamInfo_t beamInfo; - - beamInfo.m_nType = type; - beamInfo.m_vecStart = start; - beamInfo.m_vecEnd = end; - beamInfo.m_nModelIndex = modelIndex; - beamInfo.m_flLife = life; - beamInfo.m_flWidth = width; - beamInfo.m_flEndWidth = endWidth; - beamInfo.m_flFadeLength = fadeLength; - beamInfo.m_flAmplitude = amplitude; - beamInfo.m_flBrightness = brightness; - beamInfo.m_flSpeed = speed; - beamInfo.m_nStartFrame = startFrame; - beamInfo.m_flFrameRate = framerate; - beamInfo.m_flRed = r; - beamInfo.m_flGreen = g; - beamInfo.m_flBlue = b; - - CreateBeamCirclePoints( beamInfo ); -} - -//----------------------------------------------------------------------------- -// Purpose: Creates a circular beam between two points. -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamCirclePoints( BeamInfo_t &beamInfo ) -{ - Beam_t *pBeam = CreateGenericBeam( beamInfo ); - if ( !pBeam ) - return NULL; - - pBeam->type = beamInfo.m_nType; - - SetBeamAttributes( pBeam, beamInfo ); - if ( beamInfo.m_flLife == 0 ) - { - pBeam->flags |= FBEAM_FOREVER; - } - - return pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Create a beam which follows an entity -// Input : startEnt - -// modelIndex - -// life - -// width - -// r - -// g - -// b - -// brightness - -// Output : Beam_t -//----------------------------------------------------------------------------- -void CViewRenderBeams::CreateBeamFollow( int startEnt, int modelIndex, float life, float width, float endWidth, - float fadeLength, float r, float g, float b, float brightness ) -{ - BeamInfo_t beamInfo; - - beamInfo.m_pStartEnt = GetEntityByIndex( BEAMENT_ENTITY( startEnt )); - beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt ); - beamInfo.m_nModelIndex = modelIndex; - beamInfo.m_flLife = life; - beamInfo.m_flWidth = width; - beamInfo.m_flEndWidth = endWidth; - beamInfo.m_flFadeLength = fadeLength; - beamInfo.m_flBrightness = brightness; - beamInfo.m_flRed = r; - beamInfo.m_flGreen = g; - beamInfo.m_flBlue = b; - beamInfo.m_flAmplitude = life; - - CreateBeamFollow( beamInfo ); -} - -//----------------------------------------------------------------------------- -// Purpose: Create a beam which follows an entity. -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamFollow( BeamInfo_t &beamInfo ) -{ - beamInfo.m_vecStart = g_vecZero; - beamInfo.m_vecEnd = g_vecZero; - beamInfo.m_flSpeed = 1.0f; - Beam_t *pBeam = CreateGenericBeam( beamInfo ); - if ( !pBeam ) - return NULL; - - pBeam->type = TE_BEAMFOLLOW; - pBeam->flags = FBEAM_STARTENTITY; - pBeam->entity[0] = beamInfo.m_pStartEnt; - pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment; - - beamInfo.m_flFrameRate = 1.0f; - beamInfo.m_nStartFrame = 0; - - SetBeamAttributes( pBeam, beamInfo ); - - UpdateBeam( pBeam, 0 ); - - return pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Create a beam ring between two entities -// Input : startEnt - -// endEnt - -// modelIndex - -// life - -// width - -// amplitude - -// brightness - -// speed - -// startFrame - -// framerate - -// startEnt - -// Output : Beam_t -//----------------------------------------------------------------------------- -void CViewRenderBeams::CreateBeamRing( int startEnt, int endEnt, int modelIndex, float life, float width, - float endWidth, float fadeLength, float amplitude, float brightness, float speed, - int startFrame, float framerate, float r, float g, float b ) -{ - BeamInfo_t beamInfo; - - beamInfo.m_pStartEnt = GetEntityByIndex( BEAMENT_ENTITY( startEnt )); - beamInfo.m_nStartAttachment = BEAMENT_ATTACHMENT( startEnt ); - beamInfo.m_pEndEnt = GetEntityByIndex( BEAMENT_ENTITY( endEnt )); - beamInfo.m_nEndAttachment = BEAMENT_ATTACHMENT( endEnt ); - beamInfo.m_nModelIndex = modelIndex; - beamInfo.m_flLife = life; - beamInfo.m_flWidth = width; - beamInfo.m_flEndWidth = endWidth; - beamInfo.m_flFadeLength = fadeLength; - beamInfo.m_flAmplitude = amplitude; - beamInfo.m_flBrightness = brightness; - beamInfo.m_flSpeed = speed; - beamInfo.m_nStartFrame = startFrame; - beamInfo.m_flFrameRate = framerate; - beamInfo.m_flRed = r; - beamInfo.m_flGreen = g; - beamInfo.m_flBlue = b; - - CreateBeamRing( beamInfo ); -} - -//----------------------------------------------------------------------------- -// Purpose: Create a beam ring between two entities. -// Input: beamInfo - -//----------------------------------------------------------------------------- -Beam_t *CViewRenderBeams::CreateBeamRing( BeamInfo_t &beamInfo ) -{ - // Don't start temporary beams out of the PVS - if ( beamInfo.m_flLife != 0 && - ( !beamInfo.m_pStartEnt || beamInfo.m_pStartEnt->curstate.modelindex == NULL || - !beamInfo.m_pEndEnt || beamInfo.m_pEndEnt->curstate.modelindex == NULL )) - { - return NULL; - } - - beamInfo.m_vecStart = g_vecZero; - beamInfo.m_vecEnd = g_vecZero; - Beam_t *pBeam = CreateGenericBeam( beamInfo ); - if ( !pBeam ) - return NULL; - - pBeam->type = TE_BEAMRING; - pBeam->flags = FBEAM_STARTENTITY | FBEAM_ENDENTITY; - pBeam->entity[0] = beamInfo.m_pStartEnt; - pBeam->attachmentIndex[0] = beamInfo.m_nStartAttachment; - pBeam->entity[1] = beamInfo.m_pEndEnt; - pBeam->attachmentIndex[1] = beamInfo.m_nEndAttachment; - - SetBeamAttributes( pBeam, beamInfo ); - if ( beamInfo.m_flLife == 0 ) - { - pBeam->flags |= FBEAM_FOREVER; - } - - UpdateBeam( pBeam, 0 ); - - return pBeam; -} - -//----------------------------------------------------------------------------- -// Purpose: Free dead trails associated with beam -// Input : **ppparticles - -//----------------------------------------------------------------------------- -void CViewRenderBeams::FreeDeadTrails( BeamTrail_t **trail ) -{ - BeamTrail_t *kill; - BeamTrail_t *p; - - // kill all the ones hanging direcly off the base pointer - while ( 1 ) - { - kill = *trail; - if ( kill && kill->die < GetClientTime() ) - { - *trail = kill->next; - kill->next = m_pFreeTrails; - m_pFreeTrails = kill; - continue; - } - break; - } - - // kill off all the others - for ( p = *trail; p; p = p->next ) - { - while ( 1 ) - { - kill = p->next; - if ( kill && kill->die < GetClientTime() ) - { - p->next = kill->next; - kill->next = m_pFreeTrails; - m_pFreeTrails = kill; - continue; - } - break; - } - } -} - - - -//----------------------------------------------------------------------------- -// Updates beam state -//----------------------------------------------------------------------------- -void CViewRenderBeams::UpdateBeam( Beam_t *pbeam, float frametime ) -{ - pbeam->m_bCulled = false; - - if ( Mod_GetModelType( pbeam->modelIndex ) == mod_bad ) - { - pbeam->m_bCulled = true; // force to ignore - pbeam->die = GetClientTime(); - return; - } - - // If FBEAM_ONLYNOISEONCE is set, we don't want to move once we've first calculated noise - if (!( pbeam->flags & FBEAM_ONLYNOISEONCE ) ) - { - pbeam->freq += frametime; - } - else - { - pbeam->freq += frametime * RANDOM_FLOAT( 1.0f, 2.0f ); - } - - // OPTIMIZE: Do this every frame? - // UNDONE: Do this differentially somehow? - // Generate fractal noise - pbeam->rgNoise[0] = 0; - pbeam->rgNoise[NOISE_DIVISIONS] = 0; - - if ( pbeam->amplitude != 0 ) - { - if(!( pbeam->flags & FBEAM_ONLYNOISEONCE ) || !pbeam->m_bCalculatedNoise ) - { - if ( pbeam->flags & FBEAM_SINENOISE ) - { - SineNoise( pbeam->rgNoise, NOISE_DIVISIONS ); - } - else - { - FracNoise( pbeam->rgNoise, NOISE_DIVISIONS, 1.0f ); - } - pbeam->m_bCalculatedNoise = true; - } - } - - // update end points - if ( pbeam->flags & ( FBEAM_STARTENTITY|FBEAM_ENDENTITY )) - { - // Makes sure attachment[0] + attachment[1] are valid - if (!RecomputeBeamEndpoints( pbeam )) - { - pbeam->m_bCulled = true; // force to ignore - return; - } - // Compute segments from the new endpoints - pbeam->delta = pbeam->attachment[1] - pbeam->attachment[0]; - if ( pbeam->amplitude >= 0.50f ) - pbeam->segments = pbeam->delta.Length( ) * 0.25f + 3.0f; // one per 4 pixels - else - pbeam->segments = pbeam->delta.Length( ) * 0.075f + 3.0f; // one per 16 pixels - } - - // Get position data for spline beam - switch ( pbeam->type ) - { - case TE_BEAMPOINTS: - // UNDONE: Build culling volumes for other types of beams - if ( !CullBeam( pbeam->attachment[0], pbeam->attachment[1], 0 )) - { - pbeam->m_bCulled = true; // force to ignore - return; - } - break; - } - - // update life cycle - pbeam->t = pbeam->freq + (pbeam->die - GetClientTime()); - if ( pbeam->t != 0.0f ) pbeam->t = 1.0 - pbeam->freq / pbeam->t; - - // ------------------------------------------ - // check for zero fadeLength (means no fade) - // ------------------------------------------ - if ( pbeam->fadeLength == 0.0f ) - { - ASSERT( pbeam->delta.IsValid() ); - pbeam->fadeLength = pbeam->delta.Length(); - } -} - -bool CViewRenderBeams::AttemptToDie( Beam_t *pBeam ) -{ - ASSERT( pBeam != NULL ); - - // premanent beams never die automatically - if( pBeam->flags & FBEAM_FOREVER ) - return false; - - if( pBeam->type == TE_BEAMFOLLOW && pBeam->trail ) - { - // wait for all trails are dead - return false; - } - - // other beams - if( pBeam->die > GetClientTime() ) - return false; - - return true; -} - -//----------------------------------------------------------------------------- -// Purpose: Update beams created by temp entity system -//----------------------------------------------------------------------------- - -void CViewRenderBeams::UpdateTempEntBeams( void ) -{ - if ( !m_pActiveBeams ) - return; - - // Draw temporary entity beams - Beam_t* pPrev = 0; - Beam_t* pNext; - for ( Beam_t* pBeam = m_pActiveBeams; pBeam ; pBeam = pNext ) - { - // Need to store the next one since we may delete this one - pNext = pBeam->next; - - // Retire old beams - if ( AttemptToDie( pBeam ) ) - { - // Reset links - if ( pPrev ) - { - pPrev->next = pNext; - } - else - { - m_pActiveBeams = pNext; - } - - // Free the beam - BeamFree( pBeam ); - - pBeam = NULL; - continue; - } - - // Update beam state - UpdateBeam( pBeam, m_flFrameTime ); - - // Compute bounds for the beam - pBeam->ComputeBounds(); - - pPrev = pBeam; - } -} - - -//----------------------------------------------------------------------------- -// Purpose: Draw helper for beam follow beams -// Input : *pbeam - -// frametime - -// *color - -//----------------------------------------------------------------------------- -void CViewRenderBeams::DrawBeamFollow( int spriteIndex, Beam_t *pbeam, int frame, int rendermode, float frametime, - const float* color ) -{ - BeamTrail_t *particles; - BeamTrail_t *pnew; - float div; - Vector delta; - - Vector screenLast; - Vector screen; - - FreeDeadTrails( &pbeam->trail ); - - particles = pbeam->trail; - pnew = NULL; - - div = 0; - if ( pbeam->flags & FBEAM_STARTENTITY ) - { - if ( particles ) - { - delta = particles->org - pbeam->attachment[0]; - div = delta.Length( ); - - if ( div >= 32 && m_pFreeTrails ) - { - pnew = m_pFreeTrails; - m_pFreeTrails = pnew->next; - } - } - else if ( m_pFreeTrails ) - { - pnew = m_pFreeTrails; - m_pFreeTrails = pnew->next; - div = 0; - } - } - - if ( pnew ) - { - pnew->org = pbeam->attachment[0]; - pnew->die = GetClientTime() + pbeam->amplitude; - pnew->vel = g_vecZero; - - pnew->next = particles; - pbeam->trail = pnew; - particles = pnew; - } - - if ( !particles ) - { - return; - } - if ( !pnew && div != 0 ) - { - delta = pbeam->attachment[0]; - gEngfuncs.pTriAPI->WorldToScreen( pbeam->attachment[0], screenLast ); - gEngfuncs.pTriAPI->WorldToScreen( particles->org, screen ); - } - else if ( particles && particles->next ) - { - delta = particles->org; - gEngfuncs.pTriAPI->WorldToScreen( particles->org, screenLast ); - gEngfuncs.pTriAPI->WorldToScreen( particles->next->org, screen ); - particles = particles->next; - } - else - { - return; - } - - // Draw it - ::DrawBeamFollow( spriteIndex, pbeam->trail, frame, rendermode, delta, screen, screenLast, - pbeam->die, pbeam->attachment[0], pbeam->flags, pbeam->width, - pbeam->amplitude, pbeam->freq, (float*)color ); - - // Drift popcorn trail if there is a velocity - particles = pbeam->trail; - while ( particles ) - { - particles->org = particles->org + (particles->vel * frametime); - particles = particles->next; - } -} - - -//------------------------------------------------------------------------------ -// Purpose : Draw a beam based upon the viewpoint -//------------------------------------------------------------------------------ -void CViewRenderBeams::DrawLaser( Beam_t *pbeam, int frame, int rendermode, float *color, int spriteIndex ) -{ - float color2[3]; - - color2[0] = color[0]; - color2[1] = color[1]; - color2[2] = color[2]; - - Vector vecForward; - Vector beamDir = ( pbeam->attachment[1] - pbeam->attachment[0] ).Normalize(); - - AngleVectors( pViewParams->viewangles, vecForward, NULL, NULL ); - float flDot = DotProduct( beamDir, vecForward ); - - // abort if the player's looking along it away from the source - if ( flDot > 0 ) - { - return; - } - else - { - // Fade the beam if the player's not looking at the source - float flFade = pow( flDot, 10 ); - - // Fade the beam based on the player's proximity to the beam - Vector localDir = pViewParams->vieworg - pbeam->attachment[0]; - flDot = DotProduct( beamDir, localDir ); - Vector vecProjection = flDot * beamDir; - float flDistance = ( localDir - vecProjection ).Length(); - - if ( flDistance > 30 ) - { - flDistance = 1 - (( flDistance - 30 ) / 64); - if ( flDistance <= 0 ) - { - flFade = 0; - } - else - { - flFade *= pow( flDistance, 3 ); - } - } - - if (flFade < (1.0f / 255.0f)) - return; - - color2[0] *= flFade; - color2[1] *= flFade; - color2[2] *= flFade; - - //gEngfuncs.Con_Printf( "Fade: %f", flFade ); - //gEngfuncs.Con_Printf( "Dist: %f", flDistance ); - } - - DrawSegs( NOISE_DIVISIONS, pbeam->rgNoise, spriteIndex, frame, rendermode, pbeam->attachment[0], - pbeam->delta, pbeam->width, pbeam->endWidth, pbeam->amplitude, pbeam->freq, pbeam->speed, - pbeam->segments, pbeam->flags, color2, pbeam->fadeLength ); - -} - -//----------------------------------------------------------------------------- -// Purpose: Draw all beam entities -// Input : *pbeam - -// frametime - -//----------------------------------------------------------------------------- -void CViewRenderBeams::DrawBeam( Beam_t *pbeam ) -{ - ASSERT( pbeam->delta.IsValid() ); - - // Don't draw really short beams - if ( pbeam->m_bCulled || pbeam->delta.Length() < 0.1f ) - { - return; - } - - if ( Mod_GetModelType( pbeam->modelIndex ) == mod_bad ) - { - pbeam->die = GetClientTime(); - return; - } - - int frame = (( int )( pbeam->frame + GetClientTime() * pbeam->frameRate) % pbeam->frameCount ); - int rendermode = ( pbeam->flags & FBEAM_SOLID ) ? kRenderNormal : kRenderTransAdd; - - // set color - float srcColor[3]; - float color[3]; - - srcColor[0] = pbeam->r; - srcColor[1] = pbeam->g; - srcColor[2] = pbeam->b; - - if ( pbeam->flags & FBEAM_FADEIN ) - { - color[0] = srcColor[0] * pbeam->t; - color[1] = srcColor[1] * pbeam->t; - color[2] = srcColor[2] * pbeam->t; - } - else if ( pbeam->flags & FBEAM_FADEOUT ) - { - color[0] = srcColor[0] * ( 1.0f - pbeam->t ); - color[1] = srcColor[1] * ( 1.0f - pbeam->t ); - color[2] = srcColor[2] * ( 1.0f - pbeam->t ); - } - else - { - color[0] = srcColor[0]; - color[1] = srcColor[1]; - color[2] = srcColor[2]; - } - - // HACKHACK: for Salute mod - if( pbeam->type == TE_BEAMFOLLOW && pbeam->entity[0] && pbeam->entity[0]->curstate.rendermode != kRenderNormal ) - pbeam->brightness = pbeam->entity[0]->curstate.renderamt; - - color[0] *= ((float)pbeam->brightness / 255.0); - color[1] *= ((float)pbeam->brightness / 255.0); - color[2] *= ((float)pbeam->brightness / 255.0); - color[0] *= (1/255.0); - color[1] *= (1/255.0); - color[2] *= (1/255.0); - - switch( pbeam->type ) - { - case TE_BEAMDISK: - DrawDisk( NOISE_DIVISIONS, pbeam->rgNoise, pbeam->modelIndex, frame, rendermode, - pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude, - pbeam->freq, pbeam->speed, pbeam->segments, color ); - break; - case TE_BEAMCYLINDER: - DrawCylinder( NOISE_DIVISIONS, pbeam->rgNoise, pbeam->modelIndex, frame, rendermode, - pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude, - pbeam->freq, pbeam->speed, pbeam->segments, color ); - break; - case TE_BEAMPOINTS: - DrawSegs( NOISE_DIVISIONS, pbeam->rgNoise, pbeam->modelIndex, frame, rendermode, - pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->endWidth, - pbeam->amplitude, pbeam->freq, pbeam->speed, pbeam->segments, - pbeam->flags, color, pbeam->fadeLength ); - break; - case TE_BEAMFOLLOW: - DrawBeamFollow( pbeam->modelIndex, pbeam, frame, rendermode, m_flFrameTime, color ); - break; - case TE_BEAMRING: - DrawRing( NOISE_DIVISIONS, pbeam->rgNoise, FracNoise, pbeam->modelIndex, frame, rendermode, - pbeam->attachment[0], pbeam->delta, pbeam->width, pbeam->amplitude, - pbeam->freq, pbeam->speed, pbeam->segments, color ); - break; - case TE_BEAMHOSE: - DrawLaser( pbeam, frame, rendermode, color, pbeam->modelIndex ); - break; - default: - gEngfuncs.Con_Printf( "CViewRenderBeams::DrawBeam: Unknown beam type %i\n", pbeam->type ); - break; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Update the beam -//----------------------------------------------------------------------------- -void CViewRenderBeams::UpdateBeamInfo( Beam_t *pBeam, BeamInfo_t &beamInfo ) -{ - pBeam->attachment[0] = beamInfo.m_vecStart; - pBeam->attachment[1] = beamInfo.m_vecEnd; - pBeam->delta = beamInfo.m_vecEnd - beamInfo.m_vecStart; - - ASSERT( pBeam->delta.IsValid() ); - - SetBeamAttributes( pBeam, beamInfo ); -} - - -//----------------------------------------------------------------------------- -// Recomputes beam endpoints.. -//----------------------------------------------------------------------------- -bool CViewRenderBeams::RecomputeBeamEndpoints( Beam_t *pbeam ) -{ - if ( pbeam->flags & FBEAM_STARTENTITY ) - { - if( ComputeBeamEntPosition( pbeam->entity[0], pbeam->attachmentIndex[0], pbeam->attachment[0] )) - { - pbeam->flags |= FBEAM_STARTVISIBLE; - } - else if (!( pbeam->flags & FBEAM_FOREVER )) - { - pbeam->flags &= ~(FBEAM_STARTENTITY); - } - else - { - // gEngfuncs.Con_Printf( "Warning: can't find start entity\n" ); - // return false; - } - - // If we've never seen the start entity, don't display - if (!( pbeam->flags & FBEAM_STARTVISIBLE )) - return false; - } - - if ( pbeam->flags & FBEAM_ENDENTITY ) - { - if ( ComputeBeamEntPosition( pbeam->entity[1], pbeam->attachmentIndex[1], pbeam->attachment[1] )) - { - pbeam->flags |= FBEAM_ENDVISIBLE; - } - else if (!( pbeam->flags & FBEAM_FOREVER )) - { - pbeam->flags &= ~(FBEAM_ENDENTITY); - pbeam->die = GetClientTime(); - return false; - } - else - { - return false; - } - - // If we've never seen the end entity, don't display - if (!( pbeam->flags & FBEAM_ENDVISIBLE )) - return false; - } - return true; -} - -void CViewRenderBeams::ClearServerBeams( void ) -{ - m_nNumServerBeams = 0; -} - -void CViewRenderBeams::AddServerBeam( cl_entity_t *pEnvBeam ) -{ - if( m_nNumServerBeams >= MAX_BEAMS ) - { - gEngfuncs.Con_Printf( "ERROR: Too many static beams %d!\n", m_nNumServerBeams ); - return; - } - - if( pEnvBeam && !( pEnvBeam->curstate.effects & EF_NODRAW )) - { - m_pServerBeams[m_nNumServerBeams] = pEnvBeam; - m_nNumServerBeams++; - } -} - -//----------------------------------------------------------------------------- -// change client edict to viewmodel for local client in firstperson -//----------------------------------------------------------------------------- -cl_entity_t *CViewRenderBeams::LinkWithViewModel( int entindex ) -{ - if ( entindex <= 0 ) // no entity specified ? - return NULL; - - cl_entity_t *pEnt; - - pEnt = GetEntityByIndex( entindex ); - - if ( !pEnt ) - return NULL; - - if ( EV_IsLocal( pEnt->index ) && ( pViewParams->flags & RDF_THIRDPERSON ) == 0 ) - { - return GetViewModel(); // change client edict to viewmodel edict - } - - return pEnt; // unchanged -} - -ref_params_t *CViewRenderBeams::GetViewParams( void ) -{ - return pViewParams; -} - -void CViewRenderBeams::SetViewParams( ref_params_t *pparams ) -{ - // always keep refdef an actual - pViewParams = pparams; -} - -void CViewRenderBeams::UpdateBeams( int fTrans ) -{ - if( !fTrans ) - { - // get this once - m_fOldTime = m_flTime; - m_flTime = GetClientTime(); - } - - // Get frame time - m_flFrameTime = m_flTime - m_fOldTime; - // gEngfuncs.Con_DPrintf( "frametime %g\n", m_flFrameTime ); - - for( int i = 0; i < m_nNumServerBeams; i++ ) - { - cl_entity_t *pBeam = m_pServerBeams[i]; - - if( (fTrans && pBeam->curstate.renderfx & FBEAM_SOLID) || (!fTrans && !(pBeam->curstate.renderfx & FBEAM_SOLID))) - continue; - - DrawBeam( pBeam ); - } - - if ( !m_pActiveBeams ) - return; - - // Draw temporary entity beams - Beam_t *pNext, *pBeam; - - for ( pBeam = m_pActiveBeams; pBeam ; pBeam = pNext ) - { - // Need to store the next one since we may delete this one - pNext = pBeam->next; - - if( (fTrans && pBeam->flags & FBEAM_SOLID) || (!fTrans && !(pBeam->flags & FBEAM_SOLID))) - continue; - - // Update beam state - DrawBeam( pBeam ); - } -} - -//----------------------------------------------------------------------------- -// Draws a single beam -//----------------------------------------------------------------------------- -void CViewRenderBeams::DrawBeam( cl_entity_t *pbeam ) -{ - Beam_t beam; - - // NOTE: beam settings stored in various entavrs_t fields - // see effects.h for details - - // Set up the beam. - int beamType = ( pbeam->curstate.rendermode & 0x0F ); - - BeamInfo_t beamInfo; - beamInfo.m_vecStart = pbeam->origin; - beamInfo.m_vecEnd = pbeam->angles; - beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL; - beamInfo.m_nModelIndex = pbeam->curstate.modelindex; - beamInfo.m_flLife = 0; - beamInfo.m_flWidth = pbeam->curstate.scale; - beamInfo.m_flEndWidth = beamInfo.m_flWidth; - beamInfo.m_flFadeLength = 0.0f; // will be set on first call UpdateBeam - beamInfo.m_flAmplitude = (float)(pbeam->curstate.body * 0.1f); - beamInfo.m_flBrightness = pbeam->curstate.renderamt; - beamInfo.m_flSpeed = pbeam->curstate.animtime; - - SetupBeam( &beam, beamInfo ); - - beamInfo.m_nStartFrame = pbeam->curstate.frame; - beamInfo.m_flFrameRate = pbeam->curstate.framerate; - beamInfo.m_flRed = pbeam->curstate.rendercolor.r; - beamInfo.m_flGreen = pbeam->curstate.rendercolor.g; - beamInfo.m_flBlue = pbeam->curstate.rendercolor.b; - - SetBeamAttributes( &beam, beamInfo ); - - // handle code from relinking. - switch( beamType ) - { - case BEAM_ENTS: - beam.type = TE_BEAMPOINTS; - beam.flags = FBEAM_STARTENTITY|FBEAM_ENDENTITY; - beam.entity[0] = LinkWithViewModel( BEAMENT_ENTITY( pbeam->curstate.sequence )); - beam.attachmentIndex[0] = BEAMENT_ATTACHMENT( pbeam->curstate.sequence ); - beam.entity[1] = LinkWithViewModel( BEAMENT_ENTITY( pbeam->curstate.skin )); - beam.attachmentIndex[1] = BEAMENT_ATTACHMENT( pbeam->curstate.skin ); - beam.numAttachments = (beam.entity[0]) ? ((beam.entity[1]) ? 2 : 1) : 0; - break; - case BEAM_HOSE: - beam.type = TE_BEAMHOSE; - beam.flags = FBEAM_STARTENTITY|FBEAM_ENDENTITY; - beam.entity[0] = LinkWithViewModel( BEAMENT_ENTITY( pbeam->curstate.sequence )); - beam.attachmentIndex[0] = BEAMENT_ATTACHMENT( pbeam->curstate.sequence ); - beam.entity[1] = LinkWithViewModel( BEAMENT_ENTITY( pbeam->curstate.skin )); - beam.attachmentIndex[1] = BEAMENT_ATTACHMENT( pbeam->curstate.skin ); - beam.numAttachments = (beam.entity[0]) ? ((beam.entity[1]) ? 2 : 1) : 0; - break; - case BEAM_ENTPOINT: - beam.type = TE_BEAMPOINTS; - beam.flags = 0; - beam.entity[0] = LinkWithViewModel( BEAMENT_ENTITY( pbeam->curstate.sequence )); - beam.attachmentIndex[0] = BEAMENT_ATTACHMENT( pbeam->curstate.sequence ); - beam.entity[1] = LinkWithViewModel( BEAMENT_ENTITY( pbeam->curstate.skin )); - beam.attachmentIndex[1] = BEAMENT_ATTACHMENT( pbeam->curstate.skin ); - beam.numAttachments = 0; - beam.flags = 0; - if ( beam.entity[0] ) - { - beam.flags |= FBEAM_STARTENTITY; - beam.numAttachments++; - } - if ( beam.entity[1] ) - { - beam.flags |= FBEAM_ENDENTITY; - beam.numAttachments++; - } - break; - case BEAM_POINTS: - // already set up - break; - } - - beam.flags |= ( pbeam->curstate.rendermode & 0xF0 ) & (FBEAM_SINENOISE|FBEAM_SOLID|FBEAM_SHADEIN|FBEAM_SHADEOUT); - - // draw it - UpdateBeam( &beam, m_flFrameTime ); - DrawBeam( &beam ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : noise_divisions - -// *prgNoise - -// *spritemodel - -// frame - -// rendermode - -// source - -// delta - -// flags - -// *color - -// fadescale - -//----------------------------------------------------------------------------- -void DrawSegs( int noise_divisions, float *prgNoise, int modelIndex, float frame, int rendermode, - const Vector& source, const Vector& delta, float startWidth, float endWidth, float scale, - float freq, float speed, int segments, int flags, float* color, float fadeLength ) -{ - int i, noiseIndex, noiseStep; - float div, length, fraction, factor, vLast, vStep, brightness; - - if( !cl_draw_beams->value ) - return; - - ASSERT( fadeLength >= 0.0f ); - HSPRITE m_hSprite = gEngfuncs.pTriAPI->GetSpriteTexture( modelIndex, frame ); - - if ( !m_hSprite ) - return; - - if ( segments < 2 ) - return; - - length = delta.Length( ); - float flMaxWidth = max( startWidth, endWidth ) * 0.5f; - div = 1.0 / (segments - 1); - - if ( length*div < flMaxWidth * 1.414f ) - { - // Here, we have too many segments; we could get overlap... so lets have less segments - segments = (int)(length / ( flMaxWidth * 1.414f )) + 1; - if ( segments < 2 ) segments = 2; - } - - if ( segments > noise_divisions ) // UNDONE: Allow more segments? - { - segments = noise_divisions; - } - - div = 1.0 / (segments-1); - length *= 0.01; - - // UNDONE: Expose texture length scale factor to control "fuzziness" - vStep = length * div; // Texture length texels per space pixel - - // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam - // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) - vLast = fmod( freq * speed, 1 ); - - if ( flags & FBEAM_SINENOISE ) - { - if ( segments < 16 ) - { - segments = 16; - div = 1.0 / (segments - 1); - } - scale *= 10; - length = segments * (1.0f / 10); - } - else - { - scale *= length; - } - - // Iterator to resample noise waveform (it needs to be generated in powers of 2) - noiseStep = (int)((float)(noise_divisions - 1) * div * 65536.0f); - noiseIndex = 0; - - if ( flags & FBEAM_SINENOISE ) - { - noiseIndex = 0; - } - - brightness = 1.0; - if ( flags & FBEAM_SHADEIN ) - { - brightness = 0; - } - - // What fraction of beam should be faded - ASSERT( fadeLength >= 0.0f ); - float fadeFraction = fadeLength / delta.Length(); - - // BUGBUG: This code generates NANs when fadeFraction is zero! REVIST! - fadeFraction = bound( 1e-6, fadeFraction, 1.0f ); - - // Choose two vectors that are perpendicular to the beam - Vector perp1; - ComputeBeamPerpendicular( delta, &perp1 ); - - // Specify all the segments. - CBeamSegDraw segDraw; - segDraw.Start( segments, m_hSprite, rendermode, frame ); - - for ( i = 0; i < segments; i++ ) - { - ASSERT( noiseIndex < ( noise_divisions << 16 )); - CBeamSeg curSeg; - curSeg.m_flAlpha = 1; - - fraction = i * div; - - // Fade in our out beam to fadeLength - - if (( flags & FBEAM_SHADEIN ) && ( flags & FBEAM_SHADEOUT )) - { - if (fraction < 0.5) - { - brightness = 2 * (fraction / fadeFraction); - } - else - { - brightness = 2 * (1.0f - (fraction / fadeFraction)); - } - } - else if ( flags & FBEAM_SHADEIN ) - { - brightness = fraction / fadeFraction; - } - else if ( flags & FBEAM_SHADEOUT ) - { - brightness = 1.0f - (fraction / fadeFraction); - } - - // clamps - if ( brightness < 0 ) - { - brightness = 0; - } - else if ( brightness > 1 ) - { - brightness = 1; - } - - curSeg.m_vColor.x = color[0] * brightness; - curSeg.m_vColor.y = color[1] * brightness; - curSeg.m_vColor.z = color[2] * brightness; - - // UNDONE: Make this a spline instead of just a line? - curSeg.m_vPos = source + ( delta * fraction ); - - // Distort using noise - if ( scale != 0 ) - { - factor = prgNoise[noiseIndex>>16] * scale; - if ( flags & FBEAM_SINENOISE ) - { - float s, c; - SinCos( fraction * M_PI * length + freq, &s, &c ); - - curSeg.m_vPos = curSeg.m_vPos + g_pViewRenderBeams->GetViewParams()->up * (factor * s); - // Rotate the noise along the perpendicluar axis a bit to keep the bolt - // from looking diagonal - curSeg.m_vPos = curSeg.m_vPos + g_pViewRenderBeams->GetViewParams()->right * (factor * c); - } - else - { - curSeg.m_vPos = curSeg.m_vPos + perp1 * factor; - } - } - - // Specify the next segment. - if( endWidth == startWidth ) - { - curSeg.m_flWidth = startWidth * 2; - } - else - { - curSeg.m_flWidth = ((fraction*(endWidth-startWidth))+startWidth) * 2; - } - - curSeg.m_flTexCoord = vLast; - segDraw.NextSeg( &curSeg ); - - vLast += vStep; // Advance texture scroll (v axis only) - noiseIndex += noiseStep; - } - - segDraw.End(); -} - - -//----------------------------------------------------------------------------- -// Purpose: -// Input : noise_divisions - -// *prgNoise - -// *spritemodel - -// frame - -// rendermode - -// source - -// delta - -// width - -// scale - -// freq - -// speed - -// segments - -// *color - -//----------------------------------------------------------------------------- -void DrawDisk( int noise_divisions, float *prgNoise, int modelIndex, float frame, int rendermode, - const Vector& source, const Vector& delta, float width, float scale, float freq, float speed, - int segments, float* color ) -{ - int i; - float div, length, fraction, vLast, vStep; - Vector point; - float w; - - HSPRITE m_hSprite = gEngfuncs.pTriAPI->GetSpriteTexture( modelIndex, frame ); - - if ( !m_hSprite ) - return; - - if ( segments < 2 ) - return; - - if ( segments > noise_divisions ) // UNDONE: Allow more segments? - segments = noise_divisions; - - length = delta.Length( ) * 0.01f; - if ( length < 0.5f ) length = 0.5f; // Don't lose all of the noise/texture on short beams - - div = 1.0 / (segments-1); - - // UNDONE: Expose texture length scale factor to control "fuzziness" - vStep = length * div; // Texture length texels per space pixel - - // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam - // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) - vLast = fmod( freq * speed, 1 ); - scale = scale * length; - - w = freq * delta[2]; - - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - gEngfuncs.pTriAPI->RenderMode( rendermode ); - gEngfuncs.pTriAPI->Bind( m_hSprite, 0 ); // GetSpriteTexture already set frame - - gEngfuncs.pTriAPI->Begin( TRI_TRIANGLE_STRIP ); - - // NOTE: We must force the degenerate triangles to be on the edge - for ( i = 0; i < segments; i++ ) - { - float s, c; - fraction = i * div; - - point[0] = source[0]; - point[1] = source[1]; - point[2] = source[2]; - - gEngfuncs.pTriAPI->Color4f( color[0], color[1], color[2], 1.0f ); - gEngfuncs.pTriAPI->TexCoord2f( 1.0f, vLast ); - gEngfuncs.pTriAPI->Vertex3fv( point ); - - s = sin( fraction * 2 * M_PI ); - c = cos( fraction * 2 * M_PI ); - point[0] = s * w + source[0]; - point[1] = c * w + source[1]; - point[2] = source[2]; - - gEngfuncs.pTriAPI->Color4f( color[0], color[1], color[2], 1.0f ); - gEngfuncs.pTriAPI->TexCoord2f( 0.0f, vLast ); - gEngfuncs.pTriAPI->Vertex3fv( point ); - - vLast += vStep; // Advance texture scroll (v axis only) - } - - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : noise_divisions - -// *prgNoise - -// *spritemodel - -// frame - -// rendermode - -// source - -// delta - -// width - -// scale - -// freq - -// speed - -// segments - -// *color - -//----------------------------------------------------------------------------- -void DrawCylinder( int noise_divisions, float *prgNoise, int modelIndex, float frame, int rendermode, - const Vector& source, const Vector& delta, float width, float scale, float freq, float speed, - int segments, float* color ) -{ - int i; - float div, length, fraction, vLast, vStep; - Vector point; - - HSPRITE m_hSprite = gEngfuncs.pTriAPI->GetSpriteTexture( modelIndex, frame ); - - if ( !m_hSprite ) - return; - - if ( segments < 2 ) - return; - - if ( segments > noise_divisions ) // UNDONE: Allow more segments? - segments = noise_divisions; - - length = delta.Length( ) * 0.01f; - if ( length < 0.5f ) length = 0.5f; // Don't lose all of the noise/texture on short beams - - div = 1.0f / (segments - 1); - - // UNDONE: Expose texture length scale factor to control "fuzziness" - vStep = length * div; // Texture length texels per space pixel - - // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam - // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) - vLast = fmod(freq * speed, 1.0f ); - scale = scale * length; - - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - gEngfuncs.pTriAPI->RenderMode( rendermode ); - gEngfuncs.pTriAPI->Bind( m_hSprite, 0 ); // GetSpriteTexture already set frame - - gEngfuncs.pTriAPI->Begin( TRI_TRIANGLE_STRIP ); - - float radius = delta[2]; - for ( i = 0; i < segments; i++ ) - { - float s, c; - fraction = i * div; - s = sin( fraction * 2 * M_PI ); - c = cos( fraction * 2 * M_PI ); - - point[0] = s * freq * radius + source[0]; - point[1] = c * freq * radius + source[1]; - point[2] = source[2] + width; - - gEngfuncs.pTriAPI->Color4f( 0.0f, 0.0f, 0.0f, 1.0f ); - gEngfuncs.pTriAPI->TexCoord2f( 1.0f, vLast ); - gEngfuncs.pTriAPI->Vertex3fv( point ); - - point[0] = s * freq * (radius + width) + source[0]; - point[1] = c * freq * (radius + width) + source[1]; - point[2] = source[2] - width; - - gEngfuncs.pTriAPI->Color4f( color[0], color[1], color[2], 1.0f ); - gEngfuncs.pTriAPI->TexCoord2f( 0.0f, vLast ); - gEngfuncs.pTriAPI->Vertex3fv( point ); - - vLast += vStep; // Advance texture scroll (v axis only) - } - - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); - gEngfuncs.pTriAPI->CullFace( TRI_FRONT ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : noise_divisions - -// *prgNoise - -// (*pfnNoise - -//----------------------------------------------------------------------------- -void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ), - int modelIndex, float frame, int rendermode, const Vector& source, const Vector& delta, float width, - float amplitude, float freq, float speed, int segments, float *color ) -{ - int i, j, noiseIndex, noiseStep; - float div, length, fraction, factor, vLast, vStep; - Vector last1, last2, point, screen, screenLast(0,0,0), tmp, normal; - Vector center, xaxis, yaxis, zaxis; - float radius, x, y, scale; - Vector d; - - HSPRITE m_hSprite = gEngfuncs.pTriAPI->GetSpriteTexture( modelIndex, frame ); - - if ( !m_hSprite ) - return; - - d = delta; - - if ( segments < 2 ) - return; - - segments = segments * M_PI; - - if ( segments > noise_divisions * 8 ) // UNDONE: Allow more segments? - segments = noise_divisions * 8; - - length = d.Length( ) * 0.01f * M_PI; - if ( length < 0.5f ) length = 0.5f; // Don't lose all of the noise/texture on short beams - - div = 1.0 / (segments - 1); - - // UNDONE: Expose texture length scale factor to control "fuzziness" - vStep = length * div / 8.0f; // Texture length texels per space pixel - - // UNDONE: Expose this paramter as well(3.5)? Texture scroll rate along beam - // Scroll speed 3.5 -- initial texture position, scrolls 3.5/sec (1.0 is entire texture) - vLast = fmod( freq * speed, 1.0f ); - scale = amplitude * length / 8.0f; - - // Iterator to resample noise waveform (it needs to be generated in powers of 2) - noiseStep = (int)((noise_divisions - 1) * div * 65536.0) * 8; - noiseIndex = 0; - - d *= 0.5f; - center = source + d; - zaxis.Init(); - - xaxis = d; - radius = xaxis.Length( ); - - // cull beamring - // -------------------------------- - // Compute box center +/- radius - last1[0] = radius; - last1[1] = radius; - last1[2] = scale; - tmp = center + last1; // maxs - screen = center - last1; // mins - - // Is that box in PVS && frustum? - if ( !gEngfuncs.pEfxAPI->CL_IsBoxVisible( screen, tmp ) || gEngfuncs.pEfxAPI->R_CullBox( screen, tmp )) - { - return; - } - - yaxis[0] = xaxis[1]; - yaxis[1] = -xaxis[0]; - yaxis[2] = 0; - - yaxis = yaxis.Normalize( ); - yaxis *= radius; - - j = segments / 8; - - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - gEngfuncs.pTriAPI->RenderMode( rendermode ); - gEngfuncs.pTriAPI->Bind( m_hSprite, 0 ); // GetSpriteTexture already set frame - - gEngfuncs.pTriAPI->Begin( TRI_TRIANGLE_STRIP ); - - for ( i = 0; i < segments + 1; i++ ) - { - fraction = i * div; - x = sin( fraction * 2 * M_PI ); - y = cos( fraction * 2 * M_PI ); - - point[0] = xaxis[0] * x + yaxis[0] * y + center[0]; - point[1] = xaxis[1] * x + yaxis[1] * y + center[1]; - point[2] = xaxis[2] * x + yaxis[2] * y + center[2]; - - // Distort using noise - factor = prgNoise[(noiseIndex>>16) & (noise_divisions-1)] * scale; - point = point + (g_pViewRenderBeams->GetViewParams()->up * factor); - - // Rotate the noise along the perpendicluar axis a bit to keep the bolt from looking diagonal - factor = prgNoise[(noiseIndex>>16) & (noise_divisions-1)] * scale * cos(fraction * M_PI * 3 * 8 + freq); - point = point + (g_pViewRenderBeams->GetViewParams()->right * factor); - - // Transform point into screen space - gEngfuncs.pTriAPI->WorldToScreen( point, screen ); - - if ( i != 0 ) - { - // Build world-space normal to screen-space direction vector - tmp = screen - screenLast; - // We don't need Z, we're in screen space - tmp[2] = 0; - tmp = tmp.Normalize(); - - // Build point along normal line (normal is -y, x) - normal = g_pViewRenderBeams->GetViewParams()->up * tmp.x; - normal = normal - (g_pViewRenderBeams->GetViewParams()->right * -tmp.y); - - // make a wide line - last1 = point + (normal * width ); - last2 = point + (normal * -width); - - vLast += vStep; // Advance texture scroll (v axis only) - gEngfuncs.pTriAPI->Color4f( color[0], color[1], color[2], 1.0f ); - gEngfuncs.pTriAPI->TexCoord2f( 1.0f, vLast ); - gEngfuncs.pTriAPI->Vertex3fv( last2 ); - - gEngfuncs.pTriAPI->Color4f( color[0], color[1], color[2], 1.0f ); - gEngfuncs.pTriAPI->TexCoord2f( 0.0f, vLast ); - gEngfuncs.pTriAPI->Vertex3fv( last1 ); - } - - screenLast = screen; - noiseIndex += noiseStep; - - j--; - if ( j == 0 && amplitude != 0 ) - { - j = segments / 8; - (*pfnNoise)( prgNoise, noise_divisions, 1.0f ); - } - } - - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} - -//----------------------------------------------------------------------------- -// Purpose: -// Input : spritemodel - -// *pHead - -// delta - -// *screen - -// *screenLast - -// die - -// source - -// flags - -// width - -// amplitude - -// freq - -// *color - -//----------------------------------------------------------------------------- -void DrawBeamFollow( int modelIndex, BeamTrail_t* pHead, int frame, int rendermode, Vector& delta, - Vector& screen, Vector& screenLast, float die, const Vector& source, int flags, float width, - float amplitude, float freq, float* color ) -{ - float fraction; - float div; - float vLast = 0.0; - float vStep = 1.0; - Vector last1, last2, tmp, normal; - float scaledColor[3]; - - HSPRITE m_hSprite = gEngfuncs.pTriAPI->GetSpriteTexture( modelIndex, frame ); - - if ( !m_hSprite ) - return; - - // UNDONE: This won't work, screen and screenLast must be extrapolated here to fix the - // first beam segment for this trail - - // Build world-space normal to screen-space direction vector - tmp = screen - screenLast; - // We don't need Z, we're in screen space - tmp.z = 0; - tmp = tmp.Normalize( ); - - // Build point along noraml line (normal is -y, x) - normal = g_pViewRenderBeams->GetViewParams()->up * tmp.x; - normal = normal - (g_pViewRenderBeams->GetViewParams()->right * -tmp.y ); - - // Make a wide line - last1 = delta + ( normal * width ); - last2 = delta + ( normal * -width ); - - div = 1.0f / amplitude; - fraction = ( die - GetClientTime() ) * div; - byte nColor[3]; - - scaledColor[0] = color[0] * fraction; - scaledColor[1] = color[1] * fraction; - scaledColor[2] = color[2] * fraction; - nColor[0] = (byte)bound( 0, (int)(scaledColor[0] * 255.0f), 255 ); - nColor[1] = (byte)bound( 0, (int)(scaledColor[1] * 255.0f), 255 ); - nColor[2] = (byte)bound( 0, (int)(scaledColor[2] * 255.0f), 255 ); - - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - gEngfuncs.pTriAPI->RenderMode( rendermode ); - gEngfuncs.pTriAPI->Bind( m_hSprite, 0 ); // GetSpriteTexture already set frame - - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - - while ( pHead ) - { - // gEngfuncs.Con_Printf( "%.2f ", fraction ); - gEngfuncs.pTriAPI->Color4ub( nColor[0], nColor[1], nColor[2], 255 ); - gEngfuncs.pTriAPI->TexCoord2f( 1.0f, 1.0f ); - gEngfuncs.pTriAPI->Vertex3fv( last2 ); - - gEngfuncs.pTriAPI->Color4ub( nColor[0], nColor[1], nColor[2], 255 ); - gEngfuncs.pTriAPI->TexCoord2f( 0.0f, 1.0f ); - gEngfuncs.pTriAPI->Vertex3fv( last1 ); - - // Transform point into screen space - gEngfuncs.pTriAPI->WorldToScreen( pHead->org, screen ); - - // Build world-space normal to screen-space direction vector - tmp = screen - screenLast; - // We don't need Z, we're in screen space - tmp.z = 0; - tmp = tmp.Normalize(); - - // Build point along normal line (normal is -y, x) - normal = g_pViewRenderBeams->GetViewParams()->up * tmp.x; - normal = normal - (g_pViewRenderBeams->GetViewParams()->right * -tmp.y ); - - // Make a wide line - last1 = pHead->org + (normal * width ); - last2 = pHead->org + (normal * -width ); - - vLast += vStep; // Advance texture scroll (v axis only) - - if ( pHead->next != NULL ) - { - fraction = (pHead->die - GetClientTime()) * div; - scaledColor[0] = color[0] * fraction; - scaledColor[1] = color[1] * fraction; - scaledColor[2] = color[2] * fraction; - nColor[0] = (byte)bound( 0, (int)(scaledColor[0] * 255.0f), 255 ); - nColor[1] = (byte)bound( 0, (int)(scaledColor[1] * 255.0f), 255 ); - nColor[2] = (byte)bound( 0, (int)(scaledColor[2] * 255.0f), 255 ); - } - else - { - fraction = 0.0; - nColor[0] = nColor[1] = nColor[2] = 0; - } - - gEngfuncs.pTriAPI->Color4ub( nColor[0], nColor[1], nColor[2], 255 ); - gEngfuncs.pTriAPI->TexCoord2f( 0.0f, 0.0f ); - gEngfuncs.pTriAPI->Vertex3fv( last1 ); - - gEngfuncs.pTriAPI->Color4ub( nColor[0], nColor[1], nColor[2], 255 ); - gEngfuncs.pTriAPI->TexCoord2f( 1.0f, 0.0f ); - gEngfuncs.pTriAPI->Vertex3fv( last2 ); - - screenLast = screen; - - pHead = pHead->next; - } - - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} \ No newline at end of file diff --git a/client/global/r_beams.h b/client/global/r_beams.h deleted file mode 100644 index 552fb533..00000000 --- a/client/global/r_beams.h +++ /dev/null @@ -1,346 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// r_beams.h - beam rendering code -//======================================================================= - -#ifndef R_BEAMS_H -#define R_BEAMS_H - -#include "customentity.h" - -#define NOISE_DIVISIONS 64 // don't touch - many tripmines cause the crash when it equal 128 -#define MAX_BEAM_ENTS 2 // start & end entity -#define MAX_BEAMS 128 // Max simultaneous beams -#define MAX_BEAMTRAILS 2048 // default max # of particles at one time - -// beam flags -#define FBEAM_STARTENTITY 0x00000001 -#define FBEAM_ENDENTITY 0x00000002 -#define FBEAM_FADEIN 0x00000004 -#define FBEAM_FADEOUT 0x00000008 - -// BEGIN SHARED FLAGS -#define FBEAM_SINENOISE 0x00000010 -#define FBEAM_SOLID 0x00000020 -#define FBEAM_SHADEIN 0x00000040 -#define FBEAM_SHADEOUT 0x00000080 -// END SHARED FLAGS - -#define FBEAM_ONLYNOISEONCE 0x00000100 // Only calculate our noise once -#define FBEAM_STARTVISIBLE 0x10000000 // Has this client actually seen this beam's start entity yet? -#define FBEAM_ENDVISIBLE 0x20000000 // Has this client actually seen this beam's end entity yet? -#define FBEAM_ISACTIVE 0x40000000 -#define FBEAM_FOREVER 0x80000000 - -struct BeamTrail_t -{ - // NOTE: Don't add user defined fields except after these four fields. - BeamTrail_t *next; - float die; - Vector org; - Vector vel; -}; - -struct BeamInfo_t -{ - int m_nType; - - // entities - cl_entity_t *m_pStartEnt; - int m_nStartAttachment; - cl_entity_t *m_pEndEnt; - int m_nEndAttachment; - - // points - Vector m_vecStart; - Vector m_vecEnd; - - int m_nModelIndex; - const char *m_pszModelName; - - float m_flLife; - float m_flWidth; - float m_flEndWidth; - float m_flFadeLength; - float m_flAmplitude; - - float m_flBrightness; - float m_flSpeed; - - int m_nStartFrame; - float m_flFrameRate; - - float m_flRed; - float m_flGreen; - float m_flBlue; - - int m_nSegments; - int m_nFlags; - - // rings - Vector m_vecCenter; - float m_flStartRadius; - float m_flEndRadius; - - BeamInfo_t() - { - m_nType = TE_BEAMPOINTS; - m_nSegments = -1; - m_pszModelName = NULL; - m_nModelIndex = -1; - m_nFlags = 0; - } -}; - -//----------------------------------------------------------------------------- -// Purpose: Beams fill out this data structure -// This is also used for rendering -//----------------------------------------------------------------------------- - -class Beam_t -{ -public: - Beam_t(); - - // resets the beam state - void Reset(); - - // Method to computing the bounding box - void ComputeBounds(); - - const Vector& GetRenderOrigin( void ); - - // like CBeam - void SetFlags( int iFlags ); - void SetStartPos( const Vector pos ); - void SetEndPos( const Vector pos ); - void SetWidth( float flWidth ); - void SetNoise( float flAmplitude ); - void SetColor( float r, float g, float b ); - void SetBrightness( float flBrightness ); - - // bounding box... - Vector m_Mins; - Vector m_Maxs; - - // data is below.. - - // next beam in list - Beam_t *next; - - // type of beam - int type; - int flags; - - // control points for the beam - int numAttachments; - Vector attachment[MAX_BEAM_ENTS+1]; // last attachment used for DrawRing center - Vector delta; - - // 0 .. 1 over lifetime of beam - float t; - float freq; - - // time when beam should die - float die; - float width; - float endWidth; - float fadeLength; - float amplitude; - float life; - - // color - float r, g, b; - float brightness; - - // speed - float speed; - - // animation - float frameRate; - float frame; - int segments; - - // attachment entities for the beam - cl_entity_t *entity[MAX_BEAM_ENTS]; - int attachmentIndex[MAX_BEAM_ENTS]; - - // model info - int modelIndex; - int frameCount; - - float rgNoise[NOISE_DIVISIONS+1]; - - // Popcorn trail for beam follows to use - BeamTrail_t *trail; - - // for TE_BEAMRING - float start_radius; - float end_radius; - - // for FBEAM_ONLYNOISEONCE - bool m_bCalculatedNoise; - bool m_bCulled; // ignore to drawing - - float m_flDmgTime; // this is egon stuff -}; - -// ---------------------------------------------------------------- // -// CBeamSegDraw is a simple interface to beam rendering. -// ---------------------------------------------------------------- // -class CBeamSeg -{ -public: - Vector m_vPos; - Vector m_vColor; - float m_flTexCoord; // Y texture coordinate - float m_flWidth; - float m_flAlpha; -}; - -class CBeamSegDraw -{ -public: - // pass null for pMaterial if you have already set the material you want. - void Start( int nSegs, HSPRITE m_hSprite, int nRenderMode, int frame = 0 ); - void NextSeg( CBeamSeg *pSeg ); - void End(); -private: - - void SpecifySeg( const Vector &vNextPos ); - void ComputeNormal( const Vector &vStartPos, const Vector &vNextPos, Vector *pNormal ); - - -private: - Vector m_vNormalLast; - - int m_nTotalSegs; - int m_nSegsDrawn; - - CBeamSeg m_Seg; -}; - -//----------------------------------------------------------------------------- -// Purpose: Implements beam rendering apis -//----------------------------------------------------------------------------- -class CViewRenderBeams -{ -public: - CViewRenderBeams( void ); - virtual ~CViewRenderBeams( void ); - -public: - void ClearBeams( void ); - - // Updates the state of the temp ent beams - void UpdateTempEntBeams(); - - void DrawBeam( cl_entity_t *pbeam ); - void DrawBeam( Beam_t *pbeam ); - - void KillDeadBeams( cl_entity_t *pDeadEntity ); - - Beam_t *CreateBeamEnts( BeamInfo_t &beamInfo ); - Beam_t *CreateBeamEntPoint( BeamInfo_t &beamInfo ); - Beam_t *CreateBeamPoints( BeamInfo_t &beamInfo ); - Beam_t *CreateBeamRing( BeamInfo_t &beamInfo ); - Beam_t *CreateBeamCirclePoints( BeamInfo_t &beamInfo ); - Beam_t *CreateBeamFollow( BeamInfo_t &beamInfo ); - - Beam_t *CreateBeamEnts( int startEnt, int endEnt, int modelIndex, float life, float width, - float endWidth, float fadeLength, float amplitude, float brightness, float speed, - int startFrame, float framerate, float r, float g, float b, int type = -1 ); - Beam_t *CreateBeamEnts( int startEnt, int endEnt, int modelIndex, float life, float width, - float amplitude, float brightness, float speed, int startFrame, float framerate, - float r, float g, float b ); - Beam_t *CreateBeamEntPoint( int nStartEntity, const Vector *pStart, int nEndEntity, - const Vector* pEnd, int modelIndex, float life, float width, float endWidth, - float fadeLength, float amplitude, float brightness, float speed, int startFrame, - float framerate, float r, float g, float b ); - Beam_t *CreateBeamEntPoint( int startEnt, Vector end, int modelIndex, float life, float width, - float amplitude, float brightness, float speed, int startFrame, float framerate, - float r, float g, float b ); - Beam_t *CreateBeamPoints( Vector& start, Vector& end, int modelIndex, float life, float width, - float endWidth, float fadeLength, float amplitude, float brightness, float speed, - int startFrame, float framerate, float r, float g, float b ); - Beam_t *CreateBeamPoints( Vector start, Vector end, int modelIndex, float life, float width, - float amplitude, float brightness, float speed, int startFrame, float framerate, - float r, float g, float b ); - void CreateBeamRing( int startEnt, int endEnt, int modelIndex, float life, float width, - float endWidth, float fadeLength, float amplitude, float brightness, float speed, - int startFrame, float framerate, float r, float g, float b ); - void CreateBeamCirclePoints( int type, Vector& start, Vector& end, int modelIndex, float life, - float width, float endWidth, float fadeLength, float amplitude, float brightness, - float speed, int startFrame, float framerate, float r, float g, float b ); - void CreateBeamFollow( int startEnt, int modelIndex, float life, float width, float endWidth, - float fadeLength, float r, float g, float b, float brightness ); - - void FreeBeam( Beam_t *pBeam ) { BeamFree( pBeam ); } - void UpdateBeamInfo( Beam_t *pBeam, BeamInfo_t &beamInfo ); - void AddServerBeam( cl_entity_t *pEnvBeam ); - void ClearServerBeams( void ); - - void UpdateBeams( int fTrans ); // main drawing func - void SetViewParams( struct ref_params_s *pparams ); - struct ref_params_s *GetViewParams( void ); -private: - cl_entity_t *LinkWithViewModel( int entindex ); - bool AttemptToDie( Beam_t *pBeam ); - void FreeDeadTrails( BeamTrail_t **trail ); - void UpdateBeam( Beam_t *pbeam, float frametime ); - void DrawBeamFollow( int spriteIndex, Beam_t *pbeam, int frame, int rendermode, - float frametime, const float* color ); - void DrawLaser( Beam_t* pBeam, int frame, int rendermode, float* color, int spriteIndex ); - - bool RecomputeBeamEndpoints( Beam_t *pbeam ); - - int CullBeam( const Vector &start, const Vector &end, int pvsOnly ); - - // Creation - Beam_t *CreateGenericBeam( BeamInfo_t &beamInfo ); - void SetupBeam( Beam_t *pBeam, const BeamInfo_t &beamInfo ); - void SetBeamAttributes( Beam_t *pBeam, const BeamInfo_t &beamInfo ); - - // Memory Alloc/Free - Beam_t* BeamAlloc( void ); - void BeamFree( Beam_t* pBeam ); - -// DATA -private: - Beam_t m_Beams[MAX_BEAMS]; - Beam_t *m_pActiveBeams; - Beam_t *m_pFreeBeams; - - BeamTrail_t *m_pBeamTrails; - BeamTrail_t *m_pActiveTrails; - BeamTrail_t *m_pFreeTrails; - - struct ref_params_s *pViewParams; // actual refdef pointer - - float m_flTime; // the current client time - float m_fOldTime; // the time at which the HUD was last redrawn - float m_flFrameTime; // time between beam draws - - cl_entity_t *m_pServerBeams[MAX_BEAMS]; // to avoid check of all the ents - int m_nNumServerBeams; -}; - -void DrawSegs( int noise_divisions, float *prgNoise, int spriteIndex, float frame, int rendermode, const Vector& source, - const Vector& delta, float startWidth, float endWidth, float scale, float freq, float speed, - int segments, int flags, float* color, float fadeLength ); -void DrawDisk( int noise_divisions, float *prgNoise, int spriteIndex, float frame, int rendermode, const Vector& source, - const Vector& delta, float width, float scale, float freq, float speed, int segments, float* color); -void DrawCylinder( int noise_divisions, float *prgNoise, int spriteIndex, float frame, int rendermode, - const Vector& source, const Vector& delta, float width, float scale, float freq, float speed, - int segments, float* color ); -void DrawRing( int noise_divisions, float *prgNoise, void (*pfnNoise)( float *noise, int divs, float scale ), - int spriteIndex, float frame, int rendermode, const Vector& source, const Vector& delta, - float width, float amplitude, float freq, float speed, int segments, float* color ); -void DrawBeamFollow( int spriteIndex, BeamTrail_t* pHead, int frame, int rendermode, Vector& delta, Vector& screen, - Vector& screenLast, float die, const Vector& source, int flags, float width, float amplitude, - float freq, float* color ); - - -extern CViewRenderBeams *g_pViewRenderBeams; - -#endif//R_BEAMS_H \ No newline at end of file diff --git a/client/global/r_particle.cpp b/client/global/r_particle.cpp deleted file mode 100644 index e20b4476..00000000 --- a/client/global/r_particle.cpp +++ /dev/null @@ -1,887 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2010 й -// r_partsystem.cpp - particle manager -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "triangleapi.h" -#include "r_efx.h" -#include "pm_movevars.h" -#include "ev_hldm.h" -#include "hud.h" -#include "r_particle.h" -#include "r_tempents.h" - -// particle velocities -static const float r_avertexnormals[NUMVERTEXNORMALS][3] = -{ -#include "../engine/anorms.h" -}; - -// particle ramps -static int ramp1[8] = { 0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61 }; -static int ramp2[8] = { 0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66 }; -static int ramp3[6] = { 0x6d, 0x6b, 6, 5, 4, 3 }; - -static int gTracerColors[][3] = -{ -{ 255, 255, 255 }, // White -{ 255, 0, 0 }, // Red -{ 0, 255, 0 }, // Green -{ 0, 0, 255 }, // Blue -{ 0, 0, 0 }, // Tracer default, filled in from cvars, etc. -{ 255, 167, 17 }, // Yellow-orange sparks -{ 255, 130, 90 }, // Yellowish streaks (garg) -{ 55, 60, 144 }, // Blue egon streak -{ 255, 130, 90 }, // More Yellowish streaks (garg) -{ 255, 140, 90 }, // More Yellowish streaks (garg) -{ 200, 130, 90 }, // More red streaks (garg) -{ 255, 120, 70 }, // Darker red streaks (garg) -}; - -static int gSparkRamp[SPARK_COLORCOUNT][3] = -{ -{ 255, 255, 255 }, -{ 255, 247, 199 }, -{ 255, 243, 147 }, -{ 255, 243, 27 }, -{ 239, 203, 31 }, -{ 223, 171, 39 }, -{ 207, 143, 43 }, -{ 127, 59, 43 }, -{ 35, 19, 7 } -}; - -CParticleSystem *g_pParticles = NULL; - -CParticleSystem :: CParticleSystem( void ) -{ - memset( m_pParticles, 0, sizeof( CBaseParticle ) * MAX_PARTICLES ); - - m_pFreeParticles = m_pParticles; - m_pActiveParticles = NULL; -} - -CParticleSystem :: ~CParticleSystem( void ) -{ -} - -void CParticleSystem :: Clear( void ) -{ - m_pFreeParticles = m_pParticles; - m_pActiveParticles = NULL; - - for( int i = 0; i < MAX_PARTICLES; i++ ) - m_pParticles[i].m_pNext = &m_pParticles[i+1]; - - m_pParticles[MAX_PARTICLES-1].m_pNext = NULL; - - // this is used for EF_BRIGHTFIELD - for( i = 0; i < NUMVERTEXNORMALS; i++ ) - { - m_vecAvelocities[i][0] = RANDOM_LONG( 0, 255 ) * 0.01f; - m_vecAvelocities[i][1] = RANDOM_LONG( 0, 255 ) * 0.01f; - m_vecAvelocities[i][2] = RANDOM_LONG( 0, 255 ) * 0.01f; - - // also build avertexnormals - m_vecAvertexNormals[i] = Vector( r_avertexnormals[i] ); - } - - // build the local copy of particle palette - for( i = 0; i < 256; i++ ) - { - float entry[3]; - - CL_GetPaletteColor( i, entry ); - - m_uchPalette[i][0] = (byte)entry[0]; - m_uchPalette[i][1] = (byte)entry[1]; - m_uchPalette[i][2] = (byte)entry[2]; - } - - // NOTE: shader nomip automatically create default shader - // with allow change rendermodes - m_hDefaultParticle = TEX_LoadNoMip( "*particle" ); -} - -void CParticleSystem :: FreeParticle( CBaseParticle *pCur ) -{ - if( pCur->GetType( ) == pt_clientcustom && pCur->pfnDeathFunc ) - { - // call the deathfunc func before die - pCur->pfnDeathFunc( pCur ); - } - - pCur->m_pNext = m_pFreeParticles; - m_pFreeParticles = pCur; -} - -CBaseParticle *CParticleSystem :: AllocParticle( HSPRITE m_hSpr ) -{ - CBaseParticle *pAlloc; - - // never alloc particles when we not in game - if (( m_flTime - m_fOldTime ) == 0 ) - return NULL; - - if( !m_pFreeParticles ) - { - gEngfuncs.Con_Printf( "Overflow %d particles\n", MAX_PARTICLES ); - return NULL; - } - - pAlloc = m_pFreeParticles; - m_pFreeParticles = pAlloc->m_pNext; - pAlloc->m_pNext = m_pActiveParticles; - m_pActiveParticles = pAlloc; - - // clear old particle - pAlloc->SetType( pt_static ); - pAlloc->m_hSprite = m_hSpr; - pAlloc->m_Velocity = g_vecZero; - pAlloc->m_Pos = g_vecZero; - pAlloc->m_Ramp = 0; - - return pAlloc; -} - -void CParticleSystem :: DrawParticle( HSPRITE hSprite, const Vector &pos, const byte color[4], float size ) -{ - // draw the particle - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - - gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); - gEngfuncs.pTriAPI->Color4ub( color[0], color[1], color[2], color[3] ); - - gEngfuncs.pTriAPI->Bind( hSprite, 0 ); - - if ( hSprite == m_hDefaultParticle ) - { - // HACKHACK a scale up to keep particles from disappearing - size += (pos.x - m_vecOrigin.x) * m_vecForward.x; - size += (pos.y - m_vecOrigin.y) * m_vecForward.y; - size += (pos.z - m_vecOrigin.z) * m_vecForward.z; - - if( size < 20.0f ) size = 1.0f; - else size = 1.0f + size * 0.004f; - } - - Vector right, up; - - // scale the axes by radius - right = m_vecRight * size; - up = m_vecUp * size; - - // Add the 4 corner vertices. - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - gEngfuncs.pTriAPI->TexCoord2f ( 0.0f, 1.0f ); - gEngfuncs.pTriAPI->Vertex3fv ( pos - right + up ); - - gEngfuncs.pTriAPI->TexCoord2f ( 0.0f, 0.0f ); - gEngfuncs.pTriAPI->Vertex3fv ( pos + right + up ); - - gEngfuncs.pTriAPI->TexCoord2f ( 1.0f, 0.0f ); - gEngfuncs.pTriAPI->Vertex3fv ( pos + right - up ); - - gEngfuncs.pTriAPI->TexCoord2f ( 1.0f, 1.0f ); - gEngfuncs.pTriAPI->Vertex3fv ( pos - right - up ); - - gEngfuncs.pTriAPI->End(); - - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} - -void CParticleSystem :: SimulateAndRender( CBaseParticle *pParticle ) -{ - float ft = GetTimeDelta(); - float time3 = 15.0 * ft; - float time2 = 10.0 * ft; - float time1 = 5.0 * ft; - float dvel = 4 * ft; - - float grav = ft * sv_gravity * 0.05f; - - int iRamp; - - switch( pParticle->GetType( )) - { - case pt_static: - break; - - case pt_clientcustom: - if( pParticle->pfnCallback ) - pParticle->pfnCallback( pParticle, ft ); - return; - - case pt_fire: - pParticle->m_Ramp += (word)( time1 * ( 1 << SIMSHIFT )); - iRamp = pParticle->m_Ramp >> SIMSHIFT; - - if( iRamp >= 6 ) - { - pParticle->m_flLifetime = -1; - } - else - { - pParticle->SetColor( ramp3[iRamp] ); - } - pParticle->m_Velocity[2] += grav; - break; - - case pt_explode: - pParticle->m_Ramp += (word)(time2 * ( 1 << SIMSHIFT)); - iRamp = pParticle->m_Ramp >> SIMSHIFT; - if( iRamp >= 8 ) - { - pParticle->m_flLifetime = -1; - } - else - { - pParticle->SetColor( ramp1[iRamp] ); - } - pParticle->m_Velocity = pParticle->m_Velocity + pParticle->m_Velocity * dvel; - pParticle->m_Velocity.z -= grav; - break; - - case pt_explode2: - pParticle->m_Ramp += (word)(time3 * ( 1 << SIMSHIFT )); - iRamp = pParticle->m_Ramp >> SIMSHIFT; - if( iRamp >= 8 ) - { - pParticle->m_flLifetime = -1; - } - else - { - pParticle->SetColor( ramp2[iRamp] ); - } - pParticle->m_Velocity = pParticle->m_Velocity - pParticle->m_Velocity * ft; - pParticle->m_Velocity.z -= grav; - break; - - case pt_grav: - pParticle->m_Velocity.z -= grav * 20; - break; - - case pt_slowgrav: - pParticle->m_Velocity.z = grav; - break; - - case pt_vox_grav: - pParticle->m_Velocity.z -= grav * 8; - break; - - case pt_vox_slowgrav: - pParticle->m_Velocity.z -= grav * 4; - break; - - case pt_blob: - case pt_blob2: - pParticle->m_Ramp += (word)( time2 * ( 1 << SIMSHIFT )); - iRamp = pParticle->m_Ramp >> SIMSHIFT; - - if( iRamp >= SPARK_COLORCOUNT ) - { - pParticle->m_Ramp = 0; - iRamp = 0; - } - - pParticle->SetColor( gSparkRamp[iRamp] ); - - pParticle->m_Velocity[0] -= pParticle->m_Velocity[0] * 0.5f * ft; - pParticle->m_Velocity[1] -= pParticle->m_Velocity[1] * 0.5f * ft; - pParticle->m_Velocity[2] -= grav * 5; - - if ( RANDOM_LONG( 0, 3 )) - { - pParticle->SetType( pt_blob ); - pParticle->SetAlpha(0); - } - else - { - pParticle->SetType( pt_blob2 ); - pParticle->SetAlpha( 255.9f ); - } - break; - } - - HSPRITE hTexture = pParticle->m_hSprite; - - if( hTexture <= 0 ) - hTexture = m_hDefaultParticle; - - // render particle now - DrawParticle( hTexture, pParticle->m_Pos, pParticle->m_Color, 1.5f ); - - // update position. - pParticle->m_Pos = pParticle->m_Pos + pParticle->m_Velocity * ft; -} - -void CParticleSystem :: Update( void ) -{ - CBaseParticle *pCur, *pKill; - - m_fOldTime = m_flTime; - m_flTime = GetClientTime(); - - if( !cl_particles->value ) return; - - cl_entity_t *m_pPlayer = GetLocalPlayer(); - - if( !m_pPlayer ) return; - - Vector view_ofs; - - // calc vectors - AngleVectors( gHUD.m_vecAngles, m_vecForward, m_vecRight, m_vecUp ); - - // calc vieworg - gEngfuncs.pEventAPI->EV_LocalPlayerViewheight( view_ofs ); - m_vecOrigin[0] = gHUD.m_vecOrigin[0] + view_ofs.x; - m_vecOrigin[1] = gHUD.m_vecOrigin[1] + view_ofs.y; - m_vecOrigin[2] = gHUD.m_vecOrigin[2] + view_ofs.z; - - while( 1 ) - { - // free time-expired particles - pKill = m_pActiveParticles; - if ( pKill && pKill->GetLifetime() < GetClientTime() ) - { - m_pActiveParticles = pKill->m_pNext; - FreeParticle( pKill ); - continue; - } - break; - } - - for( pCur = m_pActiveParticles; pCur; pCur = pCur->m_pNext ) - { - while( 1 ) - { - pKill = pCur->m_pNext; - if ( pKill && pKill->GetLifetime() < GetClientTime() ) - { - pCur->m_pNext = pKill->m_pNext; - FreeParticle( pKill ); - continue; - } - break; - } - - SimulateAndRender( pCur ); - } -} - -/* -=============== -CL_EntityParticles - -EF_BRIGHTFIELD effect -=============== -*/ -void CParticleSystem :: EntityParticles( cl_entity_t *ent ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - float dist = 64, beamlength = 16; - Vector m_vecForward, m_vecPos; - CBaseParticle *p; - - for( int i = 0; i < NUMVERTEXNORMALS; i++ ) - { - p = AllocParticle (); - if( !p ) return; - - angle = GetClientTime() * m_vecAvelocities[i].x; - SinCos( angle, &sy, &cy ); - angle = GetClientTime() * m_vecAvelocities[i].y; - SinCos( angle, &sp, &cp ); - angle = GetClientTime() * m_vecAvelocities[i].z; - SinCos( angle, &sr, &cr ); - - m_vecForward.Init( cp * cy, cp * sy, -sp ); - - p->SetLifetime( 0.01f ); - p->SetColor( 111 ); // yellow - p->SetType( pt_explode ); - - p->m_Pos = ent->origin + m_vecAvertexNormals[i] * dist + m_vecForward * beamlength; - } -} - -/* -=============== -ParticleEffect - -PARTICLE_EFFECT on server -=============== -*/ -void CParticleSystem :: ParticleEffect( const Vector org, const Vector dir, int color, int count ) -{ - CBaseParticle *p; - - if( count == 1024 ) - { - // Quake hack: count == 255 it's a RocketExplode - ParticleExplosion( org ); - return; - } - - for( int i = 0; i < count; i++ ) - { - p = AllocParticle(); - if( !p ) return; - - p->SetLifetime( RANDOM_FLOAT( 0.1, 0.5 )); - p->SetColor(( color & ~7 ) + RANDOM_LONG( 0, 8 )); - p->SetType( pt_slowgrav ); - - for( int j = 0; j < 3; j++ ) - { - p->m_Pos[j] = org[j] + RANDOM_FLOAT( -16, 16 ); - p->m_Velocity[j] = dir[j] * 15; - } - } -} - -/* -=============== -CL_ParticleExplosion - -=============== -*/ -void CParticleSystem :: ParticleExplosion( const Vector org ) -{ - CBaseParticle *p; - - for( int i = 0; i < 1024; i++ ) - { - p = AllocParticle(); - if( !p ) return; - - p->SetLifetime( 5.0 ); - p->SetColor( ramp1[0] ); - p->m_Ramp = RANDOM_LONG( 0, 4 ); - - if( i & 1 ) - { - p->SetType( pt_explode ); - for( int j = 0; j < 3; j++ ) - { - p->m_Pos[j] = org[j] + RANDOM_FLOAT( -16, 16 ); - p->m_Velocity[j] = RANDOM_FLOAT( -256, 256 ); - } - } - else - { - p->SetType( pt_explode2 ); - for( int j = 0; j < 3; j++ ) - { - p->m_Pos[j] = org[j] + RANDOM_FLOAT( -16, 16 ); - p->m_Velocity[j] = RANDOM_FLOAT( -256, 256 ); - } - } - } -} - -/* -=============== -CL_ParticleExplosion2 - -=============== -*/ -void CParticleSystem :: ParticleExplosion2( const Vector org, int colorStart, int colorLength ) -{ - int colorMod = 0; - CBaseParticle *p; - - for( int i = 0; i < 512; i++ ) - { - p = AllocParticle(); - if( !p ) return; - - p->SetLifetime ( 0.3f ); - p->SetColor( colorStart + ( colorMod % colorLength )); - colorMod++; - - p->SetType( pt_blob ); - for ( int j = 0; j < 3; j++ ) - { - p->m_Pos[j] = org[j] + RANDOM_FLOAT( -16, 16 ); - p->m_Velocity[j] = RANDOM_FLOAT( -256, 256 ); - } - } -} - -/* -=============== -CL_BlobExplosion - -=============== -*/ -void CParticleSystem :: BlobExplosion( const Vector org ) -{ - CBaseParticle *p; - - for( int i = 0; i < 1024; i++ ) - { - p = AllocParticle(); - if( !p ) return; - - p->SetLifetime( 1.0f + RANDOM_FLOAT( 0, 0.4f )); - - if( i & 1 ) - { - p->SetType( pt_blob ); - p->SetColor( 66 + rand() % 6 ); - - for( int j = 0; j < 3; j++ ) - { - p->m_Pos[j] = org[j] + RANDOM_FLOAT( -16, 16 ); - p->m_Velocity[j] = RANDOM_FLOAT( -256, 256 ); - } - } - else - { - p->SetType( pt_blob2 ); - p->SetColor( 150 + rand() % 6 ); - - for( int j = 0; j < 3; j++ ) - { - p->m_Pos[j] = org[j] + RANDOM_FLOAT( -16, 16 ); - p->m_Velocity[j] = RANDOM_FLOAT( -256, 256 ); - } - } - } -} - -/* -=============== -CL_LavaSplash - -=============== -*/ -void CParticleSystem :: LavaSplash( const Vector org ) -{ - CBaseParticle *p; - float vel; - Vector dir; - - for ( int i = -16; i < 16; i++ ) - { - for ( int j = -16; j <16; j++ ) - { - for ( int k = 0; k < 1; k++ ) - { - p = AllocParticle(); - if( !p ) return; - - p->SetLifetime( 2.0f + RANDOM_FLOAT( 0.0f, 0.65f )); - p->SetColor( 224 + RANDOM_LONG( 0, 8 )); - p->SetType( pt_slowgrav ); - - dir[0] = j * 8 + RANDOM_LONG( 0, 8 ); - dir[1] = i * 8 + RANDOM_LONG( 0, 8 ); - dir[2] = 256; - - p->m_Pos[0] = org[0] + dir[0]; - p->m_Pos[1] = org[1] + dir[1]; - p->m_Pos[2] = org[2] + RANDOM_LONG( 0, 64 ); - - dir = dir.Normalize(); - vel = 50 + RANDOM_LONG( 0, 64 ); - p->m_Velocity = dir * vel; - } - } - } -} - -/* -=============== -CL_TeleportSplash - -=============== -*/ -void CParticleSystem :: TeleportSplash( const Vector org ) -{ - CBaseParticle *p; - Vector dir; - - for( int i = -16; i < 16; i+=4 ) - { - for( int j = -16; j < 16; j += 4 ) - { - for( int k = -24; k < 32; k += 4 ) - { - p = AllocParticle(); - if( !p ) return; - - p->SetLifetime( RANDOM_FLOAT( 0.2f, 0.36f )); - p->SetColor( RANDOM_LONG( 7, 14 )); - p->SetType( pt_slowgrav ); - - dir[0] = j * 8; - dir[1] = i * 8; - dir[2] = k * 8; - - p->m_Pos[0] = org[0] + i + RANDOM_FLOAT( -4, 4 ); - p->m_Pos[1] = org[1] + j + RANDOM_FLOAT( -4, 4 ); - p->m_Pos[2] = org[2] + k + RANDOM_FLOAT( -4, 4 ); - - dir = dir.Normalize(); - p->m_Velocity = dir * RANDOM_LONG( 50, 114 ); - } - } - } -} - -/* -=============== -CL_RocketTrail - -=============== -*/ -void CParticleSystem :: RocketTrail( const Vector org, const Vector end, int type ) -{ - vec3_t vec, start; - float len; - CBaseParticle *p; - int j, dec; - static int tracercount; - - start = org; - vec = end - start; - len = vec.Length(); - vec = vec.Normalize(); - - if( type < 128 ) - { - dec = 3; - } - else - { - dec = 1; - type -= 128; - } - - while( len > 0 ) - { - len -= dec; - - p = AllocParticle(); - if( !p ) return; - - p->SetLifetime( 2.0f ); - - switch( type ) - { - case 0: // rocket trail - p->m_Ramp = RANDOM_LONG( 0, 4 ); - p->SetColor( ramp3[p->m_Ramp] ); - p->SetType( pt_fire ); - for( j = 0; j < 3; j++ ) - p->m_Pos[j] = start[j] + ((rand()%6)-3); - break; - case 1: // smoke smoke - p->m_Ramp = RANDOM_LONG( 2, 6 ); - p->SetColor( ramp3[p->m_Ramp] ); - p->SetType( pt_fire ); - for( j = 0; j < 3; j++ ) - p->m_Pos[j] = start[j] + ((rand() % 6) - 3); - break; - case 2: // blood - p->SetType( pt_grav ); - p->SetColor( RANDOM_LONG( 67, 71 )); - for( j = 0; j < 3; j++ ) - p->m_Pos[j] = start[j] + ((rand() % 6) - 3); - break; - case 3: - case 5: // tracer - p->SetLifetime( 0.5f ); - p->SetType( pt_static ); - - if( type == 3 ) - p->SetColor( 52 + (( tracercount & 4 )<<1 )); - else p->SetColor( 230 + (( tracercount & 4 )<<1 )); - - tracercount++; - p->m_Pos = start; - - if( tracercount & 1 ) - { - p->m_Velocity[0] = 30 * vec[1]; - p->m_Velocity[1] = 30 * -vec[0]; - } - else - { - p->m_Velocity[0] = 30 * -vec[1]; - p->m_Velocity[1] = 30 * vec[0]; - } - break; - case 4: // slight blood - p->SetType( pt_grav ); - p->SetColor( RANDOM_LONG( 67, 71 )); - for( j = 0; j < 3; j++ ) - p->m_Pos[j] = start[j] + RANDOM_FLOAT( -3, 3 ); - len -= 3; - break; - case 6: // voor trail - p->SetColor( RANDOM_LONG( 152, 156 )); - p->SetType( pt_static ); - p->SetLifetime( 0.3f ); - for( j = 0; j < 3; j++ ) - p->m_Pos[j] = start[j] + RANDOM_FLOAT( -16, 16 ); - break; - } - start += vec; - } -} - -/* -============================================================================== - - CUSTOM USER PARTICLES - -============================================================================== -*/ -static void pfnSparkTracerDraw( CBaseParticle *pPart, float frametime ) -{ - float lifePerc = ( pPart->m_flLifetime - GetClientTime() ); - float scale = pPart->m_flLength; - Vector delta = pPart->m_Velocity; - - float flLength = ( pPart->m_Velocity * scale ).Length(); - float flWidth = ( flLength < pPart->m_flWidth ) ? flLength : pPart->m_flWidth; - - g_pParticles->DrawTracer(pPart->m_hSprite, pPart->m_Pos, delta * scale, flWidth, pPart->m_Color, 0.0f, 0.8f); - - float grav = frametime * sv_gravity * 0.05f; - pPart->m_Velocity.z -= grav * 8; // use vox gravity - pPart->m_Pos = pPart->m_Pos + pPart->m_Velocity * frametime; - if( lifePerc < 0.5 ) pPart->SetAlpha( lifePerc * 2 ); // fade alpha -} - -#define SPARK_ELECTRIC_MINSPEED 64.0f -#define SPARK_ELECTRIC_MAXSPEED 100.0f - -/* -=============== -CL_SparkleTracer - -=============== -*/ -void CParticleSystem :: SparkleTracer( const Vector& pos, const Vector& dir ) -{ - CBaseParticle *p; - - p = AllocParticle( m_hDefaultParticle ); - if( !p ) return; - - p->SetType( pt_clientcustom ); - p->SetLifetime( RANDOM_FLOAT( 0.5f, 1.0f )); - p->SetColor( gTracerColors[5] ); // Yellow-Orange - p->m_Pos = pos; - - p->m_flWidth = RANDOM_FLOAT( 0.35f, 0.5f ); - p->m_flLength = RANDOM_FLOAT( 0.05f, 0.08f ); - p->m_Velocity = dir * RANDOM_FLOAT( SPARK_ELECTRIC_MINSPEED, SPARK_ELECTRIC_MAXSPEED ); - p->pfnCallback = pfnSparkTracerDraw; -} - -/* -=============== -CL_StreakTracer - -=============== -*/ -void CParticleSystem :: StreakTracer( const Vector& pos, const Vector& velocity, int color ) -{ - CBaseParticle *p; - - p = AllocParticle( m_hDefaultParticle ); - if( !p ) return; - - p->SetType( pt_clientcustom ); - p->SetLifetime( RANDOM_FLOAT( 0.5f, 1.0f )); - p->SetColor( gTracerColors[color] ); // Yellow-Orange - p->m_Pos = pos; - - p->m_flWidth = RANDOM_FLOAT( 0.45f, 0.65f ); - p->m_flLength = RANDOM_FLOAT( 0.05f, 0.08f ); - p->m_Velocity = velocity; - p->pfnCallback = pfnSparkTracerDraw; -} - -static void pfnBulletTracerDraw( CBaseParticle *pPart, float frametime ) -{ - Vector delta = pPart->m_Velocity * pPart->m_flLength; - - g_pParticles->DrawTracer(pPart->m_hSprite, pPart->m_Pos, delta, pPart->m_flWidth, pPart->m_Color, 0.0f, 0.8f); - - pPart->m_Pos = pPart->m_Pos + pPart->m_Velocity * frametime; -} - -/* -=============== -CL_BulletTracer - -=============== -*/ -void CParticleSystem :: BulletTracer( const Vector& start, const Vector& end ) -{ - CBaseParticle *p; - - p = AllocParticle( m_hDefaultParticle ); - if( !p ) return; - - float vel = ((end - start).Length()) * 16; - Vector dir = ( end - start ).Normalize(); - - p->SetType( pt_clientcustom ); - p->SetLifetime( 0.5f ); // const - p->SetColor( gTracerColors[0] ); // White tracer - p->m_Pos = start; - - p->m_flWidth = RANDOM_FLOAT( 0.8f, 1.0f ); - p->m_flLength = RANDOM_FLOAT( 0.05f, 0.06f ); - p->m_Velocity = dir * vel; - p->pfnCallback = pfnBulletTracerDraw; -} - -/* -=============== -BulletImpactParticles - -=============== -*/ -void CParticleSystem :: BulletImpactParticles( const Vector &pos ) -{ - CBaseParticle *p; - - // uncomment this to enable texture based particle - // HSPRITE sprtex = SPR_Load("sprites/debris/debris_concrete01.spr"); - - g_pTempEnts->SparkShower( pos ); // Sparks - - for( int i = 0; i < 25; i++ ) - { - p = AllocParticle(); - if( !p ) return; - - p->SetLifetime( 2.0 ); - p->SetColor( 0, 0, 0 ); // 0,0,0 = black - p->SetAlpha( 255 ); - - //p->SetTexture ( sprtex ) ; // Uncomment to enable texture based particle - - if( i & 1 ) - { - p->SetType( pt_grav ); - for( int j = 0; j < 3; j++ ) - { - p->m_Pos[j] = pos[j] + RANDOM_FLOAT( -2, 3 ); // distance between particles - p->m_Velocity[j] = RANDOM_FLOAT( -70, 70 ); // speed, velocity of particles - } - } - } -} \ No newline at end of file diff --git a/client/global/r_particle.h b/client/global/r_particle.h deleted file mode 100644 index ce6f67bb..00000000 --- a/client/global/r_particle.h +++ /dev/null @@ -1,142 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2010 й -// r_particle.h - another particle manager (come from q2e 0.40) -//======================================================================= - -#ifndef R_PARTICLE_H -#define R_PARTICLE_H - -#define NUMVERTEXNORMALS 162 -#define MAX_PARTICLES 4096 - -#define SIMSHIFT 10 -#define SPARK_COLORCOUNT 9 - -class CBaseParticle -{ -public: - CBaseParticle *m_pNext; // linked list - HSPRITE m_hSprite; // custom texture - - float m_flLifetime; - byte m_Color[4]; // RGBA - not all effects need to use this. - ptype_t m_Type; - Vector m_Pos; - Vector m_Velocity; - - word m_Ramp; - byte context; // for deathfunc etc - - // tracer stuff - float m_flWidth; - float m_flLength; - - // Color and alpha values are 0 - 1 - void SetColor( int pcolor ); - void SetColor( float r, float g, float b ); // 0 - 1 - void SetColor( int color[3] ); // 0 - 255 - void SetAlpha( float a ); - - void SetType( ptype_t ptype ) { m_Type = ptype; } - ptype_t GetType( void ) { return m_Type; }; - - void SetLifetime( float life ) { m_flLifetime = GetClientTime() + life; } - float GetLifetime( void ) { return m_flLifetime; } - - void SetTexture( HSPRITE hSpr ) { m_hSprite = hSpr; } - - void (*pfnCallback)( CBaseParticle *pPart, float frametime ); // for pt_clientcustom - void (*pfnDeathFunc)( CBaseParticle *pPart ); -}; - -inline void CBaseParticle :: SetColor( int pcolor ) -{ - float entry[3]; - - CL_GetPaletteColor( pcolor, entry ); - - m_Color[0] = (byte)entry[0]; - m_Color[1] = (byte)entry[1]; - m_Color[2] = (byte)entry[2]; - m_Color[3] = 0xFF; // no alpha -} - -inline void CBaseParticle :: SetColor( int color[3] ) -{ - m_Color[0] = color[0]; - m_Color[1] = color[1]; - m_Color[2] = color[2]; - m_Color[3] = 0xFF; // no alpha -} - -inline void CBaseParticle :: SetColor( float r, float g, float b ) -{ - m_Color[0] = (byte)(r * 255.9f); - m_Color[1] = (byte)(g * 255.9f); - m_Color[2] = (byte)(b * 255.9f); -} - -inline void CBaseParticle :: SetAlpha( float a ) -{ - m_Color[3] = (byte)(a * 255.9f); -} - -class CParticleSystem -{ - CBaseParticle *m_pActiveParticles; - CBaseParticle *m_pFreeParticles; - CBaseParticle m_pParticles[MAX_PARTICLES]; // particle pool - - Vector m_vecAvertexNormals[NUMVERTEXNORMALS]; - Vector m_vecAvelocities[NUMVERTEXNORMALS]; - - // this is a cached local copy of Q1 palette (comed from engine) - byte m_uchPalette[256][3]; - - // private partsystem shaders - HSPRITE m_hDefaultParticle; - - float m_flTime; // the current client time - float m_fOldTime; // the time at which the HUD was last redrawn - - // view vectors - Vector m_vecForward; - Vector m_vecRight; - Vector m_vecUp; - Vector m_vecOrigin; // view origin - -public: - CParticleSystem( void ); - virtual ~CParticleSystem( void ); - - void Clear( void ); - void Update( void ); - void SimulateAndRender( CBaseParticle *pCur ); - void FreeParticle( CBaseParticle *pCur ); - CBaseParticle *AllocParticle( HSPRITE m_hSpr = 0 ); - float GetTimeDelta( void ) { return m_flTime - m_fOldTime; } - - // draw methods - void DrawParticle( HSPRITE hSpr, const Vector &pos, const byte color[4], float size ); - bool TracerComputeVerts( const Vector &pos, const Vector &delta, float width, Vector *pVerts ); - void DrawTracer( HSPRITE hSpr, Vector& start, Vector& delta, float width, byte *color, - float startV = 0.0f, float endV = 1.0f ); - - // begin user effects here - void EntityParticles( cl_entity_t *ent ); - void ParticleEffect( const Vector org, const Vector dir, int color, int count ); - void ParticleExplosion( const Vector org ); - void ParticleExplosion2( const Vector org, int colorStart, int colorLength ); - void BlobExplosion( const Vector org ); - void LavaSplash( const Vector org ); - void TeleportSplash( const Vector org ); - void RocketTrail( const Vector org, const Vector end, int type ); - void SparkleTracer( const Vector& pos, const Vector& dir ); - void BulletTracer( const Vector& pos, const Vector& end ); - void StreakTracer( const Vector& pos, const Vector& velocity, int color ); - void BulletImpactParticles( const Vector &pos ); -}; - -extern CParticleSystem *g_pParticles; - -#endif//R_PARTICLE_H \ No newline at end of file diff --git a/client/global/r_tempents.cpp b/client/global/r_tempents.cpp deleted file mode 100644 index 3667ac12..00000000 --- a/client/global/r_tempents.cpp +++ /dev/null @@ -1,2063 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2010 й -// r_tempents.cpp - tempentity management -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "studio_event.h" -#include "triangleapi.h" -#include "entity_types.h" -#include "pm_movevars.h" -#include "r_tempents.h" -#include "r_particle.h" -#include "pm_defs.h" -#include "ev_hldm.h" -#include "r_beams.h" -#include "hud.h" - -extern TENT *m_pEndFlare; -extern TENT *m_pLaserSpot; - -CTempEnts *g_pTempEnts; - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -CTempEnts::CTempEnts( void ) -{ - memset( m_TempEnts, 0, sizeof( TENT ) * MAX_TEMP_ENTITIES ); - - m_pFreeTempEnts = m_TempEnts; - m_pActiveTempEnts = NULL; -} - -//----------------------------------------------------------------------------- -// Purpose: -//----------------------------------------------------------------------------- -CTempEnts::~CTempEnts( void ) -{ - // free pvEngineData pointers - Clear(); -} - -void CTempEnts::TE_Prepare( TENT *pTemp, int modelIndex ) -{ - int frameCount; - - // Use these to set per-frame and termination conditions / actions - pTemp->flags = FTENT_NONE; - pTemp->die = GetClientTime() + 0.75f; - - frameCount = Mod_GetFrames( modelIndex ); - - pTemp->entity.curstate.modelindex = modelIndex; - pTemp->entity.curstate.rendermode = kRenderNormal; - pTemp->entity.curstate.renderfx = kRenderFxNone; - pTemp->entity.curstate.rendercolor.r = 255; - pTemp->entity.curstate.rendercolor.g = 255; - pTemp->entity.curstate.rendercolor.b = 255; - pTemp->frameMax = max( 0, frameCount - 1 ); - pTemp->entity.curstate.renderamt = 255; - pTemp->entity.curstate.body = 0; - pTemp->entity.curstate.skin = 0; - pTemp->fadeSpeed = 0.5f; - pTemp->hitSound = 0; - pTemp->clientIndex = 0; - pTemp->bounceFactor = 1; - pTemp->entity.curstate.scale = 1.0f; -} - -int CTempEnts::TE_Active( TENT *pTemp ) -{ - bool active = true; - float life; - - if( !pTemp ) return false; - life = pTemp->die - GetClientTime(); - - if( life < 0.0f ) - { - if( pTemp->flags & FTENT_FADEOUT ) - { - int alpha; - - if( pTemp->entity.curstate.rendermode == kRenderNormal ) - pTemp->entity.curstate.rendermode = kRenderTransTexture; - - alpha = pTemp->entity.baseline.renderamt * ( 1.0f + life * pTemp->fadeSpeed ); - - if( alpha <= 0 ) - { - active = false; - alpha = 0; - } - pTemp->entity.curstate.renderamt = alpha; - } - else - { - active = false; - } - } - return active; -} - -int CTempEnts::TE_Update( TENT *pTemp, float frametime ) -{ - float gravity, gravitySlow, fastFreq; - - fastFreq = GetClientTime() * 5.5; - gravity = -frametime * sv_gravity; - gravitySlow = gravity * 0.5; - - // in order to have tents collide with players, we have to run the player prediction code so - // that the client has the player list. We run this code once when we detect any COLLIDEALL - // tent, then set this BOOL to true so the code doesn't get run again if there's more than - // one COLLIDEALL ent for this update. (often are). - 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 ( -1 ); - - // save oldorigin - pTemp->entity.prevstate.origin = pTemp->entity.origin; - - if( pTemp->flags & FTENT_SPARKSHOWER ) - { - // adjust speed if it's time - // scale is next think time - if( GetClientTime() > pTemp->entity.baseline.scale ) - { - // show Sparks - SparkEffect( pTemp->entity.origin, 8, -200, 200 ); - - // reduce life - pTemp->entity.baseline.framerate -= 0.1f; - - if( pTemp->entity.baseline.framerate <= 0.0f ) - { - pTemp->die = GetClientTime(); - } - else - { - // so it will die no matter what - pTemp->die = GetClientTime() + 0.5f; - - // next think - pTemp->entity.baseline.scale = GetClientTime() + 0.1f; - } - } - } - else if( pTemp->flags & FTENT_PLYRATTACHMENT ) - { - cl_entity_t *pClient = GetEntityByIndex( pTemp->clientIndex ); - - if( pClient ) - { - if( EV_IsLocal( pClient->index )) - { - // NOTE: if this a local client ? - // relink attachment with her viewmodel - pClient = GetViewEntity(); - } - pTemp->entity.origin = pClient->origin + pTemp->tentOffset; - } - } - // same as FTENT_PLYRATTACHMENT but offset will be updated every frame - else if( pTemp->flags & FTENT_ATTACHMENT ) - { - cl_entity_t *pClient = GetEntityByIndex( pTemp->clientIndex ); - - if( pClient ) - { - if( EV_IsLocal( pClient->index )) - { - // NOTE: if this a local client ? - // relink attachment with him viewmodel - pClient = GetViewEntity(); - } - - pTemp->entity.origin = pClient->origin; - - if( pTemp->entity.baseline.body > 0 ) - pTemp->entity.origin += pClient->attachment[pTemp->entity.baseline.body - 1]; - } - } - else if( pTemp->flags & FTENT_SINEWAVE ) - { - pTemp->x += pTemp->entity.baseline.origin.x * frametime; - pTemp->y += pTemp->entity.baseline.origin.y * frametime; - - pTemp->entity.origin.x = pTemp->x + sin( pTemp->entity.baseline.origin.z + GetClientTime() ) * ( 10 * pTemp->entity.curstate.scale ); - pTemp->entity.origin.y = pTemp->y + sin( pTemp->entity.baseline.origin.z + fastFreq + 0.7f ) * ( 8 * pTemp->entity.curstate.scale); - pTemp->entity.origin.z = pTemp->entity.origin.z + pTemp->entity.baseline.origin[2] * frametime; - } - else if( pTemp->flags & FTENT_SPIRAL ) - { - float s, c; - s = sin( pTemp->entity.baseline.origin.z + fastFreq ); - c = cos( pTemp->entity.baseline.origin.z + fastFreq ); - - pTemp->entity.origin.x = pTemp->entity.origin.x + pTemp->entity.baseline.origin.x * frametime + 8 * sin( GetClientTime() * 20 ); - pTemp->entity.origin.y = pTemp->entity.origin.y + pTemp->entity.baseline.origin.y * frametime + 4 * sin( GetClientTime() * 30 ); - pTemp->entity.origin.z = pTemp->entity.origin.z + pTemp->entity.baseline.origin.z * frametime; - } - else - { - // just add linear velocity - pTemp->entity.origin = pTemp->entity.origin + pTemp->entity.baseline.origin * frametime; - } - - if( pTemp->flags & FTENT_SPRANIMATE ) - { - pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; - - if( pTemp->entity.curstate.frame >= pTemp->frameMax ) - { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); - - if(!( pTemp->flags & FTENT_SPRANIMATELOOP )) - { - // this animating sprite isn't set to loop, so destroy it. - pTemp->die = 0.0f; - - // restore state info - gEngfuncs.pEventAPI->EV_PopPMStates(); - return false; - } - } - } - else if( pTemp->flags & FTENT_SPRCYCLE ) - { - pTemp->entity.curstate.frame += frametime * 10; - if( pTemp->entity.curstate.frame >= pTemp->frameMax ) - { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); - } - } - - if( pTemp->flags & FTENT_SCALE ) - { - // this only used for Egon effect - pTemp->entity.curstate.scale += frametime * 10; - } - - if( pTemp->flags & FTENT_ROTATE ) - { - // just add angular velocity - pTemp->entity.angles += pTemp->entity.baseline.angles * frametime; - pTemp->entity.latched.prevangles = pTemp->entity.angles; - } - - if( pTemp->flags & ( FTENT_COLLIDEALL|FTENT_COLLIDEWORLD )) - { - Vector traceNormal; - float traceFraction = 1.0f; - - traceNormal.Init(); - - if( pTemp->flags & FTENT_COLLIDEALL ) - { - pmtrace_t pmtrace; - physent_t *pe; - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); - - if ( pmtrace.fraction != 1 ) - { - pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); - - if( !pmtrace.ent || ( pe->info != pTemp->clientIndex )) - { - traceFraction = pmtrace.fraction; - traceNormal = pmtrace.plane.normal; - - if ( pTemp->hitcallback ) - (*pTemp->hitcallback)( pTemp, &pmtrace ); - } - } - } - else if( pTemp->flags & FTENT_COLLIDEWORLD ) - { - pmtrace_t pmtrace; - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX|PM_WORLD_ONLY, -1, &pmtrace ); - - if( pmtrace.fraction != 1.0f ) - { - traceFraction = pmtrace.fraction; - traceNormal = pmtrace.plane.normal; - - if ( pTemp->flags & FTENT_SPARKSHOWER ) - { - // chop spark speeds a bit more - pTemp->entity.baseline.origin *= 0.6f; - - if( pTemp->entity.baseline.origin.Length() < 10.0f ) - pTemp->entity.baseline.framerate = 0.0f; - } - - if( pTemp->hitcallback ) - (*pTemp->hitcallback)( pTemp, &pmtrace ); - } - } - - if( traceFraction != 1.0f ) // Decent collision now, and damping works - { - float proj, damp; - - // Place at contact point - pTemp->entity.origin = pTemp->entity.prevstate.origin + (traceFraction * frametime) * pTemp->entity.baseline.origin; - - // Damp velocity - damp = pTemp->bounceFactor; - if( pTemp->flags & ( FTENT_GRAVITY|FTENT_SLOWGRAVITY )) - { - damp *= 0.5f; - if( traceNormal[2] > 0.9f ) // Hit floor? - { - if( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity * 3 ) - { - pTemp->flags &= ~(FTENT_SLOWGRAVITY|FTENT_ROTATE|FTENT_GRAVITY); - pTemp->flags &= ~(FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); - pTemp->entity.angles.x = pTemp->entity.angles.z = 0; - damp = 0; // stop - } - } - } - - if( pTemp->hitSound ) - { - PlaySound( pTemp, damp ); - } - - if( pTemp->flags & FTENT_COLLIDEKILL ) - { - // die on impact - pTemp->flags &= ~FTENT_FADEOUT; - pTemp->die = GetClientTime(); - } - else - { - // reflect velocity - if( damp != 0 ) - { - proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); - pTemp->entity.baseline.origin += (-proj * 2) * traceNormal; - - // reflect rotation (fake) - pTemp->entity.angles.y = -pTemp->entity.angles.y; - } - - if( damp != 1.0f ) - { - pTemp->entity.baseline.origin *= damp; - pTemp->entity.angles *= 0.9f; - } - } - } - } - - // FIXME: this code is right ??? - if(( pTemp->flags & FTENT_FLICKER ) && m_iTempEntFrame == pTemp->entity.curstate.effects ) - { - dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDLight( 0 ); - - dl->origin = pTemp->entity.origin; - dl->radius = 60; - dl->color.r = 255; - dl->color.g = 120; - dl->color.b = 0; - dl->die = GetClientTime() + 0.01f; - } - - if( pTemp->flags & FTENT_SMOKETRAIL ) - { - g_pParticles->RocketTrail( pTemp->entity.prevstate.origin, pTemp->entity.origin, 1 ); - } - - if( pTemp->flags & FTENT_GRAVITY ) - pTemp->entity.baseline.origin.z += gravity; - else if( pTemp->flags & FTENT_SLOWGRAVITY ) - pTemp->entity.baseline.origin.z += gravitySlow; - - if( pTemp->flags & FTENT_CLIENTCUSTOM ) - { - if( pTemp->callback ) - (*pTemp->callback)( pTemp, frametime, GetClientTime( )); - } - // restore state info - gEngfuncs.pEventAPI->EV_PopPMStates(); - - return true; -} - -void CTempEnts :: Update( void ) -{ - TENT *current, *pnext, *pprev; - - m_fOldTime = m_flTime; - m_flTime = GetClientTime(); - float frametime = m_flTime - m_fOldTime; - - if ( !m_pActiveTempEnts ) - { - return; - } - - // !!!BUGBUG -- This needs to be time based - // g-cont. it's used only for flickering dlights, what difference ? - m_iTempEntFrame = ( m_iTempEntFrame + 1 ) & 31; - - current = m_pActiveTempEnts; - - // !!! Don't simulate while paused.... This is sort of a hack, revisit. - if( frametime == 0 ) - { - while( current ) - { - gEngfuncs.CL_CreateVisibleEntity( ET_TEMPENTITY, ¤t->entity ); - current = current->next; - } - } - else - { - pprev = NULL; - - while( current ) - { - bool fTempEntFreed = false; - - pnext = current->next; - - // Kill it - if( !TE_Active( current ) || !TE_Update( current, frametime )) - { - TempEntFree( current, pprev ); - fTempEntFreed = true; - } - else - { - // renderer rejected entity for some reasons... - if( !gEngfuncs.CL_CreateVisibleEntity( ET_TEMPENTITY, ¤t->entity )) - { - if(!( current->flags & FTENT_PERSIST )) - { - // If we can't draw it this frame, just dump it. - current->die = GetClientTime(); - // don't fade out, just die - current->flags &= ~FTENT_FADEOUT; - - TempEntFree( current, pprev ); - fTempEntFreed = true; - } - } - } - - if( !fTempEntFreed ) - pprev = current; - current = pnext; - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Clear existing temp entities -//----------------------------------------------------------------------------- -void CTempEnts::Clear( void ) -{ - m_iTempEntFrame = 0; - - // update muzzleflash indexes - m_iMuzzleFlash[0] = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/muzzleflash1.spr" ); - m_iMuzzleFlash[1] = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/muzzleflash2.spr" ); - m_iMuzzleFlash[2] = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/muzzleflash3.spr" ); - m_iMuzzleFlash[3] = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/muzzleflash.spr" ); - - hSprGlowShell = TEX_Load( "renderfx/glowshell" ); - - for ( int i = 0; i < MAX_TEMP_ENTITIES-1; i++ ) - { - m_TempEnts[i].next = &m_TempEnts[i+1]; - } - - m_TempEnts[MAX_TEMP_ENTITIES-1].next = NULL; - m_pFreeTempEnts = m_TempEnts; - m_pActiveTempEnts = NULL; - - // clearing user pointers - m_pLaserSpot = NULL; - m_pEndFlare = NULL; -} - -void CTempEnts::TempEntFree( TENT *pTemp, TENT *pPrev ) -{ - // Remove from the active list. - if( pPrev ) - { - pPrev->next = pTemp->next; - } - else - { - m_pActiveTempEnts = pTemp->next; - } - - memset( pTemp, 0, sizeof( TENT )); - - // Add to the free list. - pTemp->next = m_pFreeTempEnts; - m_pFreeTempEnts = pTemp; -} - -// free the first low priority tempent it finds. -bool CTempEnts::FreeLowPriorityTempEnt( void ) -{ - TENT *pActive = m_pActiveTempEnts; - TENT *pPrev = NULL; - - while( pActive ) - { - if( pActive->priority == TENTPRIORITY_LOW ) - { - TempEntFree( pActive, pPrev ); - return true; - } - - pPrev = pActive; - pActive = pActive->next; - } - return false; -} - -//----------------------------------------------------------------------------- -// Purpose: Allocate temp entity ( normal/low priority ) -// Input : *org - -// *model - -// Output : C_LocalTempEntity -//----------------------------------------------------------------------------- -TENT *CTempEnts::TempEntAlloc( const Vector& org, int modelIndex ) -{ - TENT *pTemp; - - if ( !m_pFreeTempEnts ) - { - gEngfuncs.Con_Printf( "Overflow %d temporary ents!\n", MAX_TEMP_ENTITIES ); - return NULL; - } - - pTemp = m_pFreeTempEnts; - m_pFreeTempEnts = pTemp->next; - - TE_Prepare( pTemp, modelIndex ); - - pTemp->priority = TENTPRIORITY_LOW; - if( org ) pTemp->entity.origin = org; - - pTemp->next = m_pActiveTempEnts; - m_pActiveTempEnts = pTemp; - - return pTemp; -} - -//----------------------------------------------------------------------------- -// Purpose: Allocate a temp entity, if there are no slots, kick out a low priority -// one if possible -// Input : *org - -// *model - -// Output : C_LocalTempEntity -//----------------------------------------------------------------------------- -TENT *CTempEnts::TempEntAllocHigh( const Vector& org, int modelIndex ) -{ - TENT *pTemp; - - if ( !m_pFreeTempEnts ) - { - // no temporary ents free, so find the first active low-priority temp ent - // and overwrite it. - FreeLowPriorityTempEnt(); - } - - if ( !m_pFreeTempEnts ) - { - // didn't find anything? The tent list is either full of high-priority tents - // or all tents in the list are still due to live for > 10 seconds. - gEngfuncs.Con_Printf( "Couldn't alloc a high priority TENT!\n" ); - return NULL; - } - - // Move out of the free list and into the active list. - pTemp = m_pFreeTempEnts; - m_pFreeTempEnts = pTemp->next; - - pTemp->next = m_pActiveTempEnts; - m_pActiveTempEnts = pTemp; - - TE_Prepare( pTemp, modelIndex ); - - pTemp->priority = TENTPRIORITY_HIGH; - if( org ) pTemp->entity.origin = org; - - return pTemp; -} - - -TENT *CTempEnts::TempEntAllocNoModel( const Vector& org ) -{ - return TempEntAlloc( org, 0 ); -} - -TENT *CTempEnts::TempEntAllocCustom( const Vector& org, int modelIndex, int high, void ( *callback )( struct tent_s *ent, float frametime, float currenttime )) -{ - TENT *pTemp; - - if( high ) - { - pTemp = TempEntAllocHigh( org, modelIndex ); - } - else - { - pTemp = TempEntAlloc( org, modelIndex ); - } - - if( pTemp && callback ) - { - pTemp->callback = callback; - pTemp->flags |= FTENT_CLIENTCUSTOM; - } - - return pTemp; -} - -/* -============================================================== - - BASE TEMPENTS CODE - -============================================================== -*/ -//----------------------------------------------------------------------------- -// Purpose: Create a fizz effect -// Input : *pent - -// modelIndex - -// density - -//----------------------------------------------------------------------------- -void CTempEnts::FizzEffect( cl_entity_t *pent, int modelIndex, int density ) -{ - TENT *pTemp; - int i, width, depth, count, frameCount; - float angle, maxHeight, speed, xspeed, yspeed; - Vector origin; - Vector mins, maxs; - - if( !pent || Mod_GetModelType( modelIndex ) == mod_bad ) - return; - - count = density + 1; - density = count * 3 + 6; - - Mod_GetBounds( pent->curstate.modelindex, mins, maxs ); - - maxHeight = maxs[2] - mins[2]; - width = maxs[0] - mins[0]; - depth = maxs[1] - mins[1]; - speed = ( pent->curstate.rendercolor.r<<8 | pent->curstate.rendercolor.g ); - if( pent->curstate.rendercolor.b ) speed = -speed; - if( speed == 0.0f ) speed = 100.0f; // apply default value - - if( pent->angles[YAW] != 0.0f ) - { - angle = pent->angles[YAW] * M_PI / 180; - yspeed = sin( angle ); - xspeed = cos( angle ); - - xspeed *= speed; - yspeed *= speed; - } - else xspeed = yspeed = 0.0f; // zonly - - frameCount = Mod_GetFrames( modelIndex ); - - for ( i = 0; i < count; i++ ) - { - origin[0] = mins[0] + RANDOM_LONG( 0, width - 1 ); - origin[1] = mins[1] + RANDOM_LONG( 0, depth - 1 ); - origin[2] = mins[2]; - pTemp = TempEntAlloc( origin, modelIndex ); - - if ( !pTemp ) return; - - pTemp->flags |= FTENT_SINEWAVE; - - pTemp->x = origin[0]; - pTemp->y = origin[1]; - - float zspeed = RANDOM_LONG( 80, 140 ); - pTemp->entity.baseline.origin = Vector( xspeed, yspeed, zspeed ); - pTemp->die = GetClientTime() + ( maxHeight / zspeed ) - 0.1f; - pTemp->entity.curstate.frame = RANDOM_LONG( 0, frameCount - 1 ); - // Set sprite scale - pTemp->entity.curstate.scale = 1.0f / RANDOM_FLOAT( 2, 5 ); - pTemp->entity.curstate.rendermode = kRenderTransAlpha; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 255; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Create bubbles -// Input : *mins - -// *maxs - -// height - -// modelIndex - -// count - -// speed - -//----------------------------------------------------------------------------- -void CTempEnts::Bubbles( const Vector &mins, const Vector &maxs, float height, int modelIndex, int count, float speed ) -{ - TENT *pTemp; - int i, frameCount; - float sine, cosine; - Vector origin; - - if( Mod_GetModelType( modelIndex ) == mod_bad ) - return; - - frameCount = Mod_GetFrames( modelIndex ); - - for ( i = 0; i < count; i++ ) - { - origin[0] = RANDOM_LONG( mins[0], maxs[0] ); - origin[1] = RANDOM_LONG( mins[1], maxs[1] ); - origin[2] = RANDOM_LONG( mins[2], maxs[2] ); - pTemp = TempEntAlloc( origin, modelIndex ); - if ( !pTemp ) return; - - pTemp->flags |= FTENT_SINEWAVE; - - pTemp->x = origin[0]; - pTemp->y = origin[1]; - float angle = RANDOM_LONG( -M_PI, M_PI ); - sine = sin( angle ); - cosine = cos( angle ); - - float zspeed = RANDOM_LONG( 80, 140 ); - pTemp->entity.baseline.origin = Vector( speed * cosine, speed * sine, zspeed ); - pTemp->die = GetClientTime() + ((height - (origin[2] - mins[2])) / zspeed) - 0.1f; - pTemp->entity.curstate.frame = RANDOM_LONG( 0, frameCount - 1 ); - - // Set sprite scale - pTemp->entity.curstate.scale = 1.0 / RANDOM_FLOAT( 4, 16 ); - pTemp->entity.curstate.rendermode = kRenderTransAlpha; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 192; // g-cont. why difference with FizzEffect ??? - } -} - -//----------------------------------------------------------------------------- -// Purpose: Create bubble trail -// Input : *start - -// *end - -// height - -// modelIndex - -// count - -// speed - -//----------------------------------------------------------------------------- -void CTempEnts::BubbleTrail( const Vector &start, const Vector &end, float flWaterZ, int modelIndex, int count, float speed ) -{ - TENT *pTemp; - int i, frameCount; - float dist, angle; - Vector origin; - - if( Mod_GetModelType( modelIndex ) == mod_bad ) - return; - - frameCount = Mod_GetFrames( modelIndex ); - - for ( i = 0; i < count; i++ ) - { - dist = RANDOM_FLOAT( 0, 1.0 ); - origin = LerpPoint( start, end, dist ); - pTemp = TempEntAlloc( origin, modelIndex ); - if ( !pTemp ) return; - - pTemp->flags |= FTENT_SINEWAVE; - - pTemp->x = origin[0]; - pTemp->y = origin[1]; - angle = RANDOM_LONG( -M_PI, M_PI ); - - float zspeed = RANDOM_LONG( 80, 140 ); - pTemp->entity.baseline.origin = Vector( speed * cos( angle ), speed * sin( angle ), zspeed ); - pTemp->die = GetClientTime() + (( flWaterZ - origin[2]) / zspeed ) - 0.1f; - pTemp->entity.curstate.frame = RANDOM_LONG( 0, frameCount - 1 ); - // Set sprite scale - pTemp->entity.curstate.scale = 1.0 / RANDOM_FLOAT( 4, 8 ); - pTemp->entity.curstate.rendermode = kRenderTransAlpha; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 192; - } -} - -//----------------------------------------------------------------------------- -// Purpose: Attaches entity to player -// Input : client - -// modelIndex - -// zoffset - -// life - -//----------------------------------------------------------------------------- -void CTempEnts::AttachTentToPlayer( int client, int modelIndex, float zoffset, float life ) -{ - TENT *pTemp; - Vector position; - int frameCount; - - if ( client <= 0 || client > gEngfuncs.GetMaxClients() ) - { - gEngfuncs.Con_Printf( "Bad client in AttachTentToPlayer()!\n" ); - return; - } - - cl_entity_t *pClient = GetEntityByIndex( client ); - if ( !pClient ) - { - gEngfuncs.Con_Printf( "Couldn't get ClientEntity for %i\n", client ); - return; - } - - if( Mod_GetModelType( modelIndex ) == mod_bad ) - { - gEngfuncs.Con_Printf( "No model %d!\n", modelIndex ); - return; - } - - position = pClient->origin; - position[2] += zoffset; - - pTemp = TempEntAllocHigh( position, modelIndex ); - if ( !pTemp ) - { - gEngfuncs.Con_Printf( "No temp ent.\n" ); - return; - } - - pTemp->entity.curstate.rendermode = kRenderNormal; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 192; - pTemp->entity.curstate.renderfx = kRenderFxNoDissipation; - - pTemp->clientIndex = client; - pTemp->tentOffset[0] = 0; - pTemp->tentOffset[1] = 0; - pTemp->tentOffset[2] = zoffset; - pTemp->die = GetClientTime() + life; - pTemp->flags |= FTENT_PLYRATTACHMENT|FTENT_PERSIST; - - // is the model a sprite? - if ( Mod_GetModelType( pTemp->entity.curstate.modelindex ) == mod_sprite ) - { - frameCount = Mod_GetFrames( pTemp->entity.curstate.modelindex ); - pTemp->frameMax = frameCount - 1; - pTemp->flags |= FTENT_SPRANIMATE|FTENT_SPRANIMATELOOP; - pTemp->entity.curstate.framerate = 10; - } - else - { - // no animation support for attached clientside studio models. - pTemp->frameMax = 0; - } - - pTemp->entity.curstate.frame = 0; -} -#define FOR_EACH_LL( listName, iteratorName ) \ - for( int iteratorName=listName.Head(); iteratorName != listName.InvalidIndex(); iteratorName = listName.Next( iteratorName ) ) - -//----------------------------------------------------------------------------- -// Purpose: Detach entity from player -//----------------------------------------------------------------------------- -void CTempEnts::KillAttachedTents( int client ) -{ - if ( client <= 0 || client > gEngfuncs.GetMaxClients() ) - { - gEngfuncs.Con_Printf( "Bad client in KillAttachedTents()!\n" ); - return; - } - - for( int i = 0; i < MAX_TEMP_ENTITIES; i++ ) - { - TENT *pTemp = &m_TempEnts[i]; - - if ( pTemp->flags & FTENT_PLYRATTACHMENT ) - { - // this TENT is player attached. - // if it is attached to this client, set it to die instantly. - if ( pTemp->clientIndex == client ) - { - pTemp->die = GetClientTime(); // good enough, it will die on next tent update. - } - } - } -} - -//----------------------------------------------------------------------------- -// Purpose: Create ricochet sprite -// Input : *pos - -// *pmodel - -// duration - -// scale - -//----------------------------------------------------------------------------- -void CTempEnts::RicochetSprite( const Vector &pos, int modelIndex, float scale ) -{ - TENT *pTemp; - - pTemp = TempEntAlloc( pos, modelIndex ); - if (!pTemp) - return; - - pTemp->entity.curstate.rendermode = kRenderGlow; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 200; - pTemp->entity.curstate.renderfx = kRenderFxNoDissipation; - pTemp->entity.curstate.scale = scale; - pTemp->flags = FTENT_FADEOUT; - pTemp->fadeSpeed = 8; - pTemp->die = GetClientTime(); - - pTemp->entity.curstate.frame = 0; - pTemp->entity.angles[ROLL] = 45 * RANDOM_LONG( 0, 7 ); -} - -void CTempEnts::PlaySound( TENT *pTemp, float damp ) -{ - float fvol; - char soundname[32]; - bool isshellcasing = false; - int zvel; - - switch ( pTemp->hitSound ) - { - default: - return; // null sound - case BOUNCE_GLASS: - { - sprintf( soundname, "debris/glass%i.wav", RANDOM_LONG( 1, 4 )); - } - break; - case BOUNCE_METAL: - { - sprintf( soundname, "debris/metal%i.wav", RANDOM_LONG( 1, 6 )); - } - break; - case BOUNCE_FLESH: - { - sprintf( soundname, "debris/flesh%i.wav", RANDOM_LONG( 1, 7 )); - } - break; - case BOUNCE_WOOD: - { - sprintf( soundname, "debris/wood%i.wav", RANDOM_LONG( 1, 4 )); - } - break; - case BOUNCE_SHRAP: - { - sprintf( soundname, "weapons/ric%i.wav", RANDOM_LONG( 1, 5 )); - } - break; - case BOUNCE_SHOTSHELL: - { - sprintf( soundname, "weapons/sshell%i.wav", RANDOM_LONG( 1, 3 )); - isshellcasing = true; // shell casings have different playback parameters - } - break; - case BOUNCE_SHELL: - { - sprintf( soundname, "player/pl_shell%i.wav", RANDOM_LONG( 1, 3 )); - isshellcasing = true; // shell casings have different playback parameters - } - break; - case BOUNCE_CONCRETE: - { - sprintf( soundname, "debris/concrete%i.wav", RANDOM_LONG( 1, 3 )); - } - break; - } - - zvel = abs( pTemp->entity.baseline.origin[2] ); - - // only play one out of every n - - if ( isshellcasing ) - { - // play first bounce, then 1 out of 3 - if ( zvel < 200 && RANDOM_LONG( 0, 3 )) - return; - } - else - { - if ( RANDOM_LONG( 0, 5 )) - return; - } - - fvol = 1.0f; - - if ( damp > 0.0 ) - { - int pitch; - - if ( isshellcasing ) - { - fvol *= min ( 1.0f, ((float)zvel) / 350.0 ); - } - else - { - fvol *= min ( 1.0f, ((float)zvel) / 450.0 ); - } - - if ( !RANDOM_LONG( 0, 3 ) && !isshellcasing ) - { - pitch = RANDOM_LONG( 95, 105 ); - } - else - { - pitch = PITCH_NORM; - } - - gEngfuncs.pEventAPI->EV_PlaySound( 0, pTemp->entity.origin, CHAN_AUTO, soundname, fvol, ATTN_NORM, 0, pitch ); - } -} - -void CTempEnts::RocketFlare( const Vector& pos ) -{ - TENT *pTemp; - int modelIndex; - int nframeCount; - - modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/animglow01.spr" ); - if( !modelIndex ) return; - - nframeCount = Mod_GetFrames( modelIndex ); - - pTemp = TempEntAlloc( pos, modelIndex ); - if ( !pTemp ) return; - - pTemp->frameMax = nframeCount - 1; - pTemp->entity.curstate.rendermode = kRenderGlow; - pTemp->entity.curstate.renderfx = kRenderFxNoDissipation; - pTemp->entity.curstate.renderamt = 200; - pTemp->entity.curstate.framerate = 1.0; - pTemp->entity.curstate.frame = RANDOM_LONG( 0, nframeCount - 1 ); - pTemp->entity.curstate.scale = 1.0; - pTemp->die = GetClientTime() + 0.01f; // when 100 fps die at next frame - pTemp->flags |= FTENT_SPRANIMATE; -} - -void CTempEnts::MuzzleFlash( cl_entity_t *pEnt, int iAttachment, int type ) -{ - Vector pos; - TENT *pTemp; - int index, modelIndex, frameCount; - float scale; - - index = bound( 0, type % 10, MAX_MUZZLEFLASH - 1 ); - scale = (type / 10) * 0.1f; - if( scale == 0.0f ) scale = 0.5f; - - modelIndex = m_iMuzzleFlash[index]; - if( !modelIndex ) return; - - frameCount = Mod_GetFrames( modelIndex ); - - if( iAttachment > 0 && pEnt->attachment[iAttachment - 1] == g_vecZero ) - { - gEngfuncs.Con_Printf( "Invalid muzzleflash entity!\n" ); - return; - } - - // must set position for right culling on render - pTemp = TempEntAlloc( pEnt->origin, modelIndex ); - if( !pTemp ) return; - - pTemp->entity.curstate.rendermode = kRenderTransAdd; - pTemp->entity.curstate.renderamt = 255; - pTemp->entity.curstate.renderfx = 0; - pTemp->die = GetClientTime() + 0.05; // die at next frame - pTemp->entity.curstate.frame = RANDOM_LONG( 0, frameCount - 1 ); - pTemp->frameMax = frameCount - 1; - - // because viewentity doesn't have a valid index - if( pEnt->curstate.entityType == ET_VIEWENTITY ) - pTemp->clientIndex = GetLocalPlayer()->index; - else pTemp->clientIndex = pEnt->index; - - if( iAttachment > 0 ) - { - // store attachment as baseline->body - pTemp->entity.baseline.body = iAttachment; - pTemp->flags |= FTENT_ATTACHMENT; - } - - if( index == 0 ) - { - // Rifle flash - pTemp->entity.curstate.scale = scale * RANDOM_FLOAT( 0.5f, 0.6f ); - pTemp->entity.angles[2] = 90 * RANDOM_LONG( 0, 3 ); - } - else - { - pTemp->entity.curstate.scale = scale; - pTemp->entity.angles[2] = RANDOM_LONG( 0, 359 ); - } -} - -void CTempEnts::BloodSprite( const Vector &org, int colorIndex, int modelIndex, int modelIndex2, float size ) -{ - TENT *pTemp; - - if( Mod_GetModelType( modelIndex ) == mod_bad ) - return; - - // Large, single blood sprite is a high-priority tent - if( pTemp = TempEntAllocHigh( org, modelIndex )) - { - int frameCount; - Vector color; - - frameCount = Mod_GetFrames( modelIndex ); - pTemp->entity.curstate.rendermode = kRenderTransTexture; - pTemp->entity.curstate.renderfx = kRenderFxClampMinScale; - pTemp->entity.curstate.scale = RANDOM_FLOAT(( size / 25.0f), ( size / 35.0f )); - pTemp->flags = FTENT_SPRANIMATE; - - CL_GetPaletteColor( colorIndex, color ); - pTemp->entity.curstate.rendercolor.r = color[0]; - pTemp->entity.curstate.rendercolor.g = color[1]; - pTemp->entity.curstate.rendercolor.b = color[2]; - pTemp->entity.curstate.framerate = frameCount * 4; // Finish in 0.250 seconds - // play the whole thing once - pTemp->die = GetClientTime() + (frameCount / pTemp->entity.curstate.framerate); - - pTemp->entity.angles[2] = RANDOM_LONG( 0, 360 ); - pTemp->bounceFactor = 0; - } -} - -void CTempEnts::BreakModel( const Vector &pos, const Vector &size, const Vector &dir, float random, float life, int count, int modelIndex, char flags ) -{ - int i, frameCount; - TENT *pTemp; - char type; - - if ( !modelIndex ) return; - - type = flags & BREAK_TYPEMASK; - - if ( Mod_GetModelType( modelIndex ) == mod_bad ) - return; - - frameCount = Mod_GetFrames( modelIndex ); - - if ( count == 0 ) - { - // assume surface (not volume) - count = (size[0] * size[1] + size[1] * size[2] + size[2] * size[0]) / (3 * SHARD_VOLUME * SHARD_VOLUME); - } - - // limit to 100 pieces - if ( count > 100 ) count = 100; - - for ( i = 0; i < count; i++ ) - { - vec3_t vecSpot; - - // fill up the box with stuff - vecSpot[0] = pos[0] + RANDOM_FLOAT( -0.5f, 0.5f ) * size[0]; - vecSpot[1] = pos[1] + RANDOM_FLOAT( -0.5f, 0.5f ) * size[1]; - vecSpot[2] = pos[2] + RANDOM_FLOAT( -0.5f, 0.5f ) * size[2]; - - pTemp = TempEntAlloc( vecSpot, modelIndex ); - if( !pTemp ) return; - - // keep track of break_type, so we know how to play sound on collision - pTemp->hitSound = type; - - if( Mod_GetModelType( modelIndex ) == mod_sprite ) - pTemp->entity.curstate.frame = RANDOM_LONG( 0, frameCount - 1 ); - else if( Mod_GetModelType( modelIndex ) == mod_studio ) - pTemp->entity.curstate.body = RANDOM_LONG( 0, frameCount - 1 ); - - pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_SLOWGRAVITY; - - if ( RANDOM_LONG( 0, 255 ) < 200 ) - { - pTemp->flags |= FTENT_ROTATE; - pTemp->entity.baseline.angles[0] = RANDOM_FLOAT( -256, 255 ); - pTemp->entity.baseline.angles[1] = RANDOM_FLOAT( -256, 255 ); - pTemp->entity.baseline.angles[2] = RANDOM_FLOAT( -256, 255 ); - } - - if (( RANDOM_LONG( 0, 255 ) < 100 ) && ( flags & BREAK_SMOKE )) - pTemp->flags |= FTENT_SMOKETRAIL; - - if (( type == BREAK_GLASS ) || ( flags & BREAK_TRANS )) - { - pTemp->entity.curstate.rendermode = kRenderTransTexture; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 128; - } - else - { - pTemp->entity.curstate.rendermode = kRenderNormal; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 255; // set this for fadeout - } - - pTemp->entity.baseline.origin[0] = dir[0] + RANDOM_FLOAT( -random, random ); - pTemp->entity.baseline.origin[1] = dir[1] + RANDOM_FLOAT( -random, random ); - pTemp->entity.baseline.origin[2] = dir[2] + RANDOM_FLOAT( 0, random ); - - pTemp->die = GetClientTime() + life + RANDOM_FLOAT( 0, 1 ); // Add an extra 0-1 secs of life - } -} - -TENT *CTempEnts::TempModel( const Vector &pos, const Vector &dir, const Vector &ang, float life, int modelIndex, int soundtype ) -{ - // alloc a new tempent - TENT *pTemp = TempEntAlloc( pos, modelIndex ); - if( !pTemp ) return NULL; - - // keep track of shell type - switch( soundtype ) - { - case TE_BOUNCE_SHELL: pTemp->hitSound = BOUNCE_SHELL; break; - case TE_BOUNCE_SHOTSHELL: pTemp->hitSound = BOUNCE_SHOTSHELL; break; - } - - pTemp->entity.origin = pos; - pTemp->entity.baseline.origin = dir; - pTemp->entity.angles = ang; - - pTemp->entity.curstate.body = 0; - pTemp->flags = (FTENT_COLLIDEWORLD|FTENT_FADEOUT|FTENT_GRAVITY|FTENT_ROTATE); - pTemp->entity.baseline.angles[0] = RANDOM_FLOAT( -255, 255 ); - pTemp->entity.baseline.angles[1] = RANDOM_FLOAT( -255, 255 ); - pTemp->entity.baseline.angles[2] = RANDOM_FLOAT( -255, 255 ); - pTemp->entity.curstate.rendermode = kRenderNormal; - pTemp->entity.baseline.renderamt = 255; - pTemp->die = GetClientTime() + life; - - return pTemp; -} - -TENT *CTempEnts::DefaultSprite( const Vector &pos, int spriteIndex, float framerate ) -{ - TENT *pTemp; - int frameCount; - - if( !spriteIndex || Mod_GetModelType( spriteIndex ) != mod_sprite ) - { - gEngfuncs.Con_Printf( "No Sprite %d!\n", spriteIndex ); - return NULL; - } - - frameCount = Mod_GetFrames( spriteIndex ); - - pTemp = TempEntAlloc( pos, spriteIndex ); - if( !pTemp ) return NULL; - - pTemp->frameMax = frameCount - 1; - pTemp->entity.curstate.scale = 1.0f; - pTemp->flags |= FTENT_SPRANIMATE; - if( framerate == 0 ) framerate = 10; - - pTemp->entity.curstate.framerate = framerate; - pTemp->die = GetClientTime() + (float)frameCount / framerate; - pTemp->entity.curstate.frame = 0; - - return pTemp; -} - -/* -=============== -CL_TempSprite -=============== -*/ -TENT *CTempEnts::TempSprite( const Vector &pos, const Vector &dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ) -{ - TENT *pTemp; - int frameCount; - - if( !modelIndex ) - return NULL; - - if( Mod_GetModelType( modelIndex ) == mod_bad ) - { - gEngfuncs.Con_Printf( "No model %d!\n", modelIndex ); - return NULL; - } - - frameCount = Mod_GetFrames( modelIndex ); - - pTemp = TempEntAlloc( pos, modelIndex ); - if( !pTemp ) return NULL; - - pTemp->frameMax = frameCount - 1; - pTemp->entity.curstate.framerate = 10; - pTemp->entity.curstate.rendermode = rendermode; - pTemp->entity.curstate.renderfx = renderfx; - pTemp->entity.curstate.scale = scale; - pTemp->entity.baseline.renderamt = a * 255; - pTemp->entity.curstate.renderamt = a * 255; - pTemp->flags |= flags; - - pTemp->entity.origin = pos; - pTemp->entity.baseline.origin = dir; - - if( life ) pTemp->die = GetClientTime() + life; - else pTemp->die = GetClientTime() + (frameCount * 0.1f) + 1.0f; - pTemp->entity.curstate.frame = 0; - - return pTemp; -} - -void CTempEnts::Sprite_Explode( TENT *pTemp, float scale, int flags ) -{ - if( !pTemp ) return; - - // NOTE: Xash3D doesn't needs this stuff, because sprites - // have right rendermodes already at loading point - // but i'm leave it for backward compatibility - if( flags & TE_EXPLFLAG_NOADDITIVE ) - { - // solid sprite - pTemp->entity.curstate.rendermode = kRenderNormal; - pTemp->entity.curstate.renderamt = 255; - } - else if( flags & TE_EXPLFLAG_DRAWALPHA ) - { - // alpha sprite - pTemp->entity.curstate.rendermode = kRenderTransAlpha; - pTemp->entity.curstate.renderamt = 180; - } - else - { - // additive sprite - pTemp->entity.curstate.rendermode = kRenderTransAdd; - pTemp->entity.curstate.renderamt = 120; - } - - if( flags & TE_EXPLFLAG_ROTATE ) - { - pTemp->entity.angles[2] = RANDOM_LONG( 0, 360 ); - } - - pTemp->entity.curstate.renderfx = kRenderFxNone; - pTemp->entity.baseline.origin[2] = 8; - pTemp->entity.origin[2] += 10; - pTemp->entity.curstate.scale = scale; -} - -void CTempEnts::Sprite_Smoke( TENT *pTemp, float scale ) -{ - int iColor; - - if( !pTemp ) return; - - iColor = RANDOM_LONG( 20, 35 ); - pTemp->entity.curstate.rendermode = kRenderTransAlpha; - pTemp->entity.curstate.renderfx = kRenderFxNone; - pTemp->entity.baseline.origin[2] = 30; - pTemp->entity.curstate.rendercolor.r = iColor; - pTemp->entity.curstate.rendercolor.g = iColor; - pTemp->entity.curstate.rendercolor.b = iColor; - pTemp->entity.origin[2] += 20; - pTemp->entity.curstate.scale = scale; -} - -void CTempEnts::Sprite_Spray( const Vector &pos, const Vector &dir, int modelIndex, int count, int speed, int iRand, int renderMode ) -{ - TENT *pTemp; - float noise; - float znoise; - int i, frameCount; - - noise = (float)iRand / 100; - - // more vertical displacement - znoise = noise * 1.5f; - - if( znoise > 1 ) znoise = 1; - - if( Mod_GetModelType( modelIndex ) == mod_bad ) - { - gEngfuncs.Con_Printf( "No model %d!\n", modelIndex ); - return; - } - - frameCount = Mod_GetFrames( modelIndex ); - - for( i = 0; i < count; i++ ) - { - vec3_t velocity; - float scale; - - pTemp = TempEntAlloc( pos, modelIndex ); - if( !pTemp ) return; - - pTemp->entity.curstate.rendermode = renderMode; - pTemp->entity.curstate.renderfx = kRenderFxNoDissipation; - pTemp->entity.curstate.scale = 0.5f; - pTemp->flags |= FTENT_FADEOUT|FTENT_SLOWGRAVITY; - pTemp->fadeSpeed = 2.0f; - - // make the spittle fly the direction indicated, but mix in some noise. - velocity[0] = dir[0] + RANDOM_FLOAT( -noise, noise ); - velocity[1] = dir[1] + RANDOM_FLOAT( -noise, noise ); - velocity[2] = dir[2] + RANDOM_FLOAT( 0, znoise ); - scale = RANDOM_FLOAT(( speed * 0.8f ), ( speed * 1.2f )); - pTemp->entity.baseline.origin = velocity * scale; - pTemp->die = GetClientTime() + 0.35f; - pTemp->entity.curstate.frame = RANDOM_LONG( 0, frameCount - 1 ); - } -} - -void CTempEnts::Sprite_Trail( int type, const Vector &vecStart, const Vector &vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed ) -{ - TENT *pTemp; - vec3_t vecDelta, vecDir; - int i, flFrameCount; - - if( Mod_GetModelType( modelIndex ) == mod_bad ) - { - gEngfuncs.Con_Printf( "No model %d!\n", modelIndex ); - return; - } - - flFrameCount = Mod_GetFrames( modelIndex ); - - vecDelta = vecEnd - vecStart; - vecDir = vecDelta.Normalize(); - - flAmplitude /= 256.0; - - for ( i = 0; i < nCount; i++ ) - { - Vector vecPos, vecVel; - - // Be careful of divide by 0 when using 'count' here... - if ( i == 0 ) - { - vecPos = vecStart; - } - else - { - vecPos = vecStart + vecDelta * ( i / ( nCount - 1.0f )); - } - - pTemp = TempEntAlloc( vecPos, modelIndex ); - if( !pTemp ) return; - - pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_SPRCYCLE | FTENT_FADEOUT | FTENT_SLOWGRAVITY; - - vecVel = vecDir * flSpeed; - vecVel[0] += RANDOM_FLOAT( -127, 128 ) * flAmplitude; - vecVel[1] += RANDOM_FLOAT( -127, 128 ) * flAmplitude; - vecVel[2] += RANDOM_FLOAT( -127, 128 ) * flAmplitude; - pTemp->entity.baseline.origin = vecVel; - pTemp->entity.origin = vecPos; - - pTemp->entity.curstate.scale = flSize; - pTemp->entity.curstate.rendermode = kRenderGlow; - pTemp->entity.curstate.renderfx = kRenderFxNoDissipation; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = nRenderamt; - - pTemp->entity.curstate.frame = RANDOM_LONG( 0, flFrameCount - 1 ); - pTemp->frameMax = flFrameCount - 1; - pTemp->die = GetClientTime() + flLife + RANDOM_FLOAT( 0, 4 ); - } -} - -void CTempEnts::Large_Funnel( Vector pos, int spriteIndex, int flags ) -{ - TENT *pTemp = NULL; - CBaseParticle *pPart = NULL; - float vel; - Vector dir; - Vector dest; - Vector m_vecPos; - float flDist; - - for ( int i = -256 ; i <= 256 ; i += 32 ) - { - for ( int j = -256 ; j <= 256 ; j += 32 ) - { - if( pTemp ) - { - pPart = g_pParticles->AllocParticle (); - pTemp = NULL; - } - else - { - pTemp = TempEntAlloc( pos, spriteIndex ); - pPart = NULL; - } - - if( pTemp || pPart ) - { - if ( flags & 1 ) - { - m_vecPos = pos; - - dest[0] = pos[0] + i; - dest[1] = pos[1] + j; - dest[2] = pos[2] + RANDOM_FLOAT( 100, 800 ); - - // send particle heading to dest at a random speed - dir = dest - m_vecPos; - - vel = dest[2] / 8;// velocity based on how far particle has to travel away from org - } - else - { - m_vecPos[0] = pos[0] + i; - m_vecPos[1] = pos[1] + j; - m_vecPos[2] = pos[2] + RANDOM_FLOAT( 100, 800 ); - - // send particle heading to org at a random speed - dir = pos - m_vecPos; - - vel = m_vecPos[2] / 8;// velocity based on how far particle starts from org - } - - flDist = dir.Length(); // save the distance - dir = dir.Normalize(); - - if ( vel < 64 ) - { - vel = 64; - } - - vel += RANDOM_FLOAT( 64, 128 ); - float life = (flDist / vel); - - if( pTemp ) - { - pTemp->entity.origin = m_vecPos; - pTemp->entity.baseline.origin = dir * vel; - pTemp->entity.curstate.rendermode = kRenderTransAdd; - pTemp->flags |= FTENT_FADEOUT; - pTemp->fadeSpeed = 2.0f; - pTemp->die = GetClientTime() + RANDOM_FLOAT( life * 0.5, life ); - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt = 255; - } - - if( pPart ) - { - pPart->m_Pos = m_vecPos; - pPart->SetColor( 0.0f, 1.0f, 0.0f ); - pPart->SetType( pt_static ); - pPart->SetAlpha( 1.0f ); - - pPart->m_Velocity = dir * vel; - // die right when you get there - pPart->SetLifetime( RANDOM_FLOAT( life * 0.5, life )); - } - } - } - } -} - -void CTempEnts::SparkEffect( const Vector& pos, int count, int velocityMin, int velocityMax ) -{ - Vector m_vecDir; - - int modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/richo1.spr" ); - RicochetSprite( pos, modelIndex, RANDOM_FLOAT( 0.4, 0.6f )); - - for ( int i = 0; i < RANDOM_LONG( 1, count ); i++ ) - { - m_vecDir.x = RANDOM_FLOAT( velocityMin, velocityMax ); - m_vecDir.y = RANDOM_FLOAT( velocityMin, velocityMax ); - m_vecDir.z = RANDOM_FLOAT( velocityMin, velocityMax ); - m_vecDir = m_vecDir.Normalize(); - - g_pParticles->SparkleTracer( pos, m_vecDir ); - } -} - -void CTempEnts::SparkShower( const Vector& pos ) -{ - Vector m_vecPos, m_vecDir; - - // randomize position - m_vecPos.x = pos.x + RANDOM_FLOAT( -2, 2 ); - m_vecPos.y = pos.y + RANDOM_FLOAT( -2, 2 ); - m_vecPos.z = pos.z + RANDOM_FLOAT( -2, 2 ); - - int modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/richo1.spr" ); - RicochetSprite( m_vecPos, modelIndex, RANDOM_FLOAT( 0.4, 0.6f )); - - // create a 8 random spakle tracers - for ( int i = 0; i < 8; i++ ) - { - m_vecDir.x = RANDOM_FLOAT( -1.0f, 1.0f ); - m_vecDir.y = RANDOM_FLOAT( -1.0f, 1.0f ); - m_vecDir.z = RANDOM_FLOAT( -1.0f, 1.0f ); - - g_pParticles->SparkleTracer( m_vecPos, m_vecDir ); - } -} - -void CTempEnts::TracerEffect( const Vector &start, const Vector &end ) -{ - g_pParticles->BulletTracer( start, end ); -} - -void CTempEnts::StreakSplash( const Vector &pos, const Vector &dir, int color, int count, int speed, int velMin, int velMax ) -{ - for ( int i = 0; i < count; i++ ) - { - Vector vel; - - vel.x = (dir.x * speed) + RANDOM_FLOAT( velMin, velMax ); - vel.y = (dir.y * speed) + RANDOM_FLOAT( velMin, velMax ); - vel.z = (dir.z * speed) + RANDOM_FLOAT( velMin, velMax ); - - g_pParticles->StreakTracer( pos, vel, color ); - } -} - -void CTempEnts::WeaponFlash( cl_entity_t *pEnt, int iAttachment ) -{ - Vector pos = pEnt->origin; - - if( iAttachment > 0 ) - pos += pEnt->attachment[iAttachment - 1]; - if( pos == pEnt->origin ) return; // missing attachment - - AllocDLight( pos, 255, 180, 64, 100, 0.05f ); -} - -void CTempEnts::PlaceDecal( Vector pos, int entityIndex, int decalIndex ) -{ - HSPRITE hDecal; - cl_entity_t *pEnt; - int modelIndex = 0; - - pEnt = GetEntityByIndex( entityIndex ); - if( pEnt ) modelIndex = pEnt->curstate.modelindex; - hDecal = gEngfuncs.pEfxAPI->CL_DecalIndex( decalIndex ); - gEngfuncs.pEfxAPI->CL_DecalShoot( hDecal, entityIndex, modelIndex, pos, 0 ); -} - -void CTempEnts::PlaceDecal( Vector pos, int entityIndex, const char *decalname ) -{ - HSPRITE hDecal; - cl_entity_t *pEnt; - int modelIndex = 0; - - pEnt = GetEntityByIndex( entityIndex ); - if( pEnt ) modelIndex = pEnt->curstate.modelindex; - hDecal = gEngfuncs.pEfxAPI->CL_DecalIndexFromName( decalname ); - gEngfuncs.pEfxAPI->CL_DecalShoot( hDecal, entityIndex, modelIndex, pos, 0 ); -} - -void CTempEnts::AllocDLight( Vector pos, byte r, byte g, byte b, float radius, float time, float decay ) -{ - if( radius <= 0 ) return; - - dlight_t *dl; - - dl = gEngfuncs.pEfxAPI->CL_AllocDLight( 0 ); - - dl->origin = pos; - dl->die = GetClientTime() + time; - dl->color.r = r; - dl->color.g = g; - dl->color.b = b; - dl->radius = radius; - dl->decay = decay; -} - -void CTempEnts::AllocDLight( Vector pos, float radius, float time, float decay ) -{ - AllocDLight( pos, 255, 255, 255, radius, time, decay ); -} - -void CTempEnts::RocketTrail( Vector start, Vector end, int type ) -{ - g_pParticles->RocketTrail( start, end, type ); -} - -extern "C" -{ -void __declspec( dllexport ) HUD_TempEntUpdate ( - double frametime, // Simulation time - double client_time, // Absolute time on client - double cl_gravity, // True gravity on client - TEMPENTITY **ppTempEntFree, // List of freed temporary ents - TEMPENTITY **ppTempEntActive, // List - int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), - void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ); -} - -/* -================= -CL_UpdateTEnts - -Simulation and cleanup of temporary entities -================= -*/ -void __declspec( dllexport ) HUD_TempEntUpdate ( - double frametime, // Simulation time - double client_time, // Absolute time on client - double cl_gravity, // True gravity on client - TEMPENTITY **ppTempEntFree, // List of freed temporary ents - TEMPENTITY **ppTempEntActive, // List - int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), - void ( *Callback_TempEntPlaySound )( TEMPENTITY *pTemp, float damp ) ) -{ - static int gTempEntFrame = 0; - int i; - TEMPENTITY *pTemp, *pnext, *pprev; - float freq, gravity, gravitySlow, life, fastFreq; - - // Nothing to simulate - if ( !*ppTempEntActive ) - return; - - // in order to have tents collide with players, we have to run the player prediction code so - // that the client has the player list. We run this code once when we detect any COLLIDEALL - // tent, then set this BOOL to true so the code doesn't get run again if there's more than - // one COLLIDEALL ent for this update. (often are). - 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 ( -1 ); - - // !!!BUGBUG -- This needs to be time based - gTempEntFrame = (gTempEntFrame+1) & 31; - - pTemp = *ppTempEntActive; - - // !!! Don't simulate while paused.... This is sort of a hack, revisit. - if ( frametime <= 0 ) - { - while ( pTemp ) - { - if ( !(pTemp->flags & FTENT_NOMODEL ) ) - { - Callback_AddVisibleEntity( &pTemp->entity ); - } - pTemp = pTemp->next; - } - goto finish; - } - - pprev = NULL; - freq = client_time * 0.01; - fastFreq = client_time * 5.5; - gravity = -frametime * cl_gravity; - gravitySlow = gravity * 0.5; - - while ( pTemp ) - { - int active; - - active = 1; - - life = pTemp->die - client_time; - pnext = pTemp->next; - if ( life < 0 ) - { - if ( pTemp->flags & FTENT_FADEOUT ) - { - if (pTemp->entity.curstate.rendermode == kRenderNormal) - pTemp->entity.curstate.rendermode = kRenderTransTexture; - pTemp->entity.curstate.renderamt = pTemp->entity.baseline.renderamt * ( 1 + life * pTemp->fadeSpeed ); - if ( pTemp->entity.curstate.renderamt <= 0 ) - active = 0; - - } - else - active = 0; - } - if ( !active ) // Kill it - { - pTemp->next = *ppTempEntFree; - *ppTempEntFree = pTemp; - if ( !pprev ) // Deleting at head of list - *ppTempEntActive = pnext; - else - pprev->next = pnext; - } - else - { - pprev = pTemp; - - pTemp->entity.prevstate.origin = pTemp->entity.origin; - - if ( pTemp->flags & FTENT_SPARKSHOWER ) - { - // Adjust speed if it's time - // Scale is next think time - if ( client_time > pTemp->entity.baseline.scale ) - { - // Show Sparks - gEngfuncs.pEfxAPI->R_SparkEffect( pTemp->entity.origin, 8, -200, 200 ); - - // Reduce life - pTemp->entity.baseline.framerate -= 0.1; - - if ( pTemp->entity.baseline.framerate <= 0.0 ) - { - pTemp->die = client_time; - } - else - { - // So it will die no matter what - pTemp->die = client_time + 0.5; - - // Next think - pTemp->entity.baseline.scale = client_time + 0.1; - } - } - } - else if ( pTemp->flags & FTENT_PLYRATTACHMENT ) - { - cl_entity_t *pClient; - - pClient = GetEntityByIndex( pTemp->clientIndex ); - - pTemp->entity.origin = pClient->origin + pTemp->tentOffset; - } - else if ( pTemp->flags & FTENT_SINEWAVE ) - { - pTemp->x += pTemp->entity.baseline.origin[0] * frametime; - pTemp->y += pTemp->entity.baseline.origin[1] * frametime; - - pTemp->entity.origin[0] = pTemp->x + sin( pTemp->entity.baseline.origin[2] + client_time * pTemp->entity.prevstate.frame ) * (10*pTemp->entity.curstate.framerate); - pTemp->entity.origin[1] = pTemp->y + sin( pTemp->entity.baseline.origin[2] + fastFreq + 0.7 ) * (8*pTemp->entity.curstate.framerate); - pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; - } - else if ( pTemp->flags & FTENT_SPIRAL ) - { - float s, c; - s = sin( pTemp->entity.baseline.origin[2] + fastFreq ); - c = cos( pTemp->entity.baseline.origin[2] + fastFreq ); - - pTemp->entity.origin[0] += pTemp->entity.baseline.origin[0] * frametime + 8 * sin( client_time * 20 + (int)pTemp ); - pTemp->entity.origin[1] += pTemp->entity.baseline.origin[1] * frametime + 4 * sin( client_time * 30 + (int)pTemp ); - pTemp->entity.origin[2] += pTemp->entity.baseline.origin[2] * frametime; - } - - else - { - for ( i = 0; i < 3; i++ ) - pTemp->entity.origin[i] += pTemp->entity.baseline.origin[i] * frametime; - } - - if ( pTemp->flags & FTENT_SPRANIMATE ) - { - pTemp->entity.curstate.frame += frametime * pTemp->entity.curstate.framerate; - if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) - { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); - - if ( !(pTemp->flags & FTENT_SPRANIMATELOOP) ) - { - // this animating sprite isn't set to loop, so destroy it. - pTemp->die = client_time; - pTemp = pnext; - continue; - } - } - } - else if ( pTemp->flags & FTENT_SPRCYCLE ) - { - pTemp->entity.curstate.frame += frametime * 10; - if ( pTemp->entity.curstate.frame >= pTemp->frameMax ) - { - pTemp->entity.curstate.frame = pTemp->entity.curstate.frame - (int)(pTemp->entity.curstate.frame); - } - } -// Experiment -#if 0 - if ( pTemp->flags & FTENT_SCALE ) - pTemp->entity.curstate.framerate += 20.0 * (frametime / pTemp->entity.curstate.framerate); -#endif - - if ( pTemp->flags & FTENT_ROTATE ) - { - pTemp->entity.angles[0] += pTemp->entity.baseline.angles[0] * frametime; - pTemp->entity.angles[1] += pTemp->entity.baseline.angles[1] * frametime; - pTemp->entity.angles[2] += pTemp->entity.baseline.angles[2] * frametime; - - pTemp->entity.latched.prevangles = pTemp->entity.angles; - } - - if ( pTemp->flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD) ) - { - vec3_t traceNormal; - float traceFraction = 1; - - if ( pTemp->flags & FTENT_COLLIDEALL ) - { - pmtrace_t pmtrace; - physent_t *pe; - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX, -1, &pmtrace ); - - - if ( pmtrace.fraction != 1 ) - { - pe = gEngfuncs.pEventAPI->EV_GetPhysent( pmtrace.ent ); - - if ( !pmtrace.ent || ( pe->info != pTemp->clientIndex ) ) - { - traceFraction = pmtrace.fraction; - traceNormal = pmtrace.plane.normal; - - if ( pTemp->hitcallback ) - { - (*pTemp->hitcallback)( pTemp, &pmtrace ); - } - } - } - } - else if ( pTemp->flags & FTENT_COLLIDEWORLD ) - { - pmtrace_t pmtrace; - - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - - gEngfuncs.pEventAPI->EV_PlayerTrace( pTemp->entity.prevstate.origin, pTemp->entity.origin, PM_STUDIO_BOX | PM_WORLD_ONLY, -1, &pmtrace ); - - if ( pmtrace.fraction != 1 ) - { - traceFraction = pmtrace.fraction; - traceNormal = pmtrace.plane.normal; - - if ( pTemp->flags & FTENT_SPARKSHOWER ) - { - // chop spark speeds a bit more - pTemp->entity.baseline.origin *= 0.6f; - - if( pTemp->entity.baseline.origin.Length() < 10.0f ) - pTemp->entity.baseline.framerate = 0.0f; - } - - if ( pTemp->hitcallback ) - { - (*pTemp->hitcallback)( pTemp, &pmtrace ); - } - } - } - - if ( traceFraction != 1 ) // Decent collision now, and damping works - { - float proj, damp; - - // Place at contact point - pTemp->entity.origin = pTemp->entity.prevstate.origin + (traceFraction * frametime) * pTemp->entity.baseline.origin; - // Damp velocity - damp = pTemp->bounceFactor; - if ( pTemp->flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) - { - damp *= 0.5; - if ( traceNormal[2] > 0.9 ) // Hit floor? - { - if ( pTemp->entity.baseline.origin[2] <= 0 && pTemp->entity.baseline.origin[2] >= gravity*3 ) - { - damp = 0; // Stop - pTemp->flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); - pTemp->entity.angles[0] = 0; - pTemp->entity.angles[2] = 0; - } - } - } - - if (pTemp->hitSound) - { - Callback_TempEntPlaySound(pTemp, damp); - } - - if (pTemp->flags & FTENT_COLLIDEKILL) - { - // die on impact - pTemp->flags &= ~FTENT_FADEOUT; - pTemp->die = client_time; - } - else - { - // Reflect velocity - if ( damp != 0 ) - { - proj = DotProduct( pTemp->entity.baseline.origin, traceNormal ); - pTemp->entity.baseline.origin += (-proj * 2) * traceNormal; - // Reflect rotation (fake) - - pTemp->entity.angles[1] = -pTemp->entity.angles[1]; - } - - if ( damp != 1 ) - { - pTemp->entity.baseline.origin *= damp; - pTemp->entity.angles *= 0.9f; - } - } - } - } - - - if ( (pTemp->flags & FTENT_FLICKER) && gTempEntFrame == pTemp->entity.curstate.effects ) - { - dlight_t *dl = gEngfuncs.pEfxAPI->CL_AllocDlight (0); - dl->origin = pTemp->entity.origin; - dl->radius = 60; - dl->color.r = 255; - dl->color.g = 120; - dl->color.b = 0; - dl->die = client_time + 0.01; - } - - if ( pTemp->flags & FTENT_SMOKETRAIL ) - { - gEngfuncs.pEfxAPI->R_RocketTrail (pTemp->entity.prevstate.origin, pTemp->entity.origin, 1); - } - - if ( pTemp->flags & FTENT_GRAVITY ) - pTemp->entity.baseline.origin[2] += gravity; - else if ( pTemp->flags & FTENT_SLOWGRAVITY ) - pTemp->entity.baseline.origin[2] += gravitySlow; - - if ( pTemp->flags & FTENT_CLIENTCUSTOM ) - { - if ( pTemp->callback ) - { - ( *pTemp->callback )( pTemp, frametime, client_time ); - } - } - - // Cull to PVS (not frustum cull, just PVS) - if ( !(pTemp->flags & FTENT_NOMODEL ) ) - { - if ( !Callback_AddVisibleEntity( &pTemp->entity ) ) - { - if ( !(pTemp->flags & FTENT_PERSIST) ) - { - pTemp->die = client_time; // If we can't draw it this frame, just dump it. - pTemp->flags &= ~FTENT_FADEOUT; // Don't fade out, just die - } - } - } - } - pTemp = pnext; - } - -finish: - // Restore state info - gEngfuncs.pEventAPI->EV_PopPMStates(); -} \ No newline at end of file diff --git a/client/global/r_tempents.h b/client/global/r_tempents.h deleted file mode 100644 index e9038909..00000000 --- a/client/global/r_tempents.h +++ /dev/null @@ -1,119 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2010 й -// r_tempents.h - tempentities management -//======================================================================= - -#ifndef R_TEMPENTS_H -#define R_TEMPENTS_H - -#include "r_efx.h" - -//----------------------------------------------------------------------------- -// Purpose: implementation for temp entities -//----------------------------------------------------------------------------- - -typedef struct tent_s TENT; - -struct tent_s -{ - int flags; - float die; - float frameMax; // this is also animtime for studiomodels - float x, y, z; // probably z isn't used - float fadeSpeed; - float bounceFactor; - int hitSound; - void (*hitcallback)( struct tent_s *ent, struct pmtrace_s *ptr ); - void (*callback)( struct tent_s *ent, float frametime, float currenttime ); - TENT *next; - int priority; // 0 - low, 1 - high - short clientIndex; // if attached, this is the index of the client to stick to - // if COLLIDEALL, this is the index of the client to ignore - // TENTS with FTENT_PLYRATTACHMENT MUST set the clientindex! - vec3_t tentOffset; // if attached, client origin + tentOffset = tent origin. - cl_entity_t entity; - - // baseline.origin - velocity - // baseline.renderamt - starting fadeout intensity - // baseline.angles - angle velocity -}; - -#define MAX_TEMP_ENTITIES 500 -#define TENT_WIND_ACCEL 50 -#define MAX_MUZZLEFLASH 4 -#define SHARD_VOLUME 12.0 // on shard ever n^3 units - -class CTempEnts -{ -public: - CTempEnts( void ); - virtual ~CTempEnts( void ); - - void Update( void ); - void Clear( void ); - - void TE_Prepare( TENT *pTemp, int modelIndex ); - int TE_Active( TENT *pTemp ); - int TE_Update( TENT *pTemp, float frametime ); // return false for instantly die - - void BloodSprite( const Vector &org, int colorIndex, int modelIndex, int modelIndex2, float size ); - void RicochetSprite( const Vector &pos, int modelIndex, float scale ); - void MuzzleFlash( cl_entity_t *pEnt, int iAttachment, int type ); - TENT *TempModel( const Vector &pos, const Vector &dir, const Vector &ang, float life, int modelIndex, int soundtype ); - void BreakModel( const Vector &pos, const Vector &size, const Vector &dir, float random, float life, int count, int modelIndex, char flags ); - void Bubbles( const Vector &mins, const Vector &maxs, float height, int modelIndex, int count, float speed ); - void BubbleTrail( const Vector &start, const Vector &end, float height, int modelIndex, int count, float speed ); - void Sprite_Explode( TENT *pTemp, float scale, int flags ); - void FizzEffect( cl_entity_t *pent, int modelIndex, int density ); - TENT *DefaultSprite( const Vector &pos, int spriteIndex, float framerate ); - void Sprite_Smoke( TENT *pTemp, float scale ); - TENT *TempSprite( const Vector &pos, const Vector &dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags ); - void AttachTentToPlayer( int client, int modelIndex, float zoffset, float life ); - void KillAttachedTents( int client ); - void Sprite_Spray( const Vector &pos, const Vector &dir, int modelIndex, int count, int speed, int iRand, int renderMode = kRenderTransAlpha ); - void Sprite_Trail( int type, const Vector &vecStart, const Vector &vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed ); - void RocketFlare( const Vector& pos ); - void PlaySound( TENT *pTemp, float damp ); - void TracerEffect( const Vector &start, const Vector &end ); - void WeaponFlash( cl_entity_t *pEnt, int iAttachment ); - void PlaceDecal( Vector pos, int entityIndex, int decalIndex ); - void PlaceDecal( Vector pos, int entityIndex, const char *decalname ); - void AllocDLight( Vector pos, byte r, byte g, byte b, float radius, float time, float decay = 0.0f ); - void AllocDLight( Vector pos, float radius, float time, float decay = 0.0f ); - void RocketTrail( Vector start, Vector end, int type ); - void Large_Funnel( Vector pos, int spriteIndex, int flags ); - void SparkShower( const Vector& pos ); - void SparkEffect( const Vector& pos, int count, int velocityMin, int velocityMax ); - void StreakSplash( const Vector &pos, const Vector &dir, int color, int count, int speed, int velMin, int velMax ); -// Data -private: - float m_flTime; // the current client time - float m_fOldTime; // the time at which the HUD was last redrawn - - int m_iTempEntFrame; // used for keyed dlights only - - // Global temp entity pool - TENT m_TempEnts[MAX_TEMP_ENTITIES]; - - // Free and active temp entity lists - TENT *m_pFreeTempEnts; - TENT *m_pActiveTempEnts; - - // muzzle flash sprites - int m_iMuzzleFlash[MAX_MUZZLEFLASH]; - - void TempEntFree( TENT *pTemp, TENT *pPrev ); - bool FreeLowPriorityTempEnt( void ); -public: - TENT *TempEntAllocNoModel( const Vector& org ); - TENT *TempEntAlloc( const Vector& org, int modelindex ); - TENT *TempEntAllocHigh( const Vector& org, int modelIndex ); - TENT *TempEntAllocCustom( const Vector& org, int modelIndex, int high, void ( *callback )( struct tent_s *ent, float frametime, float currenttime )); - - // misc utility shaders - HSPRITE hSprGlowShell; // glowshell shader -}; - -extern CTempEnts *g_pTempEnts; - -#endif//R_TEMPENTS_H \ No newline at end of file diff --git a/client/global/r_tracer.cpp b/client/global/r_tracer.cpp deleted file mode 100644 index 2d4f32b1..00000000 --- a/client/global/r_tracer.cpp +++ /dev/null @@ -1,127 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2010 й -// r_tracer.cpp - draw & cull the tracer -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "triangleapi.h" -#include "r_efx.h" -#include "pm_movevars.h" -#include "ev_hldm.h" -#include "hud.h" -#include "r_particle.h" -#include "r_tempents.h" - -//----------------------------------------------------------------------------- -// Sees if the tracer is behind the camera or should be culled -//----------------------------------------------------------------------------- -static bool CullTracer( const Vector &start, const Vector &end ) -{ - Vector mins, maxs; - - // compute the bounding box - for ( int i = 0; i < 3; i++ ) - { - if ( start[i] < end[i] ) - { - mins[i] = start[i]; - maxs[i] = end[i]; - } - else - { - mins[i] = end[i]; - maxs[i] = start[i]; - } - - // Don't let it be zero sized - if ( mins[i] == maxs[i] ) - { - maxs[i] += 1; - } - } - - // check bbox - if( gEngfuncs.pEfxAPI->R_CullBox( mins, maxs ) ) - return true; // culled - - return false; -} - -//----------------------------------------------------------------------------- -// Computes the four verts to draw the tracer with -//----------------------------------------------------------------------------- -bool CParticleSystem :: TracerComputeVerts( const Vector &pos, const Vector &delta, float width, Vector *pVerts ) -{ - Vector start, end; - - start = pos; - end = start + delta; - - // Clip the tracer - if ( CullTracer( start, end )) - return false; - - Vector screenStart, screenEnd; - - // transform point into the screen space - gEngfuncs.pTriAPI->WorldToScreen( (float *)start, screenStart ); - gEngfuncs.pTriAPI->WorldToScreen( (float *)end, screenEnd ); - - Vector tmp, normal; - - tmp = screenStart - screenEnd; - // We don't need Z, we're in screen space - tmp.z = 0; - tmp = tmp.Normalize(); - - normal = m_vecUp * tmp.x; // Build point along noraml line (normal is -y, x) - normal = normal - ( m_vecRight * -tmp.y ); - - // compute four vertexes - pVerts[0] = start - normal * width; - pVerts[1] = start + normal * width; - pVerts[2] = pVerts[0] + delta; - pVerts[3] = pVerts[1] + delta; - - return true; -} - - -//----------------------------------------------------------------------------- -// draw a tracer. -//----------------------------------------------------------------------------- -void CParticleSystem :: DrawTracer( HSPRITE hSprite, Vector& start, Vector& delta, float width, byte *color, float startV, float endV ) -{ - // Clip the tracer - Vector verts[4]; - - if ( !TracerComputeVerts( start, delta, width, verts )) - return; - - // NOTE: Gotta get the winding right so it's not backface culled - // (we need to turn of backface culling for these bad boys) - - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - gEngfuncs.pTriAPI->RenderMode( kRenderTransTexture ); - if ( color ) gEngfuncs.pTriAPI->Color4ub( color[0], color[1], color[2], color[3] ); - else gEngfuncs.pTriAPI->Color4ub( 255, 255, 255, 255 ); - - gEngfuncs.pTriAPI->Bind( hSprite, 0 ); - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - - gEngfuncs.pTriAPI->TexCoord2f( 0.0f, endV ); - gEngfuncs.pTriAPI->Vertex3fv( verts[2] ); - - gEngfuncs.pTriAPI->TexCoord2f( 1.0f, endV ); - gEngfuncs.pTriAPI->Vertex3fv( verts[3] ); - - gEngfuncs.pTriAPI->TexCoord2f( 1.0f, startV ); - gEngfuncs.pTriAPI->Vertex3fv( verts[1] ); - - gEngfuncs.pTriAPI->TexCoord2f( 0.0f, startV ); - gEngfuncs.pTriAPI->Vertex3fv( verts[0] ); - - gEngfuncs.pTriAPI->End(); - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} \ No newline at end of file diff --git a/client/global/r_weather.cpp b/client/global/r_weather.cpp deleted file mode 100644 index 1158f061..00000000 --- a/client/global/r_weather.cpp +++ /dev/null @@ -1,711 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// rain.cpp - TriAPI weather effects -// based on original code from BUzer -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "r_efx.h" -#include "triangleapi.h" -#include "hud.h" -#include "r_weather.h" -#include "pm_defs.h" - -void WaterLandingEffect( cl_drip *drip ); -void ParseRainFile( void ); - -cl_drip FirstChainDrip; -cl_rainfx FirstChainFX; - -double rain_curtime; // current time -double rain_oldtime; // last time we have updated drips -double rain_timedelta; // difference between old time and current time -double rain_nextspawntime; // when the next drip should be spawned -cvar_t *cl_debugrain; -int dripcounter = 0; -int fxcounter = 0; -HSPRITE hsprWaterRing; -HSPRITE hsprDripTexture; - -/* -================================= -ProcessRain - -Must think every frame. -================================= -*/ -void ProcessRain( void ) -{ - rain_oldtime = rain_curtime; // save old time - rain_curtime = GetClientTime(); - rain_timedelta = rain_curtime - rain_oldtime; - - // first frame - if ( rain_oldtime == 0 ) - { - // fix first frame bug with nextspawntime - rain_nextspawntime = GetClientTime(); - ParseRainFile(); - return; - } - - if ( gHUD.Rain.dripsPerSecond == 0 && FirstChainDrip.p_Next == NULL ) - { - // keep nextspawntime correct - rain_nextspawntime = rain_curtime; - return; - } - - if ( rain_timedelta == 0 ) return; // not in pause - - double timeBetweenDrips = 1 / (double)gHUD.Rain.dripsPerSecond; - - cl_drip* curDrip = FirstChainDrip.p_Next; - cl_drip* nextDrip = NULL; - - cl_entity_t *player = GetLocalPlayer(); - - if( !player ) return; // not in game - - // save debug info - float debug_lifetime = 0; - int debug_howmany = 0; - int debug_attempted = 0; - int debug_dropped = 0; - - while ( curDrip != NULL ) // go through list - { - nextDrip = curDrip->p_Next; // save pointer to next drip - - if ( gHUD.Rain.weatherMode == 0 ) - curDrip->origin.z -= rain_timedelta * DRIPSPEED; // rain - else curDrip->origin.z -= rain_timedelta * SNOWSPEED; // snow - - curDrip->origin.x += rain_timedelta * curDrip->xDelta; - curDrip->origin.y += rain_timedelta * curDrip->yDelta; - - // remove drip if its origin lower than minHeight - if ( curDrip->origin.z < curDrip->minHeight ) - { - if ( curDrip->landInWater/* && gHUD.Rain.weatherMode == 0*/ ) - WaterLandingEffect( curDrip ); // create water rings - - if ( cl_debugrain->value ) - { - debug_lifetime += (rain_curtime - curDrip->birthTime); - debug_howmany++; - } - - curDrip->p_Prev->p_Next = curDrip->p_Next; // link chain - if ( nextDrip != NULL ) - nextDrip->p_Prev = curDrip->p_Prev; - delete curDrip; - - dripcounter--; - } - - curDrip = nextDrip; // restore pointer, so we can continue moving through chain - } - - int maxDelta; // maximum height randomize distance - float falltime; - if ( gHUD.Rain.weatherMode == 0 ) - { - maxDelta = DRIPSPEED * rain_timedelta; // for rain - falltime = (gHUD.Rain.globalHeight + 4096) / DRIPSPEED; - } - else - { - maxDelta = SNOWSPEED * rain_timedelta; // for snow - falltime = (gHUD.Rain.globalHeight + 4096) / SNOWSPEED; - } - - while ( rain_nextspawntime < rain_curtime ) - { - rain_nextspawntime += timeBetweenDrips; - if ( cl_debugrain->value ) debug_attempted++; - - if ( dripcounter < MAXDRIPS ) // check for overflow - { - float deathHeight; - Vector vecStart, vecEnd; - - vecStart[0] = RANDOM_FLOAT( player->origin.x - gHUD.Rain.distFromPlayer, player->origin.x + gHUD.Rain.distFromPlayer ); - vecStart[1] = RANDOM_FLOAT( player->origin.y - gHUD.Rain.distFromPlayer, player->origin.y + gHUD.Rain.distFromPlayer ); - vecStart[2] = gHUD.Rain.globalHeight; - - float xDelta = gHUD.Rain.windX + RANDOM_FLOAT( gHUD.Rain.randX * -1, gHUD.Rain.randX ); - float yDelta = gHUD.Rain.windY + RANDOM_FLOAT( gHUD.Rain.randY * -1, gHUD.Rain.randY ); - - // find a point at bottom of map - vecEnd[0] = falltime * xDelta; - vecEnd[1] = falltime * yDelta; - vecEnd[2] = -4096; - - pmtrace_t pmtrace; - gEngfuncs.pEventAPI->EV_SetTraceHull( 2 ); - gEngfuncs.pEventAPI->EV_PlayerTrace( vecStart, vecStart + vecEnd, PM_STUDIO_IGNORE, -1, &pmtrace ); - - if ( pmtrace.startsolid || pmtrace.allsolid ) - { - if ( cl_debugrain->value > 1 ) debug_dropped++; - continue; // drip cannot be placed - } - - // falling to water? - int contents = POINT_CONTENTS( pmtrace.endpos ); - - if ( contents == CONTENTS_WATER ) - { - int waterEntity = gEngfuncs.PM_WaterEntity( pmtrace.endpos ); - if ( waterEntity > 0 ) - { - cl_entity_t *pwater = GetEntityByIndex( waterEntity ); - if ( pwater && ( pwater->model != NULL ) ) - { - deathHeight = pwater->curstate.maxs[2]; - } - else - { - gEngfuncs.Con_Printf("Rain error: can't get water entity\n"); - continue; - } - } - else - { - // hit the world ? - deathHeight = pmtrace.endpos[2]; - } - } - else - { - deathHeight = pmtrace.endpos[2]; - } - - // just in case.. - if ( deathHeight > vecStart[2] ) - { - gEngfuncs.Con_Printf( "rain: can't create drip in water\n" ); - continue; - } - - - cl_drip *newClDrip = new cl_drip; - if ( !newClDrip ) - { - gHUD.Rain.dripsPerSecond = 0; // disable rain - gEngfuncs.Con_Printf( "rain: failed to allocate object!\n"); - return; - } - - vecStart[2] -= RANDOM_FLOAT( 0, maxDelta ); // randomize a bit - - newClDrip->alpha = RANDOM_FLOAT( 0.12, 0.2 ); - newClDrip->origin = vecStart; - - newClDrip->xDelta = xDelta; - newClDrip->yDelta = yDelta; - - newClDrip->birthTime = rain_curtime; // store time when it was spawned - newClDrip->minHeight = deathHeight; - - if ( contents == CONTENTS_WATER ) - newClDrip->landInWater = 1; - else newClDrip->landInWater = 0; - - // add to first place in chain - newClDrip->p_Next = FirstChainDrip.p_Next; - newClDrip->p_Prev = &FirstChainDrip; - if ( newClDrip->p_Next != NULL ) - newClDrip->p_Next->p_Prev = newClDrip; - FirstChainDrip.p_Next = newClDrip; - - dripcounter++; - } - else - { - if ( cl_debugrain->value ) - gEngfuncs.Con_Printf( "rain: drip limit overflow! %i > %i\n", dripcounter, MAXDRIPS ); - return; - } - } - - if ( cl_debugrain->value ) // print debug info - { - gEngfuncs.Con_Printf( "Rain info: Drips exist: %i\n", dripcounter ); - gEngfuncs.Con_Printf( "Rain info: FX's exist: %i\n", fxcounter ); - gEngfuncs.Con_Printf( "Rain info: Attempted/Dropped: %i, %i\n", debug_attempted, debug_dropped ); - if ( debug_howmany ) - { - float ave = debug_lifetime / (float)debug_howmany; - gEngfuncs.Con_Printf( "Rain info: Average drip life time: %f\n", ave); - } - else gEngfuncs.Con_Printf( "Rain info: Average drip life time: --\n" ); - } - return; -} - -/* -================================= -WaterLandingEffect -================================= -*/ -void WaterLandingEffect( cl_drip *drip ) -{ - if ( fxcounter >= MAXFX ) - { - gEngfuncs.Con_Printf( "Rain error: FX limit overflow!\n" ); - return; - } - - cl_rainfx *newFX = new cl_rainfx; - if ( !newFX ) - { - gEngfuncs.Con_Printf( "Rain error: failed to allocate FX object!\n"); - return; - } - - newFX->alpha = RANDOM_FLOAT( 0.6, 0.9 ); - newFX->origin = drip->origin; - newFX->origin[2] = drip->minHeight; // correct position - - newFX->birthTime = GetClientTime(); - newFX->life = RANDOM_FLOAT( 0.7f, 1.0f ); - - // add to first place in chain - newFX->p_Next = FirstChainFX.p_Next; - newFX->p_Prev = &FirstChainFX; - if ( newFX->p_Next != NULL ) - newFX->p_Next->p_Prev = newFX; - FirstChainFX.p_Next = newFX; - - fxcounter++; -} - -/* -================================= -ProcessFXObjects - -Remove all fx objects with out time to live -Call every frame before ProcessRain -================================= -*/ -void ProcessFXObjects( void ) -{ - float curtime = GetClientTime(); - - cl_rainfx* curFX = FirstChainFX.p_Next; - cl_rainfx* nextFX = NULL; - - while ( curFX != NULL ) // go through FX objects list - { - nextFX = curFX->p_Next; // save pointer to next - - // delete current? - if (( curFX->birthTime + curFX->life ) < curtime ) - { - curFX->p_Prev->p_Next = curFX->p_Next; // link chain - if ( nextFX != NULL ) - nextFX->p_Prev = curFX->p_Prev; - delete curFX; - fxcounter--; - } - curFX = nextFX; // restore pointer - } -} - -/* -================================= -ResetRain -clear memory, delete all objects -================================= -*/ -void ResetRain( void ) -{ - // delete all drips - cl_drip* delDrip = FirstChainDrip.p_Next; - FirstChainDrip.p_Next = NULL; - - while ( delDrip != NULL ) - { - cl_drip* nextDrip = delDrip->p_Next; // save pointer to next drip in chain - delete delDrip; - delDrip = nextDrip; // restore pointer - dripcounter--; - } - - // delete all FX objects - cl_rainfx* delFX = FirstChainFX.p_Next; - FirstChainFX.p_Next = NULL; - - while ( delFX != NULL ) - { - cl_rainfx* nextFX = delFX->p_Next; - delete delFX; - delFX = nextFX; - fxcounter--; - } - - InitRain(); - return; -} - -/* -================================= -InitRain -initialze system -================================= -*/ -void InitRain( void ) -{ - cl_debugrain = CVAR_REGISTER( "cl_debugrain", "0", 0 ); - - gHUD.Rain.dripsPerSecond = 0; - gHUD.Rain.distFromPlayer = 0; - gHUD.Rain.windX = 0; - gHUD.Rain.windY = 0; - gHUD.Rain.randX = 0; - gHUD.Rain.randY = 0; - gHUD.Rain.weatherMode = 0; - gHUD.Rain.globalHeight = 0; - - FirstChainDrip.birthTime = 0; - FirstChainDrip.minHeight = 0; - FirstChainDrip.origin[0]=0; - FirstChainDrip.origin[1]=0; - FirstChainDrip.origin[2]=0; - FirstChainDrip.alpha = 0; - FirstChainDrip.xDelta = 0; - FirstChainDrip.yDelta = 0; - FirstChainDrip.landInWater = 0; - FirstChainDrip.p_Next = NULL; - FirstChainDrip.p_Prev = NULL; - - FirstChainFX.alpha = 0; - FirstChainFX.birthTime = 0; - FirstChainFX.life = 0; - FirstChainFX.origin[0] = 0; - FirstChainFX.origin[1] = 0; - FirstChainFX.origin[2] = 0; - FirstChainFX.p_Next = NULL; - FirstChainFX.p_Prev = NULL; - - rain_oldtime = 0; - rain_curtime = 0; - rain_nextspawntime = 0; - - // engine will be free unused shaders after each change map - // so reload it again - hsprWaterRing = 0; - hsprDripTexture = 0; - - return; -} - -/* -=========================== -ParseRainFile - -List of settings: - drips - max raindrips\snowflakes - distance - radius of rain\snow - windx - wind shift X - windy - wind shift Y - randx - random shift X - randy - random shift Y - mode - rain = 0\snow =1 - height - max height to create raindrips\snowflakes -=========================== -*/ -void ParseRainFile( void ) -{ - if ( gHUD.Rain.distFromPlayer != 0 || gHUD.Rain.dripsPerSecond != 0 || gHUD.Rain.globalHeight != 0 ) - return; - - char mapname[256], filepath[256]; - char token[1024]; - char *pfile; - char *afile; - - strcpy( mapname, gEngfuncs.pfnGetLevelName() ); - if ( strlen( mapname ) == 0 ) - { - gEngfuncs.Con_Printf( "rain: unable to read map name\n" ); - return; - } - -// Xash3D always set bare mapname without path and extension -// mapname[strlen(mapname)-4] = 0; - - sprintf( filepath, "scripts/weather/%s.txt", mapname ); - - afile = (char *)gEngfuncs.COM_LoadFile( mapname, 5, NULL); - pfile = afile; - - if ( !pfile ) - { - if (cl_debugrain->value > 1 ) - gEngfuncs.Con_Printf( "rain: couldn't open rain settings file %s\n", mapname ); - return; - } - - while ( true ) - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - if (!pfile) - break; - - if ( !stricmp( token, "drips" )) // dripsPerSecond - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - gHUD.Rain.dripsPerSecond = atoi( token ); - } - else if ( !stricmp( token, "distance" )) // distFromPlayer - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - gHUD.Rain.distFromPlayer = atof( token ); - } - else if ( !stricmp( token, "windx" )) // windX - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - gHUD.Rain.windX = atof( token ); - } - else if ( !stricmp( token, "windy" )) // windY - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - gHUD.Rain.windY = atof( token ); - } - else if ( !stricmp( token, "randx" )) // randX - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - gHUD.Rain.randX = atof( token ); - } - else if ( !stricmp( token, "randy" )) // randY - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - gHUD.Rain.randY = atof( token ); - } - else if ( !stricmp( token, "mode" )) // weatherMode - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - gHUD.Rain.weatherMode = atoi( token ); - } - else if ( !stricmp( token, "height" )) // globalHeight - { - pfile = gEngfuncs.COM_ParseFile(pfile, token); - gHUD.Rain.globalHeight = atof( token ); - } - else gEngfuncs.Con_Printf( "rain: unknown token %s in file %s\n", token, mapname ); - } - - gEngfuncs.COM_FreeFile( afile ); -} - -//----------------------------------------------------- - -void SetPoint( float x, float y, float z, float (*matrix)[4] ) -{ - Vector point = Vector( x, y, z ), result; - - result.x = DotProduct( point, matrix[0] ) + matrix[0][3]; - result.y = DotProduct( point, matrix[1] ) + matrix[1][3]; - result.z = DotProduct( point, matrix[2] ) + matrix[2][3]; - - gEngfuncs.pTriAPI->Vertex3f( result[0], result[1], result[2] ); -} - -/* -================================= -DrawRain - -draw raindrips and snowflakes -================================= -*/ -void DrawRain( void ) -{ - if ( FirstChainDrip.p_Next == NULL ) - return; // no drips to draw - - if( hsprDripTexture == 0 ) - { - if ( gHUD.Rain.weatherMode == 0 ) - { - // load rain sprite - int modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/hi_rain.spr" ); - hsprDripTexture = gEngfuncs.pTriAPI->GetSpriteTexture( modelIndex, 0 ); - } - else - { - // load snow sprite - int modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/snowflake.spr" ); - hsprDripTexture = gEngfuncs.pTriAPI->GetSpriteTexture( modelIndex, 0 ); - } - } - if( hsprDripTexture <= 0 ) return; - - float visibleHeight = gHUD.Rain.globalHeight - SNOWFADEDIST; - - // usual triapi stuff - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - gEngfuncs.pTriAPI->Bind( hsprDripTexture, 0 ); - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - - // go through drips list - cl_drip *Drip = FirstChainDrip.p_Next; - cl_entity_t *player = GetLocalPlayer(); - if( !player ) return; // not in game yet - - if ( gHUD.Rain.weatherMode == 0 ) // draw rain - { - while ( Drip != NULL ) - { - cl_drip* nextdDrip = Drip->p_Next; - - Vector2D toPlayer; - toPlayer.x = player->origin[0] - Drip->origin[0]; - toPlayer.y = player->origin[1] - Drip->origin[1]; - toPlayer = toPlayer.Normalize(); - - toPlayer.x *= DRIP_SPRITE_HALFWIDTH; - toPlayer.y *= DRIP_SPRITE_HALFWIDTH; - - float shiftX = (Drip->xDelta / DRIPSPEED) * DRIP_SPRITE_HALFHEIGHT; - float shiftY = (Drip->yDelta / DRIPSPEED) * DRIP_SPRITE_HALFHEIGHT; - - gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, Drip->alpha ); - gEngfuncs.pTriAPI->Begin( TRI_TRIANGLES ); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f( Drip->origin[0]-toPlayer.y - shiftX, Drip->origin[1]+toPlayer.x - shiftY,Drip->origin[2] + DRIP_SPRITE_HALFHEIGHT ); - - gEngfuncs.pTriAPI->TexCoord2f( 0.5, 1 ); - gEngfuncs.pTriAPI->Vertex3f( Drip->origin[0] + shiftX, Drip->origin[1] + shiftY, Drip->origin[2]-DRIP_SPRITE_HALFHEIGHT ); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f( Drip->origin[0]+toPlayer.y - shiftX, Drip->origin[1]-toPlayer.x - shiftY, Drip->origin[2]+DRIP_SPRITE_HALFHEIGHT); - - gEngfuncs.pTriAPI->End(); - Drip = nextdDrip; - } - } - - else // draw snow - { - Vector normal; - - GetViewAngles( (float *)normal ); - - float matrix[3][4]; - AngleMatrix( normal, matrix ); // calc view matrix - - while ( Drip != NULL ) - { - cl_drip* nextdDrip = Drip->p_Next; - - matrix[0][3] = Drip->origin[0]; // write origin to matrix - matrix[1][3] = Drip->origin[1]; - matrix[2][3] = Drip->origin[2]; - - // apply start fading effect - float alpha = (Drip->origin[2] <= visibleHeight) ? Drip->alpha : ((gHUD.Rain.globalHeight - Drip->origin[2]) / (float)SNOWFADEDIST) * Drip->alpha; - - gEngfuncs.pTriAPI->Color4f( 1.0, 1.0, 1.0, alpha ); - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - SetPoint( 0, SNOW_SPRITE_HALFSIZE, SNOW_SPRITE_HALFSIZE, matrix ); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - SetPoint( 0, SNOW_SPRITE_HALFSIZE, -SNOW_SPRITE_HALFSIZE, matrix ); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - SetPoint( 0, -SNOW_SPRITE_HALFSIZE, -SNOW_SPRITE_HALFSIZE, matrix ); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - SetPoint( 0, -SNOW_SPRITE_HALFSIZE, SNOW_SPRITE_HALFSIZE, matrix ); - - gEngfuncs.pTriAPI->End(); - Drip = nextdDrip; - } - } - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} - -/* -================================= -DrawFXObjects -================================= -*/ -void DrawFXObjects( void ) -{ - if ( FirstChainFX.p_Next == NULL ) - return; // no objects to draw - - float curtime = GetClientTime(); - - // usual triapi stuff - if( hsprWaterRing == 0 ) // in case what we don't want search it if not found - { - // load water ring sprite - int modelIndex = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/waterring.spr" ); - hsprWaterRing = gEngfuncs.pTriAPI->GetSpriteTexture( modelIndex, 0 ); - } - - if( hsprWaterRing <= 0 ) return; // don't waste time - - gEngfuncs.pTriAPI->Enable( TRI_SHADER ); - gEngfuncs.pTriAPI->Bind( hsprWaterRing, 0 ); - gEngfuncs.pTriAPI->RenderMode( kRenderTransAdd ); - gEngfuncs.pTriAPI->CullFace( TRI_NONE ); - - // go through objects list - cl_rainfx* curFX = FirstChainFX.p_Next; - while ( curFX != NULL ) - { - cl_rainfx* nextFX = curFX->p_Next; - - // fadeout - float alpha = ((curFX->birthTime + curFX->life - curtime) / curFX->life) * curFX->alpha; - float size = (curtime - curFX->birthTime) * MAXRINGHALFSIZE; - float color[3]; - - // UNDONE: calc lighting right - gEngfuncs.pEfxAPI->R_LightForPoint( (const float *)curFX->origin, color ); -// gEngfuncs.Con_Printf( "color %g %g %g\n", color[0], color[1], color[2] ); - - gEngfuncs.pTriAPI->Color4f( 0.4 + color[0], 0.4 + color[1], 0.4 + color[2], alpha ); - gEngfuncs.pTriAPI->Begin( TRI_QUADS ); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 0 ); - gEngfuncs.pTriAPI->Vertex3f( curFX->origin[0] - size, curFX->origin[1] - size, curFX->origin[2] ); - - gEngfuncs.pTriAPI->TexCoord2f( 0, 1 ); - gEngfuncs.pTriAPI->Vertex3f( curFX->origin[0] - size, curFX->origin[1] + size, curFX->origin[2] ); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 1 ); - gEngfuncs.pTriAPI->Vertex3f( curFX->origin[0] + size, curFX->origin[1] + size, curFX->origin[2] ); - - gEngfuncs.pTriAPI->TexCoord2f( 1, 0 ); - gEngfuncs.pTriAPI->Vertex3f( curFX->origin[0] + size, curFX->origin[1] - size, curFX->origin[2] ); - - gEngfuncs.pTriAPI->End(); - curFX = nextFX; - } - gEngfuncs.pTriAPI->Disable( TRI_SHADER ); -} - -/* -================================= -DrawAll -================================= -*/ - -void R_DrawWeather( void ) -{ - ProcessFXObjects(); - ProcessRain(); - DrawRain(); - DrawFXObjects(); -} \ No newline at end of file diff --git a/client/global/r_weather.h b/client/global/r_weather.h deleted file mode 100644 index efa26ac1..00000000 --- a/client/global/r_weather.h +++ /dev/null @@ -1,65 +0,0 @@ -/*** -* -* Copyright (c) 1996-2004, Shambler Team. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Shambler Team. All other use, distribution, or modification is prohibited -* without written permission from Shambler Team. -* -****/ -/* -====== rain.h ======================================================== -*/ -#ifndef __RAIN_H__ -#define __RAIN_H__ - -#define DRIPSPEED 900 // speed of raindrips (pixel per secs) -#define SNOWSPEED 200 // speed of snowflakes -#define SNOWFADEDIST 80 - -#define MAXDRIPS 3000 // max raindrops -#define MAXFX 3000 // max effects - -#define DRIP_SPRITE_HALFHEIGHT 46 -#define DRIP_SPRITE_HALFWIDTH 8 -#define SNOW_SPRITE_HALFSIZE 3 - -// radius water rings -#define MAXRINGHALFSIZE 25 - -typedef struct cl_drip -{ - float birthTime; - float minHeight; // minimal height to kill raindrop - vec3_t origin; - float alpha; - - float xDelta; // side speed - float yDelta; - int landInWater; - - cl_drip* p_Next; // next drip in chain - cl_drip* p_Prev; // previous drip in chain -} cl_drip_t; - -typedef struct cl_rainfx -{ - float birthTime; - float life; - vec3_t origin; - float alpha; - - cl_rainfx* p_Next; // next fx in chain - cl_rainfx* p_Prev; // previous fx in chain -} cl_rainfx_t; - -void R_DrawWeather( void ); -void ResetRain( void ); -void InitRain( void ); - -#endif \ No newline at end of file diff --git a/client/global/studio.cpp b/client/global/studio.cpp deleted file mode 100644 index 9b612099..00000000 --- a/client/global/studio.cpp +++ /dev/null @@ -1,191 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2010 й -// studio.cpp - client side studio callbacks -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "studio.h" -#include "r_efx.h" -#include "pm_movevars.h" -#include "r_tempents.h" -#include "ev_hldm.h" -#include "r_beams.h" -#include "hud.h" - -//====================== -// DRAW BEAM EVENT -//====================== -void EV_DrawBeam ( void ) -{ - // special effect for displacer - cl_entity_t *view = GetViewModel(); - - float life = 1.05; // animtime - int m_iBeam = gEngfuncs.pEventAPI->EV_FindModelIndex( "sprites/plasma.spr" ); - int idx = GetLocalPlayer()->index; // link with client - - g_pViewRenderBeams->CreateBeamEnts( idx | 0x1000, idx | 0x2000, m_iBeam, life, 0.8, 0.5, 127, 0.6, 0, 10, 20, 100, 0 ); - g_pViewRenderBeams->CreateBeamEnts( idx | 0x1000, idx | 0x3000, m_iBeam, life, 0.8, 0.5, 127, 0.6, 0, 10, 20, 100, 0 ); - g_pViewRenderBeams->CreateBeamEnts( idx | 0x1000, idx | 0x4000, m_iBeam, life, 0.8, 0.5, 127, 0.6, 0, 10, 20, 100, 0 ); -} - -//====================== -// Eject Shell -//====================== -void EV_EjectShell( const mstudioevent_t *event, cl_entity_t *entity ) -{ - vec3_t view_ofs, ShellOrigin, ShellVelocity, forward, right, up; - vec3_t origin = entity->origin; - vec3_t angles = entity->angles; - vec3_t velocity = entity->curstate.velocity; // needs to change delta.lst to get it work - - float fR, fU; - - int shell = gEngfuncs.pEventAPI->EV_FindModelIndex( event->options ); - origin.z = origin.z - entity->curstate.usehull ? 12 : 28; - - for( int j = 0; j < 3; j++ ) - { - if( angles[j] < -180 ) - angles[j] += 360; - else if( angles[j] > 180 ) - angles[j] -= 360; - } - - angles.x = -angles.x; - AngleVectors( angles, forward, right, up ); - - fR = RANDOM_FLOAT( 50, 70 ); - fU = RANDOM_FLOAT( 100, 150 ); - - for ( int i = 0; i < 3; i++ ) - { - ShellVelocity[i] = velocity[i] + right[i] * fR + up[i] * fU + forward[i] * 25; - ShellOrigin[i] = origin[i] + view_ofs[i] + up[i] * -12 + forward[i] * 20 + right[i] * 4; - } - EV_EjectBrass ( ShellOrigin, ShellVelocity, angles[ YAW ], shell, TE_BOUNCE_SHELL ); -} - -void HUD_StudioEvent( const mstudioevent_t *event, cl_entity_t *entity ) -{ - int pitch; - float fvol; - Vector pos; - - switch( event->event ) - { - case 5001: - // MullzeFlash at attachment 1 - g_pTempEnts->MuzzleFlash( entity, 1, atoi( event->options )); - break; - case 5011: - // MullzeFlash at attachment 2 - g_pTempEnts->MuzzleFlash( entity, 2, atoi( event->options )); - break; - case 5021: - // MullzeFlash at attachment 3 - g_pTempEnts->MuzzleFlash( entity, 3, atoi( event->options )); - break; - case 5031: - // MullzeFlash at attachment 4 - g_pTempEnts->MuzzleFlash( entity, 4, atoi( event->options )); - break; - case 5002: - // SparkEffect at attachment 1 - pos = entity->curstate.origin + entity->attachment[0]; - g_pTempEnts->SparkEffect( pos, 8, -200, 200 ); - break; - case 5004: - // Client side sound - pos = entity->origin + entity->attachment[0]; - gEngfuncs.pEventAPI->EV_PlaySound( 0, pos, CHAN_AUTO, event->options, VOL_NORM, ATTN_NORM, 0, PITCH_NORM ); - break; - case 5005: - // Client side sound with random pitch (most useful for reload sounds) - pitch = 85 + RANDOM_LONG( 0, 0x1F ); - pos = entity->origin + entity->attachment[0]; - fvol = RANDOM_FLOAT( 0.7f, 0.9f ); - gEngfuncs.pEventAPI->EV_PlaySound( 0, pos, CHAN_AUTO, event->options, fvol, ATTN_NORM, 0, pitch ); - break; - case 5050: - // Special event for displacer ( Xash 0.1, XDM 3.3 ) - EV_DrawBeam (); - break; - case 5060: - EV_EjectShell( event, entity ); - break; - default: - gEngfuncs.Con_Printf( "Unhandled client-side attachment %i ( %s )\n", event->event, event->options ); - break; - } -} - -void HUD_StudioFxTransform( cl_entity_t *ent, float transform[4][4] ) -{ - switch( ent->curstate.renderfx ) - { - case kRenderFxDistort: - case kRenderFxHologram: - if(!RANDOM_LONG( 0, 49 )) - { - int axis = RANDOM_LONG( 0, 1 ); - float scale = RANDOM_FLOAT( 1, 1.484 ); - - if( axis == 1 ) axis = 2; // choose between x & z - transform[axis][0] *= scale; - transform[axis][1] *= scale; - transform[axis][2] *= scale; - } - else if(!RANDOM_LONG( 0, 49 )) - { - float offset; - int axis = RANDOM_LONG( 0, 1 ); - if( axis == 1 ) axis = 2; // choose between x & z - offset = RANDOM_FLOAT( -10, 10 ); - transform[RANDOM_LONG( 0, 2 )][3] += offset; - } - break; - case kRenderFxExplode: - float scale; - - scale = 1.0f + (gHUD.m_flTime - ent->curstate.animtime) * 10.0; - if( scale > 2 ) scale = 2; // don't blow up more than 200% - - transform[0][1] *= scale; - transform[1][1] *= scale; - transform[2][1] *= scale; - break; - } -} - -int StudioBodyVariations( int modelIndex ) -{ - studiohdr_t *pstudiohdr; - mstudiobodyparts_t *pbodypart; - int i, count; - - pstudiohdr = (studiohdr_t *)Mod_Extradata( modelIndex ); - if( !pstudiohdr ) return 0; - - count = 1; - pbodypart = (mstudiobodyparts_t *)((byte *)pstudiohdr + pstudiohdr->bodypartindex); - - // each body part has nummodels variations so there are as many total variations as there - // are in a matrix of each part by each other part - for( i = 0; i < pstudiohdr->numbodyparts; i++ ) - { - count = count * pbodypart[i].nummodels; - } - return count; -} - -// an example how to renderer determines interpolation methods -int HUD_StudioDoInterp( cl_entity_t *e ) -{ - if( r_studio_lerping->value ) - { - return (e->curstate.effects & EF_NOINTERP) ? false : true; - } - return false; -} \ No newline at end of file diff --git a/client/global/triapi.cpp b/client/global/triapi.cpp deleted file mode 100644 index f0cb7524..00000000 --- a/client/global/triapi.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// triapi.cpp - triangle rendering, if any -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "aurora.h" -#include "r_efx.h" -#include "r_particle.h" -#include "r_weather.h" -#include "r_beams.h" - -void HUD_DrawTriangles( void ) -{ -} - -void HUD_DrawTransparentTriangles( void ) -{ - R_DrawWeather(); - - // Aurora particles - g_pParticleSystems->UpdateSystems(); - - // classic particles - g_pParticles->Update(); -} - -void HUD_RenderCallback( int fTrans ) -{ - if( !fTrans ) HUD_DrawTriangles (); - else HUD_DrawTransparentTriangles(); -} \ No newline at end of file diff --git a/client/global/utils.cpp b/client/global/utils.cpp deleted file mode 100644 index aa76597a..00000000 --- a/client/global/utils.cpp +++ /dev/null @@ -1,459 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// utils.cpp - client game utilities code -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "pm_defs.h" -#include "com_model.h" -#include "hud.h" - -DLL_GLOBAL const Vector g_vecZero = Vector( 0.0f, 0.0f, 0.0f ); - -#ifdef _DEBUG -void DBG_AssertFunction( BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage ) -{ - if( fExpr ) return; - - char szOut[512]; - if( szMessage != NULL ) - sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)\n%s", szExpr, szFile, szLine, szMessage ); - else sprintf( szOut, "ASSERT FAILED:\n %s \n(%s@%d)", szExpr, szFile, szLine ); - gEngfuncs.Con_Printf( szOut ); -} -#endif // DEBUG - -// NOTE: modify these functions with caution -typedef struct -{ - char *name; - byte *buf; - int size; - int read; - BOOL badRead; - char string[2048]; // using for store strings -} user_message_t; - -static user_message_t gMsg; - -void BEGIN_READ( const char *pszName, int iSize, void *pBuf ) -{ - memset( &gMsg, 0, sizeof( gMsg )); - - gMsg.size = iSize; - gMsg.buf = (byte *)pBuf; -} - -void END_READ( void ) -{ - if( gMsg.badRead ) - { - gEngfuncs.Con_Printf( "%s was received with errors\n", gMsg.name ); - } -} - -int READ_CHAR( void ) -{ - int c; - - if( gMsg.read + 1 > gMsg.size ) - { - gMsg.badRead = true; - return -1; - } - - c = (signed char)gMsg.buf[gMsg.read]; - gMsg.read++; - - return c; -} - -int READ_BYTE( void ) -{ - int c; - - if( gMsg.read+1 > gMsg.size ) - { - gMsg.badRead = true; - return -1; - } - - c = (unsigned char)gMsg.buf[gMsg.read]; - gMsg.read++; - - return c; -} - -int READ_SHORT( void ) -{ - int c; - - if( gMsg.read + 2 > gMsg.size ) - { - gMsg.badRead = true; - return -1; - } - - c = (short)( gMsg.buf[gMsg.read] + ( gMsg.buf[gMsg.read+1] << 8 )); - gMsg.read += 2; - - return c; -} - -int READ_WORD( void ) { return READ_SHORT(); } - -int READ_LONG( void ) -{ - int c; - - if( gMsg.read + 4 > gMsg.size ) - { - gMsg.badRead = true; - return -1; - } - c = gMsg.buf[gMsg.read]+(gMsg.buf[gMsg.read+1]<<8)+(gMsg.buf[gMsg.read+2]<<16)+(gMsg.buf[gMsg.read+3]<<24); - gMsg.read += 4; - - return c; -} - -float READ_FLOAT( void ) -{ - union { float f; int l; } dat; - - dat.l = READ_LONG(); - return dat.f; -} - -char* READ_STRING( void ) -{ - int l, c; - - gMsg.string[0] = 0; - - l = 0; - do - { - if( gMsg.read+1 > gMsg.size ) break; // no more characters - - c = READ_CHAR(); - if( c == -1 || c == '\0' ) - break; - - gMsg.string[l] = c; - l++; - } while( l < sizeof( gMsg.string ) - 1 ); - - gMsg.string[l] = 0; // terminator - - return gMsg.string; -} - -float READ_COORD( void ) -{ - return (float)(READ_SHORT() * (1.0/8)); -} - -float READ_ANGLE( void ) -{ - return (float)(READ_CHAR() * (360.0/256)); -} - -float READ_HIRESANGLE( void ) -{ - return (float)(READ_SHORT() * (360.0/65536)); -} - -/* -============================================================================== - - DRAW HELPERS - -============================================================================== -*/ -void DrawImageBar( float percent, const char *szSpriteName ) -{ - int m_loading = gHUD.GetSpriteIndex( szSpriteName ); - wrect_t rcSize = gHUD.GetSpriteRect( m_loading ); - - int w = rcSize.right - rcSize.left; - int h = rcSize.bottom - rcSize.top; - DrawImageBar( percent, szSpriteName, (ScreenWidth - w)/2, (ScreenHeight - h)/2 ); -} - -void DrawImageBar( float percent, const char *szSpriteName, int x, int y ) -{ - int m_loading = gHUD.GetSpriteIndex( szSpriteName ); - HSPRITE hLoading = gHUD.GetSprite( m_loading ); - wrect_t rcBar, rcBack; - float step; - - rcBar = rcBack = gHUD.GetSpriteRect( m_loading ); - step = (float)(rcBack.right - rcBack.left) / 100; - rcBar.right = rcBar.left + (int)ceil(percent * step); - - SPR_Set( hLoading, 128, 128, 128 ); - SPR_DrawAdditive( 0, x, y, &rcBack ); // background - - SPR_Set( hLoading, 255, 160, 0 ); - SPR_DrawAdditive( 0, x, y, &rcBar ); // progress bar -} - -void AngleMatrix( const vec3_t angles, float (*matrix)[4] ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin( angle ); - cy = cos( angle ); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin( angle ); - cp = cos( angle ); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin( angle ); - cr = cos( angle ); - - // matrix = (YAW * PITCH) * ROLL - matrix[0][0] = cp*cy; - matrix[1][0] = cp*sy; - matrix[2][0] = -sp; - matrix[0][1] = sr*sp*cy+cr*-sy; - matrix[1][1] = sr*sp*sy+cr*cy; - matrix[2][1] = sr*cp; - matrix[0][2] = (cr*sp*cy+-sr*-sy); - matrix[1][2] = (cr*sp*sy+-sr*cy); - matrix[2][2] = cr*cp; - matrix[0][3] = 0.0; - matrix[1][3] = 0.0; - matrix[2][3] = 0.0; -} - -// g-cont. copied here from pm_math.cpp -void VectorAngles( const Vector &forward, Vector &angles ) -{ - float tmp, yaw, pitch; - - if (forward[1] == 0 && forward[0] == 0) - { - yaw = 0; - if (forward[2] > 0) - pitch = 90; - else - pitch = 270; - } - else - { - yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); - if (yaw < 0) - yaw += 360; - - tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); - pitch = (atan2(forward[2], tmp) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - - angles[0] = pitch; - angles[1] = yaw; - angles[2] = 0; -} - -/* -==================== -RotatePointAroundVector -==================== -*/ -void RotatePointAroundVector( Vector &dst, const Vector &dir, const Vector &point, float degrees ) -{ - float t0, t1; - float angle, c, s, d; - Vector vr, vu, vf; - - angle = DEG2RAD( degrees ); - s = sin( angle ); - c = cos( angle ); - - vf.Init( dir.x, dir.y, dir.z ); - vr.Init( vf.z, -vf.x, vf.y ); - - // find a three vectors - d = DotProduct( vf, vr ); - vr = (vr + ( vf * -d )).Normalize(); - vu = CrossProduct( vr, vf ); - - t0 = vr[0] * c + vu[0] * -s; - t1 = vr[0] * s + vu[0] * c; - dst[0] = (t0 * vr[0] + t1 * vu[0] + vf[0] * vf[0]) * point[0] - + (t0 * vr[1] + t1 * vu[1] + vf[0] * vf[1]) * point[1] - + (t0 * vr[2] + t1 * vu[2] + vf[0] * vf[2]) * point[2]; - - t0 = vr[1] * c + vu[1] * -s; - t1 = vr[1] * s + vu[1] * c; - dst[1] = (t0 * vr[0] + t1 * vu[0] + vf[1] * vf[0]) * point[0] - + (t0 * vr[1] + t1 * vu[1] + vf[1] * vf[1]) * point[1] - + (t0 * vr[2] + t1 * vu[2] + vf[1] * vf[2]) * point[2]; - - t0 = vr[2] * c + vu[2] * -s; - t1 = vr[2] * s + vu[2] * c; - dst[2] = (t0 * vr[0] + t1 * vu[0] + vf[2] * vf[0]) * point[0] - + (t0 * vr[1] + t1 * vu[1] + vf[2] * vf[1]) * point[1] - + (t0 * vr[2] + t1 * vu[2] + vf[2] * vf[2]) * point[2]; -} - -/* -==================== -UTIL_Probe - -client explosion utility -==================== -*/ -float UTIL_Probe( Vector &origin, Vector *vecDirection, float strength ) -{ - // press out - Vector endpos = origin + (( *vecDirection ) * strength ); - - // Trace into the world - pmtrace_t *trace = gEngfuncs.PM_TraceLine( origin, endpos, PM_TRACELINE_PHYSENTSONLY, 2, -1 ); - - // push back a proportional amount to the probe - (*vecDirection) = -(*vecDirection) * (1.0f - trace->fraction); - - ASSERT(( 1.0f - trace->fraction ) >= 0.0f ); - - // return the impacted proportion of the probe - return (1.0f - trace->fraction); -} - -void UTIL_GetForceDirection( Vector &origin, float magnitude, Vector *resultDirection, float *resultForce ) -{ - Vector d[6]; - - // all cardinal directions - d[0] = Vector( 1, 0, 0 ); - d[1] = Vector( -1, 0, 0 ); - d[2] = Vector( 0, 1, 0 ); - d[3] = Vector( 0, -1, 0 ); - d[4] = Vector( 0, 0, 1 ); - d[5] = Vector( 0, 0, -1 ); - - //Init the results - (*resultDirection).Init(); - (*resultForce) = 1.0f; - - // Get the aggregate force vector - for ( int i = 0; i < 6; i++ ) - { - (*resultForce) += UTIL_Probe( origin, &d[i], magnitude ); - (*resultDirection) += d[i]; - } - - // If we've hit nothing, then point up - if (( *resultDirection ) == g_vecZero ) - { - (*resultDirection) = Vector( 0, 0, 1 ); - (*resultForce) = 2.0f; // default value - } - - // Just return the direction - (*resultDirection) = (*resultDirection).Normalize(); -} - -modtype_t Mod_GetModelType( int modelIndex ) -{ - model_t *mod = GetModelPtr( modelIndex ); - - if( mod ) return mod->type; - return mod_bad; -} - -void Mod_GetBounds( int modelIndex, Vector &mins, Vector &maxs ) -{ - model_t *mod = GetModelPtr( modelIndex ); - - if( mod ) - { - mins = mod->mins; - maxs = mod->maxs; - } - else - { - gEngfuncs.Con_DPrintf( "Mod_GetBounds: NULL model %i\n", modelIndex ); - mins = g_vecZero; - maxs = g_vecZero; - } -} - -void *Mod_Extradata( int modelIndex ) -{ - model_t *mod = GetModelPtr( modelIndex ); - - if( mod && mod->type == mod_studio ) - return mod->extradata; - return NULL; -} - -int Mod_GetFrames( int modelIndex ) -{ - model_t *mod = GetModelPtr( modelIndex ); - - if( !mod ) return 1; - - int numFrames; - - if( mod->type == mod_sprite ) - numFrames = mod->numframes; - else if( mod->type == mod_studio ) - numFrames = StudioBodyVariations( modelIndex ); - if( numFrames < 1 ) numFrames = 1; - - return numFrames; -} - -//============ -// UTIL_FileExtension -// returns file extension -//============ -const char *UTIL_FileExtension( const char *in ) -{ - const char *separator, *backslash, *colon, *dot; - - separator = strrchr( in, '/' ); - backslash = strrchr( in, '\\' ); - if( !separator || separator < backslash ) - separator = backslash; - colon = strrchr( in, ':' ); - if( !separator || separator < colon ) - separator = colon; - dot = strrchr( in, '.' ); - if( dot == NULL || (separator && ( dot < separator ))) - return ""; - return dot + 1; -} - -HSPRITE LoadSprite( const char *pszName ) -{ - int i; - char sz[256]; - - if ( ScreenWidth < 640 ) - i = 320; - else - i = 640; - - sprintf( sz, pszName, i ); - - return SPR_Load( sz ); -} - -/* -==================== -VGui_ConsolePrint - -VGUI not implemented, wait for version 0.75 -==================== -*/ -void VGui_ConsolePrint( const char *text ) -{ -} \ No newline at end of file diff --git a/client/global/utils.h b/client/global/utils.h deleted file mode 100644 index 9195406e..00000000 --- a/client/global/utils.h +++ /dev/null @@ -1,244 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// utils.h - client utilities -//======================================================================= - -#ifndef UTILS_H -#define UTILS_H - -extern cl_enginefunc_t gEngfuncs; - -#include "event_api.h" -#include "enginecallback.h" -#include "shake.h" -#include "com_model.h" - -#define FILE_GLOBAL static -#define DLL_GLOBAL - -// euler angle order -#define PITCH 0 -#define YAW 1 -#define ROLL 2 - -#define RAD2DEG( x ) ((float)(x) * (float)(180.f / M_PI)) -#define DEG2RAD( x ) ((float)(x) * (float)(M_PI / 180.f)) - -// -// How did I ever live without ASSERT? -// -#ifdef _DEBUG -void DBG_AssertFunction( BOOL fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage ); -#define ASSERT( f ) DBG_AssertFunction( f, #f, __FILE__, __LINE__, NULL ) -#define ASSERTSZ( f, sz ) DBG_AssertFunction( f, #f, __FILE__, __LINE__, sz ) -#else -#define ASSERT( f ) -#define ASSERTSZ( f, sz ) -#endif - -#define GetEntityByIndex (*gEngfuncs.GetEntityByIndex) - -extern DLL_GLOBAL const Vector g_vecZero; -extern float sv_gravity; - -extern int HUD_VidInit( void ); -extern void HUD_Init( void ); -extern int HUD_Redraw( float flTime, int state ); -extern void HUD_TxferLocalOverrides( entity_state_t *state, const clientdata_t *client ); -extern int HUD_UpdateClientData( client_data_t *pcldata, float flTime ); -extern void HUD_ProcessPlayerState( entity_state_t *dst, const entity_state_t *src ); -extern int HUD_GetHullBounds( int hullnumber, float *mins, float *maxs ); -extern void HUD_UpdateOnRemove( cl_entity_t *pEdict ); -extern void HUD_Reset( void ); -extern void HUD_StartFrame( void ); -extern void HUD_Frame( double time ); -extern void HUD_Shutdown( void ); -extern void HUD_RenderCallback( int fTrans ); -extern void HUD_CreateEntities( void ); -extern int HUD_AddVisibleEntity( cl_entity_t *pEnt, int entityType ); -extern void HUD_ParticleEffect( const float *org, const float *dir, int color, int count ); -extern void HUD_StudioEvent( const struct mstudioevent_s *event, cl_entity_t *entity ); -extern void HUD_StudioFxTransform( cl_entity_t *ent, float transform[4][4] ); -extern int HUD_StudioDoInterp( cl_entity_t *e ); -extern void HUD_ParseTempEntity( void ); -extern void HUD_TempEntityMessage( int iSize, void *pbuf ); -extern void HUD_DirectorMessage( int iSize, void *pbuf ); -extern void V_CalcRefdef( struct ref_params_s *parms ); -extern void V_StartPitchDrift( void ); -extern void V_StopPitchDrift( void ); -extern void V_Init( void ); -extern void VGui_ConsolePrint( const char *text ); -extern void IN_Init( void ); -extern void IN_Shutdown( void ); -extern void IN_CreateMove( struct usercmd_s *cmd, float frametime, int active ); -extern int IN_KeyEvent( int down, int keynum, const char *pszBind ); -extern void IN_MouseEvent( int mx, int my ); - -#define VIEWPORT_SIZE 512 - -typedef void* dllhandle_t; -typedef struct dllfunction_s -{ - const char *name; - void **funcvariable; -} dllfunction_t; - -#include "cvardef.h" - -// macros to hook function calls into the HUD object -#define HOOK_MESSAGE( x ) (*gEngfuncs.pfnHookUserMsg)( #x, __MsgFunc_##x ); - -#define DECLARE_MESSAGE( y, x ) int __MsgFunc_##x(const char *pszName, int iSize, void *pbuf) \ -{ \ - return gHUD.##y.MsgFunc_##x(pszName, iSize, pbuf ); \ -} - -#define DECLARE_HUDMESSAGE( x ) int __MsgFunc_##x( const char *pszName, int iSize, void *pbuf ) \ -{ \ - return gHUD.MsgFunc_##x(pszName, iSize, pbuf ); \ -} - -#define HOOK_COMMAND( x, y ) (*gEngfuncs.pfnAddCommand)( x, __CmdFunc_##y ); -#define DECLARE_HUDCOMMAND( x ) void __CmdFunc_##x( void ) \ -{ \ - gHUD.UserCmd_##x( ); \ -} -#define DECLARE_COMMAND( y, x ) void __CmdFunc_##x( void ) \ -{ \ - gHUD.##y.UserCmd_##x( ); \ -} - -// Use this to set any co-ords in 640x480 space -#define XRES(x) ((int)(float(x) * ((float)ScreenWidth / 640.0f) + 0.5f)) -#define YRES(y) ((int)(float(y) * ((float)ScreenHeight / 480.0f) + 0.5f)) - -// ScreenHeight returns the height of the screen, in pixels -#define ScreenHeight (gHUD.m_scrinfo.iHeight) -// ScreenWidth returns the width of the screen, in pixels -#define ScreenWidth (gHUD.m_scrinfo.iWidth) - -inline void UnpackRGB( int &r, int &g, int &b, unsigned long ulRGB ) -{ - r = (ulRGB & 0xFF0000) >>16;\ - g = (ulRGB & 0xFF00) >> 8;\ - b = ulRGB & 0xFF;\ -} - -inline void ScaleColors( int &r, int &g, int &b, int a ) -{ - float x = (float)a / 255; - r = (int)(r * x); - g = (int)(g * x); - b = (int)(b * x); -} - -inline float LerpAngle( float a2, float a1, float frac ) -{ - if( a1 - a2 > 180 ) a1 -= 360; - if( a1 - a2 < -180 ) a1 += 360; - return a2 + frac * (a1 - a2); -} - -inline Vector LerpAngle( Vector a2, Vector a1, float frac ) -{ - Vector a3; - - a3.x = LerpAngle( a2.x, a1.x, frac ); - a3.y = LerpAngle( a2.y, a1.y, frac ); - a3.z = LerpAngle( a2.z, a1.z, frac ); - - return a3; -} - -inline float LerpView( float org1, float org2, float ofs1, float ofs2, float frac ) -{ - return org1 + ofs1 + frac * (org2 + ofs2 - (org1 + ofs1)); -} - -inline float LerpPoint( float oldpoint, float curpoint, float frac ) -{ - return oldpoint + frac * (curpoint - oldpoint); -} - -inline Vector LerpPoint( Vector oldpoint, Vector curpoint, float frac ) -{ - return oldpoint + frac * (curpoint - oldpoint); -} - -inline byte LerpByte( byte oldpoint, byte curpoint, float frac ) -{ - return bound( 0, oldpoint + frac * (curpoint - oldpoint), 255 ); -} - -_inline float anglemod( const float a ) -{ - return( 360.0f / 65536) * ((int)(a * (65536 / 360.0f)) & 65535); -} - -inline int ConsoleStringLen( const char *string ) -{ - int _width, _height; - GetConsoleStringSize( string, &_width, &_height ); - return _width; -} - -// message reading -extern void BEGIN_READ( const char *pszName, int iSize, void *pBuf ); -extern int READ_CHAR( void ); -extern int READ_BYTE( void ); -extern int READ_SHORT( void ); -extern int READ_WORD( void ); -extern int READ_LONG( void ); -extern float READ_FLOAT( void ); -extern char* READ_STRING( void ); -extern float READ_COORD( void ); -extern float READ_ANGLE( void ); -extern float READ_HIRESANGLE( void ); -extern void END_READ( void ); - -// misc utilities -extern void UTIL_GetForceDirection( Vector &origin, float magnitude, Vector *resultDirection, float *resultForce ); -extern void RotatePointAroundVector( Vector &dst, const Vector &dir, const Vector &point, float degrees ); - -// drawing progress bar (image must be grayscale) -extern void DrawImageBar( float percent, const char *szSpriteName ); -extern void DrawImageBar( float percent, const char *szSpriteName, int x, int y ); - -// modelinfo -int StudioBodyVariations( int modelIndex ); -modtype_t Mod_GetModelType( int modelIndex ); -void Mod_GetBounds( int modelIndex, Vector &mins, Vector &maxs ); -void *Mod_Extradata( int modelIndex ); -int Mod_GetFrames( int modelIndex ); - -// sprite loading -extern HSPRITE LoadSprite( const char *pszName ); - -// mathlib -extern void AngleMatrix( const vec3_t angles, float (*matrix)[4] ); -extern void VectorAngles( const Vector &forward, Vector &angles ); - -// from cl_view.c -extern void DrawProgressBar( void ); -extern cl_entity_t *spot; -extern float v_idlescale; -extern int g_weaponselect; -extern int g_iAlive; // indicates alive local client or not - -// input.cpp -extern cvar_t *v_centerspeed; -extern cvar_t *v_centermove; -extern cvar_t *r_studio_lerping; -extern cvar_t *m_sensitivity; -extern cvar_t *cl_forwardspeed; -extern cvar_t *cl_particles; -extern cvar_t *cl_draw_beams; -extern cvar_t *cl_lw; - -extern int CL_ButtonBits( int bResetState ); -extern void CL_ResetButtonBits( int bits ); - -// misc stuff -const char *UTIL_FileExtension( const char *in ); - -#endif//UTILS_H \ No newline at end of file diff --git a/client/global/view.cpp b/client/global/view.cpp deleted file mode 100644 index 0688c64e..00000000 --- a/client/global/view.cpp +++ /dev/null @@ -1,971 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// view.cpp - view/refresh setup functions -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "ref_params.h" -#include "triangleapi.h" -#include "pm_movevars.h" -#include "r_beams.h" -#include "studio.h" -#include "pm_defs.h" -#include "hud.h" - -extern void PM_ParticleLine( float *start, float *end, int pcolor, float life, float vert); -extern int PM_GetVisEntInfo( int ent ); -extern int PM_GetPhysEntInfo( int ent ); -extern void InterpolateAngles( float * start, float * end, float * output, float frac ); -extern void NormalizeAngles( float * angles ); -extern float Distance(const float * v1, const float * v2); -extern float AngleBetweenVectors( const float * v1, const float * v2 ); - -extern float vJumpOrigin[3]; -extern float vJumpAngles[3]; - -#define ORIGIN_BACKUP 64 -#define ORIGIN_MASK ( ORIGIN_BACKUP - 1 ) - -// global view containers -Vector v_origin, v_angles, v_cl_angles; // base client vectors -float v_idlescale, v_lastDistance; // misc variables -Vector ev_punchangle; // client punchangles -float sv_gravity; -cl_entity_t *spot; - -typedef struct -{ - Vector Origins[ORIGIN_BACKUP]; - float OriginTime[ORIGIN_BACKUP]; - Vector Angles[ORIGIN_BACKUP]; - float AngleTime[ORIGIN_BACKUP]; - int CurrentOrigin; - int CurrentAngle; -} viewinterp_t; - -typedef struct pitchdrift_s -{ - int nodrift; - float pitchvel; - float driftmove; - float laststop; -} pitchdrift_t; - -static viewinterp_t ViewInterp; -static pitchdrift_t pd; - -// view CVARS -cvar_t *scr_ofsx; -cvar_t *scr_ofsy; -cvar_t *scr_ofsz; -cvar_t *cl_vsmoothing; -cvar_t *cl_stairsmooth; -cvar_t *cl_weaponlag; - -cvar_t *cl_bobcycle; -cvar_t *cl_bob; -cvar_t *cl_bobup; -cvar_t *cl_waterdist; -cvar_t *cl_chasedist; - -cvar_t *r_studio_lerping; -cvar_t *v_iyaw_cycle; -cvar_t *v_iroll_cycle; -cvar_t *v_ipitch_cycle; -cvar_t *v_iyaw_level; -cvar_t *v_iroll_level; -cvar_t *v_ipitch_level; - -//============================================================================== -// VIEW RENDERING -//============================================================================== - -//========================== -// V_ThirdPerson -//========================== -void V_ThirdPerson( void ) -{ - // no thirdperson in multiplayer - if( gEngfuncs.GetMaxClients() > 1 ) return; - - gHUD.m_iCameraMode = 1; -} - -//========================== -// V_FirstPerson -//========================== -void V_FirstPerson( void ) -{ - gHUD.m_iCameraMode = 0; -} - -/* -============= -V_PunchAxis - -Client side punch effect -============= -*/ -void V_PunchAxis( int axis, float punch ) -{ - ev_punchangle[axis] = punch; -} - -//========================== -// V_Init -//========================== -void V_Init( void ) -{ - scr_ofsx = gEngfuncs.pfnRegisterVariable( "scr_ofsx", "0", 0 ); - scr_ofsy = gEngfuncs.pfnRegisterVariable( "scr_ofsy", "0", 0 ); - scr_ofsz = gEngfuncs.pfnRegisterVariable( "scr_ofsz", "0", 0 ); - r_studio_lerping = gEngfuncs.pfnGetCvarPointer( "r_studio_lerping" ); // get copy of engine cvar - - cl_vsmoothing = gEngfuncs.pfnRegisterVariable( "cl_vsmoothing", "0.05", 0 ); - cl_stairsmooth = gEngfuncs.pfnRegisterVariable( "cl_vstairsmooth", "100", FCVAR_ARCHIVE ); - - v_iyaw_cycle = gEngfuncs.pfnRegisterVariable( "v_iyaw_cycle", "2", 0 ); - v_iroll_cycle = gEngfuncs.pfnRegisterVariable( "v_iroll_cycle", "0.5", 0 ); - v_ipitch_cycle = gEngfuncs.pfnRegisterVariable( "v_ipitch_cycle", "1", 0 ); - v_iyaw_level = gEngfuncs.pfnRegisterVariable( "v_iyaw_level", "0.3", 0 ); - v_iroll_level = gEngfuncs.pfnRegisterVariable( "v_iroll_level", "0.1", 0 ); - v_ipitch_level = gEngfuncs.pfnRegisterVariable( "v_iyaw_level", "0.3", 0 ); - - cl_weaponlag = gEngfuncs.pfnRegisterVariable( "v_viewmodel_lag", "0.0", FCVAR_ARCHIVE ); - cl_bobcycle = gEngfuncs.pfnRegisterVariable( "cl_bobcycle","0.8", 0 ); - cl_bob = gEngfuncs.pfnRegisterVariable( "cl_bob", "0.01", 0 ); - cl_bobup = gEngfuncs.pfnRegisterVariable( "cl_bobup", "0.5", 0 ); - cl_waterdist = gEngfuncs.pfnRegisterVariable( "cl_waterdist", "4", 0 ); - cl_chasedist = gEngfuncs.pfnRegisterVariable( "cl_chasedist", "112", 0 ); - gEngfuncs.pfnAddCommand( "thirdperson", V_ThirdPerson ); - gEngfuncs.pfnAddCommand( "firstperson", V_FirstPerson ); -} - -//========================== -// V_StartPitchDrift -//========================== -void V_StartPitchDrift( void ) -{ - if( pd.laststop == GetClientTime( )) - return; - - if( pd.nodrift || !pd.pitchvel ) - { - pd.pitchvel = v_centerspeed->value; - pd.nodrift = 0; - pd.driftmove = 0; - } -} - -//========================== -// V_StopPitchDrift -//========================== -void V_StopPitchDrift( void ) -{ - pd.laststop = GetClientTime(); - pd.nodrift = 1; - pd.pitchvel = 0; -} - -//========================== -// V_DriftPitch -//========================== -void V_DriftPitch( ref_params_t *pparams ) -{ - float delta, move; - - if( gEngfuncs.IsNoClipping() || !pparams->onground || pparams->demoplayback ) - { - pd.driftmove = 0; - pd.pitchvel = 0; - return; - } - - if( pd.nodrift ) - { - if( fabs( pparams->cmd->forwardmove ) < cl_forwardspeed->value ) - pd.driftmove = 0; - else pd.driftmove += pparams->frametime; - if( pd.driftmove > v_centermove->value ) V_StartPitchDrift(); - return; - } - - delta = pparams->idealpitch - pparams->cl_viewangles[PITCH]; - - if( !delta ) - { - pd.pitchvel = 0; - return; - } - - move = pparams->frametime * pd.pitchvel; - pd.pitchvel += pparams->frametime * v_centerspeed->value; - - if( delta > 0 ) - { - if( move > delta ) - { - pd.pitchvel = 0; - move = delta; - } - pparams->cl_viewangles[PITCH] += move; - } - else if( delta < 0 ) - { - if( move > -delta ) - { - pd.pitchvel = 0; - move = -delta; - } - pparams->cl_viewangles[PITCH] -= move; - } -} - -//========================== -// V_CalcFov -//========================== -float V_CalcFov( float fov_x, float width, float height ) -{ - // check to avoid division by zero - if( fov_x < 1 || fov_x > 179 ) - { - gEngfuncs.Con_Printf( "V_CalcFov: invalid fov %g!\n", fov_x ); - fov_x = 90; - } - - float x = width / tan( DEG2RAD( fov_x ) * 0.5f ); - float half_fov_y = atan( height / x ); - return RAD2DEG( half_fov_y ) * 2; -} - -//========================== -// V_DropPunchAngle -//========================== -void V_DropPunchAngle( float frametime, Vector &ev_punchangle ) -{ - float len; - - len = ev_punchangle.Length(); - ev_punchangle = ev_punchangle.Normalize(); - - len -= (10.0 + len * 0.5) * frametime; - len = max( len, 0.0 ); - ev_punchangle *= len; -} - -void V_CalcViewModelLag( ref_params_t *pparams, Vector& origin, Vector& angles, Vector& original_angles ) -{ - static Vector m_vecLastFacing; - Vector vOriginalOrigin = origin; - Vector vOriginalAngles = angles; - - // Calculate our drift - Vector forward; - AngleVectors( angles, forward, NULL, NULL ); - - if ( pparams->frametime != 0.0f ) - { - Vector vDifference; - - vDifference = forward - m_vecLastFacing; - - float flSpeed = 5.0f; - - // If we start to lag too far behind, we'll increase the "catch up" speed. - // Solves the problem with fast cl_yawspeed, m_yaw or joysticks rotating quickly. - // The old code would slam lastfacing with origin causing the viewmodel to pop to a new position - float flDiff = vDifference.Length(); - if (( flDiff > cl_weaponlag->value ) && ( cl_weaponlag->value > 0.0f )) - { - float flScale = flDiff / cl_weaponlag->value; - flSpeed *= flScale; - } - - // FIXME: Needs to be predictable? - m_vecLastFacing = m_vecLastFacing + vDifference * ( flSpeed * pparams->frametime ); - // Make sure it doesn't grow out of control!!! - m_vecLastFacing = m_vecLastFacing.Normalize(); - origin = origin + (vDifference * -1.0f) * 5.0f; - ASSERT( m_vecLastFacing.IsValid() ); - } - - Vector right, up; - AngleVectors( original_angles, forward, right, up ); - - float pitch = original_angles[PITCH]; - - if ( pitch > 180.0f ) - { - pitch -= 360.0f; - } - else if ( pitch < -180.0f ) - { - pitch += 360.0f; - } - - if ( cl_weaponlag->value <= 0.0f ) - { - origin = vOriginalOrigin; - angles = vOriginalAngles; - } - else - { - // FIXME: These are the old settings that caused too many exposed polys on some models - origin = origin + forward * ( -pitch * 0.035f ); - origin = origin + right * ( -pitch * 0.03f ); - origin = origin + up * ( -pitch * 0.02f ); - } -} - -//========================== -// V_CalcGunAngle -//========================== -void V_CalcGunAngle( ref_params_t *pparams ) -{ - if( pparams->fov_x > 135 ) return; - - cl_entity_t *viewent = GetViewModel(); - - if( !viewent->curstate.modelindex ) - return; - - viewent->curstate.effects |= EF_MINLIGHT; - - viewent->angles[YAW] = pparams->viewangles[YAW] + pparams->crosshairangle[YAW]; - viewent->angles[PITCH] = pparams->viewangles[PITCH] - pparams->crosshairangle[PITCH] * 0.25; - viewent->angles[ROLL] = pparams->viewangles[ROLL]; - viewent->angles[ROLL] -= v_idlescale * sin(pparams->time * v_iroll_cycle->value) * v_iroll_level->value; - - // don't apply all of the v_ipitch to prevent normally unseen parts of viewmodel from coming into view. - viewent->angles[PITCH] -= v_idlescale * sin(pparams->time * v_ipitch_cycle->value) * (v_ipitch_level->value * 0.5); - viewent->angles[YAW] -= v_idlescale * sin(pparams->time * v_iyaw_cycle->value) * v_iyaw_level->value; -} - -//========================== -// V_PreRender -//========================== -void V_PreRender( ref_params_t *pparams ) -{ - // get the global gravity - sv_gravity = pparams->movevars->gravity; - - // input - pparams->intermission = gHUD.m_iIntermission; - if( gHUD.m_iCameraMode ) pparams->flags |= RDF_THIRDPERSON; - else pparams->flags &= ~RDF_THIRDPERSON; - - pparams->fov_x = gHUD.m_iFOV; // this is a final fov value - pparams->fov_y = V_CalcFov( pparams->fov_x, pparams->viewport[2], pparams->viewport[3] ); - - memset( pparams->blend, 0, sizeof( pparams->blend )); -} - -//========================== -// V_CalcGlobalFog -//========================== -void V_CalcGlobalFog( ref_params_t *pparams ) -{ - int bOn = (pparams->waterlevel < 2) && (gHUD.m_flStartDist > 0) && (gHUD.m_flEndDist > 0 && gHUD.m_flStartDist); - gEngfuncs.pTriAPI->Fog( gHUD.m_vecFogColor, gHUD.m_flStartDist, gHUD.m_flEndDist, bOn ); -} - -//========================== -// V_CalcBob -//========================== -float V_CalcBob( ref_params_t *pparams ) -{ - static double bobtime; - static float bob; - static float lasttime; - float cycle; - Vector vel; - - if( !pparams->onground || pparams->time == lasttime ) - return bob; - lasttime = pparams->time; - - bobtime += pparams->frametime; - cycle = bobtime - (int)( bobtime / cl_bobcycle->value ) * cl_bobcycle->value; - cycle /= cl_bobcycle->value; - - if( cycle < cl_bobup->value ) cycle = M_PI * cycle / cl_bobup->value; - else cycle = M_PI + M_PI * ( cycle - cl_bobup->value )/( 1.0 - cl_bobup->value ); - - vel = pparams->simvel; - vel[2] = 0; - - bob = sqrt( vel[0] * vel[0] + vel[1] * vel[1] ) * cl_bob->value; - bob = bob * 0.3 + bob * 0.7 * sin( cycle ); - bob = min( bob, 4 ); - bob = max( bob, -7 ); - return bob; -} - -//========================== -// V_AddIdle -//========================== -void V_AddIdle( ref_params_t *pparams ) -{ - pparams->viewangles[ROLL] += v_idlescale * sin(pparams->time*v_iroll_cycle->value) * v_iroll_level->value; - pparams->viewangles[PITCH] += v_idlescale * sin(pparams->time*v_ipitch_cycle->value) * v_ipitch_level->value; - pparams->viewangles[YAW] += v_idlescale * sin(pparams->time*v_iyaw_cycle->value) * v_iyaw_level->value; -} - -//========================== -// V_CalcViewRoll -//========================== -void V_CalcViewRoll( ref_params_t *pparams ) -{ - float sign, side, value; - cl_entity_t *viewentity; - Vector right; - - viewentity = GetEntityByIndex( pparams->viewentity ); - if( !viewentity ) return; - - if( pparams->health <= 0 && ( pparams->viewheight[2] != 0 )) - { - GetViewModel()->curstate.modelindex = 0; // clear the viewmodel - pparams->viewangles[ROLL] = 80; // dead view angle - return; - } - - if( pparams->demoplayback ) return; - - AngleVectors( viewentity->angles, NULL, right, NULL ); - side = right.Dot( pparams->simvel ); - sign = side < 0 ? -1 : 1; - side = fabs( side ); - value = pparams->movevars->rollangle; - if( side < pparams->movevars->rollspeed ) - side = side * value / pparams->movevars->rollspeed; - else side = value; - side = side * sign; - pparams->viewangles[ROLL] += side; -} - -//========================== -// V_SetViewport -//========================== -void V_SetViewport( ref_params_t *pparams ) -{ - pparams->viewport[0] = 0; - pparams->viewport[1] = 0; - pparams->viewport[2] = VIEWPORT_SIZE; - pparams->viewport[3] = VIEWPORT_SIZE; -} - -//========================== -// V_GetChaseOrigin -//========================== -void V_GetChaseOrigin( Vector angles, Vector origin, float distance, Vector &result ) -{ - Vector vecEnd; - Vector forward; - Vector vecStart; - pmtrace_t * trace; - int maxLoops = 8; - - cl_entity_t *ent = NULL; - int ignoreent = -1; // first, ignore no entity - - // trace back from the target using the player's view angles - AngleVectors( angles, forward, NULL, NULL ); - forward *= -1; - vecStart = origin; - vecEnd.MA( distance, vecStart, forward ); - - while( maxLoops > 0 ) - { - trace = gEngfuncs.PM_TraceLine( vecStart, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, ignoreent ); - if( trace->ent <= 0 ) break; // we hit the world or nothing, stop trace - - ent = GetEntityByIndex( PM_GetPhysEntInfo( trace->ent )); - - if ( ent == NULL ) - break; - - // hit non-player solid BSP, stop here - if( ent->curstate.solid == SOLID_BSP && !ent->player ) - break; - - // if close enought to end pos, stop, otherwise continue trace - if( trace->endpos.Distance( vecEnd ) < 1.0f ) - break; - else - { - ignoreent = trace->ent; // ignore last hit entity - vecStart = trace->endpos; - } - maxLoops--; - } - - result.MA( 4, trace->endpos, trace->plane.normal ); - v_lastDistance = trace->endpos.Distance( origin ); // real distance without offset -} - -//========================== -// V_GetChasePos -//========================== -void V_GetChasePos( ref_params_t *pparams, cl_entity_t *ent, float *cl_angles, Vector &origin, Vector &angles ) -{ - if ( !ent ) - { - // just copy a save in-map position - angles = Vector( 0, 0, 0 ); - origin = Vector( 0, 0, 0 ); - return; - } - - if ( cl_angles == NULL ) - { - // no mouse angles given, use entity angles ( locked mode ) - angles = ent->angles; - angles.x *= -1; - } - else - { - angles = cl_angles; - } - - // refresh the position - origin = ent->origin; - origin[2] += 28; // DEFAULT_VIEWHEIGHT - some offset - V_GetChaseOrigin( angles, origin, cl_chasedist->value, origin ); -} - -//========================== -// V_CalcCameraRefdef -//========================== -void V_CalcCameraRefdef( ref_params_t *pparams ) -{ - if( pparams->intermission ) return; // disable in intermission mode - - if( GetEntityByIndex( pparams->viewentity ) != GetLocalPlayer( )) - { - // this is a viewentity which sets by SET_VIEW builtin - cl_entity_t *viewentity = GetEntityByIndex( pparams->viewentity ); - if( viewentity ) - { - studiohdr_t *viewmonster = (studiohdr_t *)Mod_Extradata( viewentity->curstate.modelindex ); - float m_fLerp = pparams->lerpfrac; - - if( viewentity->curstate.movetype == MOVETYPE_STEP ) - v_origin = LerpPoint( viewentity->prevstate.origin, viewentity->curstate.origin, m_fLerp ); - else v_origin = viewentity->origin; // already interpolated - - // add view offset - if( viewmonster ) v_origin += viewmonster->eyeposition; - - if( viewentity->curstate.movetype == MOVETYPE_STEP ) - v_angles = LerpAngle( viewentity->prevstate.angles, viewentity->curstate.angles, m_fLerp ); - else v_angles = viewentity->angles; // already interpolated - - pparams->crosshairangle[ROLL] = 1; // crosshair is hided - - // refresh position - pparams->viewangles = v_angles; - pparams->vieworg = v_origin; - } - } - else pparams->crosshairangle[ROLL] = 0; // show crosshair again -} - -cl_entity_t *V_FindIntermisionSpot( ref_params_t *pparams ) -{ - cl_entity_t *ent; - int spotindex[16]; // max number of intermission spot - int k = 0, j = 0; - - // found intermission points - for( int i = 0; i < pparams->num_entities; i++ ) - { - ent = GetEntityByIndex( i ); -#if 0 - if( ent && !stricmp( ent->curstate.classname, "info_intermission" )) - { - if( j > 15 ) break; // spotlist is full - spotindex[j] = ent->index; // save entindex - j++; - } -#endif - } - - // ok, we have list of intermission spots - if( j ) - { - if( j > 1 ) k = RANDOM_LONG( 0, j - 1 ); - ent = GetEntityByIndex( spotindex[k] ); - } - else ent = GetLocalPlayer(); // just get view from player - - return ent; -} - -//========================== -// V_CalcIntermisionRefdef -//========================== -void V_CalcIntermisionRefdef( ref_params_t *pparams ) -{ - if( !pparams->intermission ) return; - - cl_entity_t *view; - float old; - - if( !spot ) spot = V_FindIntermisionSpot( pparams ); - view = GetViewModel(); - - // need to lerping position ? - pparams->vieworg = spot->origin; - pparams->viewangles = spot->angles; - view->curstate.modelindex = 0; - - // allways idle in intermission - old = v_idlescale; - v_idlescale = 1; - V_AddIdle( pparams ); - - v_idlescale = old; - v_cl_angles = pparams->cl_viewangles; - v_origin = pparams->vieworg; - v_angles = pparams->viewangles; -} - -//========================== -// V_CalcThirdPersonRefdef -//========================== -void V_CalcThirdPersonRefdef( ref_params_t *pparams ) -{ - // passed only in third person - if( gHUD.m_iCameraMode == 0 || pparams->intermission ) - return; - - // clear viewmodel for thirdperson - cl_entity_t *viewent = GetViewModel(); - viewent->curstate.modelindex = 0; - - // get current values - v_cl_angles = pparams->cl_viewangles; - v_angles = pparams->viewangles; - v_origin = pparams->vieworg; - - V_GetChasePos( pparams, GetLocalPlayer(), v_cl_angles, v_origin, v_angles ); - - // write back new values - pparams->cl_viewangles = v_cl_angles; - pparams->viewangles = v_angles; - pparams->vieworg = v_origin; - - // apply shake for thirdperson too - gEngfuncs.V_CalcShake(); - gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); -} - -//========================== -// V_CalcSendOrigin -//========================== -void V_CalcSendOrigin( ref_params_t *pparams ) -{ - // never let view origin sit exactly on a node line, because a water plane can - // dissapear when viewed with the eye exactly on it. - pparams->vieworg[0] += 1.0 / 32; - pparams->vieworg[1] += 1.0 / 32; - pparams->vieworg[2] += 1.0 / 32; -} - -//========================== -// V_CalcWaterLevel -//========================== -float V_CalcWaterLevel( ref_params_t *pparams ) -{ - float waterOffset = 0; - - if( pparams->waterlevel >= 2 ) - { - int i, contents, waterDist, waterEntity; - cl_entity_t *pwater; - vec3_t point; - waterDist = cl_waterdist->value; - - if ( 1 ) //pparams->hardware ) - { - waterEntity = gEngfuncs.PM_WaterEntity( pparams->simorg ); - if ( waterEntity >= 0 && waterEntity < pparams->max_entities ) - { - pwater = GetEntityByIndex( waterEntity ); - if ( pwater && ( pwater->model != NULL ) ) - { - waterDist += ( pwater->curstate.scale * 16 ); // Add in wave height - } - } - } - else - { - waterEntity = 0; // Don't need this in software - } - - point = pparams->vieworg; - - // eyes are above water, make sure we're above the waves - if( pparams->waterlevel == 2 ) - { - point[2] -= waterDist; - for( i = 0; i < waterDist; i++ ) - { - contents = POINT_CONTENTS( point ); - if( contents > CONTENTS_WATER ) break; - point[2] += 1; - } - waterOffset = (point[2] + waterDist) - pparams->vieworg[2]; - } - else - { - // eyes are under water. Make sure we're far enough under - point[2] += waterDist; - for( i = 0; i < waterDist; i++ ) - { - contents = POINT_CONTENTS( point ); - if( contents <= CONTENTS_WATER ) break; - point[2] -= 1; - } - waterOffset = (point[2] - waterDist) - pparams->vieworg[2]; - } - } - - // underwater refraction - if( pparams->waterlevel == 3 ) - { - float f = sin( pparams->time * 0.4 * (M_PI * 2.7)); - pparams->fov_x += f; - pparams->fov_y -= f; - } - - pparams->vieworg[2] += waterOffset; - return waterOffset; -} - -//========================== -// V_CalcScrOffset -//========================== -void V_CalcScrOffset( ref_params_t *pparams ) -{ - // don't allow cheats in multiplayer - if( pparams->maxclients > 1 ) return; - - for( int i = 0; i < 3; i++ ) - { - pparams->vieworg[i] += scr_ofsx->value * pparams->forward[i]; - pparams->vieworg[i] += scr_ofsy->value * pparams->right[i]; - pparams->vieworg[i] += scr_ofsz->value * pparams->up[i]; - } -} - -//========================== -// V_InterpolatePos -//========================== -void V_InterpolatePos( ref_params_t *pparams ) -{ - cl_entity_t *view; - - // view is the weapon model (only visible from inside body ) - view = GetViewModel(); - - if( cl_vsmoothing->value && ( pparams->smoothing && ( pparams->maxclients > 1 ))) - { - int i, foundidx; - float t; - - if( cl_vsmoothing->value < 0.0 ) CVAR_SET_FLOAT( "cl_vsmoothing", 0 ); - t = pparams->time - cl_vsmoothing->value; - for( i = 1; i < ORIGIN_MASK; i++ ) - { - foundidx = ViewInterp.CurrentOrigin - 1 - i; - if( ViewInterp.OriginTime[foundidx & ORIGIN_MASK] <= t ) break; - } - - if( i < ORIGIN_MASK && ViewInterp.OriginTime[foundidx & ORIGIN_MASK] != 0.0 ) - { - // interpolate - Vector delta; - double frac; - double dt; - Vector neworg; - - dt = ViewInterp.OriginTime[(foundidx + 1) & ORIGIN_MASK] - ViewInterp.OriginTime[foundidx & ORIGIN_MASK]; - if ( dt > 0.0 ) - { - frac = ( t - ViewInterp.OriginTime[foundidx & ORIGIN_MASK] ) / dt; - frac = min( 1.0, frac ); - delta = ViewInterp.Origins[(foundidx + 1) & ORIGIN_MASK] - ViewInterp.Origins[foundidx & ORIGIN_MASK]; - neworg.MA( frac, ViewInterp.Origins[foundidx & ORIGIN_MASK], delta ); - - // don't interpolate large changes - if( delta.Length() < 64 ) - { - delta = neworg - pparams->simorg; - pparams->simorg += delta; - pparams->vieworg += delta; - view->origin += delta; - - } - } - } - } -} - -float V_CalcStairSmoothValue( float oldz, float newz, float smoothtime, float stepheight ) -{ - if( oldz < newz ) - return bound( newz - stepheight, oldz + smoothtime * cl_stairsmooth->value, newz ); - else if( oldz > newz ) - return bound( newz, oldz - smoothtime * cl_stairsmooth->value, newz + stepheight ); - return 0.0; -} - -//========================== -// V_CalcFirstPersonRefdef -//========================== -void V_CalcFirstPersonRefdef( ref_params_t *pparams ) -{ - // don't pass in thirdperson or intermission - if( gHUD.m_iCameraMode || pparams->intermission ) - return; - - Vector angles; - float bob, waterOffset; - static float lasttime; - cl_entity_t *view = GetViewModel(); - int i; - - V_DriftPitch( pparams ); - bob = V_CalcBob( pparams ); - - // refresh the position - pparams->vieworg = pparams->simorg; - pparams->vieworg[2] += ( bob ); - pparams->vieworg += pparams->viewheight; - - pparams->viewangles = pparams->cl_viewangles; - - gEngfuncs.V_CalcShake(); - gEngfuncs.V_ApplyShake( pparams->vieworg, pparams->viewangles, 1.0 ); - - V_CalcSendOrigin( pparams ); - waterOffset = V_CalcWaterLevel( pparams ); - V_CalcViewRoll( pparams ); - V_AddIdle( pparams ); - - // offsets - angles = pparams->viewangles; - AngleVectors( angles, pparams->forward, pparams->right, pparams->up ); - V_CalcScrOffset( pparams ); - - Vector lastAngles; - - lastAngles = view->angles = pparams->cl_viewangles; - V_CalcGunAngle( pparams ); - - // use predicted origin as view origin. - view->origin = pparams->simorg; - view->origin[2] += ( waterOffset ); - view->origin += pparams->viewheight; - - // Let the viewmodel shake at about 10% of the amplitude - gEngfuncs.V_ApplyShake( view->origin, view->angles, 0.9 ); - - for( i = 0; i < 3; i++ ) - view->origin[i] += bob * 0.4 * pparams->forward[i]; - view->origin[2] += bob; - - view->angles[YAW] -= bob * 0.5; - view->angles[ROLL] -= bob * 1; - view->angles[PITCH] -= bob * 0.3; - view->origin[2] -= 1; - - // add lag - V_CalcViewModelLag( pparams, view->origin, view->angles, lastAngles ); - - // fudge position around to keep amount of weapon visible - // roughly equal with different FOV - if( pparams->viewsize == 110 ) view->origin[2] += 1; - else if( pparams->viewsize == 100 ) view->origin[2] += 2; - else if( pparams->viewsize == 90 ) view->origin[2] += 1; - else if( pparams->viewsize == 80 ) view->origin[2] += 0.5; - - pparams->viewangles += pparams->punchangle; - pparams->viewangles += ev_punchangle; - - V_DropPunchAngle( pparams->frametime, ev_punchangle ); - - static float stairoldtime = 0; - static float old_client_z = 0; - static float old_weapon_z = 0; - - // calculate how much time has passed since the last V_CalcRefdef - float smoothtime = bound( 0.0, pparams->time - stairoldtime, 0.1 ); - stairoldtime = pparams->time; - - // smooth stair stepping, but only if onground and enabled - if( !pparams->smoothing || !pparams->onground || cl_stairsmooth->value <= 0 ) - { - old_client_z = pparams->vieworg[2]; - old_weapon_z = view->origin[2]; - } - else - { - float result; - float stepheight = pparams->movevars->stepsize; - - result = V_CalcStairSmoothValue( old_client_z, pparams->vieworg[2], smoothtime, stepheight ); - if( result ) pparams->vieworg[2] = old_client_z = result; - result = V_CalcStairSmoothValue( old_weapon_z, view->origin[2], smoothtime, stepheight ); - if( result ) view->origin[2] = old_weapon_z = result; - } - - static Vector lastorg; - Vector delta; - - delta = pparams->simorg - lastorg; - - if( delta.Length() != 0.0 ) - { - ViewInterp.Origins[ViewInterp.CurrentOrigin & ORIGIN_MASK] = pparams->simorg; - ViewInterp.OriginTime[ViewInterp.CurrentOrigin & ORIGIN_MASK] = pparams->time; - ViewInterp.CurrentOrigin++; - - lastorg = pparams->simorg; - } - -// probably not needs in Xash3D -// V_InterpolatePos( pparams ); // smooth predicting moving in multiplayer - - lasttime = pparams->time; - v_origin = pparams->vieworg; -} - -//========================== -// V_CalcScreenBlend -//========================== -void V_CalcScreenBlend( ref_params_t *pparams ) -{ -#if 0 - // FIXME: get some code from q1 - pparams->blend[0] = 0.0f; - pparams->blend[1] = 0.0f; - pparams->blend[2] = 0.0f; - pparams->blend[3] = 1.0f; -#endif -} - -void V_CalcRefdef( ref_params_t *pparams ) -{ - V_PreRender( pparams ); - V_CalcGlobalFog( pparams ); - V_CalcFirstPersonRefdef( pparams ); - V_CalcThirdPersonRefdef( pparams ); - V_CalcIntermisionRefdef( pparams ); - V_CalcCameraRefdef( pparams ); - V_CalcScreenBlend( pparams ); - -} \ No newline at end of file diff --git a/client/hud/hud.cpp b/client/hud/hud.cpp deleted file mode 100644 index a0d5ad42..00000000 --- a/client/hud/hud.cpp +++ /dev/null @@ -1,469 +0,0 @@ -//======================================================================= -// Copyright (C) XashXT Group 2007 -//======================================================================= - -#include "extdll.h" -#include "utils.h" -#include "hud.h" -#include "triangleapi.h" - -#define MAX_LOGO_FRAMES 56 - -int grgLogoFrame[MAX_LOGO_FRAMES] = -{ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 13, 13, 13, 13, 13, 12, 11, 10, 9, 8, 14, 15, - 16, 17, 18, 19, 20, 20, 20, 20, 20, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, - 29, 29, 29, 29, 29, 28, 27, 26, 25, 24, 30, 31 -}; - -void CHud :: Init( void ) -{ - InitMessages(); - m_Ammo.Init(); - m_Health.Init(); - m_SayText.Init(); - m_Geiger.Init(); - m_Train.Init(); - m_Battery.Init(); - m_Flash.Init(); - m_Message.Init(); - m_Scoreboard.Init(); - m_StatusBar.Init(); - m_DeathNotice.Init(); - m_AmmoSecondary.Init(); - m_TextMessage.Init(); - m_StatusIcons.Init(); - m_Menu.Init(); - m_MOTD.Init(); - - MsgFunc_ResetHUD( 0, 0, NULL ); -} - -CHud :: ~CHud( void ) -{ - delete [] m_rghSprites; - delete [] m_rgrcRects; - delete [] m_rgszSpriteNames; - - if( m_pHudList ) - { - HUDLIST *pList; - while( m_pHudList ) - { - pList = m_pHudList; - m_pHudList = m_pHudList->pNext; - free( pList ); - } - m_pHudList = NULL; - } - - // release hud.txt file - gEngfuncs.COM_FreeFile( m_pSpriteList ); - m_pSpriteList = NULL; -} - -int CHud :: GetSpriteIndex( const char *SpriteName ) -{ - // look through the loaded sprite name list for SpriteName - for( int i = 0; i < m_iSpriteCount; i++ ) - { - if(!strncmp( SpriteName, m_rgszSpriteNames + (i * MAX_SPRITE_NAME_LENGTH), MAX_SPRITE_NAME_LENGTH )) - return i; - } - return -1; // invalid sprite -} - -void CHud :: VidInit( void ) -{ - // ---------- - // Load Sprites - // --------- - - m_hsprLogo = 0; - m_hsprCursor = 0; - m_hHudError = 0; - spot = NULL; // clear intermission spot - - // setup screen info - m_scrinfo.iSize = sizeof(m_scrinfo); - GetScreenInfo( &m_scrinfo ); - - if( ScreenWidth < 640 ) - m_iRes = 320; - else m_iRes = 640; - - // Only load this once - if ( !m_pSpriteList ) - { - // we need to load the hud.txt, and all sprites within - m_pSpriteList = SPR_GetList( "sprites/hud.txt", &m_iSpriteCountAllRes ); - - if( m_pSpriteList ) - { - // count the number of sprites of the appropriate res - m_iSpriteCount = 0; - client_sprite_t *p = m_pSpriteList; - for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - m_iSpriteCount++; - p++; - } - - // allocated memory for sprite handle arrays - m_rghSprites = new HSPRITE[m_iSpriteCount]; - m_rgrcRects = new wrect_t[m_iSpriteCount]; - m_rgszSpriteNames = new char[m_iSpriteCount * MAX_SPRITE_NAME_LENGTH]; - - p = m_pSpriteList; - int index = 0; - for ( j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - { - char sz[256]; - sprintf(sz, "sprites/%s.spr", p->szSprite); - m_rghSprites[index] = SPR_Load(sz); - m_rgrcRects[index] = p->rc; - strncpy( &m_rgszSpriteNames[index * MAX_SPRITE_NAME_LENGTH], p->szName, MAX_SPRITE_NAME_LENGTH ); - - index++; - } - p++; - } - } - else - { - gEngfuncs.Con_Printf( "Warning: hud.txt couldn't load\n" ); - CVAR_SET_FLOAT( "hud_draw", 0 ); - return; - } - } - else - { - // we have already have loaded the sprite reference from hud.txt, but - // we need to make sure all the sprites have been loaded (we've gone through a transition, or loaded a save game) - client_sprite_t *p = m_pSpriteList; - int index = 0; - for ( int j = 0; j < m_iSpriteCountAllRes; j++ ) - { - if ( p->iRes == m_iRes ) - { - char sz[256]; - sprintf( sz, "sprites/%s.spr", p->szSprite ); - m_rghSprites[index] = SPR_Load(sz); - index++; - } - - p++; - } - } - - // assumption: number_1, number_2, etc, are all listed and loaded sequentially - m_HUD_number_0 = GetSpriteIndex( "number_0" ); - m_iFontHeight = GetSpriteRect( m_HUD_number_0 ).bottom - GetSpriteRect( m_HUD_number_0 ).top; - - // loading error sprite - m_HUD_error = GetSpriteIndex( "error" ); - m_hHudError = GetSprite( m_HUD_error ); - - m_Ammo.VidInit(); - m_Health.VidInit(); - m_Geiger.VidInit(); - m_Train.VidInit(); - m_Battery.VidInit(); - m_Flash.VidInit(); - m_MOTD.VidInit(); - m_Message.VidInit(); - m_Scoreboard.VidInit(); - m_StatusBar.VidInit(); - m_DeathNotice.VidInit(); - m_SayText.VidInit(); - m_Menu.VidInit(); - m_AmmoSecondary.VidInit(); - m_TextMessage.VidInit(); - m_StatusIcons.VidInit(); -} - -void CHud :: Think( void ) -{ - HUDLIST *pList = m_pHudList; - - while( pList ) - { - if (pList->p->m_iFlags & HUD_ACTIVE) - pList->p->Think(); - pList = pList->pNext; - } - - int newfov = HUD_GetFOV(); - - if ( newfov == 0 ) - { - m_iFOV = default_fov->value; - } - else - { - m_iFOV = newfov; - } - - // the clients fov is actually set in the client data update section of the hud - - // Set a new sensitivity - if ( m_iFOV == default_fov->value ) - { - // reset to saved sensitivity - m_flMouseSensitivity = 0; - } - else - { - // set a new sensitivity that is proportional to the change from the FOV default - m_flMouseSensitivity = m_sensitivity->value * ((float)newfov / (float)default_fov->value ); - m_flMouseSensitivity *= CVAR_GET_FLOAT( "zoom_sensitivity_ratio" ); - } - - // think about default fov - if ( m_iFOV == 0 ) - { - // only let players adjust up in fov, and only if they are not overriden by something else - m_iFOV = max( default_fov->value, 90 ); - } -} - -int CHud :: UpdateClientData( client_data_t *cdata, float time ) -{ - cl_entity_t *pClient = GetLocalPlayer (); - - memcpy( m_vecOrigin, cdata->origin, sizeof( vec3_t )); - memcpy( m_vecAngles, cdata->viewangles, sizeof( vec3_t )); - - if( pClient ) - { - // TEMPORARY HACK - m_iNoClip = (pClient->curstate.movetype == MOVETYPE_NOCLIP) ? 1 : 0; - } - - m_iKeyBits = CL_ButtonBits( 0 ); - m_iWeaponBits = cdata->iWeaponBits; - - float in_fov = cdata->fov; - - Think(); - - cdata->fov = m_iFOV; - - v_idlescale = m_iConcussionEffect; - - CL_ResetButtonBits( m_iKeyBits ); - - return 1; -} - -int CHud :: Redraw( float flTime ) -{ - m_fOldTime = m_flTime; // save time of previous redraw - m_flTime = flTime; - m_flTimeDelta = (double)m_flTime - m_fOldTime; - static float m_flShotTime; - - // clock was reset, reset delta - if( m_flTimeDelta < 0 ) m_flTimeDelta = 0; - - // take a screenshot if the client's got the cvar set - if( m_flShotTime && m_flShotTime < flTime ) - { - CLIENT_COMMAND( "screenshot\n" ); - m_flShotTime = 0; - } - - if( CVAR_GET_FLOAT( "hud_draw" )) - { - HUDLIST *pList = m_pHudList; - - while( pList ) - { - if( !m_iIntermission ) - { - if(( pList->p->m_iFlags & HUD_ACTIVE ) && !(m_iHideHUDDisplay & HIDEHUD_ALL )) - pList->p->Draw( flTime ); - } - else - { - // it's an intermission, so only draw hud elements - // that are set to draw during intermissions - if( pList->p->m_iFlags & HUD_INTERMISSION ) - pList->p->Draw( flTime ); - } - pList = pList->pNext; - } - } - - // are we in demo mode? do we need to draw the logo in the top corner? - if (m_iLogo) - { - int x, y, i; - - if (m_hsprLogo == 0) - m_hsprLogo = LoadSprite("sprites/%d_logo.spr"); - - SPR_Set(m_hsprLogo, 250, 250, 250 ); - - x = SPR_Width(m_hsprLogo, 0); - x = ScreenWidth - x; - y = SPR_Height(m_hsprLogo, 0)/2; - - // Draw the logo at 20 fps - int iFrame = (int)(flTime * 20) % MAX_LOGO_FRAMES; - i = grgLogoFrame[iFrame] - 1; - - SPR_DrawAdditive(i, x, y, NULL); - } - - return 1; -} - -int CHud :: DrawHudString( int xpos, int ypos, int iMaxX, char *szIt, int r, int g, int b ) -{ - // draw the string until we hit the null character or a newline character - for( ; *szIt != 0 && *szIt != '\n'; szIt++ ) - { - int next = xpos + gHUD.m_scrinfo.charWidths[*szIt]; // variable-width fonts look cool - if ( next > iMaxX ) - return xpos; - - TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); - xpos = next; - } - - return xpos; -} - -int CHud :: DrawHudNumberString( int xpos, int ypos, int iMinX, int iNumber, int r, int g, int b ) -{ - char szString[32]; - sprintf( szString, "%d", iNumber ); - return DrawHudStringReverse( xpos, ypos, iMinX, szString, r, g, b ); - -} - -int CHud :: DrawHudStringReverse( int xpos, int ypos, int iMinX, char *szString, int r, int g, int b ) -{ - // find the end of the string - for ( char *szIt = szString; *szIt != 0; szIt++ ) - { // we should count the length? - } - - // iterate throug the string in reverse - for( szIt--; szIt != (szString-1); szIt-- ) - { - int next = xpos - gHUD.m_scrinfo.charWidths[ *szIt ]; // variable-width fonts look cool - if( next < iMinX ) - return xpos; - xpos = next; - - TextMessageDrawChar( xpos, ypos, *szIt, r, g, b ); - } - - return xpos; -} - -int CHud :: DrawHudNumber( int x, int y, int iFlags, int iNumber, int r, int g, int b ) -{ - int iWidth = GetSpriteRect( m_HUD_number_0 ).right - GetSpriteRect( m_HUD_number_0 ).left; - int k; - - if( iNumber > 0 ) - { - // SPR_Draw 100's - if( iNumber >= 100 ) - { - k = iNumber / 100; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if( iFlags & DHN_3DIGITS ) - { - x += iWidth; - } - - // SPR_Draw 10's - if( iNumber >= 10 ) - { - k = (iNumber % 100)/10; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if( iFlags & (DHN_3DIGITS|DHN_2DIGITS)) - { - x += iWidth; - } - - // SPR_Draw ones - k = iNumber % 10; - SPR_Set(GetSprite(m_HUD_number_0 + k), r, g, b ); - SPR_DrawAdditive(0, x, y, &GetSpriteRect(m_HUD_number_0 + k)); - x += iWidth; - } - else if( iFlags & DHN_DRAWZERO ) - { - SPR_Set(GetSprite(m_HUD_number_0), r, g, b ); - - // SPR_Draw 100's - if( iFlags & DHN_3DIGITS ) - { - x += iWidth; - } - - if( iFlags & (DHN_3DIGITS|DHN_2DIGITS)) x += iWidth; - SPR_DrawAdditive( 0, x, y, &GetSpriteRect(m_HUD_number_0)); - x += iWidth; - } - return x; -} - -int CHud::GetNumWidth( int iNumber, int iFlags ) -{ - if( iFlags & (DHN_3DIGITS)) return 3; - if( iFlags & (DHN_2DIGITS)) return 2; - - if( iNumber <= 0 ) - { - if( iFlags & (DHN_DRAWZERO)) - return 1; - else return 0; - } - - if( iNumber < 10 ) return 1; - if( iNumber < 100 ) return 2; - - return 3; - -} - -void CHud::AddHudElem( CHudBase *phudelem ) -{ - HUDLIST *pdl, *ptemp; - - if( !phudelem ) return; - - pdl = (HUDLIST *)malloc( sizeof( HUDLIST )); - if (!pdl) - return; - - memset(pdl, 0, sizeof(HUDLIST)); - pdl->p = phudelem; - - if( !m_pHudList ) - { - m_pHudList = pdl; - return; - } - - ptemp = m_pHudList; - - while( ptemp->pNext ) - ptemp = ptemp->pNext; - ptemp->pNext = pdl; -} \ No newline at end of file diff --git a/client/hud/hud_ammo.cpp b/client/hud/hud_ammo.cpp deleted file mode 100644 index f1a25595..00000000 --- a/client/hud/hud_ammo.cpp +++ /dev/null @@ -1,1299 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Ammo.cpp -// -// implementation of CHudAmmo class -// - -#include "extdll.h" -#include "utils.h" -#include "hud.h" -#include "hud_ammohistory.h" -#include "pm_shared.h" - -WEAPON *gpActiveSel; // NULL means off, 1 means just the menu bar, otherwise -WEAPON *gpLastSel; // Last weapon menu selection -client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iRes, int iCount ); -WeaponsResource gWR; -int g_weaponselect = 0; - -void WeaponsResource :: LoadAllWeaponSprites( void ) -{ - for( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( rgWeapons[i].iId ) LoadWeaponSprites( &rgWeapons[i] ); - } -} - -int WeaponsResource :: CountAmmo( int iId ) -{ - if ( iId < 0 ) - return 0; - - return riAmmo[iId]; -} - -int WeaponsResource :: HasAmmo( WEAPON *p ) -{ - if( !p ) - return FALSE; - - // weapons with no max ammo can always be selected - if( p->iMax1 == -1 ) - return TRUE; - - return (p->iAmmoType == -1) || p->iClip > 0 || CountAmmo(p->iAmmoType) - || CountAmmo(p->iAmmo2Type) || ( p->iFlags & WEAPON_FLAGS_SELECTONEMPTY ); -} - -void WeaponsResource :: LoadWeaponSprites( WEAPON *pWeapon ) -{ - int i, iRes; - - if (ScreenWidth < 640) - iRes = 320; - else - iRes = 640; - - char sz[128]; - - if ( !pWeapon ) - return; - - memset( &pWeapon->rcActive, 0, sizeof( wrect_t )); - memset( &pWeapon->rcInactive, 0, sizeof( wrect_t )); - memset( &pWeapon->rcAmmo, 0, sizeof( wrect_t )); - memset( &pWeapon->rcAmmo2, 0, sizeof( wrect_t )); - pWeapon->hInactive = 0; - pWeapon->hActive = 0; - pWeapon->hAmmo = 0; - pWeapon->hAmmo2 = 0; - - sprintf( sz, "sprites/%s.txt", pWeapon->szName ); - client_sprite_t *pList = SPR_GetList( sz, &i ); - - if( !pList ) return; - - client_sprite_t *p; - - p = GetSpriteList( pList, "crosshair", iRes, i ); - if( p ) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hCrosshair = SPR_Load(sz); - pWeapon->rcCrosshair = p->rc; - } - else pWeapon->hCrosshair = 0; - - p = GetSpriteList( pList, "autoaim", iRes, i ); - if( p ) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAutoaim = SPR_Load(sz); - pWeapon->rcAutoaim = p->rc; - } - else pWeapon->hAutoaim = 0; - - p = GetSpriteList( pList, "zoom", iRes, i ); - if( p ) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hZoomedCrosshair = SPR_Load(sz); - pWeapon->rcZoomedCrosshair = p->rc; - } - else - { - pWeapon->hZoomedCrosshair = pWeapon->hCrosshair; // default to non-zoomed crosshair - pWeapon->rcZoomedCrosshair = pWeapon->rcCrosshair; - } - - p = GetSpriteList( pList, "zoom_autoaim", iRes, i ); - if( p ) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hZoomedAutoaim = SPR_Load(sz); - pWeapon->rcZoomedAutoaim = p->rc; - } - else - { - pWeapon->hZoomedAutoaim = pWeapon->hZoomedCrosshair; // default to zoomed crosshair - pWeapon->rcZoomedAutoaim = pWeapon->rcZoomedCrosshair; - } - - p = GetSpriteList( pList, "weapon", iRes, i ); - if( p ) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hInactive = SPR_Load(sz); - pWeapon->rcInactive = p->rc; - gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); - } - else - { - pWeapon->hInactive = gHUD.m_hHudError; - pWeapon->rcInactive = gHUD.GetSpriteRect( gHUD.m_HUD_error ); - gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); - } - - p = GetSpriteList( pList, "weapon_s", iRes, i ); - if( p ) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hActive = SPR_Load(sz); - pWeapon->rcActive = p->rc; - } - else - { - pWeapon->hActive = gHUD.m_hHudError; - pWeapon->rcActive = gHUD.GetSpriteRect( gHUD.m_HUD_error ); - } - - p = GetSpriteList( pList, "ammo", iRes, i ); - if( p ) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAmmo = SPR_Load(sz); - pWeapon->rcAmmo = p->rc; - gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); - } - else pWeapon->hAmmo = 0; - - p = GetSpriteList( pList, "ammo2", iRes, i ); - if( p ) - { - sprintf(sz, "sprites/%s.spr", p->szSprite); - pWeapon->hAmmo2 = SPR_Load(sz); - pWeapon->rcAmmo2 = p->rc; - gHR.iHistoryGap = max( gHR.iHistoryGap, pWeapon->rcActive.bottom - pWeapon->rcActive.top ); - } - else pWeapon->hAmmo2 = 0; - - // release weapon file - gEngfuncs.COM_FreeFile( pList ); -} - -// Returns the first weapon for a given slot. -WEAPON *WeaponsResource :: GetFirstPos( int iSlot ) -{ - WEAPON *pret = NULL; - - for (int i = 0; i < MAX_WEAPON_POSITIONS; i++) - { - if( rgSlots[iSlot][i] && HasAmmo( rgSlots[iSlot][i] )) - { - pret = rgSlots[iSlot][i]; - break; - } - } - - return pret; -} - -WEAPON* WeaponsResource :: GetNextActivePos( int iSlot, int iSlotPos ) -{ - if ( iSlotPos >= MAX_WEAPON_POSITIONS || iSlot >= MAX_WEAPON_SLOTS ) - return NULL; - - WEAPON *p = gWR.rgSlots[ iSlot ][ iSlotPos+1 ]; - - if ( !p || !gWR.HasAmmo(p) ) - return GetNextActivePos( iSlot, iSlotPos + 1 ); - - return p; -} - -int giBucketHeight, giBucketWidth, giABHeight, giABWidth; // Ammo Bar width and height - -HSPRITE ghsprBuckets; // Sprite for top row of weapons menu - -DECLARE_MESSAGE( m_Ammo, CurWeapon ); // Current weapon and clip -DECLARE_MESSAGE( m_Ammo, WeaponList ); // new weapon type -DECLARE_MESSAGE( m_Ammo, AmmoX ); // update known ammo type's count -DECLARE_MESSAGE( m_Ammo, AmmoPickup ); // flashes an ammo pickup record -DECLARE_MESSAGE( m_Ammo, WeapPickup ); // flashes a weapon pickup record -DECLARE_MESSAGE( m_Ammo, HideWeapon ); // hides the weapon, ammo, and crosshair displays temporarily -DECLARE_MESSAGE( m_Ammo, ItemPickup ); -DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoVal ); -DECLARE_MESSAGE( m_AmmoSecondary, SecAmmoIcon ); - -DECLARE_COMMAND( m_Ammo, Slot1 ); -DECLARE_COMMAND( m_Ammo, Slot2 ); -DECLARE_COMMAND( m_Ammo, Slot3 ); -DECLARE_COMMAND( m_Ammo, Slot4 ); -DECLARE_COMMAND( m_Ammo, Slot5 ); -DECLARE_COMMAND( m_Ammo, Slot6 ); -DECLARE_COMMAND( m_Ammo, Slot7 ); -DECLARE_COMMAND( m_Ammo, Slot8 ); -DECLARE_COMMAND( m_Ammo, Slot9 ); -DECLARE_COMMAND( m_Ammo, Slot10 ); -DECLARE_COMMAND( m_Ammo, Close ); -DECLARE_COMMAND( m_Ammo, NextWeapon ); -DECLARE_COMMAND( m_Ammo, PrevWeapon ); - -// width of ammo fonts -#define AMMO_SMALL_WIDTH 10 -#define AMMO_LARGE_WIDTH 20 - -#define HISTORY_DRAW_TIME "5" - -int CHudAmmo::Init( void ) -{ - gHUD.AddHudElem(this); - - HOOK_MESSAGE( CurWeapon ); - HOOK_MESSAGE( WeaponList ); - HOOK_MESSAGE( AmmoPickup ); - HOOK_MESSAGE( WeapPickup ); - HOOK_MESSAGE( ItemPickup ); - HOOK_MESSAGE( HideWeapon ); - HOOK_MESSAGE( AmmoX ); - - HOOK_COMMAND( "slot1", Slot1 ); - HOOK_COMMAND( "slot2", Slot2 ); - HOOK_COMMAND( "slot3", Slot3 ); - HOOK_COMMAND( "slot4", Slot4 ); - HOOK_COMMAND( "slot5", Slot5 ); - HOOK_COMMAND( "slot6", Slot6 ); - HOOK_COMMAND( "slot7", Slot7 ); - HOOK_COMMAND( "slot8", Slot8 ); - HOOK_COMMAND( "slot9", Slot9 ); - HOOK_COMMAND( "slot10", Slot10 ); - HOOK_COMMAND( "cancelselect", Close ); - HOOK_COMMAND( "invnext", NextWeapon ); - HOOK_COMMAND( "invprev", PrevWeapon ); - - Reset(); - - CVAR_REGISTER( "hud_drawhistory_time", HISTORY_DRAW_TIME, 0 ); - CVAR_REGISTER( "hud_fastswitch", "0", FCVAR_ARCHIVE ); - - m_iFlags |= HUD_ACTIVE; //!!! - - gWR.Init(); - gHR.Init(); - - return 1; -} - -void CHudAmmo :: Reset( void ) -{ - m_fFade = 0; - m_iFlags |= HUD_ACTIVE; //!!! - - gpActiveSel = NULL; - - gHUD.m_iHideHUDDisplay = 0; - - gWR.Reset(); - gHR.Reset(); - - static wrect_t nullrc; - SetCrosshair( 0, nullrc, 0, 0, 0 ); // reset crosshair - m_pWeapon = NULL;// reset last weapon -} - -int CHudAmmo :: VidInit( void ) -{ - // Load sprites for buckets (top row of weapon menu) - m_HUD_bucket0 = gHUD.GetSpriteIndex( "bucket1" ); - m_HUD_selection = gHUD.GetSpriteIndex( "selection" ); - - ghsprBuckets = gHUD.GetSprite(m_HUD_bucket0); - giBucketWidth = gHUD.GetSpriteRect(m_HUD_bucket0).right - gHUD.GetSpriteRect(m_HUD_bucket0).left; - giBucketHeight = gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top; - - gHR.iHistoryGap = max( gHR.iHistoryGap, gHUD.GetSpriteRect(m_HUD_bucket0).bottom - gHUD.GetSpriteRect(m_HUD_bucket0).top); - - // If we've already loaded weapons, let's get new sprites - gWR.LoadAllWeaponSprites(); - - giABWidth = 20; - giABHeight = 4; - - return 1; -} - -// -// Think: -// Used for selection of weapon menu item. -// -void CHudAmmo :: Think( void ) -{ - if( gHUD.m_fPlayerDead ) - return; - - if( gHUD.m_iWeaponBits != gWR.iOldWeaponBits ) - { - gWR.iOldWeaponBits = gHUD.m_iWeaponBits; - - for (int i = MAX_WEAPONS-1; i > 0; i-- ) - { - WEAPON *p = gWR.GetWeapon(i); - - if( p ) - { - if( gHUD.m_iWeaponBits & ( 1 << p->iId )) - gWR.PickupWeapon( p ); - else gWR.DropWeapon( p ); - } - } - } - - if( gHUD.m_iFOV != gWR.iOldFOV ) - { - if( m_pWeapon ) - { - // update crosshairs - if( gHUD.m_iFOV >= 90 ) - { - // normal crosshairs - if( m_pWeapon->iOnTarget && m_pWeapon->hAutoaim ) - SetCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255 ); - else SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); - } - else - { - // zoomed crosshairs - if( m_pWeapon->iOnTarget && m_pWeapon->hZoomedAutoaim ) - SetCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255 ); - else SetCrosshair( m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255 ); - } - } - gWR.iOldFOV = gHUD.m_iFOV; - } - - if( !gpActiveSel ) return; - - // has the player selected one? - if( gHUD.m_iKeyBits & IN_ATTACK ) - { - if( gpActiveSel != (WEAPON *)1 ) - { - SERVER_COMMAND( gpActiveSel->szName ); - g_weaponselect = gpActiveSel->iId; - } - gpLastSel = gpActiveSel; - gpActiveSel = NULL; - gHUD.m_iKeyBits &= ~IN_ATTACK; - - PlaySound( "common/wpn_select.wav", 1.0f ); - } - -} - -// -// Helper function to return a Ammo pointer from id -// -HSPRITE* WeaponsResource :: GetAmmoPicFromWeapon( int iAmmoId, wrect_t& rect ) -{ - for ( int i = 0; i < MAX_WEAPONS; i++ ) - { - if ( rgWeapons[i].iAmmoType == iAmmoId ) - { - rect = rgWeapons[i].rcAmmo; - return &rgWeapons[i].hAmmo; - } - else if ( rgWeapons[i].iAmmo2Type == iAmmoId ) - { - rect = rgWeapons[i].rcAmmo2; - return &rgWeapons[i].hAmmo2; - } - } - - return NULL; -} - -// Menu Selection Code -void WeaponsResource :: SelectSlot( int iSlot, int fAdvance, int iDirection ) -{ - if( gHUD.m_Menu.m_fMenuDisplayed && (fAdvance == FALSE) && (iDirection == 1) ) - { - // menu is overriding slot use commands - gHUD.m_Menu.SelectMenuItem( iSlot + 1 ); // slots are one off the key numbers - return; - } - - if( iSlot > MAX_WEAPON_SLOTS ) - return; - - if( gHUD.m_fPlayerDead || gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS|HIDEHUD_ALL )) - return; - - if(!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)))) - return; - - if(!(gHUD.m_iWeaponBits & ~(1<<(WEAPON_SUIT)))) - return; - - WEAPON *p = NULL; - bool fastSwitch = CVAR_GET_FLOAT( "hud_fastswitch" ) != 0; - - if((gpActiveSel == NULL) || (gpActiveSel == (WEAPON *)1) || (iSlot != gpActiveSel->iSlot)) - { - PlaySound( "common/wpn_hudon.wav", 1.0f ); - p = GetFirstPos( iSlot ); - - if( p && fastSwitch ) // check for fast weapon switch mode - { - // if fast weapon switch is on, then weapons can be selected in a single keypress - // but only if there is only one item in the bucket - WEAPON *p2 = GetNextActivePos( p->iSlot, p->iSlotPos ); - if( !p2 ) - { - // only one active item in bucket, so change directly to weapon - SERVER_COMMAND( p->szName ); - g_weaponselect = p->iId; - return; - } - } - } - else - { - PlaySound( "common/wpn_moveselect.wav", 1.0f ); - if( gpActiveSel ) - p = GetNextActivePos( gpActiveSel->iSlot, gpActiveSel->iSlotPos ); - if( !p ) p = GetFirstPos( iSlot ); - } - - - if( !p ) // no selection found - { - // just display the weapon list, unless fastswitch is on just ignore it - if( !fastSwitch ) - gpActiveSel = (WEAPON *)1; - else gpActiveSel = NULL; - } - else gpActiveSel = p; -} - -//------------------------------------------------------------------------ -// Message Handlers -//------------------------------------------------------------------------ - -// -// AmmoX -- Update the count of a known type of ammo -// -int CHudAmmo::MsgFunc_AmmoX(const char *pszName, int iSize, void *pbuf) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - int iIndex = READ_BYTE(); - int iCount = READ_BYTE(); - - gWR.SetAmmo( iIndex, abs(iCount) ); - - return 1; -} - -int CHudAmmo::MsgFunc_AmmoPickup( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - int iIndex = READ_BYTE(); - int iCount = READ_BYTE(); - - // Add ammo to the history - gHR.AddToHistory( HISTSLOT_AMMO, iIndex, abs(iCount) ); - - END_READ(); - return 1; -} - -int CHudAmmo::MsgFunc_WeapPickup( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - int iIndex = READ_BYTE(); - - // Add the weapon to the history - gHR.AddToHistory( HISTSLOT_WEAP, iIndex ); - - END_READ(); - return 1; -} - -int CHudAmmo::MsgFunc_ItemPickup( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - const char *szName = READ_STRING(); - - // Add the weapon to the history - gHR.AddToHistory( HISTSLOT_ITEM, szName ); - - END_READ(); - return 1; -} - - -int CHudAmmo::MsgFunc_HideWeapon( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - gHUD.m_iHideHUDDisplay = READ_BYTE(); - - if ( IsSpectateOnly()) - return 1; - - if((m_pWeapon == NULL) || (gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ))) - { - static wrect_t nullrc; - gpActiveSel = NULL; - SetCrosshair( 0, nullrc, 0, 0, 0 ); - } - else - { - SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); - } - - END_READ(); - return 1; -} - -// -// CurWeapon: Update hud state with the current weapon and clip count. Ammo -// counts are updated with AmmoX. Server assures that the Weapon ammo type -// numbers match a real ammo type. -// -int CHudAmmo::MsgFunc_CurWeapon( const char *pszName, int iSize, void *pbuf ) -{ - static wrect_t nullrc; - int fOnTarget = FALSE; - - BEGIN_READ( pszName, iSize, pbuf ); - - int iState = READ_BYTE(); - int iId = READ_CHAR(); - int iClip = READ_CHAR(); - - // detect if we're also on target - if( iState > 1 ) - { - fOnTarget = TRUE; - } - - if( iId < 1 ) - { - SetCrosshair(0, nullrc, 0, 0, 0); - m_pWeapon = NULL; - return 0; - } - - // Is player dead??? - if((iId == -1) && (iClip == -1)) - { - gHUD.m_fPlayerDead = TRUE; - gpActiveSel = NULL; - return 1; - } - - gHUD.m_fPlayerDead = FALSE; - WEAPON *pWeapon = gWR.GetWeapon( iId ); - - if( !pWeapon ) - return 0; - - if( iClip < -1 ) - pWeapon->iClip = abs( iClip ); - else pWeapon->iClip = iClip; - - - if( iState == 0 ) // we're not the current weapon, so update no more - return 1; - - m_pWeapon = pWeapon; - m_pWeapon->iOnTarget = fOnTarget; - - // update crosshairs - if( gHUD.m_iFOV >= 90 ) - { - // normal crosshairs - if( m_pWeapon->iOnTarget && m_pWeapon->hAutoaim ) - SetCrosshair(m_pWeapon->hAutoaim, m_pWeapon->rcAutoaim, 255, 255, 255 ); - else SetCrosshair( m_pWeapon->hCrosshair, m_pWeapon->rcCrosshair, 255, 255, 255 ); - } - else - { // zoomed crosshairs - if( m_pWeapon->iOnTarget && m_pWeapon->hZoomedAutoaim ) - SetCrosshair(m_pWeapon->hZoomedAutoaim, m_pWeapon->rcZoomedAutoaim, 255, 255, 255 ); - else SetCrosshair( m_pWeapon->hZoomedCrosshair, m_pWeapon->rcZoomedCrosshair, 255, 255, 255 ); - } - - m_fFade = 200.0f; //!!! - m_iFlags |= HUD_ACTIVE; - - END_READ(); - return 1; -} - -// -// WeaponList -- Tells the hud about a new weapon type. -// -int CHudAmmo::MsgFunc_WeaponList( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - WEAPON Weapon; - - strcpy( Weapon.szName, READ_STRING() ); - Weapon.iAmmoType = (int)READ_CHAR(); - - Weapon.iMax1 = READ_BYTE(); - if( Weapon.iMax1 == 255 ) - Weapon.iMax1 = -1; - - Weapon.iAmmo2Type = READ_CHAR(); - Weapon.iMax2 = READ_BYTE(); - if( Weapon.iMax2 == 255 ) - Weapon.iMax2 = -1; - - Weapon.iSlot = READ_CHAR(); - Weapon.iSlotPos = READ_CHAR(); - Weapon.iId = READ_CHAR(); - Weapon.iFlags = READ_BYTE(); - Weapon.iClip = 0; - - gWR.AddWeapon( &Weapon ); - - END_READ(); - return 1; - -} - -//------------------------------------------------------------------------ -// Command Handlers -//------------------------------------------------------------------------ -// Slot button pressed -void CHudAmmo::SlotInput( int iSlot ) -{ - gWR.SelectSlot( iSlot, FALSE, 1 ); -} - -void CHudAmmo::UserCmd_Slot1( void ) -{ - SlotInput( 0 ); -} - -void CHudAmmo::UserCmd_Slot2( void ) -{ - SlotInput( 1 ); -} - -void CHudAmmo::UserCmd_Slot3( void ) -{ - SlotInput( 2 ); -} - -void CHudAmmo::UserCmd_Slot4( void ) -{ - SlotInput( 3 ); -} - -void CHudAmmo::UserCmd_Slot5( void ) -{ - SlotInput( 4 ); -} - -void CHudAmmo::UserCmd_Slot6( void ) -{ - SlotInput( 5 ); -} - -void CHudAmmo::UserCmd_Slot7( void ) -{ - SlotInput( 6 ); -} - -void CHudAmmo::UserCmd_Slot8( void ) -{ - SlotInput( 7 ); -} - -void CHudAmmo::UserCmd_Slot9( void ) -{ - SlotInput( 8 ); -} - -void CHudAmmo::UserCmd_Slot10( void ) -{ - SlotInput( 9 ); -} - -void CHudAmmo::UserCmd_Close( void ) -{ - if( gpActiveSel ) - { - gpLastSel = gpActiveSel; - gpActiveSel = NULL; - PlaySound( "common/wpn_hudoff.wav", 1.0f ); - } - else CLIENT_COMMAND( "escape\n" ); -} - - -// Selects the next item in the weapon menu -void CHudAmmo::UserCmd_NextWeapon( void ) -{ - if( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS|HIDEHUD_ALL))) - return; - - if( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) - gpActiveSel = m_pWeapon; - - int pos = 0; - int slot = 0; - if( gpActiveSel ) - { - pos = gpActiveSel->iSlotPos + 1; - slot = gpActiveSel->iSlot; - } - - for( int loop = 0; loop <= 1; loop++ ) - { - for( ; slot < MAX_WEAPON_SLOTS; slot++ ) - { - for( ; pos < MAX_WEAPON_POSITIONS; pos++ ) - { - WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); - - if( wsp && gWR.HasAmmo( wsp )) - { - gpActiveSel = wsp; - return; - } - } - pos = 0; - } - slot = 0; // start looking from the first slot again - } - gpActiveSel = NULL; -} - -// Selects the previous item in the menu -void CHudAmmo :: UserCmd_PrevWeapon( void ) -{ - if( gHUD.m_fPlayerDead || (gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS|HIDEHUD_ALL))) - return; - - if( !gpActiveSel || gpActiveSel == (WEAPON*)1 ) - gpActiveSel = m_pWeapon; - - int pos = MAX_WEAPON_POSITIONS-1; - int slot = MAX_WEAPON_SLOTS-1; - if( gpActiveSel ) - { - pos = gpActiveSel->iSlotPos - 1; - slot = gpActiveSel->iSlot; - } - - for( int loop = 0; loop <= 1; loop++ ) - { - for( ; slot >= 0; slot-- ) - { - for( ; pos >= 0; pos-- ) - { - WEAPON *wsp = gWR.GetWeaponSlot( slot, pos ); - - if( wsp && gWR.HasAmmo( wsp )) - { - gpActiveSel = wsp; - return; - } - } - pos = MAX_WEAPON_POSITIONS-1; - } - slot = MAX_WEAPON_SLOTS-1; - } - gpActiveSel = NULL; -} - - - -//------------------------------------------------------------------------- -// Drawing code -//------------------------------------------------------------------------- - -int CHudAmmo::Draw( float flTime ) -{ - int a, x, y, r, g, b; - int AmmoWidth; - - if(!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)))) - return 1; - - if((gHUD.m_iHideHUDDisplay & (HIDEHUD_WEAPONS|HIDEHUD_ALL))) - return 1; - - // Draw Weapon Menu - DrawWList( flTime ); - - // Draw ammo pickup history - gHR.DrawAmmoHistory( flTime ); - - if(!( m_iFlags & HUD_ACTIVE )) - return 0; - - if( !m_pWeapon ) - { - return 0; - } - - WEAPON *pw = m_pWeapon; // shorthand - - // SPR_Draw Ammo - if((pw->iAmmoType < 0) && (pw->iAmmo2Type < 0)) - return 0; - - - int iFlags = DHN_DRAWZERO; // draw 0 values - - AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - - a = (int) max( MIN_ALPHA, m_fFade ); - - if( m_fFade > 0 ) - m_fFade -= (gHUD.m_flTimeDelta * 20); - - UnpackRGB( r,g,b, gHUD.m_iHUDColor ); - - ScaleColors(r, g, b, a ); - - // Does this weapon have a clip? - y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - - // Does weapon have any ammo at all? - if( m_pWeapon->iAmmoType > 0 ) - { - int iIconWidth = m_pWeapon->rcAmmo.right - m_pWeapon->rcAmmo.left; - - if( pw->iClip >= 0 ) - { - // room for the number and the '|' and the current ammo - - x = ScreenWidth - (8 * AmmoWidth) - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, pw->iClip, r, g, b ); - - wrect_t rc; - rc.top = 0; - rc.left = 0; - rc.right = AmmoWidth; - rc.bottom = 100; - - int iBarWidth = AmmoWidth/10; - - x += AmmoWidth/2; - - UnpackRGB(r,g,b, gHUD.m_iHUDColor); - - // draw the | bar - FillRGBA( x, y, iBarWidth, gHUD.m_iFontHeight, r, g, b, a ); - - x += iBarWidth + AmmoWidth / 2; - - // GL Seems to need this - ScaleColors( r, g, b, a ); - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); - } - else - { - // SPR_Draw a bullets only line - x = ScreenWidth - 4 * AmmoWidth - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags | DHN_3DIGITS, gWR.CountAmmo(pw->iAmmoType), r, g, b); - } - - // Draw the ammo Icon - int iOffset = (m_pWeapon->rcAmmo.bottom - m_pWeapon->rcAmmo.top) / 8; - SPR_Set( m_pWeapon->hAmmo, r, g, b ); - SPR_DrawAdditive( 0, x, y - iOffset, &m_pWeapon->rcAmmo ); - } - - // Does weapon have secondary ammo? - if( pw->iAmmo2Type > 0 ) - { - int iIconWidth = m_pWeapon->rcAmmo2.right - m_pWeapon->rcAmmo2.left; - - // Do we have secondary ammo? - if((pw->iAmmo2Type != 0) && (gWR.CountAmmo(pw->iAmmo2Type) > 0)) - { - y -= gHUD.m_iFontHeight + gHUD.m_iFontHeight/4; - x = ScreenWidth - 4 * AmmoWidth - iIconWidth; - x = gHUD.DrawHudNumber(x, y, iFlags|DHN_3DIGITS, gWR.CountAmmo(pw->iAmmo2Type), r, g, b); - - // Draw the ammo Icon - SPR_Set(m_pWeapon->hAmmo2, r, g, b); - int iOffset = (m_pWeapon->rcAmmo2.bottom - m_pWeapon->rcAmmo2.top)/8; - SPR_DrawAdditive(0, x, y - iOffset, &m_pWeapon->rcAmmo2); - } - } - return 1; -} - - -// -// Draws the ammo bar on the hud -// -int DrawBar( int x, int y, int width, int height, float f ) -{ - int r, g, b; - - if( f < 0 ) f = 0; - if( f > 1 ) f = 1; - - if( f ) - { - int w = f * width; - - // Always show at least one pixel if we have ammo. - if( w <= 0 ) w = 1; - UnpackRGB( r, g, b, RGB_GREENISH ); - FillRGBA( x, y, w, height, r, g, b, 255 ); - x += w; - width -= w; - } - - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - - FillRGBA( x, y, width, height, r, g, b, 128 ); - return (x + width); -} - -void DrawAmmoBar( WEAPON *p, int x, int y, int width, int height ) -{ - if( !p ) return; - - if( p->iAmmoType != -1 ) - { - if( !gWR.CountAmmo( p->iAmmoType )) - return; - - float f = (float)gWR.CountAmmo(p->iAmmoType)/(float)p->iMax1; - - x = DrawBar(x, y, width, height, f); - - // Do we have secondary ammo too? - if( p->iAmmo2Type != -1 ) - { - f = (float)gWR.CountAmmo(p->iAmmo2Type) / (float)p->iMax2; - - x += 5; //!!! - DrawBar( x, y, width, height, f ); - } - } -} - -// -// Draw Weapon Menu -// -int CHudAmmo::DrawWList( float flTime ) -{ - int r,g,b,x,y,a,i; - - if( !gpActiveSel ) - return 0; - - int iActiveSlot; - - if( gpActiveSel == (WEAPON *)1 ) - iActiveSlot = -1; // current slot has no weapons - else iActiveSlot = gpActiveSel->iSlot; - - x = 10; //!!! - y = 10; //!!! - - - // Ensure that there are available choices in the active slot - if( iActiveSlot > 0 ) - { - if( !gWR.GetFirstPos( iActiveSlot ) ) - { - gpActiveSel = (WEAPON *)1; - iActiveSlot = -1; - } - } - - // Draw top line - for( i = 0; i < MAX_WEAPON_SLOTS; i++ ) - { - int iWidth; - - UnpackRGB( r,g,b, gHUD.m_iHUDColor ); - - if( iActiveSlot == i ) - a = 255; - else a = 192; // not used ??? - - ScaleColors( r, g, b, 255 ); - SPR_Set( gHUD.GetSprite( m_HUD_bucket0 + i ), r, g, b ); - - // make active slot wide enough to accomodate gun pictures - if( i == iActiveSlot ) - { - WEAPON *p = gWR.GetFirstPos(iActiveSlot); - if ( p ) - iWidth = p->rcActive.right - p->rcActive.left; - else iWidth = giBucketWidth; - } - else iWidth = giBucketWidth; - - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_bucket0 + i)); - - x += iWidth + 5; - } - - - a = 128; //!!! - x = 10; - - // Draw all of the buckets - for( i = 0; i < MAX_WEAPON_SLOTS; i++ ) - { - y = giBucketHeight + 10; - - // If this is the active slot, draw the bigger pictures, - // otherwise just draw boxes - if( i == iActiveSlot ) - { - WEAPON *p = gWR.GetFirstPos( i ); - int iWidth = giBucketWidth; - if( p ) iWidth = p->rcActive.right - p->rcActive.left; - - for( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) - { - p = gWR.GetWeaponSlot( i, iPos ); - - if( !p || !p->iId ) - continue; - - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - - // if active, then we must have ammo. - if( gpActiveSel == p ) - { - SPR_Set( p->hActive, r, g, b ); - SPR_DrawAdditive( 0, x, y, &p->rcActive ); - - SPR_Set( gHUD.GetSprite(m_HUD_selection), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( m_HUD_selection )); - } - else - { - // Draw Weapon if Red if no ammo - - if( gWR.HasAmmo( p )) - ScaleColors( r, g, b, 192 ); - else - { - UnpackRGB( r, g, b, RGB_REDISH ); - ScaleColors( r, g, b, 128 ); - } - - SPR_Set( p->hInactive, r, g, b ); - SPR_DrawAdditive( 0, x, y, &p->rcInactive ); - } - - // Draw Ammo Bar - DrawAmmoBar( p, x + giABWidth/2, y, giABWidth, giABHeight ); - y += p->rcActive.bottom - p->rcActive.top + 5; - } - - x += iWidth + 5; - } - else - { - // Draw Row of weapons. - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - - for( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ ) - { - WEAPON *p = gWR.GetWeaponSlot( i, iPos ); - - if( !p || !p->iId ) - continue; - - if( gWR.HasAmmo(p) ) - { - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - a = 128; - } - else - { - UnpackRGB( r, g, b, RGB_REDISH ); - a = 96; - } - - FillRGBA( x, y, giBucketWidth, giBucketHeight, r, g, b, a ); - y += giBucketHeight + 5; - } - x += giBucketWidth + 5; - } - } - - return 1; -} - -int CHudAmmoSecondary :: Init( void ) -{ - HOOK_MESSAGE( SecAmmoVal ); - HOOK_MESSAGE( SecAmmoIcon ); - - gHUD.AddHudElem( this ); - m_HUD_ammoicon = 0; - - for( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) - m_iAmmoAmounts[i] = -1; // -1 means don't draw this value - Reset(); - - return 1; -} - -void CHudAmmoSecondary :: Reset( void ) -{ - m_fFade = 0; -} - -int CHudAmmoSecondary :: VidInit( void ) -{ - return 1; -} - -int CHudAmmoSecondary :: Draw( float flTime ) -{ - if(( gHUD.m_iHideHUDDisplay & ( HIDEHUD_WEAPONS | HIDEHUD_ALL ))) - return 1; - - // draw secondary ammo icons above normal ammo readout - int a, x, y, r, g, b, AmmoWidth; - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - a = (int) max( MIN_ALPHA, m_fFade ); - if( m_fFade > 0 ) - m_fFade -= (gHUD.m_flTimeDelta * 20); // slowly lower alpha to fade out icons - ScaleColors( r, g, b, a ); - - AmmoWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - - y = ScreenHeight - (gHUD.m_iFontHeight*4); // this is one font height higher than the weapon ammo values - x = ScreenWidth - AmmoWidth; - - if( m_HUD_ammoicon ) - { - // Draw the ammo icon - x -= (gHUD.GetSpriteRect(m_HUD_ammoicon).right - gHUD.GetSpriteRect(m_HUD_ammoicon).left); - y -= (gHUD.GetSpriteRect(m_HUD_ammoicon).top - gHUD.GetSpriteRect(m_HUD_ammoicon).bottom); - - SPR_Set( gHUD.GetSprite(m_HUD_ammoicon), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect(m_HUD_ammoicon) ); - } - else - { - // move the cursor by the '0' char instead, since we don't have an icon to work with - x -= AmmoWidth; - y -= (gHUD.GetSpriteRect(gHUD.m_HUD_number_0).top - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).bottom); - } - - // draw the ammo counts, in reverse order, from right to left - for( int i = MAX_SEC_AMMO_VALUES-1; i >= 0; i-- ) - { - if( m_iAmmoAmounts[i] < 0 ) - continue; // negative ammo amounts imply that they shouldn't be drawn - - // half a char gap between the ammo number and the previous pic - x -= (AmmoWidth / 2); - - // draw the number, right-aligned - x -= (gHUD.GetNumWidth( m_iAmmoAmounts[i], DHN_DRAWZERO ) * AmmoWidth); - gHUD.DrawHudNumber( x, y, DHN_DRAWZERO, m_iAmmoAmounts[i], r, g, b ); - - if ( i != 0 ) - { - // draw the divider bar - x -= (AmmoWidth / 2); - FillRGBA(x, y, (AmmoWidth/10), gHUD.m_iFontHeight, r, g, b, a); - } - } - return 1; -} - -// Message handler for Secondary Ammo Value -// accepts one value: -// string: sprite name -int CHudAmmoSecondary :: MsgFunc_SecAmmoIcon( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - m_HUD_ammoicon = gHUD.GetSpriteIndex( READ_STRING() ); - - END_READ(); - return 1; -} - -// Message handler for Secondary Ammo Icon -// Sets an ammo value -// takes two values: -// byte: ammo index -// byte: ammo value -int CHudAmmoSecondary :: MsgFunc_SecAmmoVal( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - int index = READ_BYTE(); - if( index < 0 || index >= MAX_SEC_AMMO_VALUES ) - return 1; - - m_iAmmoAmounts[index] = READ_BYTE(); - m_iFlags |= HUD_ACTIVE; - - // check to see if there is anything left to draw - int count = 0; - for( int i = 0; i < MAX_SEC_AMMO_VALUES; i++ ) - { - count += max( 0, m_iAmmoAmounts[i] ); - } - - if( count == 0 ) - { - // the ammo fields are all empty, so turn off this hud area - m_iFlags &= ~HUD_ACTIVE; - return 1; - } - - // make the icons light up - m_fFade = 200.0f; - END_READ(); - - return 1; -} - -/* -================================= - GetSpriteList - -Finds and returns the matching -sprite name 'psz' in the given sprite list 'pList' -iCount is the number of items in the pList -================================= -*/ -client_sprite_t *GetSpriteList( client_sprite_t *pList, const char *psz, int iRes, int iCount ) -{ - if( !pList ) return NULL; - - int i = iCount; - client_sprite_t *p = pList; - - while( i-- ) - { - if ((!strcmp(psz, p->szName)) && (p->iRes == iRes)) - return p; - p++; - } - return NULL; -} \ No newline at end of file diff --git a/client/hud/hud_death.cpp b/client/hud/hud_death.cpp deleted file mode 100644 index c37ae6eb..00000000 --- a/client/hud/hud_death.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// death notice -// -#include "extdll.h" -#include "utils.h" -#include "hud.h" - -DECLARE_MESSAGE( m_DeathNotice, DeathMsg ); - -struct DeathNoticeItem -{ - char szKiller[MAX_PLAYER_NAME_LENGTH*2]; - char szVictim[MAX_PLAYER_NAME_LENGTH*2]; - int iId; // the index number of the associated sprite - int iSuicide; - int iTeamKill; - int iNonPlayerKill; - float flDisplayTime; -}; - -#define MAX_DEATHNOTICES 4 -static int DEATHNOTICE_DISPLAY_TIME = 6; - -#define DEATHNOTICE_TOP 32 - -DeathNoticeItem rgDeathNoticeList[ MAX_DEATHNOTICES + 1 ]; - - -int CHudDeathNotice :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( DeathMsg ); - - CVAR_REGISTER( "hud_deathnotice_time", "6", 0 ); - - return 1; -} - - -void CHudDeathNotice :: InitHUDData( void ) -{ - memset( rgDeathNoticeList, 0, sizeof( rgDeathNoticeList )); -} - - -int CHudDeathNotice :: VidInit( void ) -{ - m_HUD_d_skull = gHUD.GetSpriteIndex( "d_skull" ); - - return 1; -} - -int CHudDeathNotice :: Draw( float flTime ) -{ - int x, y, r, g, b; - - for( int i = 0; i < MAX_DEATHNOTICES; i++ ) - { - if( rgDeathNoticeList[i].iId == 0 ) - break; // we've gone through them all - - if( rgDeathNoticeList[i].flDisplayTime < flTime ) - { - // display time has expired - // remove the current item from the list - memmove( &rgDeathNoticeList[i], &rgDeathNoticeList[i+1], sizeof(DeathNoticeItem) * (MAX_DEATHNOTICES - i)); - i--; // continue on the next item; stop the counter getting incremented - continue; - } - - rgDeathNoticeList[i].flDisplayTime = min( rgDeathNoticeList[i].flDisplayTime, gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME ); - - // Draw the death notice - - y = YRES( DEATHNOTICE_TOP ) + 2 + (20 * i); //!!! - - int id = (rgDeathNoticeList[i].iId == -1) ? m_HUD_d_skull : rgDeathNoticeList[i].iId; - x = ScreenWidth - ConsoleStringLen(rgDeathNoticeList[i].szVictim) - (gHUD.GetSpriteRect(id).right - gHUD.GetSpriteRect(id).left); - - if ( !rgDeathNoticeList[i].iSuicide ) - { - x -= (5 + ConsoleStringLen( rgDeathNoticeList[i].szKiller ) ); - - // Draw killers name - x = 5 + DrawConsoleString( x, y, rgDeathNoticeList[i].szKiller ); - } - - r = 255; g = 80; b = 0; - if ( rgDeathNoticeList[i].iTeamKill ) - { - r = 10; g = 240; b = 10; // display it in sickly green - } - - // Draw death weapon - SPR_Set( gHUD.GetSprite(id), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( id )); - - x += (gHUD.GetSpriteRect( id ).right - gHUD.GetSpriteRect( id ).left ); - - // Draw victims name (if it was a player that was killed) - if ( rgDeathNoticeList[i].iNonPlayerKill == FALSE ) - { - x = DrawConsoleString( x, y, rgDeathNoticeList[i].szVictim ); - } - } - return 1; -} - -// This message handler may be better off elsewhere -int CHudDeathNotice :: MsgFunc_DeathMsg( const char *pszName, int iSize, void *pbuf ) -{ - m_iFlags |= HUD_ACTIVE; - - BEGIN_READ( pszName, iSize, pbuf ); - - int killer = READ_BYTE(); - int victim = READ_BYTE(); - - char killedwith[32]; - strcpy( killedwith, "d_" ); - strncat( killedwith, READ_STRING(), 32 ); - - gHUD.m_Scoreboard.DeathMsg( killer, victim ); - - for ( int i = 0; i < MAX_DEATHNOTICES; i++ ) - { - if ( rgDeathNoticeList[i].iId == 0 ) - break; - } - if ( i == MAX_DEATHNOTICES ) - { - // move the rest of the list forward to make room for this item - memmove( rgDeathNoticeList, rgDeathNoticeList+1, sizeof( DeathNoticeItem ) * MAX_DEATHNOTICES ); - i = MAX_DEATHNOTICES - 1; - } - - gHUD.m_Scoreboard.GetAllPlayersInfo(); - - char *killer_name = gHUD.m_Scoreboard.m_PlayerInfoList[ killer ].name; - char *victim_name = gHUD.m_Scoreboard.m_PlayerInfoList[ victim ].name; - if( !killer_name ) killer_name = ""; - if( !victim_name ) victim_name = ""; - - strncpy( rgDeathNoticeList[i].szKiller, killer_name, MAX_PLAYER_NAME_LENGTH ); - strncpy( rgDeathNoticeList[i].szVictim, victim_name, MAX_PLAYER_NAME_LENGTH ); - - // Is it a non-player object kill? - if ( ((char)victim) == -1 ) - { - rgDeathNoticeList[i].iNonPlayerKill = TRUE; - - // Store the object's name in the Victim slot (skip the d_ bit) - strcpy( rgDeathNoticeList[i].szVictim, killedwith+2 ); - } - else - { - if( killer == victim || killer == 0 ) - rgDeathNoticeList[i].iSuicide = TRUE; - - if( !strcmp( killedwith, "d_teammate" ) ) - rgDeathNoticeList[i].iTeamKill = TRUE; - } - - // Find the sprite in the list - int spr = gHUD.GetSpriteIndex( killedwith ); - - rgDeathNoticeList[i].iId = spr; - - DEATHNOTICE_DISPLAY_TIME = CVAR_GET_FLOAT( "hud_deathnotice_time" ); - rgDeathNoticeList[i].flDisplayTime = gHUD.m_flTime + DEATHNOTICE_DISPLAY_TIME; - - if( rgDeathNoticeList[i].iNonPlayerKill ) - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed a " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - ConsolePrint( "\n" ); - } - else - { - // record the death notice in the console - if ( rgDeathNoticeList[i].iSuicide ) - { - ConsolePrint( rgDeathNoticeList[i].szVictim ); - - if ( !strcmp( killedwith, "d_world" ) ) - { - ConsolePrint( " died" ); - } - else - { - ConsolePrint( " killed self" ); - } - } - else if ( rgDeathNoticeList[i].iTeamKill ) - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed his teammate " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - } - else - { - ConsolePrint( rgDeathNoticeList[i].szKiller ); - ConsolePrint( " killed " ); - ConsolePrint( rgDeathNoticeList[i].szVictim ); - } - - if ( killedwith && *killedwith && (*killedwith > 13 ) && strcmp( killedwith, "d_world" ) && !rgDeathNoticeList[i].iTeamKill ) - { - ConsolePrint( " with " ); - - // replace the code names with the 'real' names - if( !strcmp( killedwith+2, "egon" ) ) - strcpy( killedwith, "d_gluon gun" ); - if( !strcmp( killedwith+2, "gauss" ) ) - strcpy( killedwith, "d_tau cannon" ); - - ConsolePrint( killedwith+2 ); // skip over the "d_" part - } - ConsolePrint( "\n" ); - } - return 1; -} \ No newline at end of file diff --git a/client/hud/hud_flashlight.cpp b/client/hud/hud_flashlight.cpp deleted file mode 100644 index 2b12c105..00000000 --- a/client/hud/hud_flashlight.cpp +++ /dev/null @@ -1,140 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// flashlight.cpp -// -// implementation of CHudFlashlight class -// - -#include "extdll.h" -#include "utils.h" -#include "hud.h" - -DECLARE_MESSAGE( m_Flash, FlashBat ) -DECLARE_MESSAGE( m_Flash, Flashlight ) - -int CHudFlashlight :: Init( void ) -{ - m_fFade = 0; - m_fOn = 0; - - HOOK_MESSAGE( Flashlight ); - HOOK_MESSAGE( FlashBat ); - - m_iFlags |= HUD_ACTIVE; - - gHUD.AddHudElem( this ); - - return 1; -} - -void CHudFlashlight :: Reset( void ) -{ - m_fFade = 0; - m_fOn = 0; -} - -int CHudFlashlight :: VidInit( void ) -{ - int HUD_flash_empty = gHUD.GetSpriteIndex( "flash_empty" ); - int HUD_flash_full = gHUD.GetSpriteIndex( "flash_full" ); - int HUD_flash_beam = gHUD.GetSpriteIndex( "flash_beam" ); - - m_hSprite1 = gHUD.GetSprite( HUD_flash_empty ); - m_hSprite2 = gHUD.GetSprite( HUD_flash_full ); - m_hBeam = gHUD.GetSprite( HUD_flash_beam ); - m_prc1 = &gHUD.GetSpriteRect( HUD_flash_empty ); - m_prc2 = &gHUD.GetSpriteRect( HUD_flash_full ); - m_prcBeam = &gHUD.GetSpriteRect( HUD_flash_beam ); - m_iWidth = m_prc2->right - m_prc2->left; - return 1; -} - -int CHudFlashlight:: MsgFunc_FlashBat(const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - int x = READ_BYTE(); - m_iBat = x; - m_flBat = ((float)x) / 100.0; - - END_READ(); - return 1; -} - -int CHudFlashlight :: MsgFunc_Flashlight( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - m_fOn = READ_BYTE(); - int x = READ_BYTE(); - m_iBat = x; - m_flBat = ((float)x) / 100.0; - - END_READ(); - return 1; -} - -int CHudFlashlight :: Draw( float flTime ) -{ - if(gHUD.m_iHideHUDDisplay & (HIDEHUD_FLASHLIGHT|HIDEHUD_ALL)) - return 1; - - int r, g, b, x, y, a; - wrect_t rc; - - if(!(gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)))) - return 1; - - if( m_fOn ) - a = 225; - else a = MIN_ALPHA; - - if( m_flBat < 0.20 ) - UnpackRGB( r, g, b, RGB_REDISH ); - else UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - - ScaleColors( r, g, b, a ); - - y = (m_prc1->bottom - m_prc2->top) / 2; - x = ScreenWidth - m_iWidth - m_iWidth / 2; - - // draw the flashlight casing - SPR_Set( m_hSprite1, r, g, b ); - SPR_DrawAdditive( 0, x, y, m_prc1 ); - - if( m_fOn ) - { - // draw the flashlight beam - x = ScreenWidth - m_iWidth / 2; - - SPR_Set( m_hBeam, r, g, b ); - SPR_DrawAdditive( 0, x, y, m_prcBeam ); - } - - // draw the flashlight energy level - x = ScreenWidth - m_iWidth - m_iWidth / 2; - int iOffset = m_iWidth * (1.0 - m_flBat); - - if( iOffset < m_iWidth ) - { - rc = *m_prc2; - rc.left += iOffset; - - SPR_Set( m_hSprite2, r, g, b ); - SPR_DrawAdditive( 0, x + iOffset, y, &rc ); - } - return 1; -} diff --git a/client/hud/hud_geiger.cpp b/client/hud/hud_geiger.cpp deleted file mode 100644 index 4ddbae1b..00000000 --- a/client/hud/hud_geiger.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Geiger.cpp -// -// implementation of CHudAmmo class -// - -#include "extdll.h" -#include "utils.h" -#include "hud.h" - -DECLARE_MESSAGE( m_Geiger, Geiger ) - -int CHudGeiger::Init( void ) -{ - HOOK_MESSAGE( Geiger ); - - m_iGeigerRange = 0; - m_iFlags = 0; - - gHUD.AddHudElem( this ); - - return 1; -} - -int CHudGeiger::VidInit( void ) -{ - return 1; -} - -int CHudGeiger::MsgFunc_Geiger( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - // update geiger data - m_iGeigerRange = READ_BYTE(); - m_iGeigerRange = m_iGeigerRange << 2; - - m_iFlags |= HUD_ACTIVE; - - END_READ(); - - return 1; -} - -int CHudGeiger::Draw( float flTime ) -{ - int pct; - float flvol; - int rg[3]; - int i; - - if( m_iGeigerRange < 1000 && m_iGeigerRange > 0 ) - { - // peicewise linear is better than continuous formula for this - if( m_iGeigerRange > 800 ) - { - pct = 0; //gEngfuncs.Con_Printf( "range > 800\n" ); - } - else if( m_iGeigerRange > 600 ) - { - pct = 2; - flvol = 0.4; //gEngfuncs.Con_Printf( "range > 600\n" ); - rg[0] = 1; - rg[1] = 1; - i = 2; - } - else if( m_iGeigerRange > 500 ) - { - pct = 4; - flvol = 0.5; //gEngfuncs.Con_Printf( "range > 500\n" ); - rg[0] = 1; - rg[1] = 2; - i = 2; - } - else if( m_iGeigerRange > 400 ) - { - pct = 8; - flvol = 0.6; //gEngfuncs.Con_Printf( "range > 400\n" ); - rg[0] = 1; - rg[1] = 2; - rg[2] = 3; - i = 3; - } - else if( m_iGeigerRange > 300 ) - { - pct = 8; - flvol = 0.7; //gEngfuncs.Con_Printf( "range > 300\n" ); - rg[0] = 2; - rg[1] = 3; - rg[2] = 4; - i = 3; - } - else if( m_iGeigerRange > 200 ) - { - pct = 28; - flvol = 0.78; //gEngfuncs.Con_Printf( "range > 200\n" ); - rg[0] = 2; - rg[1] = 3; - rg[2] = 4; - i = 3; - } - else if( m_iGeigerRange > 150 ) - { - pct = 40; - flvol = 0.80; //gEngfuncs.Con_Printf( "range > 150\n" ); - rg[0] = 3; - rg[1] = 4; - rg[2] = 5; - i = 3; - } - else if( m_iGeigerRange > 100 ) - { - pct = 60; - flvol = 0.85; //gEngfuncs.Con_Printf( "range > 100\n" ); - rg[0] = 3; - rg[1] = 4; - rg[2] = 5; - i = 3; - } - else if( m_iGeigerRange > 75 ) - { - pct = 80; - flvol = 0.9; - rg[0] = 4; - rg[1] = 5; - rg[2] = 6; - i = 3; - } - else if( m_iGeigerRange > 50 ) - { - pct = 90; - flvol = 0.95; - rg[0] = 5; - rg[1] = 6; - i = 2; - } - else - { - pct = 95; - flvol = 1.0; - rg[0] = 5; - rg[1] = 6; - i = 2; - } - - flvol = flvol * RANDOM_FLOAT( 0.25, 0.5 ); - - if( RANDOM_LONG( 0, 128 ) < pct ) - { - char sz[256]; - - int j = RANDOM_LONG( 0, 2 ); - if( i > 2 ) - j += RANDOM_LONG( 0, 2 ); - - // player/geiger6.wav isn't used ? - sprintf( sz, "player/geiger%d.wav", j + 1 ); - PlaySound( sz, flvol ); - - } - } - return 1; -} \ No newline at end of file diff --git a/client/hud/hud_health.cpp b/client/hud/hud_health.cpp deleted file mode 100644 index 484b3944..00000000 --- a/client/hud/hud_health.cpp +++ /dev/null @@ -1,451 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Health.cpp -// -// implementation of CHudHealth class -// - -#include "extdll.h" -#include "utils.h" -#include "hud.h" - -DECLARE_MESSAGE( m_Health, Health ) -DECLARE_MESSAGE( m_Health, Damage ) - -#define PAIN_NAME "sprites/%d_pain.spr" -#define DAMAGE_NAME "sprites/%d_dmg.spr" - -int giDmgHeight, giDmgWidth; - -int giDmgFlags[NUM_DMG_TYPES] = -{ - DMG_POISON, - DMG_ACID, - DMG_FREEZE|DMG_SLOWFREEZE, - DMG_DROWN, - DMG_BURN|DMG_SLOWBURN, - DMG_NERVEGAS, - DMG_RADIATION, - DMG_SHOCK, - DMG_CALTROP, - DMG_TRANQ, - DMG_CONCUSS, - DMG_HALLUC -}; - -int CHudHealth :: Init( void ) -{ - HOOK_MESSAGE( Health ); - HOOK_MESSAGE( Damage ); - m_iHealth = 100; - m_fFade = 0; - m_iFlags = 0; - m_bitsDamage = 0; - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - giDmgHeight = 0; - giDmgWidth = 0; - - memset( m_dmg, 0, sizeof(DAMAGE_IMAGE) * NUM_DMG_TYPES ); - gHUD.AddHudElem( this ); - - return 1; -} - -void CHudHealth :: Reset( void ) -{ - // make sure the pain compass is cleared when the player respawns - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - - // force all the flashing damage icons to expire - m_bitsDamage = 0; - for( int i = 0; i < NUM_DMG_TYPES; i++ ) - { - m_dmg[i].fExpire = 0; - } -} - -int CHudHealth :: VidInit( void ) -{ - m_hSprite = 0; - - m_HUD_dmg_bio = gHUD.GetSpriteIndex( "dmg_bio" ) + 1; - m_HUD_cross = gHUD.GetSpriteIndex( "cross" ); - - 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; - return 1; -} - -int CHudHealth :: MsgFunc_Health( const char *pszName, int iSize, void *pbuf ) -{ - // TODO: update local health data - BEGIN_READ( pszName, iSize, pbuf ); - int x = READ_BYTE(); - - m_iFlags |= HUD_ACTIVE; - - // only update the fade if we've changed health - if( x != m_iHealth ) - { - m_fFade = FADE_TIME; - m_iHealth = x; - } - END_READ(); - - return 1; -} - -int CHudHealth :: MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - int armor = READ_BYTE(); // armor - int damageTaken = READ_BYTE(); // health - long bitsDamage = READ_LONG(); // damage bits - - vec3_t vecFrom; - - for( int i = 0 ; i < 3 ; i++) - vecFrom[i] = READ_COORD(); - - UpdateTiles( gHUD.m_flTime, bitsDamage ); - - // actually took damage? - if( damageTaken > 0 || armor > 0 ) - CalcDamageDirection(vecFrom); - END_READ(); - - return 1; -} - -// Returns back a color from the -// Green <-> Yellow <-> Red ramp -void CHudHealth :: GetPainColor( int &r, int &g, int &b ) -{ - int iHealth = m_iHealth; - - if( iHealth > 25 ) - iHealth -= 25; - else if( iHealth < 0 ) - iHealth = 0; - - if( m_iHealth > 25 ) - { - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - } - else - { - r = 250; - g = 0; - b = 0; - } -} - -int CHudHealth :: Draw( float flTime ) -{ - int r, g, b; - int a = 0, x, y; - int HealthWidth; - - if((gHUD.m_iHideHUDDisplay & HIDEHUD_HEALTH) || IsSpectateOnly()) - return 1; - - if( !m_hSprite ) - m_hSprite = LoadSprite( PAIN_NAME ); - - // has health changed? Flash the health # - if( m_fFade ) - { - m_fFade -= (gHUD.m_flTimeDelta * 20); - if( m_fFade <= 0 ) - { - a = MIN_ALPHA; - m_fFade = 0; - } - - // fade the health number back to dim - a = MIN_ALPHA + (m_fFade/FADE_TIME) * 128; - - } - else a = MIN_ALPHA; - - // if health is getting low, make it bright red - if( m_iHealth <= 15 ) a = 255; - - GetPainColor( r, g, b ); - ScaleColors( r, g, b, a ); - - // Only draw health if we have the suit. - if( gHUD.m_iWeaponBits & (1<<(WEAPON_SUIT)) ) - { - HealthWidth = gHUD.GetSpriteRect(gHUD.m_HUD_number_0).right - gHUD.GetSpriteRect(gHUD.m_HUD_number_0).left; - int CrossWidth = gHUD.GetSpriteRect(m_HUD_cross).right - gHUD.GetSpriteRect(m_HUD_cross).left; - - y = ScreenHeight - gHUD.m_iFontHeight - gHUD.m_iFontHeight / 2; - x = CrossWidth / 2; - - SPR_Set( gHUD.GetSprite( m_HUD_cross ), r, g, b ); - SPR_DrawAdditive( 0, x, y, &gHUD.GetSpriteRect( m_HUD_cross )); - - x = CrossWidth + HealthWidth / 2; - - x = gHUD.DrawHudNumber( x, y, DHN_3DIGITS | DHN_DRAWZERO, m_iHealth, r, g, b ); - - x += HealthWidth / 2; - - int iHeight = gHUD.m_iFontHeight; - int iWidth = HealthWidth / 10; - - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - FillRGBA( x, y, iWidth, iHeight, r, g, b, a ); - } - - DrawDamage( flTime ); - return DrawPain( flTime ); -} - -void CHudHealth :: CalcDamageDirection( Vector vecFrom ) -{ - Vector forward, right, up; - float side, front; - Vector vecOrigin, vecAngles; - - if( vecFrom == Vector( 0, 0, 0 )) - { - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 0; - return; - } - - memcpy( vecOrigin, gHUD.m_vecOrigin, sizeof( vec3_t )); - memcpy( vecAngles, gHUD.m_vecAngles, sizeof( vec3_t )); - - vecFrom -= vecOrigin; - - float flDistToTarget = vecFrom.Length(); - - vecFrom = vecFrom.Normalize(); - AngleVectors( vecAngles, forward, right, up ); - - front = vecFrom.Dot( right ); - side = vecFrom.Dot( forward ); - - if( flDistToTarget <= 50 ) - { - m_fAttackFront = m_fAttackRear = m_fAttackRight = m_fAttackLeft = 1; - } - else - { - if( side > 0 ) - { - if( side > 0.3 ) - m_fAttackFront = max( m_fAttackFront, side ); - } - else - { - float f = fabs( side ); - if( f > 0.3 ) - m_fAttackRear = max( m_fAttackRear, f ); - } - - if( front > 0 ) - { - if( front > 0.3 ) - m_fAttackRight = max( m_fAttackRight, front ); - } - else - { - float f = fabs( front ); - if( f > 0.3 ) - m_fAttackLeft = max( m_fAttackLeft, f ); - } - } -} - -int CHudHealth :: DrawPain( float flTime ) -{ - if(!( m_fAttackFront || m_fAttackRear || m_fAttackLeft || m_fAttackRight )) - return 1; - - int r, g, b; - int x, y, a, shade; - - // TODO: get the shift value of the health - a = 255; // max brightness until then - - float fFade = gHUD.m_flTimeDelta * 2; - - // SPR_Draw top - if( m_fAttackFront > 0.4 ) - { - GetPainColor( r, g, b ); - shade = a * max( m_fAttackFront, 0.5 ); - ScaleColors( r, g, b, shade ); - SPR_Set( m_hSprite, r, g, b ); - - x = ScreenWidth / 2 - SPR_Width( m_hSprite, 0 ) / 2; - y = ScreenHeight / 2 - SPR_Height( m_hSprite, 0 ) * 3; - SPR_DrawAdditive( 0, x, y, NULL ); - m_fAttackFront = max( 0, m_fAttackFront - fFade ); - } - else m_fAttackFront = 0; - - if( m_fAttackRight > 0.4 ) - { - GetPainColor( r, g, b ); - shade = a * max( m_fAttackRight, 0.5 ); - ScaleColors( r, g, b, shade ); - SPR_Set( m_hSprite, r, g, b ); - - x = ScreenWidth / 2 + SPR_Width( m_hSprite, 1 ) * 2; - y = ScreenHeight / 2 - SPR_Height( m_hSprite,1 ) / 2; - SPR_DrawAdditive( 1, x, y, NULL ); - m_fAttackRight = max( 0, m_fAttackRight - fFade ); - } - else m_fAttackRight = 0; - - if( m_fAttackRear > 0.4 ) - { - GetPainColor( r, g, b ); - shade = a * max( m_fAttackRear, 0.5 ); - ScaleColors(r, g, b, shade); - SPR_Set(m_hSprite, r, g, b ); - - x = ScreenWidth / 2 - SPR_Width( m_hSprite, 2 ) / 2; - y = ScreenHeight / 2 + SPR_Height( m_hSprite, 2 ) * 2; - SPR_DrawAdditive( 2, x, y, NULL); - m_fAttackRear = max( 0, m_fAttackRear - fFade ); - } - else m_fAttackRear = 0; - - if( m_fAttackLeft > 0.4 ) - { - GetPainColor( r, g, b ); - shade = a * max( m_fAttackLeft, 0.5 ); - ScaleColors( r, g, b, shade ); - SPR_Set( m_hSprite, r, g, b ); - - x = ScreenWidth / 2 - SPR_Width( m_hSprite, 3 ) * 3; - y = ScreenHeight / 2 - SPR_Height( m_hSprite,3 ) / 2; - SPR_DrawAdditive( 3, x, y, NULL ); - - m_fAttackLeft = max( 0, m_fAttackLeft - fFade ); - } - else m_fAttackLeft = 0; - - return 1; -} - -int CHudHealth :: DrawDamage( float flTime ) -{ - int r, g, b, a; - DAMAGE_IMAGE *pdmg; - - if( !m_bitsDamage ) - return 1; - - UnpackRGB( r, g, b, gHUD.m_iHUDColor ); - - a = (int)(fabs(sin( flTime * 2)) * 256.0 ); - - ScaleColors( r, g, b, a ); - - // draw all the items - for( int i = 0; i < NUM_DMG_TYPES; i++ ) - { - if( m_bitsDamage & giDmgFlags[i] ) - { - pdmg = &m_dmg[i]; - SPR_Set( gHUD.GetSprite( m_HUD_dmg_bio + i ), r, g, b ); - SPR_DrawAdditive( 0, pdmg->x, pdmg->y, &gHUD.GetSpriteRect( m_HUD_dmg_bio + i )); - } - } - - // check for bits that should be expired - for( i = 0; i < NUM_DMG_TYPES; i++ ) - { - DAMAGE_IMAGE *pdmg = &m_dmg[i]; - - if( m_bitsDamage & giDmgFlags[i] ) - { - pdmg->fExpire = min( flTime + DMG_IMAGE_LIFE, pdmg->fExpire ); - - // when the time has expired and the flash is at the low point of the cycle - if( pdmg->fExpire <= flTime && a < 40 ) - { - pdmg->fExpire = 0; - - int y = pdmg->y; - pdmg->x = pdmg->y = 0; - - // move everyone above down - for( int j = 0; j < NUM_DMG_TYPES; j++ ) - { - pdmg = &m_dmg[j]; - if(( pdmg->y ) && ( pdmg->y < y )) - pdmg->y += giDmgHeight; - - } - m_bitsDamage &= ~giDmgFlags[i]; // clear the bits - } - } - } - return 1; -} - -void CHudHealth :: UpdateTiles( float flTime, long bitsDamage ) -{ - DAMAGE_IMAGE *pdmg; - - // Which types are new? - long bitsOn = ~m_bitsDamage & bitsDamage; - - for( int i = 0; i < NUM_DMG_TYPES; i++ ) - { - pdmg = &m_dmg[i]; - - // is this one already on? - if( m_bitsDamage & giDmgFlags[i] ) - { - pdmg->fExpire = flTime + DMG_IMAGE_LIFE; // extend the duration - if( !pdmg->fBaseline ) - pdmg->fBaseline = flTime; - } - - // are we just turning it on? - if( bitsOn & giDmgFlags[i] ) - { - // put this one at the bottom - pdmg->x = giDmgWidth / 8; - pdmg->y = ScreenHeight - giDmgHeight * 2; - pdmg->fExpire=flTime + DMG_IMAGE_LIFE; - - // move everyone else up - for( int j = 0; j < NUM_DMG_TYPES; j++ ) - { - if( j == i ) continue; - - pdmg = &m_dmg[j]; - if( pdmg->y ) - pdmg->y -= giDmgHeight; - - } - pdmg = &m_dmg[i]; - } - } - - // damage bits are only turned on here; they are turned off when the draw time has expired (in DrawDamage()) - m_bitsDamage |= bitsDamage; -} diff --git a/client/hud/hud_motd.cpp b/client/hud/hud_motd.cpp deleted file mode 100644 index 7eefb780..00000000 --- a/client/hud/hud_motd.cpp +++ /dev/null @@ -1,132 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// -// for displaying a server-sent message of the day -// - -#include "extdll.h" -#include "utils.h" -#include "hud.h" - -DECLARE_MESSAGE( m_MOTD, MOTD ); - -int CHudMOTD :: MOTD_DISPLAY_TIME; - -int CHudMOTD :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( MOTD ); - CVAR_REGISTER( "motd_display_time", "6", 0 ); - m_iFlags &= ~HUD_ACTIVE; // start out inactive - m_szMOTD[0] = 0; - - return 1; -} - -int CHudMOTD :: VidInit( void ) -{ - // Load sprites here - - return 1; -} - -void CHudMOTD :: Reset( void ) -{ - m_iFlags &= ~HUD_ACTIVE; // start out inactive - m_szMOTD[0] = 0; - m_iLines = 0; - m_flActiveTill = 0; -} - -#define LINE_HEIGHT 13 - -int CHudMOTD :: Draw( float fTime ) -{ - // Draw MOTD line-by-line - - if( m_flActiveTill < gHUD.m_flTime ) - { - // finished with MOTD, disable it - m_szMOTD[0] = 0; - m_iLines = 0; - m_iFlags &= ~HUD_ACTIVE; - return 1; - } - - // cap activetill time to the display time - m_flActiveTill = min( gHUD.m_flTime + MOTD_DISPLAY_TIME, m_flActiveTill ); - - // find the top of where the MOTD should be drawn, so the whole thing is centered in the screen - int ypos = max(((ScreenHeight - (m_iLines * LINE_HEIGHT)) / 2) - 40, 30 ); // shift it up slightly - char *ch = m_szMOTD; - while( *ch ) - { - int line_length = 0; // count the length of the current line - for( char *next_line = ch; *next_line != '\n' && *next_line != 0; next_line++ ) - line_length += gHUD.m_scrinfo.charWidths[ *next_line ]; - char *top = next_line; - if( *top == '\n' ) - *top = 0; - else - top = NULL; - - // find where to start drawing the line - int xpos = (ScreenWidth - line_length) / 2; - - gHUD.DrawHudString( xpos, ypos, ScreenWidth, ch, 255, 180, 0 ); - - ypos += LINE_HEIGHT; - - if( top ) *top = '\n'; // restore - - ch = next_line; - if( *ch == '\n' ) - ch++; - - if ( ypos > ( ScreenHeight - 20 )) - break; // don't let it draw too low - } - return 1; -} - -int CHudMOTD :: MsgFunc_MOTD( const char *pszName, int iSize, void *pbuf ) -{ - if( m_iFlags & HUD_ACTIVE ) - { - Reset(); // clear the current MOTD in prep for this one - } - - BEGIN_READ( pszName, iSize, pbuf ); - - int is_finished = READ_BYTE(); - strcat( m_szMOTD, READ_STRING() ); - - if( is_finished ) - { - m_iFlags |= HUD_ACTIVE; - - MOTD_DISPLAY_TIME = CVAR_GET_FLOAT( "motd_display_time" ); - m_flActiveTill = gHUD.m_flTime + MOTD_DISPLAY_TIME; - - for( char *sz = m_szMOTD; *sz != 0; sz++ ) // count the number of lines in the MOTD - { - if( *sz == '\n' ) - m_iLines++; - } - } - return 1; -} \ No newline at end of file diff --git a/client/hud/hud_msg.cpp b/client/hud/hud_msg.cpp deleted file mode 100644 index d5133ee6..00000000 --- a/client/hud/hud_msg.cpp +++ /dev/null @@ -1,359 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// hud_msg.cpp -// -#include "extdll.h" -#include "utils.h" -#include "hud.h" -#include "aurora.h" -#include "ref_params.h" - -// CHud message handlers -DECLARE_HUDMESSAGE( Logo ); -DECLARE_HUDMESSAGE( HUDColor ); -DECLARE_HUDMESSAGE( SetFog ); -DECLARE_HUDMESSAGE( SetFOV ); -DECLARE_HUDMESSAGE( RainData ); -DECLARE_HUDMESSAGE( SetBody ); -DECLARE_HUDMESSAGE( SetSkin ); -DECLARE_HUDMESSAGE( ResetHUD ); -DECLARE_HUDMESSAGE( InitHUD ); -DECLARE_HUDMESSAGE( ViewMode ); -DECLARE_HUDMESSAGE( Particle ); -DECLARE_HUDMESSAGE( Concuss ); -DECLARE_HUDMESSAGE( GameMode ); -DECLARE_HUDMESSAGE( ServerName ); -DECLARE_HUDCOMMAND( ChangeLevel ); - -cvar_t *cl_lw = NULL; -float g_lastFOV = 0.0f; - -int CHud :: InitMessages( void ) -{ - HOOK_MESSAGE( Logo ); - HOOK_MESSAGE( ResetHUD ); - HOOK_MESSAGE( GameMode ); - HOOK_MESSAGE( ServerName ); - HOOK_MESSAGE( InitHUD ); - HOOK_MESSAGE( ViewMode ); - HOOK_MESSAGE( Concuss ); - HOOK_MESSAGE( HUDColor ); - HOOK_MESSAGE( Particle ); - HOOK_MESSAGE( SetFog ); - HOOK_MESSAGE( SetFOV ); - HOOK_MESSAGE( RainData ); - HOOK_MESSAGE( SetBody ); - HOOK_MESSAGE( SetSkin ); - - HOOK_COMMAND( "hud_changelevel", ChangeLevel ); // send by engine - - m_iLogo = 0; - m_iFOV = 0; - m_iHUDColor = RGB_YELLOWISH; // 255, 160, 0 - - CVAR_REGISTER( "zoom_sensitivity_ratio", "1.2", 0 ); - default_fov = CVAR_REGISTER( "default_fov", "90", 0 ); - CVAR_REGISTER( "hud_draw", "1", 0 ); - CVAR_REGISTER( "hud_takesshots", "0", 0 ); - cl_lw = gEngfuncs.pfnGetCvarPointer( "cl_lw" ); - - // clear any old HUD list - if( m_pHudList ) - { - HUDLIST *pList; - while( m_pHudList ) - { - pList = m_pHudList; - m_pHudList = m_pHudList->pNext; - free( pList ); - } - m_pHudList = NULL; - } - - m_flTime = 1.0; - - return 1; -} - -void CHud :: UserCmd_ChangeLevel( void ) -{ -} - -int CHud :: MsgFunc_Logo( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - // update Train data - m_iLogo = READ_BYTE(); - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_ResetHUD(const char *pszName, int iSize, void *pbuf ) -{ - // clear all hud data - HUDLIST *pList = m_pHudList; - - while( pList ) - { - if( pList->p ) pList->p->Reset(); - pList = pList->pNext; - } - - // reset sensitivity - m_flMouseSensitivity = 0; - - // reset concussion effect - m_iConcussionEffect = 0; - - m_iIntermission = 0; - - // reset windspeed - m_vecWindVelocity = Vector( 0, 0, 0 ); - - // reset fog - m_flStartDist = 0; - m_flEndDist = 0; - - return 1; -} - -int CHud :: MsgFunc_ViewMode( const char *pszName, int iSize, void *pbuf ) -{ - // CAM_ToFirstPerson(); - return 1; -} - -int CHud :: MsgFunc_InitHUD( const char *pszName, int iSize, void *pbuf ) -{ - m_flStartDist = 0; - m_flEndDist = 0; - m_iIntermission = 0; - - // prepare all hud data - HUDLIST *pList = m_pHudList; - - while( pList ) - { - if( pList->p ) - pList->p->InitHUDData(); - pList = pList->pNext; - } - return 1; -} - -int CHud::MsgFunc_HUDColor(const char *pszName, int iSize, void *pbuf) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - m_iHUDColor = READ_LONG(); - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_SetFog( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - m_vecFogColor.x = (float)(READ_BYTE() / 255.0f); - m_vecFogColor.y = (float)(READ_BYTE() / 255.0f); - m_vecFogColor.z = (float)(READ_BYTE() / 255.0f); - - m_flStartDist = READ_SHORT(); - m_flEndDist = READ_SHORT(); - - END_READ(); - - return 1; -} - -int CHud::MsgFunc_SetFOV(const char *pszName, int iSize, void *pbuf) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - int newfov = READ_BYTE(); - int def_fov = CVAR_GET_FLOAT( "default_fov" ); - - //Weapon prediction already takes care of changing the fog. ( g_lastFOV ). - if ( cl_lw && cl_lw->value ) - { - END_READ(); - return 1; - } - - g_lastFOV = newfov; - - if ( newfov == 0 ) - { - m_iFOV = def_fov; - } - else - { - m_iFOV = newfov; - } - - // the clients fov is actually set in the client data update section of the hud - - // Set a new sensitivity - if ( m_iFOV == def_fov ) - { - // reset to saved sensitivity - m_flMouseSensitivity = 0; - } - else - { - // set a new sensitivity that is proportional to the change from the FOV default - m_flMouseSensitivity = m_sensitivity->value * ((float)newfov / (float)def_fov ); - m_flMouseSensitivity *= CVAR_GET_FLOAT( "zoom_sensitivity_ratio" ); - } - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_GameMode( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - m_Teamplay = READ_BYTE(); - - END_READ(); - - return 1; -} - - -int CHud :: MsgFunc_Damage( const char *pszName, int iSize, void *pbuf ) -{ - int armor, blood; - int i; - float count; - - BEGIN_READ( pszName, iSize, pbuf ); - armor = READ_BYTE(); - blood = READ_BYTE(); - - float from[3]; - for( i = 0; i < 3; i++ ) - from[i] = READ_COORD(); - - count = (blood * 0.5) + (armor * 0.5); - if( count < 10 ) count = 10; - - END_READ(); - - // TODO: kick viewangles, show damage visually - - return 1; -} - -int CHud :: MsgFunc_Concuss( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - m_iConcussionEffect = READ_BYTE(); - if( m_iConcussionEffect ) - m_StatusIcons.EnableIcon( "dmg_concuss", 255, 160, 0 ); - else m_StatusIcons.DisableIcon( "dmg_concuss" ); - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_RainData( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - Rain.dripsPerSecond = READ_SHORT(); - Rain.distFromPlayer = READ_COORD(); - Rain.windX = READ_COORD(); - Rain.windY = READ_COORD(); - Rain.randX = READ_COORD(); - Rain.randY = READ_COORD(); - Rain.weatherMode = READ_SHORT(); - Rain.globalHeight= READ_COORD(); // FIXME: calc on client side ? - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_SetBody( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - cl_entity_t *viewmodel = GetViewModel(); - viewmodel->curstate.body = READ_BYTE(); - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_SetSkin( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - cl_entity_t *viewmodel = GetViewModel(); - viewmodel->curstate.skin = READ_BYTE(); - - END_READ(); - - return 1; -} - -int CHud :: MsgFunc_Particle( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - int idx = READ_SHORT(); - char *sz = READ_STRING(); - - CreateAurora( idx, sz ); - - END_READ(); - - return 1; -} - -int CHud::MsgFunc_ServerName( const char *pszName, int iSize, void *pbuf ) -{ - char m_szServerName[32]; - - BEGIN_READ( pszName, iSize, pbuf ); - strncpy( m_szServerName, READ_STRING(), 32 ); - END_READ(); - - return 1; -} - -/* -===================== -HUD_GetFOV - -Returns last FOV -===================== -*/ -float HUD_GetFOV( void ) -{ - return g_lastFOV; -} \ No newline at end of file diff --git a/client/hud/hud_saytext.cpp b/client/hud/hud_saytext.cpp deleted file mode 100644 index d1550c94..00000000 --- a/client/hud/hud_saytext.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// saytext.cpp -// -// implementation of CHudSayText class -// - -#include "extdll.h" -#include "utils.h" -#include "hud.h" - -#define MAX_LINES 5 -#define MAX_CHARS_PER_LINE 256 /* it can be less than this, depending on char size */ - -// allow 20 pixels on either side of the text -#define MAX_LINE_WIDTH ( ScreenWidth - 40 ) -#define LINE_START 10 -static float SCROLL_SPEED = 5; - -static char g_szLineBuffer[ MAX_LINES + 1 ][ MAX_CHARS_PER_LINE ]; -static float flScrollTime = 0; // the time at which the lines next scroll up - -static int Y_START = 0; -static int line_height = 0; - -DECLARE_MESSAGE( m_SayText, SayText ); - -int CHudSayText :: Init( void ) -{ - gHUD.AddHudElem( this ); - - HOOK_MESSAGE( SayText ); - - InitHUDData(); - - CVAR_REGISTER( "hud_saytext_time", "5", 0 ); - m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission - - return 1; -} - -void CHudSayText :: InitHUDData( void ) -{ - memset( g_szLineBuffer, 0, sizeof g_szLineBuffer ); -} - -int CHudSayText :: VidInit( void ) -{ - return 1; -} - - -void ScrollTextUp( void ) -{ - ConsolePrint( g_szLineBuffer[0] ); // move the first line into the console buffer - memmove( g_szLineBuffer[0], g_szLineBuffer[1], sizeof(g_szLineBuffer) - sizeof(g_szLineBuffer[0]) ); // overwrite the first line - - if( g_szLineBuffer[0][0] == ' ' ) // also scroll up following lines - { - g_szLineBuffer[0][0] = 2; - ScrollTextUp(); - } -} - -int CHudSayText :: Draw( float flTime ) -{ - int y = Y_START; - - // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset - flScrollTime = min( flScrollTime, flTime + CVAR_GET_FLOAT( "hud_saytext_time" )); - - // make sure the scrolltime is within reasonable bounds, to guard against the clock being reset - flScrollTime = min( flScrollTime, flTime + CVAR_GET_FLOAT( "hud_saytext_time" )); - - if( flScrollTime <= flTime ) - { - if( *g_szLineBuffer[0] ) - { - flScrollTime = flTime + CVAR_GET_FLOAT( "hud_saytext_time" ); - // push the console up - ScrollTextUp(); - } - else - { - // buffer is empty, just disable drawing of this section - m_iFlags &= ~HUD_ACTIVE; - } - } - - for ( int i = 0; i < MAX_LINES; i++ ) - { - if ( *g_szLineBuffer[i] ) - DrawConsoleString( LINE_START, y, g_szLineBuffer[i] ); - - y += line_height; - } - return 1; -} - -int CHudSayText :: MsgFunc_SayText( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - - int client_index = READ_BYTE(); // the client who spoke the message - SayTextPrint( READ_STRING(), iSize - 1, client_index ); - END_READ(); - - return 1; -} - -void CHudSayText :: SayTextPrint( const char *pszBuf, int iBufSize, int clientIndex ) -{ - // find an empty string slot - for( int i = 0; i < MAX_LINES; i++ ) - { - if( !*g_szLineBuffer[i] ) - break; - } - - if( i == MAX_LINES ) - { - // force scroll buffer up - ScrollTextUp(); - i = MAX_LINES - 1; - } - - strncpy( g_szLineBuffer[i], pszBuf, max(iBufSize -1, MAX_CHARS_PER_LINE-1) ); - - // make sure the text fits in one line - EnsureTextFitsInOneLineAndWrapIfHaveTo( i ); - - // set scroll time - if( i == 0 ) - { - flScrollTime = gHUD.m_flTime + CVAR_GET_FLOAT( "hud_saytext_time" ); - } - - m_iFlags |= HUD_ACTIVE; - PlaySound( "common/menu2.wav", 1.0f ); - - Y_START = ScreenHeight - 60; - Y_START -= (line_height * (MAX_LINES+1)); - -} - -void CHudSayText :: EnsureTextFitsInOneLineAndWrapIfHaveTo( int line ) -{ - int line_width = 0; - GetConsoleStringSize( g_szLineBuffer[line], &line_width, &line_height ); - - if((line_width + LINE_START) > MAX_LINE_WIDTH ) - { - // string is too long to fit on line - // scan the string until we find what word is too long, and wrap the end of the sentence after the word - int length = LINE_START; - int tmp_len = 0; - char *last_break = NULL; - for ( char *x = g_szLineBuffer[line]; *x != 0; x++ ) - { - char buf[2]; - buf[1] = 0; - - if( *x == ' ' && x != g_szLineBuffer[line] ) // store each line break, except for the very first character - last_break = x; - - buf[0] = *x; // get the length of the current character - GetConsoleStringSize( buf, &tmp_len, &line_height ); - length += tmp_len; - - if( length > MAX_LINE_WIDTH ) - { - // needs to be broken up - if( !last_break ) - last_break = x-1; - x = last_break; - - // find an empty string slot - for( int j = 0; j < MAX_LINES; j++ ) - { - if( !*g_szLineBuffer[j] ) - break; - } - if( j == MAX_LINES ) - { - j = MAX_LINES - 1; - } - - // copy remaining string into next buffer, making sure it starts with a space character - if( (char)*last_break == (char)' ' ) - { - int linelen = strlen(g_szLineBuffer[j]); - int remaininglen = strlen(last_break); - - if( (linelen - remaininglen) <= MAX_CHARS_PER_LINE ) - strcat( g_szLineBuffer[j], last_break ); - } - else - { - if( (strlen(g_szLineBuffer[j]) - strlen(last_break) - 2) < MAX_CHARS_PER_LINE ) - { - strcat( g_szLineBuffer[j], " " ); - strcat( g_szLineBuffer[j], last_break ); - } - } - - *last_break = 0; // cut off the last string - - EnsureTextFitsInOneLineAndWrapIfHaveTo( j ); - break; - } - } - } -} \ No newline at end of file diff --git a/client/hud/hud_scoreboard.cpp b/client/hud/hud_scoreboard.cpp deleted file mode 100644 index b47b5f06..00000000 --- a/client/hud/hud_scoreboard.cpp +++ /dev/null @@ -1,504 +0,0 @@ -/*** -* -* Copyright (c) 1999, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// -// Scoreboard.cpp -// -// implementation of CHudScoreboard class -// - -#include "extdll.h" -#include "utils.h" -#include "hud.h" - -DECLARE_COMMAND( m_Scoreboard, ShowScores ); -DECLARE_COMMAND( m_Scoreboard, HideScores ); - -DECLARE_MESSAGE( m_Scoreboard, ScoreInfo ); -DECLARE_MESSAGE( m_Scoreboard, TeamInfo ); -DECLARE_MESSAGE( m_Scoreboard, TeamScore ); - -int CHudScoreboard :: Init( void ) -{ - gHUD.AddHudElem( this ); - - // Hook messages & commands here - HOOK_COMMAND( "+showscores", ShowScores ); - HOOK_COMMAND( "-showscores", HideScores ); - - HOOK_MESSAGE( ScoreInfo ); - HOOK_MESSAGE( TeamScore ); - HOOK_MESSAGE( TeamInfo ); - - InitHUDData(); - - return 1; -} - - -int CHudScoreboard :: VidInit( void ) -{ - // Load sprites here - - return 1; -} - -void CHudScoreboard :: InitHUDData( void ) -{ - memset( m_PlayerExtraInfo, 0, sizeof m_PlayerExtraInfo ); - m_iLastKilledBy = 0; - m_fLastKillTime = 0; - m_iPlayerNum = 0; - m_iNumTeams = 0; - memset( m_TeamInfo, 0, sizeof m_TeamInfo ); - - m_iFlags &= ~HUD_ACTIVE; // starts out inactive - - m_iFlags |= HUD_INTERMISSION; // is always drawn during an intermission -} - -/* The scoreboard -We have a minimum width of 1-320 - we could have the field widths scale with it? -*/ - -// X positions -// relative to the side of the scoreboard -#define NAME_RANGE_MIN 20 -#define NAME_RANGE_MAX 145 -#define KILLS_RANGE_MIN 130 -#define KILLS_RANGE_MAX 170 -#define DIVIDER_POS 180 -#define DEATHS_RANGE_MIN 185 -#define DEATHS_RANGE_MAX 210 -#define PING_RANGE_MIN 245 -#define PING_RANGE_MAX 295 - -#define SCOREBOARD_WIDTH 320 - -// Y positions -#define ROW_GAP 13 -#define ROW_RANGE_MIN 15 -#define ROW_RANGE_MAX ( ScreenHeight - 50 ) - -int CHudScoreboard :: Draw( float fTime ) -{ - if( !m_iShowscoresHeld && gHUD.m_Health.m_iHealth > 0 && !gHUD.m_iIntermission ) - return 1; - - GetAllPlayersInfo(); - - // just sort the list on the fly - // list is sorted first by frags, then by deaths - float list_slot = 0; - int xpos_rel = (ScreenWidth - SCOREBOARD_WIDTH) / 2; - - // print the heading line - int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - int xpos = NAME_RANGE_MIN + xpos_rel; - - if( !gHUD.m_Teamplay ) - gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Player", 255, 140, 0 ); - else gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, "Teams", 255, 140, 0 ); - - gHUD.DrawHudStringReverse( KILLS_RANGE_MAX + xpos_rel, ypos, 0, "frags", 255, 140, 0 ); - gHUD.DrawHudString( DIVIDER_POS + xpos_rel, ypos, ScreenWidth, "/", 255, 140, 0 ); - gHUD.DrawHudString( DEATHS_RANGE_MIN + xpos_rel + 5, ypos, ScreenWidth, "deaths", 255, 140, 0 ); - gHUD.DrawHudString( PING_RANGE_MAX + xpos_rel - 35, ypos, ScreenWidth, "ping", 255, 140, 0 ); - - list_slot += 1.2; - ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - xpos = NAME_RANGE_MIN + xpos_rel; - FillRGBA( xpos - 5, ypos, PING_RANGE_MAX - 5, 1, 255, 140, 0, 255); // draw the seperator line - - list_slot += 0.8; - - if ( !gHUD.m_Teamplay ) - { - // it's not teamplay, so just draw a simple player list - DrawPlayers( xpos_rel, list_slot ); - return 1; - } - - // clear out team scores - for ( int i = 1; i <= m_iNumTeams; i++ ) - { - if ( !m_TeamInfo[i].scores_overriden ) - m_TeamInfo[i].frags = m_TeamInfo[i].deaths = 0; - m_TeamInfo[i].ping = m_TeamInfo[i].packetloss = 0; - } - - // recalc the team scores, then draw them - for ( i = 1; i < MAX_PLAYERS; i++ ) - { - if ( m_PlayerInfoList[i].name == NULL ) - continue; // empty player slot, skip - - if ( m_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - // find what team this player is in - for ( int j = 1; j <= m_iNumTeams; j++ ) - { - if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) ) - break; - } - if ( j > m_iNumTeams ) // player is not in a team, skip to the next guy - continue; - - if ( !m_TeamInfo[j].scores_overriden ) - { - m_TeamInfo[j].frags += m_PlayerExtraInfo[i].frags; - m_TeamInfo[j].deaths += m_PlayerExtraInfo[i].deaths; - } - - m_TeamInfo[j].ping += m_PlayerInfoList[i].ping; - m_TeamInfo[j].packetloss += m_PlayerInfoList[i].packetloss; - - if ( m_PlayerInfoList[i].thisplayer ) - m_TeamInfo[j].ownteam = TRUE; - else - m_TeamInfo[j].ownteam = FALSE; - } - - // find team ping/packetloss averages - for ( i = 1; i <= m_iNumTeams; i++ ) - { - m_TeamInfo[i].already_drawn = FALSE; - - if ( m_TeamInfo[i].players > 0 ) - { - m_TeamInfo[i].ping /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping - m_TeamInfo[i].packetloss /= m_TeamInfo[i].players; // use the average ping of all the players in the team as the teams ping - } - } - - // Draw the teams - while ( 1 ) - { - int highest_frags = -99999; int lowest_deaths = 99999; - int best_team = 0; - - for ( i = 1; i <= m_iNumTeams; i++ ) - { - if ( m_TeamInfo[i].players < 0 ) - continue; - - if ( !m_TeamInfo[i].already_drawn && m_TeamInfo[i].frags >= highest_frags ) - { - if ( m_TeamInfo[i].frags > highest_frags || m_TeamInfo[i].deaths < lowest_deaths ) - { - best_team = i; - lowest_deaths = m_TeamInfo[i].deaths; - highest_frags = m_TeamInfo[i].frags; - } - } - } - - // draw the best team on the scoreboard - if ( !best_team ) - break; - - // draw out the best team - team_info_t *team_info = &m_TeamInfo[best_team]; - - ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - - // check we haven't drawn too far down - if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border - break; - - xpos = NAME_RANGE_MIN + xpos_rel; - int r = 255, g = 225, b = 55; // draw the stuff kinda yellowish - - if ( team_info->ownteam ) // if it is their team, draw the background different color - { - // overlay the background in blue, then draw the score text over it - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 ); - } - - // draw their name (left to right) - gHUD.DrawHudString( xpos, ypos, NAME_RANGE_MAX + xpos_rel, team_info->name, r, g, b ); - - // draw kills (right to left) - xpos = KILLS_RANGE_MAX + xpos_rel; - gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, team_info->frags, r, g, b ); - - // draw divider - xpos = DIVIDER_POS + xpos_rel; - gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); - - // draw deaths - xpos = DEATHS_RANGE_MAX + xpos_rel; - gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, team_info->deaths, r, g, b ); - - // draw ping - // draw ping & packetloss - static char buf[64]; - sprintf( buf, "%d", team_info->ping ); - xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; - UnpackRGB( r, g, b, RGB_YELLOWISH ); - gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); - - team_info->already_drawn = TRUE; // set the already_drawn to be TRUE, so this team won't get drawn again - list_slot++; - - // draw all the players that belong to this team, indented slightly - list_slot = DrawPlayers( xpos_rel, list_slot, 10, team_info->name ); - } - - // draw all the players who are not in a team - list_slot += 0.5; - DrawPlayers( xpos_rel, list_slot, 0, "" ); - - return 1; -} - -// returns the ypos where it finishes drawing -int CHudScoreboard :: DrawPlayers( int xpos_rel, float list_slot, int nameoffset, char *team ) -{ - // draw the players, in order, and restricted to team if set - while ( 1 ) - { - // Find the top ranking player - int highest_frags = -99999; int lowest_deaths = 99999; - int best_player = 0; - - for ( int i = 1; i < MAX_PLAYERS; i++ ) - { - if ( m_PlayerInfoList[i].name && m_PlayerExtraInfo[i].frags >= highest_frags ) - { - if ( !(team && stricmp(m_PlayerExtraInfo[i].teamname, team)) ) // make sure it is the specified team - { - extra_player_info_t *pl_info = &m_PlayerExtraInfo[i]; - if ( pl_info->frags > highest_frags || pl_info->deaths < lowest_deaths ) - { - best_player = i; - lowest_deaths = pl_info->deaths; - highest_frags = pl_info->frags; - } - } - } - } - - if ( !best_player ) - break; - - // draw out the best player - hud_player_info_t *pl_info = &m_PlayerInfoList[best_player]; - - int ypos = ROW_RANGE_MIN + (list_slot * ROW_GAP); - - // check we haven't drawn too far down - if ( ypos > ROW_RANGE_MAX ) // don't draw to close to the lower border - break; - - int xpos = NAME_RANGE_MIN + xpos_rel; - int r = 255, g = 255, b = 255; - if ( best_player == m_iLastKilledBy && m_fLastKillTime && m_fLastKillTime > gHUD.m_flTime ) - { - if ( pl_info->thisplayer ) - { // green is the suicide color? i wish this could do grey... - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 80, 155, 0, 70 ); - } - else - { // Highlight the killers name - overlay the background in red, then draw the score text over it - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 255, 0, 0, ((float)15 * (float)(m_fLastKillTime - gHUD.m_flTime)) ); - } - } - else if ( pl_info->thisplayer ) // if it is their name, draw it a different color - { - // overlay the background in blue, then draw the score text over it - FillRGBA( NAME_RANGE_MIN + xpos_rel - 5, ypos, PING_RANGE_MAX - 5, ROW_GAP, 0, 0, 255, 70 ); - } - - // draw their name (left to right) - gHUD.DrawHudString( xpos + nameoffset, ypos, NAME_RANGE_MAX + xpos_rel, pl_info->name, r, g, b ); - - // draw kills (right to left) - xpos = KILLS_RANGE_MAX + xpos_rel; - gHUD.DrawHudNumberString( xpos, ypos, KILLS_RANGE_MIN + xpos_rel, m_PlayerExtraInfo[best_player].frags, r, g, b ); - - // draw divider - xpos = DIVIDER_POS + xpos_rel; - gHUD.DrawHudString( xpos, ypos, xpos + 20, "/", r, g, b ); - - // draw deaths - xpos = DEATHS_RANGE_MAX + xpos_rel; - gHUD.DrawHudNumberString( xpos, ypos, DEATHS_RANGE_MIN + xpos_rel, m_PlayerExtraInfo[best_player].deaths, r, g, b ); - - // draw ping & packetloss - static char buf[64]; - sprintf( buf, "%d", m_PlayerInfoList[best_player].ping ); - xpos = ((PING_RANGE_MAX - PING_RANGE_MIN) / 2) + PING_RANGE_MIN + xpos_rel + 25; - gHUD.DrawHudStringReverse( xpos, ypos, xpos - 50, buf, r, g, b ); - - pl_info->name = NULL; // set the name to be NULL, so this client won't get drawn again - list_slot++; - } - return list_slot; -} - -void CHudScoreboard :: GetAllPlayersInfo( void ) -{ - for ( int i = 1; i < MAX_PLAYERS; i++ ) - { - GetPlayerInfo( i, &m_PlayerInfoList[i] ); - - if ( m_PlayerInfoList[i].thisplayer ) - m_iPlayerNum = i; // !!!HACK: this should be initialized elsewhere... maybe gotten from the engine - } -} - -int CHudScoreboard :: MsgFunc_ScoreInfo( const char *pszName, int iSize, void *pbuf ) -{ - m_iFlags |= HUD_ACTIVE; - - BEGIN_READ( pszName, iSize, pbuf ); - short cl = READ_BYTE(); - short frags = READ_SHORT(); - short deaths = READ_SHORT(); - - if( cl > 0 && cl <= MAX_PLAYERS ) - { - m_PlayerExtraInfo[cl].frags = frags; - m_PlayerExtraInfo[cl].deaths = deaths; - } - END_READ(); - - return 1; -} - -// Message handler for TeamInfo message -// accepts two values: -// byte: client number -// string: client team name -int CHudScoreboard :: MsgFunc_TeamInfo( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - short cl = READ_BYTE(); - - if( cl > 0 && cl <= MAX_PLAYERS ) - { - // set the players team - strncpy( m_PlayerExtraInfo[cl].teamname, READ_STRING(), MAX_TEAM_NAME ); - } - - // rebuild the list of teams - - // clear out player counts from teams - for ( int i = 1; i <= m_iNumTeams; i++ ) - { - m_TeamInfo[i].players = 0; - } - - // rebuild the team list - GetAllPlayersInfo(); - m_iNumTeams = 0; - for ( i = 1; i < MAX_PLAYERS; i++ ) - { - if ( m_PlayerInfoList[i].name == NULL ) - continue; - - if ( m_PlayerExtraInfo[i].teamname[0] == 0 ) - continue; // skip over players who are not in a team - - // is this player in an existing team? - for ( int j = 1; j <= m_iNumTeams; j++ ) - { - if ( m_TeamInfo[j].name[0] == '\0' ) - break; - - if ( !stricmp( m_PlayerExtraInfo[i].teamname, m_TeamInfo[j].name ) ) - break; - } - - if ( j > m_iNumTeams ) - { // they aren't in a listed team, so make a new one - // search through for an empty team slot - for ( int j = 1; j <= m_iNumTeams; j++ ) - { - if ( m_TeamInfo[j].name[0] == '\0' ) - break; - } - m_iNumTeams = max( j, m_iNumTeams ); - - strncpy( m_TeamInfo[j].name, m_PlayerExtraInfo[i].teamname, MAX_TEAM_NAME ); - m_TeamInfo[j].players = 0; - } - - m_TeamInfo[j].players++; - } - - // clear out any empty teams - for ( i = 1; i <= m_iNumTeams; i++ ) - { - if ( m_TeamInfo[i].players < 1 ) - memset( &m_TeamInfo[i], 0, sizeof(team_info_t) ); - } - END_READ(); - - return 1; -} - -// Message handler for TeamScore message -// accepts three values: -// string: team name -// short: teams kills -// short: teams deaths -// if this message is never received, then scores will simply be the combined totals of the players. -int CHudScoreboard :: MsgFunc_TeamScore( const char *pszName, int iSize, void *pbuf ) -{ - BEGIN_READ( pszName, iSize, pbuf ); - char *TeamName = READ_STRING(); - - // find the team matching the name - for ( int i = 1; i <= m_iNumTeams; i++ ) - { - if ( !stricmp( TeamName, m_TeamInfo[i].name ) ) - break; - } - if ( i > m_iNumTeams ) - return 1; - - // use this new score data instead of combined player scores - m_TeamInfo[i].scores_overriden = TRUE; - m_TeamInfo[i].frags = READ_SHORT(); - m_TeamInfo[i].deaths = READ_SHORT(); - END_READ(); - - return 1; -} - -void CHudScoreboard :: DeathMsg( int killer, int victim ) -{ - // if we were the one killed, or the world killed us, set the scoreboard to indicate suicide - if ( victim == m_iPlayerNum || killer == 0 ) - { - m_iLastKilledBy = killer ? killer : m_iPlayerNum; - m_fLastKillTime = gHUD.m_flTime + 10; // display who we were killed by for 10 seconds - - if ( killer == m_iPlayerNum ) - m_iLastKilledBy = m_iPlayerNum; - } -} - -void CHudScoreboard :: UserCmd_ShowScores( void ) -{ - m_iShowscoresHeld = TRUE; -} - -void CHudScoreboard :: UserCmd_HideScores( void ) -{ - m_iShowscoresHeld = FALSE; -} diff --git a/common/cl_entity.h b/common/cl_entity.h index e1816b04..aca26004 100644 --- a/common/cl_entity.h +++ b/common/cl_entity.h @@ -48,7 +48,9 @@ typedef struct typedef struct { - float animtime; // Time stamp for this movement + // Time stamp for this movement + float animtime; + vec3_t origin; vec3_t angles; } position_history_t; @@ -59,10 +61,12 @@ typedef struct cl_entity_s cl_entity_t; #define HISTORY_MASK ( HISTORY_MAX - 1 ) #include "entity_state.h" +#include "event_args.h" +#include "playerinfo.h" struct cl_entity_s { - int index; // Index into cl_entities ( always match actual slot ) + int index; // Index into cl_entities ( should match actual slot, but not necessarily ) qboolean player; // True if this entity is a "player" entity_state_t baseline; // The original state from which to delta during an uncompressed message @@ -77,12 +81,14 @@ struct cl_entity_s latchedvars_t latched; // Variables used by studio model rendering routines // Information based on interplocation, extrapolation, prediction, or just copied from last msg received. + // float lastmove; // Actual render position and angles vec3_t origin; vec3_t angles; + // Attachment points vec3_t attachment[4]; // Other entity local information @@ -95,16 +101,6 @@ struct cl_entity_s float syncbase; // for client-side animations -- used by obsolete alias animation system, remove? int visframe; // last frame this entity was found in an active leaf colorVec cvFloorColor; - - // INCOMPATIBLE!!! - vec3_t absmin, absmax; - - // Attachment points - vec3_t attachment_angles[4]; - float m_flPrevEventFrame; // previous event frame - int m_iEventSequence; // current event sequence - cl_entity_t *onground; // Entity standing on - link_t area; // linked to a division node or leaf }; #endif//CL_ENTITY_H \ No newline at end of file diff --git a/common/com_model.h b/common/com_model.h index cbe90868..9e4cd67d 100644 --- a/common/com_model.h +++ b/common/com_model.h @@ -13,10 +13,14 @@ ENGINE MODEL FORMAT ============================================================================== */ +#define STUDIO_RENDER 1 +#define STUDIO_EVENTS 2 + // surface flags #define SURF_PLANEBACK BIT( 0 ) #define CONTENTS_NODE 1 // fake contents to determine nodes +#define ZISCALE ((float)0x8000) // model types typedef enum @@ -28,6 +32,14 @@ typedef enum mod_studio } modtype_t; +typedef struct alight_s +{ + int ambientlight; // clip at 128 + int shadelight; // clip at 192 - ambientlight + vec3_t color; + float *plightvec; +} alight_t; + typedef struct mplane_s { vec3_t normal; @@ -117,11 +129,13 @@ typedef struct mnode_s typedef struct model_s { char name[64]; // model name - byte *mempool; // private mempool int registration_sequence; // shared modelinfo modtype_t type; // model type + int numframes; // sprite's framecount + byte *mempool; // private mempool (was synctype) + int flags; // hl compatibility vec3_t mins, maxs; // bounding box at angles '0 0 0' // brush model @@ -169,7 +183,7 @@ typedef struct model_s byte *lightdata; // for GetEntityIllum byte *extradata; // models extradata - int numframes; // sprite's framecount + char *entities; } model_t; #endif//COM_MODEL_H \ No newline at end of file diff --git a/common/const.h b/common/const.h index 88d9d3a6..f579675c 100644 --- a/common/const.h +++ b/common/const.h @@ -732,7 +732,6 @@ typedef int string_t; typedef unsigned char byte; typedef unsigned short word; -typedef float vec_t; #undef true #undef false @@ -773,4 +772,22 @@ typedef struct link_s typedef struct edict_s edict_t; +typedef struct +{ + vec3_t normal; + float dist; +} plane_t; + +typedef struct +{ + qboolean allsolid; // if true, plane is not valid + qboolean startsolid; // if true, the initial point was in a solid area + qboolean inopen, inwater; + float fraction; // time completed, 1.0 = didn't hit anything + vec3_t endpos; // final position + plane_t plane; // surface normal at impact + edict_t *ent; // entity the surface is on + int hitgroup; // 0 == generic, non zero is specific body part +} trace_t; + #endif//CONST_H \ No newline at end of file diff --git a/common/entity_types.h b/common/entity_types.h index 0e9df46d..69791528 100644 --- a/common/entity_types.h +++ b/common/entity_types.h @@ -23,6 +23,5 @@ #define ET_FRAGMENTED 4 // BMODEL or SPRITE that was split across BSP nodes #define ET_VIEWENTITY 5 // special case for firstperson viewmodel #define ET_PORTAL 6 // this is portal surface -#define ET_SKYPORTAL 7 // env_sky use this #endif//ENTITY_TYPES_H \ No newline at end of file diff --git a/common/mathlib.h b/common/mathlib.h index 9fe0bffa..3c18e336 100644 --- a/common/mathlib.h +++ b/common/mathlib.h @@ -14,6 +14,8 @@ ****/ // mathlib.h +#include + typedef float vec_t; typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4]; // x,y,z,w diff --git a/common/netadr.h b/common/netadr.h index f0ed6a18..16aafe30 100644 --- a/common/netadr.h +++ b/common/netadr.h @@ -21,7 +21,9 @@ typedef enum NA_UNUSED, NA_LOOPBACK, NA_BROADCAST, - NA_IP + NA_IP, + NA_IPX, + NA_BROADCAST_IPX } netadrtype_t; typedef struct netadr_s diff --git a/game_shared/pm_debug.h b/common/nowin.h similarity index 61% rename from game_shared/pm_debug.h rename to common/nowin.h index c856ea17..f193ec10 100644 --- a/game_shared/pm_debug.h +++ b/common/nowin.h @@ -12,13 +12,12 @@ * without written permission from Valve LLC. * ****/ -#ifndef PM_DEBUG_H -#define PM_DEBUG_H -#pragma once -void PM_ViewEntity( void ); -void PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life); -void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert); -void PM_ShowClipBox( void ); +#ifndef INC_NOWIN_H +#define INC_NOWIN_H +#ifndef _WIN32 -#endif // PMOVEDBG_H +#include + +#endif//!_WIN32 +#endif//INC_NOWIN_H \ No newline at end of file diff --git a/common/playerinfo.h b/common/playerinfo.h new file mode 100644 index 00000000..5a5b4a22 --- /dev/null +++ b/common/playerinfo.h @@ -0,0 +1,47 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + +#ifndef PLAYERINFO_H +#define PLAYERINFO_H + +#define MAX_SCOREBOARDNAME 32 +#define MAX_INFO_STRING 256 + +typedef struct player_info_s +{ + int userid; // User id on server + char userinfo[MAX_INFO_STRING]; // User info string + char name[MAX_SCOREBOARDNAME]; // Name (extracted from userinfo) + int spectator; // Spectator or not, unused + + int ping; + int packet_loss; + + // skin information + char model[64]; + int topcolor; + int bottomcolor; + + // last frame rendered + int renderframe; + + // Gait frame estimation + int gaitsequence; + float gaitframe; + float gaityaw; + vec3_t prevgaitorigin; +} player_info_t; + +#endif//PLAYERINFO_H \ No newline at end of file diff --git a/common/pmtrace.h b/common/pmtrace.h index 4dbd89d4..e2779ad6 100644 --- a/common/pmtrace.h +++ b/common/pmtrace.h @@ -22,12 +22,13 @@ typedef struct float dist; } pmplane_t; -typedef struct pmtrace_s +typedef struct pmtrace_s pmtrace_t; + +struct pmtrace_s { qboolean allsolid; // if true, plane is not valid qboolean startsolid; // if true, the initial point was in a solid area - qboolean inopen; - qboolean inwater; // End point is in empty space or in water + qboolean inopen, inwater; // End point is in empty space or in water float fraction; // time completed, 1.0 = didn't hit anything vec3_t endpos; // final position pmplane_t plane; // surface normal at impact @@ -35,6 +36,6 @@ typedef struct pmtrace_s vec3_t deltavelocity; // Change in player's velocity caused by impact. // Only run on server. int hitgroup; -} pmtrace_t; +}; #endif//PM_TRACE_H \ No newline at end of file diff --git a/common/qfont.h b/common/qfont.h index 40ba2728..8489dffc 100644 --- a/common/qfont.h +++ b/common/qfont.h @@ -16,16 +16,8 @@ #ifndef QFONT_H #define QFONT_H -/* -======================================================================== +// Font stuff -.QFONT image format - -======================================================================== -*/ -#define QCHAR_WIDTH 16 -#define QFONT_WIDTH 16 // valve fonts used contant sizes -#define QFONT_HEIGHT ((128 - 32) / 16) #define NUM_GLYPHS 256 typedef struct @@ -34,14 +26,13 @@ typedef struct short charwidth; } charinfo; -typedef struct +typedef struct qfont_s { - int width; - int height; + int width, height; int rowcount; int rowheight; charinfo fontinfo[NUM_GLYPHS]; - byte data[4]; // variable sized + byte data[4]; } qfont_t; #endif//QFONT_H \ No newline at end of file diff --git a/common/r_efx.h b/common/r_efx.h index aee496a2..4ad60eef 100644 --- a/common/r_efx.h +++ b/common/r_efx.h @@ -83,7 +83,6 @@ color24 gTracerColors[] = #define FTENT_NOMODEL 0x00040000 // Doesn't have a model, never try to draw ( it just triggers other things ) #define FTENT_CLIENTCUSTOM 0x00080000 // Must specify callback. Callback function is responsible for killing tempent and updating fields ( unless other flags specify how to do things ) #define FTENT_SCALE 0x00100000 // An experiment -#define FTENT_ATTACHMENT 0x00200000 // This is a dynamically relinked attachment (update every frame) typedef struct tempent_s TEMPENTITY; typedef struct tempent_s @@ -117,17 +116,6 @@ typedef struct efx_api_s efx_api_t; struct efx_api_s { - void (*R_GetPaletteColor)( int colorIndex, float *outColor ); - int (*CL_DecalIndex)( int id ); - int (*CL_DecalIndexFromName)( const char *szDecalName ); - void (*CL_DecalShoot)( HSPRITE hDecal, int entityIndex, int modelIndex, float *pos, int flags ); - void (*R_PlayerDecal)( HSPRITE hDecal, int entityIndex, float *pos, byte *color ); - dlight_t* (*CL_AllocDLight)( int key ); - dlight_t* (*CL_AllocELight)( int key ); - void (*R_LightForPoint)( const float *rgflOrigin, float *lightValue ); - int (*CL_IsBoxVisible)( const float *mins, const float *maxs ); - int (*R_CullBox)( const float *mins, const float *maxs ); -// ORIGINAL HL INTEFACE particle_t *(*R_AllocParticle)( void (*callback)( struct particle_s *particle, float frametime )); void (*R_BlobExplosion)( float *org ); void (*R_Blood)( float *org, float *dir, int pcolor, int speed ); diff --git a/common/r_studioint.h b/common/r_studioint.h new file mode 100644 index 00000000..88ac5fd8 --- /dev/null +++ b/common/r_studioint.h @@ -0,0 +1,150 @@ +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + + +#ifndef R_STUDIOINT_H +#define R_STUDIOINT_H + +#define STUDIO_INTERFACE_VERSION 1 + +typedef struct engine_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc )( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check )( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); + // Retrieve model pointer for the named model + struct model_s *( *Mod_ForName )( const char *name, int crash_if_missing ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata )( struct model_s *mod ); + // Retrieve indexed model from client side model precache list + struct model_s *( *GetModelByIndex )( int index ); + // Get entity that is set for rendering + struct cl_entity_s * ( *GetCurrentEntity )( void ); + // Get referenced player_info_t + struct player_info_s *( *PlayerInfo )( int index ); + // Get most recently received player state data from network system + struct entity_state_s *( *GetPlayerState )( int index ); + // Get viewentity + struct cl_entity_s * ( *GetViewEntity )( void ); + // Get current frame count, and last two timestampes on client + void ( *GetTimes )( int *framecount, double *current, double *old ); + // Get a pointer to a cvar by name + struct cvar_s *( *GetCvar )( const char *name ); + // Get current render origin and view vectors ( up, right and vpn ) + void ( *GetViewInfo )( float *origin, float *upv, float *rightv, float *vpnv ); + // Get sprite model used for applying chrome effect + struct model_s *( *GetChromeSprite )( void ); + // Get model counters so we can incement instrumentation + void ( *GetModelCounters )( int **s, int **a ); + // Get software scaling coefficients + void ( *GetAliasScale )( float *x, float *y ); + + // Get bone, light, alias, and rotation matrices + float ****( *StudioGetBoneTransform )( void ); + float ****( *StudioGetLightTransform )( void ); + float ***( *StudioGetAliasTransform )( void ); + float ***( *StudioGetRotationMatrix )( void ); + + // Set up body part, and get submodel pointers + void ( *StudioSetupModel )( int bodypart, void **ppbodypart, void **ppsubmodel ); + // Check if entity's bbox is in the view frustum + int ( *StudioCheckBBox )( void ); + // Apply lighting effects to model + void ( *StudioDynamicLight )( struct cl_entity_s *ent, struct alight_s *plight ); + void ( *StudioEntityLight )( struct alight_s *plight ); + void ( *StudioSetupLighting )( struct alight_s *plighting ); + + // Draw mesh vertices + void ( *StudioDrawPoints )( void ); + + // Draw hulls around bones + void ( *StudioDrawHulls )( void ); + // Draw bbox around studio models + void ( *StudioDrawAbsBBox )( void ); + // Draws bones + void ( *StudioDrawBones )( void ); + // Loads in appropriate texture for model + void ( *StudioSetupSkin )( void *ptexturehdr, int index ); + // Sets up for remapped colors + void ( *StudioSetRemapColors )( int top, int bottom ); + // Set's player model and returns model pointer + struct model_s *( *SetupPlayerModel )( int index ); + // Fires any events embedded in animation + void ( *StudioClientEvents )( void ); + // Retrieve/set forced render effects flags + int ( *GetForceFaceFlags )( void ); + void ( *SetForceFaceFlags )( int flags ); + // Tell engine the value of the studio model header + void ( *StudioSetHeader )( void *header ); + // Tell engine which model_t * is being renderered + void ( *SetRenderModel )( struct model_s *model ); + + // Final state setup and restore for rendering + void ( *SetupRenderer )( int rendermode ); + void ( *RestoreRenderer )( void ); + + // Set render origin for applying chrome effect + void ( *SetChromeOrigin )( void ); + + // True if using D3D/OpenGL + int ( *IsHardware )( void ); + + // Only called by hardware interface + void ( *GL_StudioDrawShadow )( void ); + void ( *GL_SetRenderMode )( int mode ); +} engine_studio_api_t; + +typedef struct server_studio_api_s +{ + // Allocate number*size bytes and zero it + void *( *Mem_Calloc )( int number, size_t size ); + // Check to see if pointer is in the cache + void *( *Cache_Check )( struct cache_user_s *c ); + // Load file into cache ( can be swapped out on demand ) + void ( *LoadCacheFile )( char *path, struct cache_user_s *cu ); + // Retrieve pointer to studio model data block from a model + void *( *Mod_Extradata )( struct model_s *mod ); +} server_studio_api_t; + +// client blending +typedef struct r_studio_interface_s +{ + int version; + int ( *StudioDrawModel )( int flags ); + int ( *StudioDrawPlayer )( int flags, struct entity_state_s *pplayer ); +} r_studio_interface_t; + +// server blending +#define SV_BLENDING_INTERFACE_VERSION 1 + +typedef struct sv_blending_interface_s +{ + int version; + + void ( *SV_StudioSetupBones )( struct model_s *pModel, + float frame, + int sequence, + const vec3_t angles, + const vec3_t origin, + const byte *pcontroller, + const byte *pblending, + int iBone, + const edict_t *pEdict ); +} sv_blending_interface_t; + +#endif//R_STUDIOINT_H \ No newline at end of file diff --git a/common/ref_params.h b/common/ref_params.h index bf8c875b..86fa9dde 100644 --- a/common/ref_params.h +++ b/common/ref_params.h @@ -1,25 +1,21 @@ -//======================================================================= -// Copyright XashXT Group 2009 й -// ref_params.h - client rendering state -//======================================================================= +/*** +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +****/ + #ifndef REF_PARAMS_H #define REF_PARAMS_H -// renderer flags -#define RDF_NOWORLDMODEL (1<<0) // used for player configuration screen -#define RDF_PORTALINVIEW (1<<1) // draw portal pass -#define RDF_SKYPORTALINVIEW (1<<2) // draw skyportal instead of regular sky -#define RDF_NOFOVADJUSTMENT (1<<3) // do not adjust fov for widescreen -#define RDF_THIRDPERSON (1<<4) // enable chase cam instead firstperson - -typedef struct skyportal_s -{ - float fov; - float scale; - vec3_t vieworg; - vec3_t viewanglesOffset; -} skyportal_t; - typedef struct ref_params_s { // output @@ -30,50 +26,50 @@ typedef struct ref_params_s vec3_t right; vec3_t up; - float frametime; // client frametime - float time; // client time + // Client frametime; + float frametime; + // Client time + float time; + // Misc int intermission; int paused; int spectator; - int onground; // true if client is onground + int onground; int waterlevel; - vec3_t simvel; // client velocity (came from server) - vec3_t simorg; // client origin (without viewheight) + vec3_t simvel; + vec3_t simorg; vec3_t viewheight; float idealpitch; - vec3_t cl_viewangles; // predicted angles - + vec3_t cl_viewangles; int health; - vec3_t crosshairangle; // pfnCrosshairAngle values from server + vec3_t crosshairangle; float viewsize; - vec3_t punchangle; // receivied from server + vec3_t punchangle; int maxclients; - int viewentity; // entity that set with svc_setview else localclient - int num_entities; // entities actual count (was int playernum;) + int viewentity; + int playernum; int max_entities; int demoplayback; - float lerpfrac; // interpolate value ( increase from 0.0 to 1.0 ) was int hardware; - int smoothing; // client movement predicting is running + int hardware; + int smoothing; - struct usercmd_s *cmd; // last issued usercmd - struct movevars_s *movevars; // sv.movevars + // Last issued usercmd + struct usercmd_s *cmd; - int viewport[4]; // x, y, width, height + // Movevars + struct movevars_s *movevars; + + int viewport[4]; // the viewport coordinates x, y, width, height int nextView; // the renderer calls ClientDLL_CalcRefdef() and Renderview // so long in cycles until this value is 0 (multiple views) - int flags; // renderer setup flags (was int onlyClientDraw;) + int onlyClientDraw; // if !=0 nothing is drawn by the engine except clientDraw functions - // Xash Renderer Specifics - skyportal_t skyportal; // sky protal setup is done in HUD_UpdateEntityVars - float blend[4]; // rgba 0-1 full screen blend - - float fov_x; - float fov_y; // fov_y = V_CalcFov( fov_x, viewport[2], viewport[3] ); + float fov_x, fov_y; // actual fov can be overrided on nextView } ref_params_t; #endif//REF_PARAMS_H \ No newline at end of file diff --git a/common/triangleapi.h b/common/triangleapi.h index a609bf64..4606efd7 100644 --- a/common/triangleapi.h +++ b/common/triangleapi.h @@ -32,12 +32,6 @@ typedef enum #define TRI_TRIANGLE_STRIP 5 #define TRI_QUAD_STRIP 6 -typedef enum -{ - TRI_SHADER = 1, - TRI_MAXCAPS -} TRI_CAPS; - typedef struct triangleapi_s { int version; @@ -53,18 +47,11 @@ typedef struct triangleapi_s void (*Vertex3f)( float x, float y, float z ); void (*Brightness)( float brightness ); void (*CullFace)( TRICULLSTYLE style ); - int (*GetSpriteTexture)( int spriteIndex, int spriteFrame ); + int (*SpriteTexture)( struct model_s *pSpriteModel, int frame ); int (*WorldToScreen)( float *world, float *screen ); // Returns 1 if it's z clipped void (*Fog)( float flFogColor[3], float flStart, float flEnd, int bOn ); //Works just like GL_FOG, flFogColor is r/g/b. void (*ScreenToWorld)( float *screen, float *world ); - // Xash3D interface starts here - int (*LoadShader)( const char *szShaderName, int fShaderNoMip ); - void (*Enable)( int cap ); - void (*Disable)( int cap ); - void (*Normal3f)( float x, float y, float z ); - void (*Normal3fv)( const float *v ); - void (*Bind)( int shader, int frame ); // use handle that return LoadShader } triangleapi_t; #endif//TRIANGLEAPI_H \ No newline at end of file diff --git a/debug.bat b/debug.bat index ebef8cad..029ea7aa 100644 --- a/debug.bat +++ b/debug.bat @@ -11,13 +11,13 @@ call vcvars32 %MSDEV% dlls/hl.dsp %CONFIG%"hl - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% client/client.dsp %CONFIG%"client - Win32 Debug" %build_target% +%MSDEV% cl_dll/cl_dll.dsp %CONFIG%"cl_dll - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 %MSDEV% engine/engine.dsp %CONFIG%"engine - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% gameui/gameui.dsp %CONFIG%"gameui - Win32 Debug" %build_target% +%MSDEV% mainui/mainui.dsp %CONFIG%"mainui - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 %MSDEV% launch/launch.dsp %CONFIG%"launch - Win32 Debug" %build_target% @@ -29,7 +29,7 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% snd_dx/snd_dx.dsp %CONFIG%"snd_dx - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% xtools/xtools.dsp %CONFIG%"xtools - Win32 Debug" %build_target% +%MSDEV% utils/utils.dsp %CONFIG%"utils - Win32 Debug" %build_target% if errorlevel 1 set BUILD_ERROR=1 if "%BUILD_ERROR%"=="" goto build_ok @@ -52,14 +52,14 @@ goto done rem //delete log files if exist dlls\hl.plg del /f /q dlls\hl.plg -if exist client\client.plg del /f /q client\client.plg +if exist cl_dll\cl_dll.plg del /f /q cl_dll\cl_dll.plg if exist engine\engine.plg del /f /q engine\engine.plg -if exist gameui\gameui.plg del /f /q gameui\gameui.plg +if exist mainui\mainui.plg del /f /q mainui\mainui.plg if exist launch\launch.plg del /f /q launch\launch.plg if exist vid_gl\vid_gl.plg del /f /q vid_gl\vid_gl.plg if exist viewer\viewer.plg del /f /q viewer\viewer.plg if exist snd_dx\snd_dx.plg del /f /q snd_dx\snd_dx.plg -if exist xtools\xtools.plg del /f /q xtools\xtools.plg +if exist utils\utils.plg del /f /q utils\utils.plg echo echo Build succeeded! diff --git a/dlls/animating.cpp b/dlls/animating.cpp index 1a6595eb..6afc3956 100644 --- a/dlls/animating.cpp +++ b/dlls/animating.cpp @@ -247,7 +247,7 @@ int CBaseAnimating :: GetBodygroup( int iGroup ) } -int CBaseAnimating :: ExtractBbox( int sequence, Vector &mins, Vector &maxs ) +int CBaseAnimating :: ExtractBbox( int sequence, float *mins, float *maxs ) { return ::ExtractBbox( GET_MODEL_PTR( ENT(pev) ), sequence, mins, maxs ); } diff --git a/dlls/animation.cpp b/dlls/animation.cpp index 6db230d1..14b6087c 100644 --- a/dlls/animation.cpp +++ b/dlls/animation.cpp @@ -16,10 +16,22 @@ #include #include -#include "extdll.h" -#include "studio.h" -#include "util.h" +#include "../common/nowin.h" +typedef int BOOL; +#define TRUE 1 +#define FALSE 0 + +// hack into header files that we can ship +typedef int qboolean; +typedef unsigned char byte; +#include "mathlib.h" +#include "const.h" +#include "progdefs.h" +#include "edict.h" +#include "eiface.h" + +#include "studio.h" #ifndef ACTIVITY_H #include "activity.h" @@ -35,7 +47,17 @@ #include "scriptevent.h" #endif -int ExtractBbox( void *pmodel, int sequence, Vector &mins, Vector &maxs ) +#ifndef ENGINECALLBACK_H +#include "enginecallback.h" +#endif + +extern globalvars_t *gpGlobals; + +#pragma warning( disable : 4244 ) + + + +int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ) { studiohdr_t *pstudiohdr; @@ -116,7 +138,7 @@ int LookupActivityHeaviest( void *pmodel, entvars_t *pev, int activity ) return seq; } -void GetEyePosition ( void *pmodel, Vector &vecEyePosition ) +void GetEyePosition ( void *pmodel, float *vecEyePosition ) { studiohdr_t *pstudiohdr; @@ -128,7 +150,7 @@ void GetEyePosition ( void *pmodel, Vector &vecEyePosition ) return; } - vecEyePosition = pstudiohdr->eyeposition; + VectorCopy ( pstudiohdr->eyeposition, vecEyePosition ); } int LookupSequence( void *pmodel, const char *label ) @@ -193,10 +215,7 @@ void SequencePrecache( void *pmodel, const char *pSequenceName ) ALERT( at_error, "Bad sound event %d in sequence %s :: %s (sound is \"%s\")\n", pevent[i].event, pstudiohdr->name, pSequenceName, pevent[i].options ); } - // g-cont. old code crash server when using StringTable - // new code working fine in both modes - PRECACHE_SOUND( (char *)STRING( ALLOC_STRING( pevent[i].options )) ); -// PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) ); + PRECACHE_SOUND( (char *)(gpGlobals->pStringBase + ALLOC_STRING(pevent[i].options) ) ); } } } diff --git a/dlls/animation.h b/dlls/animation.h index e835fcac..77281673 100644 --- a/dlls/animation.h +++ b/dlls/animation.h @@ -31,14 +31,14 @@ int GetSequenceFlags( void *pmodel, entvars_t *pev ); int LookupAnimationEvents( void *pmodel, entvars_t *pev, float flStart, float flEnd ); float SetController( void *pmodel, entvars_t *pev, int iController, float flValue ); float SetBlending( void *pmodel, entvars_t *pev, int iBlender, float flValue ); -void GetEyePosition( void *pmodel, Vector &vecEyePosition ); +void GetEyePosition( void *pmodel, float *vecEyePosition ); void SequencePrecache( void *pmodel, const char *pSequenceName ); int FindTransition( void *pmodel, int iEndingAnim, int iGoalAnim, int *piDir ); void SetBodygroup( void *pmodel, entvars_t *pev, int iGroup, int iValue ); int GetBodygroup( void *pmodel, entvars_t *pev, int iGroup ); int GetAnimationEvent( void *pmodel, entvars_t *pev, MonsterEvent_t *pMonsterEvent, float flStart, float flEnd, int index ); -int ExtractBbox( void *pmodel, int sequence, Vector &mins, Vector &maxs ); +int ExtractBbox( void *pmodel, int sequence, float *mins, float *maxs ); // From /engine/studio.h #define STUDIO_LOOPING 0x0001 diff --git a/dlls/cbase.cpp b/dlls/cbase.cpp index 52fb7188..73c63ae3 100644 --- a/dlls/cbase.cpp +++ b/dlls/cbase.cpp @@ -23,9 +23,9 @@ void EntvarsKeyvalue( entvars_t *pev, KeyValueData *pkvd ); -extern void PM_Move ( struct playermove_s *ppmove, int server ); -extern void PM_Init ( struct playermove_s *ppmove ); -extern char PM_FindTextureType( char *name ); +extern "C" void PM_Move ( struct playermove_s *ppmove, int server ); +extern "C" void PM_Init ( struct playermove_s *ppmove ); +extern "C" char PM_FindTextureType( char *name ); extern Vector VecBModelOrigin( entvars_t* pevBModel ); extern DLL_GLOBAL Vector g_vecAttackDir; diff --git a/dlls/cbase.h b/dlls/cbase.h index cbee60d7..d3e13d0c 100644 --- a/dlls/cbase.h +++ b/dlls/cbase.h @@ -482,7 +482,7 @@ public: void GetAttachment ( int iAttachment, Vector &origin, Vector &angles ); void SetBodygroup( int iGroup, int iValue ); int GetBodygroup( int iGroup ); - int ExtractBbox( int sequence, Vector &mins, Vector &maxs ); + int ExtractBbox( int sequence, float *mins, float *maxs ); void SetSequenceBox( void ); // animation needs diff --git a/dlls/client.cpp b/dlls/client.cpp index eca23299..224fd883 100644 --- a/dlls/client.cpp +++ b/dlls/client.cpp @@ -33,7 +33,7 @@ #include "soundent.h" #include "gamerules.h" #include "game.h" -#include "../engine/customentity.h" +#include "customentity.h" #include "weapons.h" #include "weaponinfo.h" #include "usercmd.h" @@ -199,6 +199,9 @@ void ClientPutInServer( edict_t *pEntity ) pPlayer->pev->effects |= EF_NOINTERP; } +#include "voice_gamemgr.h" +extern CVoiceGameMgr g_VoiceGameMgr; + //// HOST_SAY // String comes in as // say blah blah blah @@ -305,6 +308,10 @@ void Host_Say( edict_t *pEntity, int teamonly ) if ( !(client->IsNetClient()) ) // Not a client ? (should never be true) continue; + // can the receiver hear the sender? or has he muted him? + if ( g_VoiceGameMgr.PlayerHasBlockedPlayer( client, player ) ) + continue; + if ( teamonly && g_pGameRules->PlayerRelationship(client, CBaseEntity::Instance(pEntity)) != GR_TEAMMATE ) continue; @@ -394,37 +401,7 @@ void ClientCommand( edict_t *pEntity ) GetClassPtr((CBasePlayer *)pev)->GiveNamedItem( STRING(iszItem) ); } } - else if ( FStrEq(pcmd, "fire" )) - { - if ( g_flWeaponCheat != 0.0) - { - CBaseEntity *pPlayer = CBaseEntity::Instance(pEntity); - if (CMD_ARGC() > 1) - { - FireTargets(CMD_ARGV(1), pPlayer, pPlayer, USE_TOGGLE, 0); - } - else - { - TraceResult tr; - UTIL_MakeVectors(pev->v_angle); - UTIL_TraceLine( - pev->origin + pev->view_ofs, - pev->origin + pev->view_ofs + gpGlobals->v_forward * 1024, - dont_ignore_monsters, pEntity, &tr - ); - if (tr.pHit) - { - CBaseEntity *pHitEnt = CBaseEntity::Instance(tr.pHit); - if (pHitEnt) - { - pHitEnt->Use(pPlayer, pPlayer, USE_TOGGLE, 0); - ClientPrint( &pEntity->v, HUD_PRINTCONSOLE, UTIL_VarArgs( "Fired %s \"%s\"\n", STRING(pHitEnt->pev->classname), STRING(pHitEnt->pev->targetname) ) ); - } - } - } - } - } else if ( FStrEq(pcmd, "drop" ) ) { // player is dropping an item. @@ -968,14 +945,15 @@ we could also use the pas/ pvs that we set in SetupVisibility, if we wanted to. */ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ) { - int i; + int i; // don't send if flagged for NODRAW and it's not the host getting the message - if (( ent->v.effects == EF_NODRAW ) && ( ent != host )) + if ( ( ent->v.effects == EF_NODRAW ) && + ( ent != host ) ) return 0; // Ignore ents without valid / visible models - if ( !ent->v.modelindex || !STRING( ent->v.model )) + if ( !ent->v.modelindex || !STRING( ent->v.model ) ) return 0; // Don't send spectators to other players @@ -988,7 +966,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h // If pSet is NULL, then the test will always succeed and the entity will be added to the update if ( ent != host ) { - if ( !ENGINE_CHECK_VISIBILITY( ent, pSet )) + if ( !ENGINE_CHECK_VISIBILITY( (const struct edict_s *)ent, pSet ) ) { // env_sky is visible always if( !FClassnameIs( ent, "env_sky" )) @@ -1003,7 +981,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h if ( ent->v.flags & FL_SKIPLOCALHOST ) { if ( hostflags & 4 ) return 0; // it's a portal pass - if (( hostflags & 1 ) && ( ent->v.owner == host )) + if ( ( hostflags & 1 ) && ( ent->v.owner == host ) ) return 0; } @@ -1032,8 +1010,8 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h memset( state, 0, sizeof( *state ) ); // Assign index so we can track this entity from frame to frame and - // delta from it. - state->number = e; + // delta from it. + state->number = e; state->entityType = ENTITY_NORMAL; // Flag custom entities. @@ -1057,7 +1035,7 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h memcpy( state->startpos, ent->v.startpos, 3 * sizeof( float ) ); memcpy( state->endpos, ent->v.endpos, 3 * sizeof( float ) ); memcpy( state->velocity, ent->v.velocity, 3 * sizeof( float ) ); - + state->impacttime = ent->v.impacttime; state->starttime = ent->v.starttime; @@ -1070,14 +1048,18 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h // This non-player entity is being moved by the game .dll and not the physics simulation system // make sure that we interpolate it's position on the client if it moves - if ( !player && ent->v.animtime && ent->v.velocity == g_vecZero ) + if ( !player && + ent->v.animtime && + ent->v.velocity[ 0 ] == 0 && + ent->v.velocity[ 1 ] == 0 && + ent->v.velocity[ 2 ] == 0 ) { state->eflags |= EFLAG_SLERP; } - state->scale = ent->v.scale; - state->solid = ent->v.solid; - state->colormap = ent->v.colormap; + state->scale = ent->v.scale; + state->solid = ent->v.solid; + state->colormap = ent->v.colormap; state->movetype = ent->v.movetype; state->sequence = ent->v.sequence; @@ -1139,14 +1121,14 @@ int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *h state->weaponmodel = MODEL_INDEX( STRING( ent->v.weaponmodel ) ); state->gaitsequence = ent->v.gaitsequence; - state->spectator = ent->v.flags & FL_SPECTATOR; + state->spectator = ent->v.flags & FL_SPECTATOR; state->friction = ent->v.friction; state->gravity = ent->v.gravity; -// state->team = ent->v.team; +// state->team = ent->v.team; // state->usehull = ( ent->v.flags & FL_DUCKING ) ? 1 : 0; - state->health = ent->v.health; + state->health = ent->v.health; } return 1; @@ -1166,8 +1148,8 @@ void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, st { baseline->origin = entity->v.origin; baseline->angles = entity->v.angles; - baseline->frame = entity->v.frame; - baseline->skin = (short)entity->v.skin; + baseline->frame = entity->v.frame; + baseline->skin = (short)entity->v.skin; // render information baseline->rendermode = (byte)entity->v.rendermode; @@ -1179,31 +1161,31 @@ void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, st if ( player ) { - baseline->mins = player_mins; - baseline->maxs = player_maxs; + baseline->mins = player_mins; + baseline->maxs = player_maxs; baseline->colormap = eindex; baseline->modelindex = playermodelindex; baseline->friction = 1.0; baseline->movetype = MOVETYPE_WALK; - baseline->scale = entity->v.scale; - baseline->solid = SOLID_SLIDEBOX; + baseline->scale = entity->v.scale; + baseline->solid = SOLID_SLIDEBOX; baseline->framerate = 1.0; baseline->gravity = 1.0; } else { - baseline->mins = entity->v.mins; - baseline->maxs = entity->v.maxs; + baseline->mins = entity->v.mins; + baseline->maxs = entity->v.maxs; baseline->colormap = 0; baseline->modelindex = entity->v.modelindex;//SV_ModelIndex(pr_strings + entity->v.model); baseline->movetype = entity->v.movetype; - baseline->scale = entity->v.scale; - baseline->solid = entity->v.solid; + baseline->scale = entity->v.scale; + baseline->solid = entity->v.solid; baseline->framerate = entity->v.framerate; baseline->gravity = entity->v.gravity; } @@ -1463,15 +1445,9 @@ void RegisterEncoders( void ) DELTA_ADDENCODER( "Player_Encode", Player_Encode ); } -/* -================= -GetWeaponData - -Engine call this function only for clients with cl_lw == 1 -================= -*/ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) { +#if defined( CLIENT_WEAPONS ) int i; weapon_data_t *item; entvars_t *pev = &player->v; @@ -1480,7 +1456,7 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) ItemInfo II; - memset( info, 0, 32 * sizeof( weapon_data_t )); + memset( info, 0, 32 * sizeof( weapon_data_t ) ); if ( !pl ) return 1; @@ -1509,27 +1485,29 @@ int GetWeaponData( struct edict_s *player, struct weapon_data_s *info ) item->m_iId = II.iId; item->m_iClip = gun->m_iClip; - item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001 ); - item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001 ); + item->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle, -0.001 ); + item->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack, -0.001 ); item->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack, -0.001 ); - item->m_fInReload = gun->m_fInReload; - item->m_fInSpecialReload = gun->m_fInSpecialReload; - item->fuser1 = max( gun->pev->fuser1, -0.001 ); - item->fuser2 = gun->m_flStartThrow; - item->fuser3 = gun->m_flReleaseThrow; - item->iuser1 = gun->m_chargeReady; - item->iuser2 = gun->m_fInAttack; - item->iuser3 = gun->m_fireState; + item->m_fInReload = gun->m_fInReload; + item->m_fInSpecialReload = gun->m_fInSpecialReload; + item->fuser1 = max( gun->pev->fuser1, -0.001 ); + item->fuser2 = gun->m_flStartThrow; + item->fuser3 = gun->m_flReleaseThrow; + item->iuser1 = gun->m_chargeReady; + item->iuser2 = gun->m_fInAttack; + item->iuser3 = gun->m_fireState; -// item->m_flPumpTime = max( gun->m_flPumpTime, -0.001 ); +// item->m_flPumpTime = max( gun->m_flPumpTime, -0.001 ); } } pPlayerItem = pPlayerItem->m_pNext; } } } - +#else + memset( info, 0, 32 * sizeof( weapon_data_t ) ); +#endif return 1; } @@ -1572,7 +1550,7 @@ void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clien cd->pushmsec = ent->v.pushmsec; - // engine determine which client is using predicting +#if defined( CLIENT_WEAPONS ) if ( sendweapons ) { entvars_t *pev = (entvars_t *)&ent->v; @@ -1612,13 +1590,14 @@ void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clien if ( pl->m_pActiveItem->m_iId == WEAPON_RPG ) { - cd->vuser2.y = (( CRpg * )pl->m_pActiveItem)->m_fSpotActive; - cd->vuser2.z = (( CRpg * )pl->m_pActiveItem)->m_cActiveRockets; + cd->vuser2.y = ( ( CRpg * )pl->m_pActiveItem)->m_fSpotActive; + cd->vuser2.z = ( ( CRpg * )pl->m_pActiveItem)->m_cActiveRockets; } } } } } +#endif } /* @@ -1634,7 +1613,9 @@ void CmdStart( const edict_t *player, const struct usercmd_s *cmd, unsigned int entvars_t *pev = (entvars_t *)&player->v; CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - if ( !pl ) return; + if( !pl ) + return; + if ( pl->pev->groupinfo != 0 ) { UTIL_SetGroupTrace( pl->pev->groupinfo, GROUP_OP_AND ); @@ -1650,13 +1631,13 @@ CmdEnd Each cmdstart is exactly matched with a cmd end, clean up any group trace flags, etc. here ================= */ -void CmdEnd( const edict_t *player ) +void CmdEnd ( const edict_t *player ) { entvars_t *pev = (entvars_t *)&player->v; CBasePlayer *pl = ( CBasePlayer *) CBasePlayer::Instance( pev ); - if ( !pl ) return; - + if( !pl ) + return; if ( pl->pev->groupinfo != 0 ) { UTIL_UnsetGroupTrace(); @@ -1698,19 +1679,19 @@ int GetHullBounds( int hullnumber, float *mins, float *maxs ) switch ( hullnumber ) { - case 0: // Normal player - VEC_HULL_MIN.CopyToArray( mins ); - VEC_HULL_MAX.CopyToArray( maxs ); + case 0: // Normal player + mins = VEC_HULL_MIN; + maxs = VEC_HULL_MAX; iret = 1; break; - case 1: // Crouched player - VEC_DUCK_HULL_MIN.CopyToArray( mins ); - VEC_DUCK_HULL_MAX.CopyToArray( maxs ); + case 1: // Crouched player + mins = VEC_DUCK_HULL_MIN; + maxs = VEC_DUCK_HULL_MAX; iret = 1; break; - case 2: // Point based hull - g_vecZero.CopyToArray( mins ); - g_vecZero.CopyToArray( maxs ); + case 2: // Point based hull + mins = Vector( 0, 0, 0 ); + maxs = Vector( 0, 0, 0 ); iret = 1; break; } diff --git a/dlls/client.h b/dlls/client.h index 8bf3acd9..2e0b38ed 100644 --- a/dlls/client.h +++ b/dlls/client.h @@ -42,7 +42,7 @@ extern void SpectatorThink ( edict_t *pEntity ); extern void Sys_Error( const char *error_string ); extern void SetupVisibility( edict_t *pViewEntity, edict_t *pClient, unsigned char **pvs, unsigned char **pas ); -extern void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); +extern void UpdateClientData ( const struct edict_s *ent, int sendweapons, struct clientdata_s *cd ); extern int AddToFullPack( struct entity_state_s *state, int e, edict_t *ent, edict_t *host, int hostflags, int player, unsigned char *pSet ); extern void CreateBaseline( int player, int eindex, struct entity_state_s *baseline, struct edict_s *entity, int playermodelindex, vec3_t player_mins, vec3_t player_maxs ); extern void RegisterEncoders( void ); diff --git a/dlls/crossbow.cpp b/dlls/crossbow.cpp index 69e2149c..049d6f1c 100644 --- a/dlls/crossbow.cpp +++ b/dlls/crossbow.cpp @@ -315,7 +315,7 @@ BOOL CCrossbow::Deploy( ) return DefaultDeploy( "models/v_crossbow.mdl", "models/p_crossbow.mdl", CROSSBOW_DRAW2, "bow" ); } -void CCrossbow::Holster( void ) +void CCrossbow::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE;// cancel any reload in progress. @@ -324,7 +324,7 @@ void CCrossbow::Holster( void ) SecondaryAttack( ); } - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if (m_iClip) SendWeaponAnim( CROSSBOW_HOLSTER1 ); else @@ -333,7 +333,12 @@ void CCrossbow::Holster( void ) void CCrossbow::PrimaryAttack( void ) { + +#ifdef CLIENT_DLL if ( m_fInZoom && bIsMultiplayer() ) +#else + if ( m_fInZoom && g_pGameRules->IsMultiplayer() ) +#endif { FireSniperBolt(); return; @@ -345,7 +350,7 @@ void CCrossbow::PrimaryAttack( void ) // this function only gets called in multiplayer void CCrossbow::FireSniperBolt() { - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; if (m_iClip == 0) { @@ -359,15 +364,11 @@ void CCrossbow::FireSniperBolt() m_iClip--; int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); @@ -406,15 +407,11 @@ void CCrossbow::FireBolt() m_iClip--; int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrossbow, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType], 0, 0 ); @@ -451,14 +448,14 @@ void CCrossbow::FireBolt() // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.75; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; if (m_iClip != 0) - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 5.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; else - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.75; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; } @@ -475,8 +472,8 @@ void CCrossbow::SecondaryAttack() m_fInZoom = 1; } - pev->nextthink = m_pPlayer->WeaponTimeBase() + 0.1; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 1.0; + pev->nextthink = UTIL_WeaponTimeBase() + 0.1; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; } @@ -503,7 +500,7 @@ void CCrossbow::WeaponIdle( void ) ResetEmptySound( ); - if ( m_flTimeWeaponIdle < m_pPlayer->WeaponTimeBase() ) + if ( m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) { float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0, 1 ); if (flRand <= 0.75) @@ -516,19 +513,19 @@ void CCrossbow::WeaponIdle( void ) { SendWeaponAnim( CROSSBOW_IDLE2 ); } - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } else { if (m_iClip) { SendWeaponAnim( CROSSBOW_FIDGET1 ); - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 90.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; } else { SendWeaponAnim( CROSSBOW_FIDGET2 ); - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 80.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 30.0; } } } diff --git a/dlls/crowbar.cpp b/dlls/crowbar.cpp index b01a1865..f301de7f 100644 --- a/dlls/crowbar.cpp +++ b/dlls/crowbar.cpp @@ -91,9 +91,9 @@ BOOL CCrowbar::Deploy( ) return DefaultDeploy( "models/v_crowbar.mdl", "models/p_crowbar.mdl", CROWBAR_DRAW, "crowbar" ); } -void CCrowbar::Holster( void ) +void CCrowbar::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; SendWeaponAnim( CROWBAR_HOLSTER ); } @@ -168,7 +168,7 @@ void CCrowbar::SwingAgain( void ) int CCrowbar::Swing( int fFirst ) { int fDidHit = FALSE; - BOOL bHit = FALSE; + TraceResult tr; UTIL_MakeVectors (m_pPlayer->pev->v_angle); @@ -193,27 +193,17 @@ int CCrowbar::Swing( int fFirst ) } #endif - int flags; + PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usCrowbar, + 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0, + 0.0, 0, 0.0 ); - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } if ( tr.flFraction >= 1.0 ) { - if ( fFirst ) + if (fFirst) { - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usCrowbar, - 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0, 0, 0, - 0.0, 0, 0.0 ); - // miss - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); @@ -242,15 +232,15 @@ int CCrowbar::Swing( int fFirst ) ClearMultiDamage( ); - if (( m_flNextPrimaryAttack + 1 < m_pPlayer->WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) + if ( (m_flNextPrimaryAttack + 1 < UTIL_WeaponTimeBase() ) || g_pGameRules->IsMultiplayer() ) { // first swing does full damage - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB ); + pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar, gpGlobals->v_forward, &tr, DMG_CLUB ); } else { // subsequent swings do half - pEntity->TraceAttack( m_pPlayer->pev, gSkillData.plrDmgCrowbar / 2, gpGlobals->v_forward, &tr, DMG_CLUB ); + pEntity->TraceAttack(m_pPlayer->pev, gSkillData.plrDmgCrowbar / 2, gpGlobals->v_forward, &tr, DMG_CLUB ); } ApplyMultiDamage( m_pPlayer->pev, m_pPlayer->pev ); @@ -314,23 +304,15 @@ int CCrowbar::Swing( int fFirst ) m_pPlayer->m_iWeaponVolume = flVol * CROWBAR_WALLHIT_VOLUME; #endif - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.25; - + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; + SetThink( Smack ); - pev->nextthink = m_pPlayer->WeaponTimeBase() + 0.2; - + pev->nextthink = UTIL_WeaponTimeBase() + 0.2; + } return fDidHit; } -void CCrowbar:: WeaponIdle( void ) -{ - if ( m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) return; - float flRand = RANDOM_FLOAT(0, 1); - if ( flRand <= 0.5 ) - { - SendWeaponAnim( CROWBAR_IDLE ); - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + RANDOM_FLOAT ( 10, 15 ); - } -} \ No newline at end of file + + diff --git a/dlls/effects.cpp b/dlls/effects.cpp index 2a648ad1..5d7a1b38 100644 --- a/dlls/effects.cpp +++ b/dlls/effects.cpp @@ -2265,122 +2265,4 @@ void CItemSoda::CanTouch ( CBaseEntity *pOther ) SetTouch ( NULL ); SetThink ( SUB_Remove ); pev->nextthink = gpGlobals->time; -} - -#ifdef BSHIFT_DLL -//========================================================= -// env_warpball -//========================================================= -#define SF_REMOVE_ON_FIRE 0x0001 -#define SF_KILL_CENTER 0x0002 - -class CEnvWarpBall : public CBaseEntity -{ -public: - void Precache( void ); - void Spawn( void ) { Precache(); } - void Think( void ); - void KeyValue( KeyValueData *pkvd ); - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - virtual int ObjectCaps( void ) { return CBaseEntity :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } - Vector vecOrigin; -}; - -LINK_ENTITY_TO_CLASS( env_warpball, CEnvWarpBall ); - -void CEnvWarpBall :: KeyValue( KeyValueData *pkvd ) -{ - if (FStrEq(pkvd->szKeyName, "radius")) - { - pev->button = atoi(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "warp_target")) - { - pev->message = ALLOC_STRING(pkvd->szValue); - pkvd->fHandled = TRUE; - } - if (FStrEq(pkvd->szKeyName, "damage_delay")) - { - pev->frags = atof(pkvd->szValue); - pkvd->fHandled = TRUE; - } - else - CBaseEntity::KeyValue( pkvd ); -} - -void CEnvWarpBall::Precache( void ) -{ - PRECACHE_MODEL( "sprites/lgtning.spr" ); - PRECACHE_MODEL( "sprites/Fexplo1.spr" ); - PRECACHE_SOUND( "debris/beamstart2.wav" ); - PRECACHE_SOUND( "debris/beamstart7.wav" ); -} - -void CEnvWarpBall::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - int iTimes = 0; - int iDrawn = 0; - TraceResult tr; - Vector vecDest; - CBeam *pBeam; - CBaseEntity *pEntity = UTIL_FindEntityByTargetname ( NULL, STRING(pev->message)); - edict_t *pos; - - if(pEntity)//target found ? - { - vecOrigin = pEntity->pev->origin; - pos = pEntity->edict(); - } - else - { //use as center - vecOrigin = pev->origin; - pos = edict(); - } - EMIT_SOUND( pos, CHAN_BODY, "debris/beamstart2.wav", 1, ATTN_NORM ); - UTIL_ScreenShake( vecOrigin, 6, 160, 1.0, pev->button ); - CSprite *pSpr = CSprite::SpriteCreate( "sprites/Fexplo1.spr", vecOrigin, TRUE ); - pSpr->AnimateAndDie( 18 ); - pSpr->SetTransparency(kRenderGlow, 77, 210, 130, 255, kRenderFxNoDissipation); - EMIT_SOUND( pos, CHAN_ITEM, "debris/beamstart7.wav", 1, ATTN_NORM ); - int iBeams = RANDOM_LONG(20, 40); - while (iDrawn < iBeams && iTimes < (iBeams * 3)) - { - vecDest = pev->button * (Vector(RANDOM_FLOAT(-1,1), RANDOM_FLOAT(-1,1), RANDOM_FLOAT(-1,1)).Normalize()); - UTIL_TraceLine( vecOrigin, vecOrigin + vecDest, ignore_monsters, NULL, &tr); - if (tr.flFraction != 1.0) - { - // we hit something. - iDrawn++; - pBeam = CBeam::BeamCreate("sprites/lgtning.spr", 200); - pBeam->PointsInit( vecOrigin, tr.vecEndPos ); - pBeam->SetColor( 20, 243, 20 ); - pBeam->SetNoise( 65 ); - pBeam->SetBrightness( 220 ); - pBeam->SetWidth( 30 ); - pBeam->SetScrollRate( 35 ); - pBeam->SetThink(&CBeam:: SUB_Remove ); - pBeam->pev->nextthink = gpGlobals->time + RANDOM_FLOAT(0.5, 1.6); - } - iTimes++; - } - pev->nextthink = gpGlobals->time + pev->frags; -} - -void CEnvWarpBall::Think( void ) -{ - SUB_UseTargets( this, USE_TOGGLE, 0); - - if ( pev->spawnflags & SF_KILL_CENTER ) - { - CBaseEntity *pMonster = NULL; - - while ((pMonster = UTIL_FindEntityInSphere( pMonster, vecOrigin, 72 )) != NULL) - { - if ( FBitSet( pMonster->pev->flags, FL_MONSTER ) || FClassnameIs( pMonster->pev, "player")) - pMonster->TakeDamage ( pev, pev, 100, DMG_GENERIC ); - } - } - if ( pev->spawnflags & SF_REMOVE_ON_FIRE ) UTIL_Remove( this ); -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/dlls/egon.cpp b/dlls/egon.cpp index 7a98c43b..43cde79b 100644 --- a/dlls/egon.cpp +++ b/dlls/egon.cpp @@ -107,12 +107,12 @@ int CEgon::AddToPlayer( CBasePlayer *pPlayer ) -void CEgon::Holster( void ) +void CEgon::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; SendWeaponAnim( EGON_HOLSTER ); - EndAttack(); + EndAttack(); } int CEgon::GetItemInfo(ItemInfo *p) @@ -183,15 +183,11 @@ void CEgon::Attack( void ) Vector vecSrc = m_pPlayer->GetGunPosition( ); int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif switch( m_fireState ) { @@ -199,7 +195,7 @@ void CEgon::Attack( void ) { if ( !HasAmmo() ) { - m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.25; + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.25; PlayEmptySound( ); return; } @@ -211,8 +207,8 @@ void CEgon::Attack( void ) m_shakeTime = 0; m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.1; - pev->fuser1 = m_pPlayer->WeaponTimeBase() + 2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; + pev->fuser1 = UTIL_WeaponTimeBase() + 2; pev->dmgtime = gpGlobals->time + GetPulseInterval(); m_fireState = FIRE_CHARGE; @@ -224,7 +220,7 @@ void CEgon::Attack( void ) Fire( vecSrc, vecAiming ); m_pPlayer->m_iWeaponVolume = EGON_PRIMARY_VOLUME; - if ( pev->fuser1 <= m_pPlayer->WeaponTimeBase() ) + if ( pev->fuser1 <= UTIL_WeaponTimeBase() ) { PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usEgonFire, 0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, m_fireState, m_fireMode, 0, 0 ); pev->fuser1 = 1000; @@ -233,7 +229,7 @@ void CEgon::Attack( void ) if ( !HasAmmo() ) { EndAttack(); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 1.0; + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; } } @@ -284,6 +280,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) #endif + float timedist; switch ( m_fireMode ) @@ -300,7 +297,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) } ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - if ( bIsMultiplayer() ) + if ( g_pGameRules->IsMultiplayer() ) { // multiplayer uses 1 ammo every 1/10th second if ( gpGlobals->time >= m_flAmmoUseTime ) @@ -337,7 +334,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) } ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); - if ( bIsMultiplayer() ) + if ( g_pGameRules->IsMultiplayer() ) { // radius damage a little more potent in multiplayer. ::RadiusDamage( tr.vecEndPos, pev, m_pPlayer->pev, gSkillData.plrDmgEgonWide/4, 128, CLASS_NONE, DMG_ENERGYBEAM | DMG_BLAST | DMG_ALWAYSGIB ); @@ -346,7 +343,7 @@ void CEgon::Fire( const Vector &vecOrigSrc, const Vector &vecDir ) if ( !m_pPlayer->IsAlive() ) return; - if ( bIsMultiplayer() ) + if ( g_pGameRules->IsMultiplayer() ) { //multiplayer uses 5 ammo/second if ( gpGlobals->time >= m_flAmmoUseTime ) @@ -418,6 +415,7 @@ void CEgon::UpdateEffect( const Vector &startPoint, const Vector &endPoint, floa void CEgon::CreateEffect( void ) { + #ifndef CLIENT_DLL DestroyEffect(); @@ -460,11 +458,13 @@ void CEgon::CreateEffect( void ) m_pNoise->SetNoise( 2 ); } #endif + } void CEgon::DestroyEffect( void ) { + #ifndef CLIENT_DLL if ( m_pBeam ) { @@ -485,6 +485,7 @@ void CEgon::DestroyEffect( void ) m_pSprite = NULL; } #endif + } @@ -506,12 +507,12 @@ void CEgon::WeaponIdle( void ) if ( flRand <= 0.5 ) { iAnim = EGON_IDLE1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } else { iAnim = EGON_FIDGET1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; } SendWeaponAnim( iAnim ); @@ -529,8 +530,8 @@ void CEgon::EndAttack( void ) PLAYBACK_EVENT_FULL( FEV_GLOBAL | FEV_RELIABLE, m_pPlayer->edict(), m_usEgonStop, 0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, bMakeNoise, 0, 0, 0 ); - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 2.0; - m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; m_fireState = FIRE_OFF; diff --git a/dlls/enginecallback.h b/dlls/enginecallback.h index d5a74b90..aad3724d 100644 --- a/dlls/enginecallback.h +++ b/dlls/enginecallback.h @@ -81,7 +81,7 @@ inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin = NU #define WRITE_COORD (*g_engfuncs.pfnWriteCoord) #define WRITE_STRING (*g_engfuncs.pfnWriteString) #define WRITE_ENTITY (*g_engfuncs.pfnWriteEntity) -#define CVAR_REGISTER (*g_engfuncs.pfnCvar_RegisterVariable) +#define CVAR_REGISTER (*g_engfuncs.pfnCVarRegister) #define CVAR_GET_FLOAT (*g_engfuncs.pfnCVarGetFloat) #define CVAR_GET_STRING (*g_engfuncs.pfnCVarGetString) #define CVAR_SET_FLOAT (*g_engfuncs.pfnCVarSetFloat) @@ -133,7 +133,6 @@ inline void *GET_PRIVATE( edict_t *pent ) #define ENGINE_SET_PAS (*g_engfuncs.pfnSetFatPAS) #define ENGINE_CHECK_VISIBILITY (*g_engfuncs.pfnCheckVisibility) -#define ENGINE_BOX_VISIBLE (*g_engfuncs.pfnCheckVisible) #define DELTA_SET ( *g_engfuncs.pfnDeltaSetField ) #define DELTA_UNSET ( *g_engfuncs.pfnDeltaUnsetField ) diff --git a/dlls/extdll.h b/dlls/extdll.h index b5cb5947..31e48554 100644 --- a/dlls/extdll.h +++ b/dlls/extdll.h @@ -33,17 +33,30 @@ #pragma warning(disable : 4100) // unreferenced formal parameter // Prevent tons of unused windows definitions +#ifdef _WIN32 #define WIN32_LEAN_AND_MEAN #define NOWINRES #define NOSERVICE #define NOMCX #define NOIME #include "windows.h" - +#else // _WIN32 +#define FALSE 0 +#define TRUE (!FALSE) +typedef unsigned long ULONG; +typedef unsigned char BYTE; +typedef int BOOL; +#define MAX_PATH PATH_MAX +#include +#include +#ifndef min +#define min(a,b) (((a) < (b)) ? (a) : (b)) +#endif #ifndef max #define max(a,b) (((a) > (b)) ? (a) : (b)) #define _vsnprintf(a,b,c,d) vsnprintf(a,b,c,d) #endif +#endif //_WIN32 // Misc C-runtime library headers #include "stdio.h" @@ -64,10 +77,10 @@ typedef float vec_t; // needed before including progdefs.h // Shared engine/DLL constants #include "const.h" #include "progdefs.h" -#include "../engine/edict.h" +#include "edict.h" // Shared header describing protocol between engine and DLLs -#include "../engine/eiface.h" +#include "eiface.h" // Shared header between the client DLL and the game DLLs #include "cdll_dll.h" diff --git a/dlls/game.cpp b/dlls/game.cpp index fc8678d5..b4b6da75 100644 --- a/dlls/game.cpp +++ b/dlls/game.cpp @@ -452,10 +452,6 @@ cvar_t sk_player_leg3 = { "sk_player_leg3","1" }; // This gets called one time when the game is initialied void GameDLLInit( void ) { -#ifndef SYS_SHAREDSTRINGS - // tell engine what we want use StringTable system instead of shared strings - gpGlobals->pStringBase = NULL; -#endif // Register cvars here: g_psv_gravity = CVAR_GET_POINTER( "sv_gravity" ); @@ -889,7 +885,3 @@ void GameDLLInit( void ) SERVER_COMMAND( "exec skill.cfg\n" ); } -// perform any shutdown operations -void GameDLLShutdown( void ) -{ -} \ No newline at end of file diff --git a/dlls/gauss.cpp b/dlls/gauss.cpp index 8bc6e7cf..d89a41cf 100644 --- a/dlls/gauss.cpp +++ b/dlls/gauss.cpp @@ -45,11 +45,16 @@ LINK_ENTITY_TO_CLASS( weapon_gauss, CGauss ); float CGauss::GetFullChargeTime( void ) { +#ifdef CLIENT_DLL if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { - return 1.5f; + return 1.5; } - return 4.0f; + + return 4; } #ifdef CLIENT_DLL @@ -125,11 +130,11 @@ BOOL CGauss::Deploy( ) return DefaultDeploy( "models/v_gauss.mdl", "models/p_gauss.mdl", GAUSS_DRAW, "gauss" ); } -void CGauss::Holster( void ) +void CGauss::Holster( int skiplocal /* = 0 */ ) { PLAYBACK_EVENT_FULL( FEV_RELIABLE | FEV_GLOBAL, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; SendWeaponAnim( GAUSS_HOLSTER ); m_fInAttack = 0; @@ -142,14 +147,14 @@ void CGauss::PrimaryAttack() if ( m_pPlayer->pev->waterlevel == 3 ) { PlayEmptySound( ); - m_flNextSecondaryAttack = m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.15; + m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] < 2 ) { PlayEmptySound( ); - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; return; } @@ -160,8 +165,8 @@ void CGauss::PrimaryAttack() StartFire(); m_fInAttack = 0; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.2; } void CGauss::SecondaryAttack() @@ -180,51 +185,40 @@ void CGauss::SecondaryAttack() PlayEmptySound( ); } - m_flNextSecondaryAttack = m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; return; } - int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } - if ( m_fInAttack == 0 ) { if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0 ) { EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; return; } m_fPrimaryFire = FALSE; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--;// take one ammo just to start the spin - m_pPlayer->m_flNextAmmoBurn = m_pPlayer->WeaponTimeBase(); + m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase(); // spin up m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; SendWeaponAnim( GAUSS_SPINUP ); m_fInAttack = 1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; m_pPlayer->m_flStartCharge = gpGlobals->time; - m_pPlayer->m_flAmmoStartCharge = m_pPlayer->WeaponTimeBase() + GetFullChargeTime(); + m_pPlayer->m_flAmmoStartCharge = UTIL_WeaponTimeBase() + GetFullChargeTime(); - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); + PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 110, 0, 0, 0 ); m_iSoundState = SND_CHANGE_PITCH; } else if (m_fInAttack == 1) { - if (m_flTimeWeaponIdle < m_pPlayer->WeaponTimeBase()) + if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase()) { SendWeaponAnim( GAUSS_SPIN ); m_fInAttack = 2; @@ -233,17 +227,21 @@ void CGauss::SecondaryAttack() else { // during the charging process, eat one bit of ammo every once in a while - if ( m_pPlayer->WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) + if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flNextAmmoBurn && m_pPlayer->m_flNextAmmoBurn != 1000 ) { - if ( bIsMultiplayer() ) +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = m_pPlayer->WeaponTimeBase() + 0.1; + m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.1; } else { m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_pPlayer->m_flNextAmmoBurn = m_pPlayer->WeaponTimeBase() + 0.3; + m_pPlayer->m_flNextAmmoBurn = UTIL_WeaponTimeBase() + 0.3; } } @@ -252,12 +250,12 @@ void CGauss::SecondaryAttack() // out of ammo! force the gun to fire StartFire(); m_fInAttack = 0; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1; return; } - if ( m_pPlayer->WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) + if ( UTIL_WeaponTimeBase() >= m_pPlayer->m_flAmmoStartCharge ) { // don't eat any more ammo after gun is fully charged. m_pPlayer->m_flNextAmmoBurn = 1000; @@ -272,13 +270,13 @@ void CGauss::SecondaryAttack() if ( m_iSoundState == 0 ) ALERT( at_console, "sound state %d\n", m_iSoundState ); - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 ); + PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussSpin, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, pitch, 0, ( m_iSoundState == SND_CHANGE_PITCH ) ? 1 : 0, 0 ); m_iSoundState = SND_CHANGE_PITCH; // hack for going through level transitions m_pPlayer->m_iWeaponVolume = GAUSS_PRIMARY_CHARGE_VOLUME; - // m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.1; + // m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.1; if ( m_pPlayer->m_flStartCharge < gpGlobals->time - 10 ) { // Player charged up too long. Zap him. @@ -286,17 +284,14 @@ void CGauss::SecondaryAttack() EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/electro6.wav", 1.0, ATTN_NORM, 0, 75 + RANDOM_LONG(0,0x3f)); m_fInAttack = 0; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 1.0; - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 1.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; #ifndef CLIENT_DLL m_pPlayer->TakeDamage( VARS(eoNullEntity), VARS(eoNullEntity), 50, DMG_SHOCK ); UTIL_ScreenFade( m_pPlayer, Vector(255,128,0), 2, 0.5, 128, FFADE_IN ); #endif SendWeaponAnim( GAUSS_IDLE ); - - // g-cont. kill spinning sound after shock (SDK 2.3 bug) - PLAYBACK_EVENT_FULL( flags | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); // Player may have been killed and this weapon dropped, don't execute any more code after this! return; @@ -386,25 +381,15 @@ void CGauss::Fire( Vector vecOrigSrc, Vector vecDir, float flDamage ) if ( m_fPrimaryFire == false ) g_irunninggausspred = true; #endif - - int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } // The main firing event is sent unreliably so it won't be delayed. - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); + PLAYBACK_EVENT_FULL( FEV_NOTHOST, m_pPlayer->edict(), m_usGaussFire, 0.0, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, flDamage, 0.0, 0, 0, m_fPrimaryFire ? 1 : 0, 0 ); // This reliable event is used to stop the spinning sound // It's delayed by a fraction of second to make sure it is delayed by 1 frame on the client // It's sent reliably anyway, which could lead to other delays - PLAYBACK_EVENT_FULL( flags | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); + + PLAYBACK_EVENT_FULL( FEV_NOTHOST | FEV_RELIABLE, m_pPlayer->edict(), m_usGaussFire, 0.01, (float *)&m_pPlayer->pev->origin, (float *)&m_pPlayer->pev->angles, 0.0, 0.0, 0, 0, 0, 1 ); /*ALERT( at_console, "%f %f %f\n%f %f %f\n", @@ -570,14 +555,14 @@ void CGauss::WeaponIdle( void ) m_pPlayer->m_flPlayAftershock = 0.0; } - if (m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase()) + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) return; if (m_fInAttack != 0) { StartFire(); m_fInAttack = 0; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 2.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0; } else { @@ -586,17 +571,17 @@ void CGauss::WeaponIdle( void ) if (flRand <= 0.5) { iAnim = GAUSS_IDLE; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } else if (flRand <= 0.75) { iAnim = GAUSS_IDLE2; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } else { iAnim = GAUSS_FIDGET; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; } return; diff --git a/dlls/genericmonster.cpp b/dlls/genericmonster.cpp index 0d926a14..8f40be61 100644 --- a/dlls/genericmonster.cpp +++ b/dlls/genericmonster.cpp @@ -20,17 +20,15 @@ #include "cbase.h" #include "monsters.h" #include "schedule.h" -#include "talkmonster.h" // For holograms, make them not solid so the player can walk through them -#define SF_GENERICMONSTER_NOTSOLID 4 -#define SF_HEAD_CONTROLLER 8 +#define SF_GENERICMONSTER_NOTSOLID 4 //========================================================= // Monster's Anim Events Go Here //========================================================= -class CGenericMonster : public CTalkMonster +class CGenericMonster : public CBaseMonster { public: void Spawn( void ); @@ -122,11 +120,6 @@ void CGenericMonster :: Spawn() MonsterInit(); - if ( pev->spawnflags & SF_HEAD_CONTROLLER ) - { - m_afCapability = bits_CAP_TURN_HEAD; - } - if ( pev->spawnflags & SF_GENERICMONSTER_NOTSOLID ) { pev->solid = SOLID_NOT; @@ -139,8 +132,6 @@ void CGenericMonster :: Spawn() //========================================================= void CGenericMonster :: Precache() { - CTalkMonster::Precache(); - TalkInit(); PRECACHE_MODEL( (char *)STRING(pev->model) ); } diff --git a/dlls/glock.cpp b/dlls/glock.cpp index 451e2348..b0a04b9a 100644 --- a/dlls/glock.cpp +++ b/dlls/glock.cpp @@ -34,6 +34,28 @@ enum glock_e { GLOCK_ADD_SILENCER }; +class CGlock : public CBasePlayerWeapon +{ +public: + void Spawn( void ); + void Precache( void ); + int iItemSlot( void ) { return 2; } + int GetItemInfo(ItemInfo *p); + + void PrimaryAttack( void ); + void SecondaryAttack( void ); + void GlockFire( float flSpread, float flCycleTime, BOOL fUseAutoAim ); + BOOL Deploy( void ); + void Reload( void ); + void WeaponIdle( void ); + +private: + int m_iShell; + + + unsigned short m_usFireGlock1; + unsigned short m_usFireGlock2; +}; LINK_ENTITY_TO_CLASS( weapon_glock, CGlock ); LINK_ENTITY_TO_CLASS( weapon_9mmhandgun, CGlock ); @@ -110,7 +132,7 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) if (m_fFireOnEmpty) { PlayEmptySound(); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.2; + m_flNextPrimaryAttack = gpGlobals->time + 0.2; } return; @@ -120,31 +142,60 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; - int flags; +#if defined ( OLD_WEAPONS ) + if (m_iClip != 0) + SendWeaponAnim( GLOCK_SHOOT ); + else + SendWeaponAnim( GLOCK_SHOOT_EMPTY ); +#endif - if( IsLocalWeapon( )) + if ( fUseAutoAim ) { - flags = FEV_NOTHOST; + PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock1, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); } else { - flags = 0; + PLAYBACK_EVENT_FULL( 0, m_pPlayer->edict(), m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); } // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); +#if defined ( OLD_WEAPONS ) + UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); + + Vector vecShellVelocity = m_pPlayer->pev->velocity + + gpGlobals->v_right * RANDOM_FLOAT(50,70) + + gpGlobals->v_up * RANDOM_FLOAT(100,150) + + gpGlobals->v_forward * 25; + EjectBrass ( pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_up * -12 + gpGlobals->v_forward * 32 + gpGlobals->v_right * 6 , vecShellVelocity, pev->angles.y, m_iShell, TE_BOUNCE_SHELL ); +#endif + // silenced if (pev->body == 1) { m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; +#if defined ( OLD_WEAPONS ) + switch(RANDOM_LONG(0,1)) + { + case 0: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun1.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); + break; + case 1: + EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun2.wav", RANDOM_FLOAT(0.9, 1.0), ATTN_NORM); + break; + } +#endif } else { // non-silenced m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; +#if defined ( OLD_WEAPONS ) + EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/pl_gun3.wav", RANDOM_FLOAT(0.92, 1.0), ATTN_NORM, 0, 98 + RANDOM_LONG(0,3)); +#endif } Vector vecSrc = m_pPlayer->GetGunPosition( ); @@ -159,36 +210,34 @@ void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) vecAiming = gpGlobals->v_forward; } - Vector vecDir; - vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + m_pPlayer->FireBullets( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0 ); - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); - - m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + flCycleTime; + m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->time + flCycleTime; if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); + +#if defined ( OLD_WEAPONS ) + m_pPlayer->pev->punchangle.x -= 2; +#endif } void CGlock::Reload( void ) { - if ( m_pPlayer->ammo_9mm <= 0 ) - return; - int iResult; if (m_iClip == 0) iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); else - iResult = DefaultReload( 17, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); + iResult = DefaultReload( 18, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); if (iResult) { - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = gpGlobals->time + RANDOM_FLOAT ( 10, 15 ); } } @@ -200,29 +249,28 @@ void CGlock::WeaponIdle( void ) m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); - if ( m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) + if (m_flTimeWeaponIdle > gpGlobals->time) return; // only idle if the slid isn't back if (m_iClip != 0) { int iAnim; - float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 ); - + float flRand = RANDOM_FLOAT(0, 1); if (flRand <= 0.3 + 0 * 0.75) { iAnim = GLOCK_IDLE3; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 49.0 / 16; + m_flTimeWeaponIdle = gpGlobals->time + 49.0 / 16; } else if (flRand <= 0.6 + 0 * 0.875) { iAnim = GLOCK_IDLE1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 60.0 / 16.0; + m_flTimeWeaponIdle = gpGlobals->time + 60.0 / 16.0; } else { iAnim = GLOCK_IDLE2; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 40.0 / 16.0; + m_flTimeWeaponIdle = gpGlobals->time + 40.0 / 16.0; } SendWeaponAnim( iAnim ); } diff --git a/dlls/h_cycler.cpp b/dlls/h_cycler.cpp index ed146e77..a306359f 100644 --- a/dlls/h_cycler.cpp +++ b/dlls/h_cycler.cpp @@ -315,7 +315,7 @@ public: void PrimaryAttack( void ); void SecondaryAttack( void ); BOOL Deploy( void ); - void Holster( void ); + void Holster( int skiplocal = 0 ); int m_iszModel; int m_iModel; }; @@ -342,16 +342,16 @@ void CWeaponCycler::Spawn( ) BOOL CWeaponCycler::Deploy( ) { m_pPlayer->pev->viewmodel = m_iszModel; - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; SendWeaponAnim( 0 ); m_iClip = 0; return TRUE; } -void CWeaponCycler::Holster( void ) +void CWeaponCycler::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; } diff --git a/dlls/h_export.cpp b/dlls/h_export.cpp index 36dec5a3..96a57fd7 100644 --- a/dlls/h_export.cpp +++ b/dlls/h_export.cpp @@ -30,22 +30,40 @@ enginefuncs_t g_engfuncs; globalvars_t *gpGlobals; +#ifdef _WIN32 + // Required DLL entry point -BOOL WINAPI DllMain( HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved ) +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) { - if ( fdwReason == DLL_PROCESS_ATTACH ) - { - - } - else if ( fdwReason == DLL_PROCESS_DETACH ) - { - - } + if (fdwReason == DLL_PROCESS_ATTACH) + { + } + else if (fdwReason == DLL_PROCESS_DETACH) + { + } return TRUE; } -void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +void DLLEXPORT GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) { - memcpy( &g_engfuncs, pengfuncsFromEngine, sizeof( enginefuncs_t )); + memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); gpGlobals = pGlobals; } + + +#else + +extern "C" { + +void GiveFnptrsToDll( enginefuncs_t* pengfuncsFromEngine, globalvars_t *pGlobals ) +{ + memcpy(&g_engfuncs, pengfuncsFromEngine, sizeof(enginefuncs_t)); + gpGlobals = pGlobals; +} + +} + +#endif diff --git a/dlls/handgrenade.cpp b/dlls/handgrenade.cpp index b61e4bae..007ad662 100644 --- a/dlls/handgrenade.cpp +++ b/dlls/handgrenade.cpp @@ -47,6 +47,7 @@ void CHandGrenade::Spawn( ) #ifndef CLIENT_DLL pev->dmg = gSkillData.plrDmgHandGrenade; #endif + m_iDefaultAmmo = HANDGRENADE_DEFAULT_GIVE; FallInit();// get ready to fall down. @@ -90,9 +91,9 @@ BOOL CHandGrenade::CanHolster( void ) return ( m_flStartThrow == 0 ); } -void CHandGrenade::Holster( void ) +void CHandGrenade::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if ( m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) { @@ -117,7 +118,7 @@ void CHandGrenade::PrimaryAttack() m_flReleaseThrow = 0; SendWeaponAnim( HANDGRENADE_PINPULL ); - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; } } @@ -127,7 +128,7 @@ void CHandGrenade::WeaponIdle( void ) if ( m_flReleaseThrow == 0 && m_flStartThrow ) m_flReleaseThrow = gpGlobals->time; - if ( m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; if ( m_flStartThrow ) @@ -174,8 +175,8 @@ void CHandGrenade::WeaponIdle( void ) m_flReleaseThrow = 0; m_flStartThrow = 0; - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ]--; @@ -184,7 +185,7 @@ void CHandGrenade::WeaponIdle( void ) // just threw last grenade // set attack times in the future, and weapon idle in the future so we can see the whole throw // animation, weapon idle will automatically retire the weapon for us. - m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.5;// ensure that the animation can finish playing + m_flTimeWeaponIdle = m_flNextSecondaryAttack = m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5;// ensure that the animation can finish playing } return; } @@ -203,7 +204,7 @@ void CHandGrenade::WeaponIdle( void ) return; } - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); m_flReleaseThrow = -1; return; } @@ -215,12 +216,12 @@ void CHandGrenade::WeaponIdle( void ) if (flRand <= 0.75) { iAnim = HANDGRENADE_IDLE; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. } else { iAnim = HANDGRENADE_FIDGET; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 75.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 75.0 / 30.0; } SendWeaponAnim( iAnim ); diff --git a/dlls/hl.dsp b/dlls/hl.dsp index c8762604..7eeed72c 100644 --- a/dlls/hl.dsp +++ b/dlls/hl.dsp @@ -19,6 +19,7 @@ CFG=hl - Win32 Release !MESSAGE !MESSAGE "hl - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE "hl - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "hl - Win32 Profile" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -38,13 +39,13 @@ RSC=rc.exe # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\hl\!release" -# PROP Intermediate_Dir "..\temp\hl\!release" +# PROP Output_Dir "..\temp\dlls\!release" +# PROP Intermediate_Dir "..\temp\dlls\!release" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\dlls" /I "..\common" /I "..\engine" /I "..\game_shared" /I "..\\" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c -# SUBTRACT CPP /Fr /YX +# ADD CPP /nologo /G5 /MT /W3 /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /Fr /YX /FD /c +# SUBTRACT CPP /Z # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -54,15 +55,15 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386 -# ADD LINK32 msvcrt.lib /nologo /subsystem:windows /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /def:".\hl.def" -# SUBTRACT LINK32 /profile /map /debug +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\hl.def" +# SUBTRACT LINK32 /profile /map # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\hl\!release -InputPath=\Xash3D\src_main\temp\hl\!release\hl.dll +TargetDir=\Xash3D\src_main\temp\dlls\!release +InputPath=\Xash3D\src_main\temp\dlls\!release\hl.dll SOURCE="$(InputPath)" -"D:\Xash3D\valve\bin\server.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\hl.dll "D:\Xash3D\valve\bin\server.dll" +"D:\Xash3D\valve\dlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\hl.dll "D:\Xash3D\valve\dlls\hl.dll" # End Custom Build @@ -75,31 +76,68 @@ SOURCE="$(InputPath)" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\temp\hl\!debug" -# PROP Intermediate_Dir "..\temp\hl\!debug" +# PROP Output_Dir "..\temp\dlls\!debug" +# PROP Intermediate_Dir "..\temp\dlls\!debug" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\dlls" /I "..\common" /I "..\engine" /I "..\game_shared" /I "..\\" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c -# SUBTRACT CPP /YX +# ADD CPP /nologo /G5 /MTd /W3 /Gm /ZI /Od /I "..\dlls" /I "..\engine" /I "..\common" /I "..\game_shared" /I "..\pm_shared" /I "..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /FR /YX /FD /c # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "_DEBUG" -# ADD RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /i "..\engine" /d "_DEBUG" BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386 -# ADD LINK32 msvcrtd.lib /nologo /subsystem:windows /dll /debug /machine:I386 /nodefaultlib:"libc.lib" /def:".\hl.def" /pdbtype:sept +# ADD LINK32 user32.lib advapi32.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\hl.def" # SUBTRACT LINK32 /profile # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\hl\!debug -InputPath=\Xash3D\src_main\temp\hl\!debug\hl.dll +TargetDir=\Xash3D\src_main\temp\dlls\!debug +InputPath=\Xash3D\src_main\temp\dlls\!debug\hl.dll SOURCE="$(InputPath)" -"D:\Xash3D\valve\bin\server.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\hl.dll "D:\Xash3D\valve\bin\server.dll" +"D:\Xash3D\valve\dlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\hl.dll "D:\Xash3D\valve\dlls\hl.dll" + +# End Custom Build + +!ELSEIF "$(CFG)" == "hl - Win32 Profile" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\hl___Win" +# PROP BASE Intermediate_Dir ".\hl___Win" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "..\temp\dlls\!profile" +# PROP Intermediate_Dir "..\temp\dlls\!profile" +# PROP Ignore_Export_Lib 1 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /G5 /MT /W3 /GX /Zi /O2 /I "..\engine" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /YX /c +# SUBTRACT BASE CPP /Fr +# ADD CPP /nologo /G5 /MT /W3 /Zi /O2 /I "..\dlls" /I "..\engine" /I "..\common" /I "..\pm_shared" /I "..\game_shared" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "QUIVER" /D "VOXEL" /D "QUAKE2" /D "VALVE_DLL" /D "CLIENT_WEAPONS" /YX /FD /c +# SUBTRACT CPP /Fr +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /debug /machine:I386 /def:".\hl.def" +# SUBTRACT BASE LINK32 /profile +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib /nologo /subsystem:windows /dll /profile /debug /machine:I386 /def:".\hl.def" +# Begin Custom Build +TargetDir=\Xash3D\src_main\temp\dlls\!profile +InputPath=\Xash3D\src_main\temp\dlls\!profile\hl.dll +SOURCE="$(InputPath)" + +"D:\Xash3D\valve\dlls\hl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\hl.dll "D:\Xash3D\valve\dlls\hl.dll" # End Custom Build @@ -109,6 +147,7 @@ SOURCE="$(InputPath)" # Name "hl - Win32 Release" # Name "hl - Win32 Debug" +# Name "hl - Win32 Profile" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat;for;f90" @@ -250,10 +289,6 @@ SOURCE=.\globals.cpp # End Source File # Begin Source File -SOURCE=.\glock.cpp -# End Source File -# Begin Source File - SOURCE=.\gman.cpp # End Source File # Begin Source File @@ -298,6 +333,10 @@ SOURCE=.\hgrunt.cpp # End Source File # Begin Source File +SOURCE=.\wpn_shared\hl_wpn_glock.cpp +# End Source File +# Begin Source File + SOURCE=.\hornet.cpp # End Source File # Begin Source File @@ -386,15 +425,15 @@ SOURCE=.\player.cpp # End Source File # Begin Source File -SOURCE=..\game_shared\pm_debug.cpp +SOURCE=..\pm_shared\pm_debug.c # End Source File # Begin Source File -SOURCE=..\game_shared\pm_math.cpp +SOURCE=..\pm_shared\pm_math.c # End Source File # Begin Source File -SOURCE=..\game_shared\pm_shared.cpp +SOURCE=..\pm_shared\pm_shared.c # End Source File # Begin Source File @@ -498,6 +537,10 @@ SOURCE=.\util.cpp # End Source File # Begin Source File +SOURCE=..\game_shared\voice_gamemgr.cpp +# End Source File +# Begin Source File + SOURCE=.\weapons.cpp # End Source File # Begin Source File @@ -618,27 +661,27 @@ SOURCE=.\player.h # End Source File # Begin Source File -SOURCE=..\game_shared\pm_debug.h +SOURCE=..\pm_shared\pm_debug.h # End Source File # Begin Source File -SOURCE=..\game_shared\pm_defs.h +SOURCE=..\pm_shared\pm_defs.h # End Source File # Begin Source File -SOURCE=..\game_shared\pm_info.h +SOURCE=..\pm_shared\pm_info.h # End Source File # Begin Source File -SOURCE=..\game_shared\pm_materials.h +SOURCE=..\pm_shared\pm_materials.h # End Source File # Begin Source File -SOURCE=..\game_shared\pm_movevars.h +SOURCE=..\pm_shared\pm_movevars.h # End Source File # Begin Source File -SOURCE=..\game_shared\pm_shared.h +SOURCE=..\pm_shared\pm_shared.h # End Source File # Begin Source File diff --git a/dlls/hornetgun.cpp b/dlls/hornetgun.cpp index 56531564..76b48894 100644 --- a/dlls/hornetgun.cpp +++ b/dlls/hornetgun.cpp @@ -76,6 +76,7 @@ int CHgun::AddToPlayer( CBasePlayer *pPlayer ) { if ( CBasePlayerWeapon::AddToPlayer( pPlayer ) ) { + #ifndef CLIENT_DLL if ( g_pGameRules->IsMultiplayer() ) { @@ -83,6 +84,7 @@ int CHgun::AddToPlayer( CBasePlayer *pPlayer ) pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] = HORNET_MAX_CARRY; } #endif + MESSAGE_BEGIN( MSG_ONE, gmsgWeapPickup, NULL, pPlayer->pev ); WRITE_BYTE( m_iId ); MESSAGE_END(); @@ -114,9 +116,9 @@ BOOL CHgun::Deploy( ) return DefaultDeploy( "models/v_hgun.mdl", "models/p_hgun.mdl", HGUN_UP, "hive" ); } -void CHgun::Holster( void ) +void CHgun::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; SendWeaponAnim( HGUN_DOWN ); //!!!HACKHACK - can't select hornetgun if it's empty! no way to get ammo for it, either. @@ -152,15 +154,11 @@ void CHgun::PrimaryAttack() m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_TRACK, 0, 0, 0 ); @@ -171,12 +169,12 @@ void CHgun::PrimaryAttack() m_flNextPrimaryAttack = m_flNextPrimaryAttack + 0.25; - if (m_flNextPrimaryAttack < m_pPlayer->WeaponTimeBase() ) + if (m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) { - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.25; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.25; } - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -243,15 +241,11 @@ void CHgun::SecondaryAttack( void ) #endif int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usHornetFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, FIREMODE_FAST, 0, 0, 0 ); @@ -263,8 +257,8 @@ void CHgun::SecondaryAttack( void ) // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - m_flNextPrimaryAttack = m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -285,7 +279,7 @@ void CHgun::WeaponIdle( void ) { Reload( ); - if (m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase()) + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) return; int iAnim; @@ -293,17 +287,17 @@ void CHgun::WeaponIdle( void ) if (flRand <= 0.75) { iAnim = HGUN_IDLE1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 30.0 / 16 * (2); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); } else if (flRand <= 0.875) { iAnim = HGUN_FIDGETSWAY; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 40.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; } else { iAnim = HGUN_FIDGETSHAKE; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 35.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 35.0 / 16.0; } SendWeaponAnim( iAnim ); } diff --git a/dlls/items.cpp b/dlls/items.cpp index 76c95296..dec47540 100644 --- a/dlls/items.cpp +++ b/dlls/items.cpp @@ -340,72 +340,3 @@ class CItemLongJump : public CItem }; LINK_ENTITY_TO_CLASS( item_longjump, CItemLongJump ); - -#ifdef BSHIFT_DLL -class CItemArmorVest : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/barney_vest.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/barney_vest.mdl"); - PRECACHE_SOUND( "items/gunpickup2.wav" ); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) && - (pPlayer->pev->weapons & (1<pev->armorvalue += 60; - pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY); - - EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - - MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); - MESSAGE_END(); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS(item_armorvest, CItemArmorVest); - - -class CItemHelmet : public CItem -{ - void Spawn( void ) - { - Precache( ); - SET_MODEL(ENT(pev), "models/barney_helmet.mdl"); - CItem::Spawn( ); - } - void Precache( void ) - { - PRECACHE_MODEL ("models/barney_helmet.mdl"); - PRECACHE_SOUND( "items/gunpickup2.wav" ); - } - BOOL MyTouch( CBasePlayer *pPlayer ) - { - if ((pPlayer->pev->armorvalue < MAX_NORMAL_BATTERY) && - (pPlayer->pev->weapons & (1<pev->armorvalue += 40; - pPlayer->pev->armorvalue = min(pPlayer->pev->armorvalue, MAX_NORMAL_BATTERY); - - EMIT_SOUND( pPlayer->edict(), CHAN_ITEM, "items/gunpickup2.wav", 1, ATTN_NORM ); - - MESSAGE_BEGIN( MSG_ONE, gmsgItemPickup, NULL, pPlayer->pev ); - WRITE_STRING( STRING(pev->classname) ); - MESSAGE_END(); - return TRUE; - } - return FALSE; - } -}; -LINK_ENTITY_TO_CLASS(item_helmet, CItemHelmet); -#endif \ No newline at end of file diff --git a/dlls/mp5.cpp b/dlls/mp5.cpp index c18b00e5..8ee2ce89 100644 --- a/dlls/mp5.cpp +++ b/dlls/mp5.cpp @@ -131,14 +131,14 @@ void CMP5::PrimaryAttack() if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = 0.15; return; } if (m_iClip <= 0) { PlayEmptySound(); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = 0.15; return; } @@ -157,7 +157,11 @@ void CMP5::PrimaryAttack() Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecDir; +#ifdef CLIENT_DLL if ( !bIsMultiplayer() ) +#else + if ( !g_pGameRules->IsMultiplayer() ) +#endif { // optimized multiplayer. Widened to make it easier to hit a moving player vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_6DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); @@ -168,16 +172,12 @@ void CMP5::PrimaryAttack() vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_3DEGREES, 8192, BULLET_PLAYER_MP5, 2, 0, m_pPlayer->pev, m_pPlayer->random_seed ); } - int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usMP5, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); @@ -185,12 +185,12 @@ void CMP5::PrimaryAttack() // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.1; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; - if ( m_flNextPrimaryAttack < m_pPlayer->WeaponTimeBase() ) - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.1; + if ( m_flNextPrimaryAttack < UTIL_WeaponTimeBase() ) + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -201,7 +201,7 @@ void CMP5::SecondaryAttack( void ) if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = 0.15; return; } @@ -215,7 +215,7 @@ void CMP5::SecondaryAttack( void ) m_pPlayer->m_iWeaponFlash = BRIGHT_GUN_FLASH; m_pPlayer->m_iExtraSoundTypes = bits_SOUND_DANGER; - m_pPlayer->m_flStopExtraSoundTime = m_pPlayer->WeaponTimeBase() + 0.2; + m_pPlayer->m_flStopExtraSoundTime = UTIL_WeaponTimeBase() + 0.2; m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]--; @@ -225,24 +225,22 @@ void CMP5::SecondaryAttack( void ) UTIL_MakeVectors( m_pPlayer->pev->v_angle + m_pPlayer->pev->punchangle ); // we don't add in player velocity anymore. - CGrenade::ShootContact( m_pPlayer->pev, m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16, gpGlobals->v_forward * 800 ); + CGrenade::ShootContact( m_pPlayer->pev, + m_pPlayer->pev->origin + m_pPlayer->pev->view_ofs + gpGlobals->v_forward * 16, + gpGlobals->v_forward * 800 ); int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usMP52 ); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 1; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 5;// idle pretty soon after shooting. + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5;// idle pretty soon after shooting. if (!m_pPlayer->m_rgAmmo[m_iSecondaryAmmoType]) // HEV suit - indicate out of ammo condition @@ -264,7 +262,7 @@ void CMP5::WeaponIdle( void ) m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); - if ( m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; int iAnim; @@ -282,7 +280,7 @@ void CMP5::WeaponIdle( void ) SendWeaponAnim( iAnim ); - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); // how long till we do this again. } diff --git a/dlls/multiplay_gamerules.cpp b/dlls/multiplay_gamerules.cpp index 9239a60f..2e2cab75 100644 --- a/dlls/multiplay_gamerules.cpp +++ b/dlls/multiplay_gamerules.cpp @@ -25,7 +25,8 @@ #include "skill.h" #include "game.h" #include "items.h" -#include "hltv.h" +#include "voice_gamemgr.h" +#include "hltv.h" extern DLL_GLOBAL CGameRules *g_pGameRules; extern DLL_GLOBAL BOOL g_fGameOver; @@ -42,12 +43,34 @@ extern int g_teamplay; float g_flIntermissionStartTime = 0; +CVoiceGameMgr g_VoiceGameMgr; + +class CMultiplayGameMgrHelper : public IVoiceGameMgrHelper +{ +public: + virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) + { + if ( g_teamplay ) + { + if ( g_pGameRules->PlayerRelationship( pListener, pTalker ) != GR_TEAMMATE ) + { + return false; + } + } + + return true; + } +}; +static CMultiplayGameMgrHelper g_GameMgrHelper; + //********************************************************* // Rules for the half-life multiplayer game. //********************************************************* CHalfLifeMultiplay :: CHalfLifeMultiplay() { + g_VoiceGameMgr.Init(&g_GameMgrHelper, gpGlobals->maxClients); + RefreshSkillData(); m_flIntermissionEndTime = 0; g_flIntermissionStartTime = 0; @@ -93,6 +116,9 @@ CHalfLifeMultiplay :: CHalfLifeMultiplay() BOOL CHalfLifeMultiplay::ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { + if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) + return TRUE; + return CGameRules::ClientCommand(pPlayer, pcmd); } @@ -160,6 +186,8 @@ extern cvar_t mp_chattime; //========================================================= void CHalfLifeMultiplay :: Think ( void ) { + g_VoiceGameMgr.Update(gpGlobals->frametime); + ///// Check game rules ///// static int last_frags; static int last_time; @@ -369,6 +397,7 @@ BOOL CHalfLifeMultiplay :: GetNextBestWeapon( CBasePlayer *pPlayer, CBasePlayerI //========================================================= BOOL CHalfLifeMultiplay :: ClientConnected( edict_t *pEntity, const char *pszName, const char *pszAddress, char szRejectReason[ 128 ] ) { + g_VoiceGameMgr.ClientConnected(pEntity); return TRUE; } diff --git a/dlls/plats.cpp b/dlls/plats.cpp index a2de3e2c..a566d7ff 100644 --- a/dlls/plats.cpp +++ b/dlls/plats.cpp @@ -624,7 +624,6 @@ void CFuncPlatRot :: RotMove( Vector &destAngle, float time ) // //====================== TRAIN code ================================================== // -#define SF_TRAIN_WAIT_RETRIGGER 1 class CFuncTrain : public CBasePlatTrain { diff --git a/dlls/player.cpp b/dlls/player.cpp index f4092d7a..bd791e18 100644 --- a/dlls/player.cpp +++ b/dlls/player.cpp @@ -1769,7 +1769,7 @@ void CBasePlayer::PreThink(void) // Debounced button codes for pressed/released // UNDONE: Do we need auto-repeat? - m_afButtonPressed = buttonsChanged & pev->button; // The changed ones still down are "pressed" + m_afButtonPressed = buttonsChanged & pev->button; // The changed ones still down are "pressed" m_afButtonReleased = buttonsChanged & (~pev->button); // The ones not down are "released" g_pGameRules->PlayerThink( this ); @@ -1890,8 +1890,6 @@ void CBasePlayer::PreThink(void) pev->velocity = g_vecZero; } } - - /* Time based Damage works as follows: 1) There are several types of timebased damage: @@ -2569,9 +2567,8 @@ void CBasePlayer::PostThink() m_afButtonLast = pev->button; pt_end: - if( WeaponTimeBase( ) != 0.0f ) return; // predicting is dsiabled - - // Decay timers on weapons +#if defined( CLIENT_WEAPONS ) + // Decay timers on weapons // go through all of the weapons and make a list of the ones to pack for ( int i = 0 ; i < MAX_ITEM_TYPES ; i++ ) { @@ -2587,12 +2584,12 @@ pt_end: if ( gun && gun->UseDecrement() ) { - gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 ); + gun->m_flNextPrimaryAttack = max( gun->m_flNextPrimaryAttack - gpGlobals->frametime, -1.0 ); gun->m_flNextSecondaryAttack = max( gun->m_flNextSecondaryAttack - gpGlobals->frametime, -0.001 ); if ( gun->m_flTimeWeaponIdle != 1000 ) { - gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 ); + gun->m_flTimeWeaponIdle = max( gun->m_flTimeWeaponIdle - gpGlobals->frametime, -0.001 ); } if ( gun->pev->fuser1 != 1000 ) @@ -2632,6 +2629,11 @@ pt_end: if ( m_flAmmoStartCharge < -0.001 ) m_flAmmoStartCharge = -0.001; } + + +#else + return; +#endif } @@ -2796,7 +2798,7 @@ void CBasePlayer::Spawn( void ) m_flFieldOfView = 0.5;// some monsters use this to determine whether or not the player is looking at them. m_bloodColor = BLOOD_COLOR_RED; - m_flNextAttack = WeaponTimeBase(); + m_flNextAttack = UTIL_WeaponTimeBase(); StartSneaking(); m_iFlashBattery = 99; @@ -2882,8 +2884,9 @@ void CBasePlayer :: Precache( void ) m_iClientBattery = -1; -// g-cont. old bug wnen hud lose train HUD after save\restore or changelevel -// m_iTrain = TRAIN_NEW; + m_flFlashLightTime = 1; + + m_iTrain |= TRAIN_NEW; // Make sure any necessary user messages have been registered LinkUserMessages(); @@ -2931,16 +2934,15 @@ int CBasePlayer::Restore( CRestore &restore ) pev->origin = VARS(pentSpawnSpot)->origin + Vector(0,0,1); pev->angles = VARS(pentSpawnSpot)->angles; } - pev->v_angle.z = 0; // Clear out roll pev->angles = pev->v_angle; pev->fixangle = TRUE; // turn this way immediately - // Copied from spawn() for now +// Copied from spawn() for now m_bloodColor = BLOOD_COLOR_RED; - g_ulModelIndexPlayer = pev->modelindex; + g_ulModelIndexPlayer = pev->modelindex; if ( FBitSet(pev->flags, FL_DUCKING) ) { @@ -2967,13 +2969,12 @@ int CBasePlayer::Restore( CRestore &restore ) RenewItems(); +#if defined( CLIENT_WEAPONS ) // HACK: This variable is saved/restored in CBaseMonster as a time variable, but we're using it - // as just a counter. Ideally, this needs its own variable that's saved as a plain float. - // Barring that, we clear it out here instead of using the incorrect restored time value. - if( WeaponTimeBase() == 0.0f ) - { - m_flNextAttack = WeaponTimeBase(); - } + // as just a counter. Ideally, this needs its own variable that's saved as a plain float. + // Barring that, we clear it out here instead of using the incorrect restored time value. + m_flNextAttack = UTIL_WeaponTimeBase(); +#endif return status; } @@ -3266,12 +3267,6 @@ CBaseEntity *FindEntityForward( CBaseEntity *pMe ) return NULL; } -float CBasePlayer :: WeaponTimeBase( void ) -{ - if( ENGINE_CANSKIP( edict() )) - return 0.0f; // local weapons enabled - return gpGlobals->time; // non-predicted weapons -} BOOL CBasePlayer :: FlashlightIsOn( void ) { @@ -3327,7 +3322,6 @@ void CBasePlayer :: ForceClientDllUpdate( void ) { m_iClientHealth = -1; m_iClientBattery = -1; - m_flFlashLightTime = 1; m_iTrain |= TRAIN_NEW; // Force new train message. m_fWeapon = FALSE; // Force weapon send m_fKnownItem = FALSE; // Force weaponinit messages. @@ -3594,7 +3588,6 @@ void CBasePlayer::CheatImpulseCommands( int iImpulse ) { if ( pEntity->pev->takedamage ) pEntity->SetThink(SUB_Remove); - else UTIL_Remove( pEntity ); } break; } @@ -3756,12 +3749,16 @@ Called every frame by the player PreThink */ void CBasePlayer::ItemPreFrame() { - if ( m_flNextAttack > WeaponTimeBase( )) +#if defined( CLIENT_WEAPONS ) + if ( m_flNextAttack > 0 ) +#else + if ( gpGlobals->time < m_flNextAttack ) +#endif { return; } - if ( !m_pActiveItem ) + if (!m_pActiveItem) return; m_pActiveItem->ItemPreFrame( ); @@ -3783,7 +3780,11 @@ void CBasePlayer::ItemPostFrame() if ( m_pTank != NULL ) return; - if( m_flNextAttack > WeaponTimeBase( )) +#if defined( CLIENT_WEAPONS ) + if ( m_flNextAttack > 0 ) +#else + if ( gpGlobals->time < m_flNextAttack ) +#endif { return; } diff --git a/dlls/player.h b/dlls/player.h index a2cf73ec..cbf95809 100644 --- a/dlls/player.h +++ b/dlls/player.h @@ -223,17 +223,15 @@ public: static TYPEDESCRIPTION m_playerSaveData[]; // Player is moved across the transition by other means - virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } + virtual int ObjectCaps( void ) { return CBaseMonster :: ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } virtual void Precache( void ); - BOOL IsOnLadder( void ); - BOOL FlashlightIsOn( void ); - void FlashlightTurnOn( void ); - void FlashlightTurnOff( void ); - - float WeaponTimeBase( void ); + BOOL IsOnLadder( void ); + BOOL FlashlightIsOn( void ); + void FlashlightTurnOn( void ); + void FlashlightTurnOff( void ); - void UpdatePlayerSound ( void ); - void DeathSound ( void ); + void UpdatePlayerSound ( void ); + void DeathSound ( void ); int Classify ( void ); void SetAnimation( PLAYER_ANIM playerAnim ); diff --git a/dlls/python.cpp b/dlls/python.cpp index ad20c484..89d6231c 100644 --- a/dlls/python.cpp +++ b/dlls/python.cpp @@ -98,7 +98,11 @@ void CPython::Precache( void ) BOOL CPython::Deploy( ) { +#ifdef CLIENT_DLL if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { // enable laser sight geometry. pev->body = 1; @@ -108,11 +112,11 @@ BOOL CPython::Deploy( ) pev->body = 0; } - return DefaultDeploy( "models/v_357.mdl", "models/p_357.mdl", PYTHON_DRAW, "python", pev->body ); + return DefaultDeploy( "models/v_357.mdl", "models/p_357.mdl", PYTHON_DRAW, "python", UseDecrement(), pev->body ); } -void CPython::Holster( void ) +void CPython::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE;// cancel any reload in progress. @@ -121,14 +125,18 @@ void CPython::Holster( void ) SecondaryAttack(); } - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); SendWeaponAnim( PYTHON_HOLSTER ); } void CPython::SecondaryAttack( void ) { +#ifdef CLIENT_DLL if ( !bIsMultiplayer() ) +#else + if ( !g_pGameRules->IsMultiplayer() ) +#endif { return; } @@ -144,7 +152,7 @@ void CPython::SecondaryAttack( void ) m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 40; } - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = 0.5; } void CPython::PrimaryAttack() @@ -153,7 +161,7 @@ void CPython::PrimaryAttack() if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = 0.15; return; } @@ -164,7 +172,7 @@ void CPython::PrimaryAttack() else { EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_cock1.wav", 0.8, ATTN_NORM); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = 0.15; } return; @@ -189,16 +197,12 @@ void CPython::PrimaryAttack() Vector vecDir; vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, VECTOR_CONE_1DEGREES, 8192, BULLET_PLAYER_357, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); - int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } + int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usFirePython, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, 0, 0 ); @@ -206,8 +210,8 @@ void CPython::PrimaryAttack() // HEV suit - indicate out of ammo condition m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.75; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flNextPrimaryAttack = 0.75; + m_flTimeWeaponIdle = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -222,7 +226,14 @@ void CPython::Reload( void ) m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 0; // 0 means reset to default fov } - if (DefaultReload( 6, PYTHON_RELOAD, 2.0, bIsMultiplayer( ))) + int bUseScope = FALSE; +#ifdef CLIENT_DLL + bUseScope = bIsMultiplayer(); +#else + bUseScope = g_pGameRules->IsMultiplayer(); +#endif + + if (DefaultReload( 6, PYTHON_RELOAD, 2.0, bUseScope )) { m_flSoundDelay = 1.5; } @@ -236,13 +247,13 @@ void CPython::WeaponIdle( void ) m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); // ALERT( at_console, "%.2f\n", gpGlobals->time - m_flSoundDelay ); - if (m_flSoundDelay != 0 && m_flSoundDelay <= m_pPlayer->WeaponTimeBase() ) + if (m_flSoundDelay != 0 && m_flSoundDelay <= UTIL_WeaponTimeBase() ) { EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "weapons/357_reload1.wav", RANDOM_FLOAT(0.8, 0.9), ATTN_NORM); m_flSoundDelay = 0; } - if (m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; int iAnim; @@ -250,25 +261,32 @@ void CPython::WeaponIdle( void ) if (flRand <= 0.5) { iAnim = PYTHON_IDLE1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + (70.0/30.0); + m_flTimeWeaponIdle = (70.0/30.0); } else if (flRand <= 0.7) { iAnim = PYTHON_IDLE2; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + (60.0/30.0); + m_flTimeWeaponIdle = (60.0/30.0); } else if (flRand <= 0.9) { iAnim = PYTHON_IDLE3; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + (88.0/30.0); + m_flTimeWeaponIdle = (88.0/30.0); } else { iAnim = PYTHON_FIDGET; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + (170.0/30.0); + m_flTimeWeaponIdle = (170.0/30.0); } - - SendWeaponAnim( iAnim, bIsMultiplayer( )); + + int bUseScope = FALSE; +#ifdef CLIENT_DLL + bUseScope = bIsMultiplayer(); +#else + bUseScope = g_pGameRules->IsMultiplayer(); +#endif + + SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0, bUseScope ); } diff --git a/dlls/rpg.cpp b/dlls/rpg.cpp index d3918588..dcda1573 100644 --- a/dlls/rpg.cpp +++ b/dlls/rpg.cpp @@ -47,21 +47,13 @@ LINK_ENTITY_TO_CLASS( laser_spot, CLaserSpot ); //========================================================= //========================================================= -CLaserSpot *CLaserSpot::CreateSpot( entvars_t *pevOwner ) +CLaserSpot *CLaserSpot::CreateSpot( void ) { CLaserSpot *pSpot = GetClassPtr( (CLaserSpot *)NULL ); pSpot->Spawn(); pSpot->pev->classname = MAKE_STRING("laser_spot"); - if( pevOwner ) - { - // predictable laserspot (cl_lw must be set to 1) - pSpot->pev->flags |= FL_SKIPLOCALHOST; - pSpot->pev->owner = ENT( pevOwner ); - pevOwner->effects |= EF_LASERSPOT; - } - return pSpot; } @@ -77,7 +69,7 @@ void CLaserSpot::Spawn( void ) pev->renderfx = kRenderFxNoDissipation; pev->renderamt = 255; - SET_MODEL( ENT( pev ), "sprites/laserdot.spr" ); + SET_MODEL(ENT(pev), "sprites/laserdot.spr"); UTIL_SetOrigin( pev, pev->origin ); }; @@ -87,8 +79,6 @@ void CLaserSpot::Spawn( void ) void CLaserSpot::Suspend( float flSuspendTime ) { pev->effects |= EF_NODRAW; - if( pev->owner ) - pev->owner->v.effects &= ~EF_LASERSPOT; SetThink( Revive ); pev->nextthink = gpGlobals->time + flSuspendTime; @@ -101,9 +91,6 @@ void CLaserSpot::Revive( void ) { pev->effects &= ~EF_NODRAW; - if( pev->owner ) - pev->owner->v.effects |= EF_LASERSPOT; - SetThink( NULL ); } @@ -156,7 +143,7 @@ void CRpgRocket :: Spawn( void ) pev->velocity = gpGlobals->v_forward * 250; pev->gravity = 0.5; - pev->nextthink = gpGlobals->time + RANDOM_FLOAT( 0.3, 0.5 ); + pev->nextthink = gpGlobals->time + 0.4; pev->dmg = gSkillData.plrDmgRPG; } @@ -318,7 +305,7 @@ void CRpg::Reload( void ) // Set the next attack time into the future so that WeaponIdle will get called more often // than reload, allowing the RPG LTD to be updated - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; if ( m_cActiveRockets && m_fSpotActive ) { @@ -331,7 +318,7 @@ void CRpg::Reload( void ) if ( m_pSpot && m_fSpotActive ) { m_pSpot->Suspend( 2.1 ); - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 2.1; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.1; } #endif @@ -339,7 +326,7 @@ void CRpg::Reload( void ) iResult = DefaultReload( RPG_MAX_CLIP, RPG_RELOAD, 2 ); if ( iResult ) - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } @@ -351,7 +338,11 @@ void CRpg::Spawn( ) SET_MODEL(ENT(pev), "models/w_rpg.mdl"); m_fSpotActive = 1; +#ifdef CLIENT_DLL if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { // more default ammo in multiplay. m_iDefaultAmmo = RPG_DEFAULT_GIVE * 2; @@ -434,11 +425,11 @@ BOOL CRpg::CanHolster( void ) return TRUE; } -void CRpg::Holster( void ) +void CRpg::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE;// cancel any reload in progress. - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; SendWeaponAnim( RPG_HOLSTER1 ); @@ -446,13 +437,14 @@ void CRpg::Holster( void ) if (m_pSpot) { m_pSpot->Killed( NULL, GIB_NEVER ); - m_pPlayer->pev->effects &= ~EF_LASERSPOT; m_pSpot = NULL; } #endif } + + void CRpg::PrimaryAttack() { if ( m_iClip ) @@ -477,22 +469,18 @@ void CRpg::PrimaryAttack() // Ken signed up for this as a global change (sjb) int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT( flags, m_pPlayer->edict(), m_usRpg ); m_iClip--; - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 1.5; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 1.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; } else { @@ -510,12 +498,11 @@ void CRpg::SecondaryAttack() if (!m_fSpotActive && m_pSpot) { m_pSpot->Killed( NULL, GIB_NORMAL ); - m_pPlayer->pev->effects &= ~EF_LASERSPOT; m_pSpot = NULL; } #endif - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.2; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.2; } @@ -525,7 +512,7 @@ void CRpg::WeaponIdle( void ) ResetEmptySound( ); - if ( m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) @@ -539,7 +526,7 @@ void CRpg::WeaponIdle( void ) else iAnim = RPG_IDLE; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 90.0 / 15.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 15.0; } else { @@ -548,14 +535,14 @@ void CRpg::WeaponIdle( void ) else iAnim = RPG_FIDGET; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 3.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3.0; } SendWeaponAnim( iAnim ); } else { - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1; } } @@ -569,11 +556,11 @@ void CRpg::UpdateSpot( void ) { if (!m_pSpot) { - m_pSpot = CLaserSpot::CreateSpot( m_pPlayer->pev ); + m_pSpot = CLaserSpot::CreateSpot(); } UTIL_MakeVectors( m_pPlayer->pev->v_angle ); - Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecSrc = m_pPlayer->GetGunPosition( );; Vector vecAiming = gpGlobals->v_forward; TraceResult tr; @@ -603,7 +590,11 @@ class CRpgAmmo : public CBasePlayerAmmo { int iGive; - if ( bIsMultiplayer() ) +#ifdef CLIENT_DLL + if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { // hand out more ammo per rocket in multiplayer. iGive = AMMO_RPGCLIP_GIVE * 2; diff --git a/dlls/satchel.cpp b/dlls/satchel.cpp index 336062c8..7c5ff451 100644 --- a/dlls/satchel.cpp +++ b/dlls/satchel.cpp @@ -178,7 +178,11 @@ int CSatchel::AddDuplicate( CBasePlayerItem *pOriginal ) { CSatchel *pSatchel; +#ifdef CLIENT_DLL if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { pSatchel = (CSatchel *)pOriginal; @@ -288,8 +292,8 @@ BOOL CSatchel::CanDeploy( void ) BOOL CSatchel::Deploy( ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 1.0; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 1.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); if ( m_chargeReady ) return DefaultDeploy( "models/v_satchel_radio.mdl", "models/p_satchel_radio.mdl", SATCHEL_RADIO_DRAW, "hive" ); @@ -301,9 +305,9 @@ BOOL CSatchel::Deploy( ) } -void CSatchel::Holster( void ) +void CSatchel::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if ( m_chargeReady ) { @@ -313,7 +317,6 @@ void CSatchel::Holster( void ) { SendWeaponAnim( SATCHEL_DROP ); } - EMIT_SOUND(ENT(m_pPlayer->pev), CHAN_WEAPON, "common/null.wav", 1.0, ATTN_NORM); if ( !m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] && !m_chargeReady ) @@ -356,9 +359,9 @@ void CSatchel::PrimaryAttack() } m_chargeReady = 2; - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; break; } @@ -408,15 +411,15 @@ void CSatchel::Throw( void ) m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]--; - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 1.0; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; } } void CSatchel::WeaponIdle( void ) { - if ( m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; switch( m_chargeReady ) @@ -451,12 +454,12 @@ void CSatchel::WeaponIdle( void ) // use tripmine animations strcpy( m_pPlayer->m_szAnimExtention, "trip" ); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.5; m_chargeReady = 0; break; } - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 );// how long till we do this again. } //========================================================= diff --git a/dlls/scientist.cpp b/dlls/scientist.cpp index 529cf65b..ab37d9cd 100644 --- a/dlls/scientist.cpp +++ b/dlls/scientist.cpp @@ -115,10 +115,6 @@ private: LINK_ENTITY_TO_CLASS( monster_scientist, CScientist ); -#ifdef BSHIFT_DLL -LINK_ENTITY_TO_CLASS( monster_rosenberg, CScientist ); -#endif - TYPEDESCRIPTION CScientist::m_SaveData[] = { DEFINE_FIELD( CScientist, m_painTime, FIELD_TIME ), @@ -432,9 +428,7 @@ void CScientist::DeclineFollowing( void ) { Talk( 10 ); m_hTalkTarget = m_hEnemy; - if ( FClassnameIs(pev, "monster_rosenberg")) - PlaySentence( "RO_POK", 2, VOL_NORM, ATTN_NORM ); - else PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); + PlaySentence( "SC_POK", 2, VOL_NORM, ATTN_NORM ); } @@ -444,9 +438,7 @@ void CScientist :: Scream( void ) { Talk( 10 ); m_hTalkTarget = m_hEnemy; - if ( FClassnameIs(pev, "monster_rosenberg")) - PlaySentence( "RO_SCREAM", RANDOM_FLOAT(3, 6), VOL_NORM, ATTN_NORM ); - else PlaySentence( "SC_SCREAM", RANDOM_FLOAT(3, 6), VOL_NORM, ATTN_NORM ); + PlaySentence( "SC_SCREAM", RANDOM_FLOAT(3, 6), VOL_NORM, ATTN_NORM ); } } @@ -467,9 +459,7 @@ void CScientist :: StartTask( Task_t *pTask ) // if ( FOkToSpeak() ) Talk( 2 ); m_hTalkTarget = m_hTargetEnt; - if ( FClassnameIs(pev, "monster_rosenberg")) - PlaySentence( "RO_HEAL", 2, VOL_NORM, ATTN_IDLE ); - else PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); + PlaySentence( "SC_HEAL", 2, VOL_NORM, ATTN_IDLE ); TaskComplete(); break; @@ -490,16 +480,10 @@ void CScientist :: StartTask( Task_t *pTask ) { Talk( 2 ); m_hTalkTarget = m_hEnemy; - if ( FClassnameIs(pev, "monster_rosenberg")) - { - PlaySentence( "RO_FEAR", 5, VOL_NORM, ATTN_NORM ); - } + if ( m_hEnemy->IsPlayer() ) + PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); else - { - if ( m_hEnemy->IsPlayer() ) - PlaySentence( "SC_PLFEAR", 5, VOL_NORM, ATTN_NORM ); - else PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); - } + PlaySentence( "SC_FEAR", 5, VOL_NORM, ATTN_NORM ); } TaskComplete(); break; @@ -680,11 +664,7 @@ void CScientist :: Spawn( void ) pev->solid = SOLID_SLIDEBOX; pev->movetype = MOVETYPE_STEP; m_bloodColor = BLOOD_COLOR_RED; - - if ( FClassnameIs(pev, "monster_rosenberg")) - pev->health = gSkillData.scientistHealth * 2; - else pev->health = gSkillData.scientistHealth; - + pev->health = gSkillData.scientistHealth; 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 scientists will notice player and say hello m_MonsterState = MONSTERSTATE_NONE; @@ -720,9 +700,7 @@ void CScientist :: Precache( void ) PRECACHE_SOUND("scientist/sci_pain3.wav"); PRECACHE_SOUND("scientist/sci_pain4.wav"); PRECACHE_SOUND("scientist/sci_pain5.wav"); -#ifdef BSHIFT_DLL - PRECACHE_SOUND("rosenberg/ro_pain1.wav"); -#endif + // every new scientist must call this, otherwise // when a level is loaded, nobody will talk (time is reset to 0) TalkInit(); @@ -744,55 +722,27 @@ void CScientist :: TalkInit() // scientists speach group names (group names are in sentences.txt) - // scientists speach group names (group names are in sentences.txt) - if ( FClassnameIs(pev, "monster_rosenberg")) - { - m_szGrp[TLK_ANSWER] = "RO_ANSWER"; - m_szGrp[TLK_QUESTION] = "RO_QUESTION"; - m_szGrp[TLK_IDLE] = "RO_IDLE"; - m_szGrp[TLK_STARE] = "RO_STARE"; - 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_HELLO] = "RO_HELLO"; + m_szGrp[TLK_ANSWER] = "SC_ANSWER"; + m_szGrp[TLK_QUESTION] = "SC_QUESTION"; + m_szGrp[TLK_IDLE] = "SC_IDLE"; + m_szGrp[TLK_STARE] = "SC_STARE"; + m_szGrp[TLK_USE] = "SC_OK"; + m_szGrp[TLK_UNUSE] = "SC_WAIT"; + m_szGrp[TLK_STOP] = "SC_STOP"; + m_szGrp[TLK_NOSHOOT] = "SC_SCARED"; + m_szGrp[TLK_HELLO] = "SC_HELLO"; - m_szGrp[TLK_PLHURT1] = "!RO_CUREA"; - m_szGrp[TLK_PLHURT2] = "!RO_CUREB"; - m_szGrp[TLK_PLHURT3] = "!RO_CUREC"; + m_szGrp[TLK_PLHURT1] = "!SC_CUREA"; + m_szGrp[TLK_PLHURT2] = "!SC_CUREB"; + m_szGrp[TLK_PLHURT3] = "!SC_CUREC"; - m_szGrp[TLK_PHELLO] = "RO_PHELLO"; - m_szGrp[TLK_PIDLE] = "RO_PIDLE"; - m_szGrp[TLK_PQUESTION] = "RO_PQUEST"; - m_szGrp[TLK_SMELL] = "RO_SMELL"; + m_szGrp[TLK_PHELLO] = "SC_PHELLO"; + m_szGrp[TLK_PIDLE] = "SC_PIDLE"; + m_szGrp[TLK_PQUESTION] = "SC_PQUEST"; + m_szGrp[TLK_SMELL] = "SC_SMELL"; - m_szGrp[TLK_WOUND] = "RO_WOUND"; - m_szGrp[TLK_MORTAL] = "RO_MORTAL"; - } - else - { - m_szGrp[TLK_ANSWER] = "SC_ANSWER"; - m_szGrp[TLK_QUESTION] = "SC_QUESTION"; - m_szGrp[TLK_IDLE] = "SC_IDLE"; - m_szGrp[TLK_STARE] = "SC_STARE"; - m_szGrp[TLK_USE] = "SC_OK"; - m_szGrp[TLK_UNUSE] = "SC_WAIT"; - m_szGrp[TLK_STOP] = "SC_STOP"; - m_szGrp[TLK_NOSHOOT] = "SC_SCARED"; - m_szGrp[TLK_HELLO] = "SC_HELLO"; - - m_szGrp[TLK_PLHURT1] = "!SC_CUREA"; - m_szGrp[TLK_PLHURT2] = "!SC_CUREB"; - m_szGrp[TLK_PLHURT3] = "!SC_CUREC"; - - m_szGrp[TLK_PHELLO] = "SC_PHELLO"; - m_szGrp[TLK_PIDLE] = "SC_PIDLE"; - m_szGrp[TLK_PQUESTION] = "SC_PQUEST"; - m_szGrp[TLK_SMELL] = "SC_SMELL"; - - m_szGrp[TLK_WOUND] = "SC_WOUND"; - m_szGrp[TLK_MORTAL] = "SC_MORTAL"; - } + m_szGrp[TLK_WOUND] = "SC_WOUND"; + m_szGrp[TLK_MORTAL] = "SC_MORTAL"; // get voice for head switch (pev->body % 3) @@ -803,9 +753,6 @@ void CScientist :: TalkInit() case HEAD_LUTHER: m_voicePitch = 95; break; //luther case HEAD_SLICK: m_voicePitch = 100; break;//slick } - - if ( FClassnameIs(pev, "monster_rosenberg")) - m_voicePitch = 95; // rosenberg has too low voice } int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) @@ -813,11 +760,8 @@ int CScientist :: TakeDamage( entvars_t *pevInflictor, entvars_t *pevAttacker, f if ( pevInflictor && pevInflictor->flags & FL_CLIENT ) { - if ( !FClassnameIs(pev, "monster_rosenberg")) - { - Remember( bits_MEMORY_PROVOKED ); - StopFollowing( TRUE ); - } + Remember( bits_MEMORY_PROVOKED ); + StopFollowing( TRUE ); } // make sure friends talk about it if player hurts scientist... @@ -848,12 +792,6 @@ void CScientist :: PainSound ( void ) m_painTime = gpGlobals->time + RANDOM_FLOAT(0.5, 0.75); - if ( FClassnameIs(pev, "monster_rosenberg")) - { - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "rosenberg/ro_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); - return; - } - switch (RANDOM_LONG(0,4)) { case 0: EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "scientist/sci_pain1.wav", 1, ATTN_NORM, 0, GetVoicePitch()); break; @@ -1033,7 +971,7 @@ Schedule_t *CScientist :: GetSchedule ( void ) } return GetScheduleOfType( SCHED_TARGET_FACE ); // Just face and follow. } - else if ( !FClassnameIs(pev, "monster_rosenberg")) // UNDONE: When afraid, scientist won't move out of your way. Keep This? If not, write move away scared + else // UNDONE: When afraid, scientist won't move out of your way. Keep This? If not, write move away scared { if ( HasConditions( bits_COND_NEW_ENEMY ) ) // I just saw something new and scary, react return GetScheduleOfType( SCHED_FEAR ); // React to something scary diff --git a/dlls/shotgun.cpp b/dlls/shotgun.cpp index 6c323543..dfa084b8 100644 --- a/dlls/shotgun.cpp +++ b/dlls/shotgun.cpp @@ -122,7 +122,7 @@ void CShotgun::PrimaryAttack() if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } @@ -140,15 +140,12 @@ void CShotgun::PrimaryAttack() m_iClip--; int flags; +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; @@ -157,7 +154,11 @@ void CShotgun::PrimaryAttack() Vector vecDir; +#ifdef CLIENT_DLL if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { vecDir = m_pPlayer->FireBulletsPlayer( 4, vecSrc, vecAiming, VECTOR_CONE_DM_SHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); } @@ -177,12 +178,12 @@ void CShotgun::PrimaryAttack() if (m_iClip != 0) m_flPumpTime = gpGlobals->time + 0.5; - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.75; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 0.75; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.75; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.75; if (m_iClip != 0) - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 5.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 5.0; else - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.75; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.75; m_fInSpecialReload = 0; } @@ -193,7 +194,7 @@ void CShotgun::SecondaryAttack( void ) if (m_pPlayer->pev->waterlevel == 3) { PlayEmptySound( ); - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.15; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.15; return; } @@ -211,27 +212,27 @@ void CShotgun::SecondaryAttack( void ) int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; // player "shoot" animation m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); - Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecSrc = m_pPlayer->GetGunPosition( ); Vector vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecDir; +#ifdef CLIENT_DLL if ( bIsMultiplayer() ) +#else + if ( g_pGameRules->IsMultiplayer() ) +#endif { // tuned for deathmatch vecDir = m_pPlayer->FireBulletsPlayer( 8, vecSrc, vecAiming, VECTOR_CONE_DM_DOUBLESHOTGUN, 2048, BULLET_PLAYER_BUCKSHOT, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); @@ -251,10 +252,10 @@ void CShotgun::SecondaryAttack( void ) if (m_iClip != 0) m_flPumpTime = gpGlobals->time + 0.95; - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 1.5; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 1.5; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.5; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.5; if (m_iClip != 0) - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 6.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 6.0; else m_flTimeWeaponIdle = 1.5; @@ -269,7 +270,7 @@ void CShotgun::Reload( void ) return; // don't reload until recoil is done - if (m_flNextPrimaryAttack > m_pPlayer->WeaponTimeBase()) + if (m_flNextPrimaryAttack > UTIL_WeaponTimeBase()) return; // check to see if we're ready to reload @@ -277,15 +278,15 @@ void CShotgun::Reload( void ) { SendWeaponAnim( SHOTGUN_START_RELOAD ); m_fInSpecialReload = 1; - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.6; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.6; - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 1.0; - m_flNextSecondaryAttack = m_pPlayer->WeaponTimeBase() + 1.0; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.6; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.6; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 1.0; + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0; return; } else if (m_fInSpecialReload == 1) { - if (m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase()) + if (m_flTimeWeaponIdle > UTIL_WeaponTimeBase()) return; // was waiting for gun to move to side m_fInSpecialReload = 2; @@ -297,8 +298,8 @@ void CShotgun::Reload( void ) SendWeaponAnim( SHOTGUN_RELOAD ); - m_flNextReload = m_pPlayer->WeaponTimeBase() + 0.5; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 0.5; + m_flNextReload = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 0.5; } else { @@ -323,7 +324,7 @@ void CShotgun::WeaponIdle( void ) m_flPumpTime = 0; } - if (m_flTimeWeaponIdle < m_pPlayer->WeaponTimeBase() ) + if (m_flTimeWeaponIdle < UTIL_WeaponTimeBase() ) { if (m_iClip == 0 && m_fInSpecialReload == 0 && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { @@ -343,7 +344,7 @@ void CShotgun::WeaponIdle( void ) // play cocking sound EMIT_SOUND_DYN(ENT(m_pPlayer->pev), CHAN_ITEM, "weapons/scock1.wav", 1, ATTN_NORM, 0, 95 + RANDOM_LONG(0,0x1f)); m_fInSpecialReload = 0; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 1.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.5; } } else @@ -353,17 +354,17 @@ void CShotgun::WeaponIdle( void ) if (flRand <= 0.8) { iAnim = SHOTGUN_IDLE_DEEP; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + (60.0/12.0);// * RANDOM_LONG(2, 5); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (60.0/12.0);// * RANDOM_LONG(2, 5); } else if (flRand <= 0.95) { iAnim = SHOTGUN_IDLE; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + (20.0/9.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); } else { iAnim = SHOTGUN_IDLE4; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + (20.0/9.0); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + (20.0/9.0); } SendWeaponAnim( iAnim ); } diff --git a/dlls/squeakgrenade.cpp b/dlls/squeakgrenade.cpp index 24ca29b5..5b7ce72c 100644 --- a/dlls/squeakgrenade.cpp +++ b/dlls/squeakgrenade.cpp @@ -476,9 +476,9 @@ BOOL CSqueak::Deploy( ) } -void CSqueak::Holster( void ) +void CSqueak::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if ( !m_pPlayer->m_rgAmmo[ m_iPrimaryAmmoType ] ) { @@ -512,18 +512,14 @@ void CSqueak::PrimaryAttack() // find place to toss monster UTIL_TraceLine( trace_origin + gpGlobals->v_forward * 20, trace_origin + gpGlobals->v_forward * 64, dont_ignore_monsters, NULL, &tr ); - int flags; + int flags; +#ifdef CLIENT_WEAPONS + flags = FEV_NOTHOST; +#else + flags = 0; +#endif - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } - - PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSnarkFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usSnarkFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); if ( tr.fAllSolid == 0 && tr.fStartSolid == 0 && tr.flFraction > 0.25 ) { @@ -549,8 +545,8 @@ void CSqueak::PrimaryAttack() m_fJustThrown = 1; - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.3; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 1.0; + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; } } } @@ -564,7 +560,7 @@ void CSqueak::SecondaryAttack( void ) void CSqueak::WeaponIdle( void ) { - if ( m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; if (m_fJustThrown) @@ -578,7 +574,7 @@ void CSqueak::WeaponIdle( void ) } SendWeaponAnim( SQUEAK_UP ); - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); return; } @@ -587,17 +583,17 @@ void CSqueak::WeaponIdle( void ) if (flRand <= 0.75) { iAnim = SQUEAK_IDLE1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 30.0 / 16 * (2); + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 30.0 / 16 * (2); } else if (flRand <= 0.875) { iAnim = SQUEAK_FIDGETFIT; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 70.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 70.0 / 16.0; } else { iAnim = SQUEAK_FIDGETNIP; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 80.0 / 16.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 80.0 / 16.0; } SendWeaponAnim( iAnim ); } diff --git a/dlls/talkmonster.cpp b/dlls/talkmonster.cpp index 7826a8ee..76ac05b7 100644 --- a/dlls/talkmonster.cpp +++ b/dlls/talkmonster.cpp @@ -928,7 +928,7 @@ int CTalkMonster :: FOkToSpeak( void ) if (gpGlobals->time <= CTalkMonster::g_talkWaitTime) return FALSE; - if ( pev->spawnflags & SF_MONSTER_GAG && !FClassnameIs(pev, "monster_generic") ) + if ( pev->spawnflags & SF_MONSTER_GAG ) return FALSE; if ( m_MonsterState == MONSTERSTATE_PRONE ) diff --git a/dlls/teamplay_gamerules.cpp b/dlls/teamplay_gamerules.cpp index a9987a94..db99778f 100644 --- a/dlls/teamplay_gamerules.cpp +++ b/dlls/teamplay_gamerules.cpp @@ -68,6 +68,9 @@ CHalfLifeTeamplay :: CHalfLifeTeamplay() extern cvar_t timeleft, fragsleft; +#include "voice_gamemgr.h" +extern CVoiceGameMgr g_VoiceGameMgr; + void CHalfLifeTeamplay :: Think ( void ) { ///// Check game rules ///// @@ -77,6 +80,8 @@ void CHalfLifeTeamplay :: Think ( void ) int frags_remaining = 0; int time_remaining = 0; + g_VoiceGameMgr.Update(gpGlobals->frametime); + if ( g_fGameOver ) // someone else quit the game already { CHalfLifeMultiplay::Think(); @@ -140,6 +145,9 @@ void CHalfLifeTeamplay :: Think ( void ) //========================================================= BOOL CHalfLifeTeamplay :: ClientCommand( CBasePlayer *pPlayer, const char *pcmd ) { + if(g_VoiceGameMgr.ClientCommand(pPlayer, pcmd)) + return TRUE; + if ( FStrEq( pcmd, "menuselect" ) ) { if ( CMD_ARGC() < 2 ) diff --git a/dlls/triggers.cpp b/dlls/triggers.cpp index 08dc88a7..bd36a082 100644 --- a/dlls/triggers.cpp +++ b/dlls/triggers.cpp @@ -2072,25 +2072,11 @@ void CTriggerGravity::GravityTouch( CBaseEntity *pOther ) pOther->pev->gravity = pev->gravity; } -#ifdef BSHIFT_DLL -class CTriggerPlayerFreeze : public CBaseDelay -{ -public: - void Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ); - int ObjectCaps( void ) { return CBaseDelay::ObjectCaps() & ~FCAP_ACROSS_TRANSITION; } -}; -LINK_ENTITY_TO_CLASS( trigger_playerfreeze, CTriggerPlayerFreeze ); -void CTriggerPlayerFreeze::Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value ) -{ - if ( !pActivator || !pActivator->IsPlayer() ) - pActivator = CBaseEntity::Instance(g_engfuncs.pfnPEntityOfEntIndex( 1 )); - if (pActivator->pev->flags & FL_FROZEN) - ((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(TRUE); - else ((CBasePlayer *)((CBaseEntity *)pActivator))->EnableControl(FALSE); -} -#endif + + + // this is a really bad idea. class CTriggerChangeTarget : public CBaseDelay diff --git a/dlls/tripmine.cpp b/dlls/tripmine.cpp index b6ea116e..81ff1044 100644 --- a/dlls/tripmine.cpp +++ b/dlls/tripmine.cpp @@ -222,7 +222,7 @@ void CTripmineGrenade :: PowerupThink( void ) MakeBeam( ); // play enabled sound - EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "weapons/mine_activate.wav", 0.5, ATTN_NORM, 1.0, 75 ); + EMIT_SOUND_DYN( ENT(pev), CHAN_VOICE, "weapons/mine_activate.wav", 0.5, ATTN_NORM, 1.0, 75 ); } pev->nextthink = gpGlobals->time + 0.1; } @@ -369,7 +369,11 @@ void CTripmine::Spawn( ) m_iDefaultAmmo = TRIPMINE_DEFAULT_GIVE; +#ifdef CLIENT_DLL if ( !bIsMultiplayer() ) +#else + if ( !g_pGameRules->IsDeathmatch() ) +#endif { UTIL_SetSize(pev, Vector(-16, -16, 0), Vector(16, 16, 28) ); } @@ -403,14 +407,14 @@ int CTripmine::GetItemInfo(ItemInfo *p) BOOL CTripmine::Deploy( ) { - pev->body = 0; + //pev->body = 0; return DefaultDeploy( "models/v_tripmine.mdl", "models/p_tripmine.mdl", TRIPMINE_DRAW, "trip" ); } -void CTripmine::Holster( void ) +void CTripmine::Holster( int skiplocal /* = 0 */ ) { - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; if (!m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]) { @@ -438,15 +442,11 @@ void CTripmine::PrimaryAttack( void ) UTIL_TraceLine( vecSrc, vecSrc + vecAiming * 128, dont_ignore_monsters, ENT( m_pPlayer->pev ), &tr ); int flags; - - if( IsLocalWeapon( )) - { - flags = FEV_NOTHOST; - } - else - { - flags = 0; - } +#ifdef CLIENT_WEAPONS + flags = FEV_NOTHOST; +#else + flags = 0; +#endif PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), m_usTripFire, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, 0.0, 0.0, 0, 0, 0, 0 ); @@ -481,13 +481,13 @@ void CTripmine::PrimaryAttack( void ) } - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.3; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); } void CTripmine::WeaponIdle( void ) { - if ( m_flTimeWeaponIdle > m_pPlayer->WeaponTimeBase() ) + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) return; if ( m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] > 0 ) @@ -505,17 +505,17 @@ void CTripmine::WeaponIdle( void ) if (flRand <= 0.25) { iAnim = TRIPMINE_IDLE1; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 90.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 90.0 / 30.0; } else if (flRand <= 0.75) { iAnim = TRIPMINE_IDLE2; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 60.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 30.0; } else { iAnim = TRIPMINE_FIDGET; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 100.0 / 30.0; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 100.0 / 30.0; } SendWeaponAnim( iAnim ); diff --git a/dlls/util.cpp b/dlls/util.cpp index c7a42d55..ab27c186 100644 --- a/dlls/util.cpp +++ b/dlls/util.cpp @@ -31,6 +31,15 @@ #include "weapons.h" #include "gamerules.h" +float UTIL_WeaponTimeBase( void ) +{ +#if defined( CLIENT_WEAPONS ) + return 0.0; +#else + return gpGlobals->time; +#endif +} + static unsigned int glSeed = 0; unsigned int seed_table[ 256 ] = @@ -1653,7 +1662,6 @@ static int gSizes[FIELD_TYPECOUNT] = sizeof(float), // FIELD_TIME sizeof(int), // FIELD_MODELNAME sizeof(int), // FIELD_SOUNDNAME - sizeof(float), // FIELD_WEAPONTIME }; @@ -1802,7 +1810,7 @@ unsigned short CSaveRestoreBuffer :: TokenHash( const char *pszToken ) for ( int i=0; itokenCount; i++ ) { #if _DEBUG - static int beentheredonethat = FALSE; + static qboolean beentheredonethat = FALSE; if ( i > 50 && !beentheredonethat ) { beentheredonethat = TRUE; @@ -2064,13 +2072,6 @@ int CSave :: WriteFields( const char *pname, void *pBaseData, TYPEDESCRIPTION *p case FIELD_TIME: WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); break; - case FIELD_WEAPONTIME: - // NOTE: save\restore allowed only in singleplayer and client always has entindx == 1 - // but this code may does wrong results if client switch cl_lw before restore - if( ENGINE_CANSKIP( INDEXENT( 1 ))) - WriteFloat( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - else WriteTime( pTest->fieldName, (float *)pOutputData, pTest->fieldSize ); - break; case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: @@ -2248,17 +2249,6 @@ int CRestore::ReadField( void *pBaseData, TYPEDESCRIPTION *pFields, int fieldCou case FIELD_FLOAT: *((float *)pOutputData) = *(float *)pInputData; break; - case FIELD_WEAPONTIME: - // NOTE: save\restore allowed only in singleplayer and client always has entindx == 1 - // but this code may does wrong results if client switch cl_lw before restore - timeData = *(float *)pInputData; - if( !ENGINE_CANSKIP( INDEXENT( 1 ))) - { - // Re-base time variables - timeData += time; - } - *((float *)pOutputData) = timeData; - break; case FIELD_MODELNAME: case FIELD_SOUNDNAME: case FIELD_STRING: diff --git a/dlls/util.h b/dlls/util.h index 43352d0a..48655158 100644 --- a/dlls/util.h +++ b/dlls/util.h @@ -26,23 +26,9 @@ inline void MESSAGE_BEGIN( int msg_dest, int msg_type, const float *pOrigin, ent extern globalvars_t *gpGlobals; -// defaulting to use StringTable -// #define SYS_SHAREDSTRINGS - -#ifdef SYS_SHAREDSTRINGS - - // Use this instead of ALLOC_STRING on constant strings - #define STRING( offset ) (const char *)(gpGlobals->pStringBase + (int)offset) - #define MAKE_STRING(str) ((int)str - (int)STRING(0)) - -#else - // NOTE: Xash3D have a StringTable system which compress strings in memory - // and not produce duplicated strings. If we want to use this system we must - // reset pStringBase in the GameDllInit (see game.cpp for details) - #define STRING (*g_engfuncs.pfnSzFromIndex) - #define MAKE_STRING ALLOC_STRING - -#endif +// Use this instead of ALLOC_STRING on constant strings +#define STRING(offset) (const char *)(gpGlobals->pStringBase + (int)offset) +#define MAKE_STRING(str) ((int)str - (int)STRING(0)) inline edict_t *FIND_ENTITY_BY_CLASSNAME(edict_t *entStart, const char *pszName) { @@ -549,4 +535,6 @@ void UTIL_SetGroupTrace( int groupmask, int op ); void UTIL_UnsetGroupTrace( void ); int UTIL_SharedRandomLong( unsigned int seed, int low, int high ); -float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); \ No newline at end of file +float UTIL_SharedRandomFloat( unsigned int seed, float low, float high ); + +float UTIL_WeaponTimeBase( void ); diff --git a/dlls/weapons.cpp b/dlls/weapons.cpp index 164e28e1..f8187790 100644 --- a/dlls/weapons.cpp +++ b/dlls/weapons.cpp @@ -76,17 +76,6 @@ int MaxAmmoCarry( int iszName ) return -1; } -/* -===================== -bIsMultiplayer - -Returns if it's multiplayer. -===================== -*/ -BOOL bIsMultiplayer( void ) -{ - return g_pGameRules->IsMultiplayer(); -} /* ============================================================================== @@ -413,6 +402,7 @@ void W_Precache(void) g_sModelIndexLaser = PRECACHE_MODEL( (char *)g_pModelNameLaser ); g_sModelIndexLaserDot = PRECACHE_MODEL("sprites/laserdot.spr"); + // used by explosions PRECACHE_MODEL ("models/grenade.mdl"); PRECACHE_MODEL ("sprites/explode1.spr"); @@ -430,20 +420,6 @@ void W_Precache(void) PRECACHE_SOUND ("items/weapondrop1.wav");// weapon falls to the ground - // g-cont. precache here resources that was precached in the engine (in original HL of course) - - // custom muzzleflashes - PRECACHE_MODEL ("sprites/muzzleflash1.spr"); - PRECACHE_MODEL ("sprites/muzzleflash2.spr"); - PRECACHE_MODEL ("sprites/muzzleflash3.spr"); - PRECACHE_MODEL ("sprites/muzzleflash.spr"); - - // ricochet sprite - PRECACHE_MODEL ("sprites/richo1.spr"); - - // rocket flare - PRECACHE_MODEL ("sprites/animglow01.spr"); - } @@ -453,20 +429,31 @@ TYPEDESCRIPTION CBasePlayerItem::m_SaveData[] = { DEFINE_FIELD( CBasePlayerItem, m_pPlayer, FIELD_CLASSPTR ), DEFINE_FIELD( CBasePlayerItem, m_pNext, FIELD_CLASSPTR ), + //DEFINE_FIELD( CBasePlayerItem, m_fKnown, FIELD_INTEGER ),Reset to zero on load DEFINE_FIELD( CBasePlayerItem, m_iId, FIELD_INTEGER ), + // DEFINE_FIELD( CBasePlayerItem, m_iIdPrimary, FIELD_INTEGER ), + // DEFINE_FIELD( CBasePlayerItem, m_iIdSecondary, FIELD_INTEGER ), }; IMPLEMENT_SAVERESTORE( CBasePlayerItem, CBaseAnimating ); TYPEDESCRIPTION CBasePlayerWeapon::m_SaveData[] = { - DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_WEAPONTIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_WEAPONTIME ), - DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_WEAPONTIME ), +#if defined( CLIENT_WEAPONS ) + DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_FLOAT ), + DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_FLOAT ), + DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_FLOAT ), +#else // CLIENT_WEAPONS + DEFINE_FIELD( CBasePlayerWeapon, m_flNextPrimaryAttack, FIELD_TIME ), + DEFINE_FIELD( CBasePlayerWeapon, m_flNextSecondaryAttack, FIELD_TIME ), + DEFINE_FIELD( CBasePlayerWeapon, m_flTimeWeaponIdle, FIELD_TIME ), +#endif // CLIENT_WEAPONS DEFINE_FIELD( CBasePlayerWeapon, m_iPrimaryAmmoType, FIELD_INTEGER ), DEFINE_FIELD( CBasePlayerWeapon, m_iSecondaryAmmoType, FIELD_INTEGER ), DEFINE_FIELD( CBasePlayerWeapon, m_iClip, FIELD_INTEGER ), DEFINE_FIELD( CBasePlayerWeapon, m_iDefaultAmmo, FIELD_INTEGER ), +// DEFINE_FIELD( CBasePlayerWeapon, m_iClientClip, FIELD_INTEGER ) , reset to zero on load so hud gets updated correctly +// DEFINE_FIELD( CBasePlayerWeapon, m_iClientWeaponState, FIELD_INTEGER ), reset to zero on load so hud gets updated correctly }; IMPLEMENT_SAVERESTORE( CBasePlayerWeapon, CBasePlayerItem ); @@ -637,14 +624,25 @@ void CBasePlayerItem::DefaultTouch( CBaseEntity *pOther ) SUB_UseTargets( pOther, USE_TOGGLE, 0 ); // UNDONE: when should this happen? } -BOOL CBasePlayerWeapon::CanAttack( float attack_time ) +BOOL CanAttack( float attack_time, float curtime, BOOL isPredicted ) { - return ( attack_time <= m_pPlayer->WeaponTimeBase( )) ? TRUE : FALSE; +#if defined( CLIENT_WEAPONS ) + if ( !isPredicted ) +#else + if ( 1 ) +#endif + { + return ( attack_time <= curtime ) ? TRUE : FALSE; + } + else + { + return ( attack_time <= 0.0 ) ? TRUE : FALSE; + } } void CBasePlayerWeapon::ItemPostFrame( void ) { - if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= m_pPlayer->WeaponTimeBase() )) + if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { // complete the reload. int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); @@ -658,7 +656,7 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_fInReload = FALSE; } - if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack )) + if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) { if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) { @@ -669,7 +667,7 @@ void CBasePlayerWeapon::ItemPostFrame( void ) SecondaryAttack(); m_pPlayer->pev->button &= ~IN_ATTACK2; } - else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack )) + else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) { if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) { @@ -690,19 +688,19 @@ void CBasePlayerWeapon::ItemPostFrame( void ) m_fFireOnEmpty = FALSE; - if ( !IsUseable() && m_flNextPrimaryAttack < m_pPlayer->WeaponTimeBase()) + if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { // weapon isn't useable, switch. if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) { - m_flNextPrimaryAttack = m_pPlayer->WeaponTimeBase() + 0.3; + m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; return; } } else { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing - if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < m_pPlayer->WeaponTimeBase()) + if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { Reload(); return; @@ -752,7 +750,7 @@ void CBasePlayerItem::Kill( void ) pev->nextthink = gpGlobals->time + .1; } -void CBasePlayerItem::Holster( void ) +void CBasePlayerItem::Holster( int skiplocal /* = 0 */ ) { m_pPlayer->pev->viewmodel = 0; m_pPlayer->pev->weaponmodel = 0; @@ -859,21 +857,24 @@ int CBasePlayerWeapon::UpdateClientData( CBasePlayer *pPlayer ) return 1; } -BOOL CBasePlayerWeapon::IsLocalWeapon( void ) -{ - return ENGINE_CANSKIP( m_pPlayer->edict() ) ? TRUE : FALSE; -} -void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int body ) +void CBasePlayerWeapon::SendWeaponAnim( int iAnim, int skiplocal, int body ) { + if ( UseDecrement() ) + skiplocal = 1; + else + skiplocal = 0; + m_pPlayer->pev->weaponanim = iAnim; - if( UseDecrement() && IsLocalWeapon( )) +#if defined( CLIENT_WEAPONS ) + if ( skiplocal && ENGINE_CANSKIP( m_pPlayer->edict() ) ) return; +#endif MESSAGE_BEGIN( MSG_ONE, SVC_WEAPONANIM, NULL, m_pPlayer->pev ); - WRITE_BYTE( iAnim ); // sequence number - WRITE_BYTE( pev->body ); // weaponmodel bodygroup. + WRITE_BYTE( iAnim ); // sequence number + WRITE_BYTE( pev->body ); // weaponmodel bodygroup. MESSAGE_END(); } @@ -981,7 +982,7 @@ BOOL CBasePlayerWeapon :: CanDeploy( void ) return TRUE; } -BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int body ) +BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, int iAnim, char *szAnimExt, int skiplocal /* = 0 */, int body ) { if (!CanDeploy( )) return FALSE; @@ -990,10 +991,10 @@ BOOL CBasePlayerWeapon :: DefaultDeploy( char *szViewModel, char *szWeaponModel, m_pPlayer->pev->viewmodel = MAKE_STRING(szViewModel); m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); strcpy( m_pPlayer->m_szAnimExtention, szAnimExt ); - SendWeaponAnim( iAnim, body ); + SendWeaponAnim( iAnim, skiplocal, body ); - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + 0.5f; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 1.0f; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + 0.5; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 1.0; return TRUE; } @@ -1009,14 +1010,14 @@ BOOL CBasePlayerWeapon :: DefaultReload( int iClipSize, int iAnim, float fDelay, if (j == 0) return FALSE; - m_pPlayer->m_flNextAttack = m_pPlayer->WeaponTimeBase() + fDelay; + m_pPlayer->m_flNextAttack = UTIL_WeaponTimeBase() + fDelay; //!!UNDONE -- reload sound goes here !!! - SendWeaponAnim( iAnim, body ); + SendWeaponAnim( iAnim, UseDecrement() ? 1 : 0 ); m_fInReload = TRUE; - m_flTimeWeaponIdle = m_pPlayer->WeaponTimeBase() + 3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 3; return TRUE; } @@ -1050,7 +1051,7 @@ int CBasePlayerWeapon::SecondaryAmmoIndex( void ) return -1; } -void CBasePlayerWeapon::Holster( void ) +void CBasePlayerWeapon::Holster( int skiplocal /* = 0 */ ) { m_fInReload = FALSE; // cancel any reload in progress. m_pPlayer->pev->viewmodel = 0; diff --git a/dlls/weapons.h b/dlls/weapons.h index 9cbdbb50..aaa98247 100644 --- a/dlls/weapons.h +++ b/dlls/weapons.h @@ -49,10 +49,10 @@ public: void EXPORT TumbleThink( void ); virtual void BounceSound( void ); - virtual int BloodColor( void ) { return DONT_BLEED; } + virtual int BloodColor( void ) { return DONT_BLEED; } virtual void Killed( entvars_t *pevAttacker, int iGib ); - BOOL m_fRegisteredSound; // whether or not this grenade has issued its DANGER sound to the world sound list yet. + BOOL m_fRegisteredSound;// whether or not this grenade has issued its DANGER sound to the world sound list yet. }; @@ -62,30 +62,32 @@ public: #define ITEM_SECURITY 3 #define ITEM_BATTERY 4 -#define WEAPON_NONE 0 -#define WEAPON_CROWBAR 1 -#define WEAPON_GLOCK 2 -#define WEAPON_PYTHON 3 -#define WEAPON_MP5 4 -#define WEAPON_CHAINGUN 5 -#define WEAPON_CROSSBOW 6 -#define WEAPON_SHOTGUN 7 -#define WEAPON_RPG 8 -#define WEAPON_GAUSS 9 -#define WEAPON_EGON 10 +#define WEAPON_NONE 0 +#define WEAPON_CROWBAR 1 +#define WEAPON_GLOCK 2 +#define WEAPON_PYTHON 3 +#define WEAPON_MP5 4 +#define WEAPON_CHAINGUN 5 +#define WEAPON_CROSSBOW 6 +#define WEAPON_SHOTGUN 7 +#define WEAPON_RPG 8 +#define WEAPON_GAUSS 9 +#define WEAPON_EGON 10 #define WEAPON_HORNETGUN 11 #define WEAPON_HANDGRENADE 12 -#define WEAPON_TRIPMINE 13 -#define WEAPON_SATCHEL 14 -#define WEAPON_SNARK 15 +#define WEAPON_TRIPMINE 13 +#define WEAPON_SATCHEL 14 +#define WEAPON_SNARK 15 #define WEAPON_ALLWEAPONS (~(1<classname = MAKE_STRING("weapon_9mmhandgun"); // hack to allow for old names + Precache( ); + m_iId = WEAPON_GLOCK; + SET_MODEL(ENT(pev), "models/w_9mmhandgun.mdl"); + + m_iDefaultAmmo = GLOCK_DEFAULT_GIVE; + + FallInit();// get ready to fall down. +} + + +void CGlock::Precache( void ) +{ + PRECACHE_MODEL("models/v_9mmhandgun.mdl"); + PRECACHE_MODEL("models/w_9mmhandgun.mdl"); + PRECACHE_MODEL("models/p_9mmhandgun.mdl"); + + m_iShell = PRECACHE_MODEL ("models/shell.mdl");// brass shell + + PRECACHE_SOUND("items/9mmclip1.wav"); + PRECACHE_SOUND("items/9mmclip2.wav"); + + PRECACHE_SOUND ("weapons/pl_gun1.wav");//silenced handgun + PRECACHE_SOUND ("weapons/pl_gun2.wav");//silenced handgun + PRECACHE_SOUND ("weapons/pl_gun3.wav");//handgun + + m_usFireGlock1 = PRECACHE_EVENT( 1, "events/glock1.sc" ); + m_usFireGlock2 = PRECACHE_EVENT( 1, "events/glock2.sc" ); +} + +int CGlock::GetItemInfo(ItemInfo *p) +{ + p->pszName = STRING(pev->classname); + p->pszAmmo1 = "9mm"; + p->iMaxAmmo1 = _9MM_MAX_CARRY; + p->pszAmmo2 = NULL; + p->iMaxAmmo2 = -1; + p->iMaxClip = GLOCK_MAX_CLIP; + p->iSlot = 1; + p->iPosition = 0; + p->iFlags = 0; + p->iId = m_iId = WEAPON_GLOCK; + p->iWeight = GLOCK_WEIGHT; + + return 1; +} + +BOOL CGlock::Deploy( ) +{ + // pev->body = 1; + return DefaultDeploy( "models/v_9mmhandgun.mdl", "models/p_9mmhandgun.mdl", GLOCK_DRAW, "onehanded", /*UseDecrement() ? 1 : 0*/ 0 ); +} + +void CGlock::SecondaryAttack( void ) +{ + GlockFire( 0.1, 0.2, FALSE ); +} + +void CGlock::PrimaryAttack( void ) +{ + GlockFire( 0.01, 0.3, TRUE ); +} + +void CGlock::GlockFire( float flSpread , float flCycleTime, BOOL fUseAutoAim ) +{ + if (m_iClip <= 0) + { + if (m_fFireOnEmpty) + { + PlayEmptySound(); + m_flNextPrimaryAttack = UTIL_WeaponTimeBase() + 0.2; + } + + return; + } + + m_iClip--; + + m_pPlayer->pev->effects = (int)(m_pPlayer->pev->effects) | EF_MUZZLEFLASH; + + int flags; + +#if defined( CLIENT_WEAPONS ) + flags = FEV_NOTHOST; +#else + flags = 0; +#endif + + // player "shoot" animation + m_pPlayer->SetAnimation( PLAYER_ATTACK1 ); + + // silenced + if (pev->body == 1) + { + m_pPlayer->m_iWeaponVolume = QUIET_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = DIM_GUN_FLASH; + } + else + { + // non-silenced + m_pPlayer->m_iWeaponVolume = NORMAL_GUN_VOLUME; + m_pPlayer->m_iWeaponFlash = NORMAL_GUN_FLASH; + } + + Vector vecSrc = m_pPlayer->GetGunPosition( ); + Vector vecAiming; + + if ( fUseAutoAim ) + { + vecAiming = m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + } + else + { + vecAiming = gpGlobals->v_forward; + } + + Vector vecDir; + vecDir = m_pPlayer->FireBulletsPlayer( 1, vecSrc, vecAiming, Vector( flSpread, flSpread, flSpread ), 8192, BULLET_PLAYER_9MM, 0, 0, m_pPlayer->pev, m_pPlayer->random_seed ); + + PLAYBACK_EVENT_FULL( flags, m_pPlayer->edict(), fUseAutoAim ? m_usFireGlock1 : m_usFireGlock2, 0.0, (float *)&g_vecZero, (float *)&g_vecZero, vecDir.x, vecDir.y, 0, 0, ( m_iClip == 0 ) ? 1 : 0, 0 ); + + m_flNextPrimaryAttack = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + flCycleTime; + + if (!m_iClip && m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] <= 0) + // HEV suit - indicate out of ammo condition + m_pPlayer->SetSuitUpdate("!HEV_AMO0", FALSE, 0); + + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); +} + + +void CGlock::Reload( void ) +{ + if ( m_pPlayer->ammo_9mm <= 0 ) + return; + + int iResult; + + if (m_iClip == 0) + iResult = DefaultReload( 17, GLOCK_RELOAD, 1.5 ); + else + iResult = DefaultReload( 17, GLOCK_RELOAD_NOT_EMPTY, 1.5 ); + + if (iResult) + { + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + UTIL_SharedRandomFloat( m_pPlayer->random_seed, 10, 15 ); + } +} + + + +void CGlock::WeaponIdle( void ) +{ + ResetEmptySound( ); + + m_pPlayer->GetAutoaimVector( AUTOAIM_10DEGREES ); + + if ( m_flTimeWeaponIdle > UTIL_WeaponTimeBase() ) + return; + + // only idle if the slid isn't back + if (m_iClip != 0) + { + int iAnim; + float flRand = UTIL_SharedRandomFloat( m_pPlayer->random_seed, 0.0, 1.0 ); + + if (flRand <= 0.3 + 0 * 0.75) + { + iAnim = GLOCK_IDLE3; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 49.0 / 16; + } + else if (flRand <= 0.6 + 0 * 0.875) + { + iAnim = GLOCK_IDLE1; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 60.0 / 16.0; + } + else + { + iAnim = GLOCK_IDLE2; + m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 40.0 / 16.0; + } + SendWeaponAnim( iAnim, 1 ); + } +} + + + + + + + + +class CGlockAmmo : public CBasePlayerAmmo +{ + void Spawn( void ) + { + Precache( ); + SET_MODEL(ENT(pev), "models/w_9mmclip.mdl"); + CBasePlayerAmmo::Spawn( ); + } + void Precache( void ) + { + PRECACHE_MODEL ("models/w_9mmclip.mdl"); + PRECACHE_SOUND("items/9mmclip1.wav"); + } + BOOL AddAmmo( CBaseEntity *pOther ) + { + if (pOther->GiveAmmo( AMMO_GLOCKCLIP_GIVE, "9mm", _9MM_MAX_CARRY ) != -1) + { + EMIT_SOUND(ENT(pev), CHAN_ITEM, "items/9mmclip1.wav", 1, ATTN_NORM); + return TRUE; + } + return FALSE; + } +}; +LINK_ENTITY_TO_CLASS( ammo_glockclip, CGlockAmmo ); +LINK_ENTITY_TO_CLASS( ammo_9mmclip, CGlockAmmo ); + + + + + + + + + + + + + + + diff --git a/common/cdll_int.h b/engine/cdll_int.h similarity index 72% rename from common/cdll_int.h rename to engine/cdll_int.h index 406af349..81dbf74d 100644 --- a/common/cdll_int.h +++ b/engine/cdll_int.h @@ -188,7 +188,7 @@ typedef struct cl_enginefuncs_s struct model_s *(*CL_LoadModel)( const char *modelname, int *index ); int (*CL_CreateVisibleEntity)( int type, struct cl_entity_s *ent ); - struct model_s* (*pfnGetModelPtr)( int modelIndex ); + const struct model_s* (*GetSpritePointer)( HSPRITE hSprite ); void (*pfnPlaySoundByNameAtLocation)( char *szSound, float volume, float *origin ); unsigned short (*pfnPrecacheEvent)( int type, const char* psz ); @@ -254,41 +254,50 @@ typedef struct cl_enginefuncs_s #define CLDLL_INTERFACE_VERSION 7 -typedef struct -{ - int (*pfnVidInit)( void ); - void (*pfnInit)( void ); - int (*pfnRedraw)( float flTime, int state ); - int (*pfnUpdateClientData)( struct client_data_s *pcldata, float flTime ); - int (*pfnGetHullBounds)( int hullnumber, float *mins, float *maxs ); - void (*pfnTxferLocalOverrides)( struct entity_state_s *state, const struct clientdata_s *client ); - void (*pfnProcessPlayerState)( struct entity_state_s *dst, const struct entity_state_s *src ); - void (*pfnUpdateOnRemove)( struct cl_entity_s *pEdict ); - void (*pfnReset)( void ); - void (*pfnStartFrame)( void ); - void (*pfnFrame)( double time ); - void (*pfnShutdown)( void ); - void (*pfnDrawTriangles)( int fTrans ); - void (*pfnCreateEntities)( void ); - int (*pfnAddVisibleEntity)( struct cl_entity_s *pEnt, int entityType ); - void (*pfnStudioEvent)( const struct mstudioevent_s *event, struct cl_entity_s *entity ); - void (*pfnStudioFxTransform)( struct cl_entity_s *pEdict, float transform[4][4] ); - void (*pfnCalcRefdef)( struct ref_params_s *parms ); - void (*pfnPM_Move)( struct playermove_s *ppmove, int server ); - void (*pfnPM_Init)( struct playermove_s *ppmove ); - char (*pfnPM_FindTextureType)( char *name ); - void (*pfnCmdStart)( const struct cl_entity_s *player, int runfuncs ); - void (*pfnCmdEnd)( const struct cl_entity_s *player, const struct usercmd_s *cmd, unsigned int random_seed ); - void (*pfnCreateMove)( struct usercmd_s *cmd, float frametime, int active ); - void (*pfnMouseEvent)( int mx, int my ); - int (*pfnKeyEvent)( int down, int keynum, const char *pszBind ); - void (*VGui_ConsolePrint)( const char *text ); - void (*pfnParticleEffect)( const float *org, const float *dir, int color, int count ); // SV_ParticleEffect - void (*pfnTempEntityMessage)( int iSize, void *pbuf ); - void (*pfnDirectorMessage)( int iSize, void *pbuf ); -} HUD_FUNCTIONS; +extern void ClientDLL_Init( void ); // from cdll_int.c +extern void ClientDLL_Shutdown( void ); +extern void ClientDLL_HudInit( void ); +extern void ClientDLL_HudVidInit( void ); +extern void ClientDLL_UpdateClientData( void ); +extern void ClientDLL_Frame( double time ); +extern void ClientDLL_HudRedraw( int intermission ); +extern void ClientDLL_MoveClient( struct playermove_s *ppmove ); +extern void ClientDLL_ClientMoveInit( struct playermove_s *ppmove ); +extern char ClientDLL_ClientTextureType( char *name ); -typedef int (*CLIENTAPI)( HUD_FUNCTIONS *pFunctionTable, cl_enginefunc_t* engfuncs ); +extern void ClientDLL_CreateMove( float frametime, struct usercmd_s *cmd, int active ); +extern void ClientDLL_ActivateMouse( void ); +extern void ClientDLL_DeactivateMouse( void ); +extern void ClientDLL_MouseEvent( int mstate ); +extern void ClientDLL_ClearStates( void ); +extern int ClientDLL_IsThirdPerson( void ); +extern void ClientDLL_GetCameraOffsets( float *ofs ); +extern int ClientDLL_GraphKeyDown( void ); +extern struct kbutton_s *ClientDLL_FindKey( const char *name ); +extern void ClientDLL_CAM_Think( void ); +extern void ClientDLL_IN_Accumulate( void ); +extern void ClientDLL_CalcRefdef( struct ref_params_s *pparams ); +extern int ClientDLL_AddEntity( int type, struct cl_entity_s *ent ); +extern void ClientDLL_CreateEntities( void ); + +extern void ClientDLL_DrawNormalTriangles( void ); +extern void ClientDLL_DrawTransparentTriangles( void ); +extern void ClientDLL_StudioEvent( const struct mstudioevent_s *event, const struct cl_entity_s *entity ); +extern void ClientDLL_PostRunCmd( struct local_state_s *from, struct local_state_s *to, struct usercmd_s *cmd, int runfuncs, double time, unsigned int random_seed ); +extern void ClientDLL_TxferLocalOverrides( struct entity_state_s *state, const struct clientdata_s *client ); +extern void ClientDLL_ProcessPlayerState( struct entity_state_s *dst, const struct entity_state_s *src ); +extern void ClientDLL_TxferPredictionData ( struct entity_state_s *ps, const struct entity_state_s *pps, struct clientdata_s *pcd, const struct clientdata_s *ppcd, struct weapon_data_s *wd, const struct weapon_data_s *pwd ); +extern void ClientDLL_ReadDemoBuffer( int size, unsigned char *buffer ); +extern int ClientDLL_ConnectionlessPacket( const struct netadr_s *net_from, const char *args, char *response_buffer, int *response_buffer_size ); +extern int ClientDLL_GetHullBounds( int hullnumber, float *mins, float *maxs ); + +extern void ClientDLL_VGui_ConsolePrint(const char* text); + +extern int ClientDLL_Key_Event( int down, int keynum, const char *pszCurrentBinding ); +extern void ClientDLL_TempEntUpdate( double ft, double ct, double grav, struct tempent_s **ppFreeTE, struct tempent_s **ppActiveTE, int ( *addTEntity )( struct cl_entity_s *pEntity ), void ( *playTESound )( struct tempent_s *pTemp, float damp ) ); +extern struct cl_entity_s *ClientDLL_GetUserEntity( int index ); +extern void ClientDLL_VoiceStatus(int entindex, qboolean bTalking); +extern void ClientDLL_DirectorMessage( int iSize, void *pbuf ); #ifdef __cplusplus } diff --git a/engine/client/cl_beam.c b/engine/client/cl_beam.c index fbb83e80..3a03bd09 100644 --- a/engine/client/cl_beam.c +++ b/engine/client/cl_beam.c @@ -67,13 +67,23 @@ static void SineNoise( float *noise, int divs ) } } +static cl_entity_t *CL_GetBeamEntityByIndex( int index ) +{ + cl_entity_t *ent; + + if( index > 0 ) index = BEAMENT_ENTITY( index ); + ent = CL_GetEntityByIndex( index ); + + return ent; +} + static qboolean ComputeBeamEntPosition( int beamEnt, vec3_t pt ) { cl_entity_t *pEnt; int nAttachment; - pEnt = CL_GetEntityByIndex( BEAMENT_ENTITY( beamEnt )); - nAttachment = BEAMENT_ATTACHMENT( beamEnt ); + pEnt = CL_GetBeamEntityByIndex( beamEnt ); + nAttachment = ( beamEnt > 0 ) ? BEAMENT_ATTACHMENT( beamEnt ) : 0; if( !pEnt ) { @@ -81,7 +91,7 @@ static qboolean ComputeBeamEntPosition( int beamEnt, vec3_t pt ) return false; } - if(( pEnt->index - 1 ) == cl.playernum && !( cl.refdef.flags & RDF_THIRDPERSON )) + if(( pEnt->index - 1 ) == cl.playernum && !cl.thirdperson ) { // if we view beam at firstperson use viewmodel instead pEnt = &clgame.viewent; @@ -89,7 +99,7 @@ static qboolean ComputeBeamEntPosition( int beamEnt, vec3_t pt ) // get attachment if( nAttachment > 0 ) - VectorAdd( pEnt->origin, pEnt->attachment[nAttachment - 1], pt ); + VectorCopy( pEnt->attachment[nAttachment - 1], pt ); else VectorCopy( pEnt->origin, pt ); return true; @@ -209,7 +219,6 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3 segs_drawn = 0; total_segs = segments; - re->Enable( TRI_SHADER ); re->RenderMode( rendermode ); re->Bind( m_hSprite, frame ); // GetSpriteTexture already set frame re->Begin( TRI_TRIANGLE_STRIP ); @@ -340,7 +349,6 @@ static void CL_DrawSegs( int modelIndex, float frame, int rendermode, const vec3 } re->End(); - re->Disable( TRI_SHADER ); } /* @@ -380,7 +388,6 @@ static void CL_DrawDisk( int modelIndex, float frame, int rendermode, const vec3 w = freq * delta[2]; - re->Enable( TRI_SHADER ); re->RenderMode( rendermode ); re->Bind( m_hSprite, 0 ); // GetSpriteTexture already set frame @@ -411,7 +418,6 @@ static void CL_DrawDisk( int modelIndex, float frame, int rendermode, const vec3 } re->End(); - re->Disable( TRI_SHADER ); } /* @@ -449,7 +455,6 @@ static void CL_DrawCylinder( int modelIndex, float frame, int rendermode, const vLast = fmod( freq * speed, 1.0f ); scale = scale * length; - re->Enable( TRI_SHADER ); re->CullFace( TRI_NONE ); // FIXME: get it to work properly with enabled culling re->RenderMode( rendermode ); re->Bind( m_hSprite, 0 ); // GetSpriteTexture already set frame @@ -483,7 +488,6 @@ static void CL_DrawCylinder( int modelIndex, float frame, int rendermode, const } re->End(); - re->Disable( TRI_SHADER ); re->CullFace( TRI_FRONT ); } @@ -565,7 +569,6 @@ void CL_DrawRing( int modelIndex, float frame, int rendermode, const vec3_t sour j = segments / 8; - re->Enable( TRI_SHADER ); re->RenderMode( rendermode ); re->Bind( m_hSprite, 0 ); // GetSpriteTexture already set frame @@ -602,8 +605,6 @@ void CL_DrawRing( int modelIndex, float frame, int rendermode, const vec3_t sour // Build point along normal line (normal is -y, x) VectorScale( cl.refdef.up, tmp[0], normal ); VectorMA( normal, tmp[1], cl.refdef.right, normal ); -// FIXME: check this -// normal = normal - (g_pViewRenderBeams->GetViewParams()->right * -tmp.y); // make a wide line VectorMA( point, width, normal, last1 ); @@ -631,7 +632,6 @@ void CL_DrawRing( int modelIndex, float frame, int rendermode, const vec3_t sour } re->End(); - re->Disable( TRI_SHADER ); } /* @@ -729,9 +729,6 @@ static void DrawBeamFollow( int modelIndex, particle_t *pHead, int frame, int re VectorScale( cl.refdef.up, tmp[0], normal ); // Build point along noraml line (normal is -y, x) VectorMA( normal, tmp[1], cl.refdef.right, normal ); -// FIXME: check this -// normal = normal - (g_pViewRenderBeams->GetViewParams()->right * -tmp.y ); - // make a wide line VectorMA( delta, width, normal, last1 ); VectorMA( delta, -width, normal, last2 ); @@ -744,7 +741,6 @@ static void DrawBeamFollow( int modelIndex, particle_t *pHead, int frame, int re nColor[1] = (byte)bound( 0, (int)(scaledColor[1] * 255.0f), 255 ); nColor[2] = (byte)bound( 0, (int)(scaledColor[2] * 255.0f), 255 ); - re->Enable( TRI_SHADER ); re->RenderMode( rendermode ); re->Bind( m_hSprite, 0 ); // GetSpriteTexture already set frame @@ -773,9 +769,6 @@ static void DrawBeamFollow( int modelIndex, particle_t *pHead, int frame, int re VectorScale( cl.refdef.up, tmp[0], normal ); VectorMA( normal, tmp[1], cl.refdef.right, normal ); -// FIXME: check this -// normal = normal - (g_pViewRenderBeams->GetViewParams()->right * -tmp.y ); - // Make a wide line VectorMA( pHead->org, width, normal, last1 ); VectorMA( pHead->org, -width, normal, last2 ); @@ -810,7 +803,6 @@ static void DrawBeamFollow( int modelIndex, particle_t *pHead, int frame, int re } re->End(); - re->Disable( TRI_SHADER ); } /* @@ -972,6 +964,9 @@ BEAM *CL_AllocBeam( void ) pBeam = cl_free_beams; cl_free_beams = pBeam->next; + + Mem_Set( pBeam, 0, sizeof( *pBeam )); + pBeam->next = cl_active_beams; cl_active_beams = pBeam; @@ -991,9 +986,6 @@ void CL_FreeBeam( BEAM *pBeam ) // free particles that have died off. CL_FreeDeadTrails( &pBeam->particles ); - // clear us out - Mem_Set( pBeam, 0, sizeof( *pBeam )); - // now link into free list; pBeam->next = cl_free_beams; cl_free_beams = pBeam; @@ -1020,7 +1012,7 @@ void CL_KillDeadBeams( cl_entity_t *pDeadEntity ) pnext = pbeam->next; // link into new list. - if( CL_GetEntityByIndex( pbeam->startEntity ) != pDeadEntity ) + if( CL_GetBeamEntityByIndex( pbeam->startEntity ) != pDeadEntity ) { pbeam->next = pnewlist; pnewlist = pbeam; @@ -1257,9 +1249,12 @@ void CL_UpdateBeam( BEAM *pbeam, float frametime ) break; } - // update life cycle - pbeam->t = pbeam->freq + ( pbeam->die - cl.time ); - if( pbeam->t != 0.0f ) pbeam->t = 1.0f - pbeam->freq / pbeam->t; + if( pbeam->flags & ( FBEAM_FADEIN|FBEAM_FADEOUT )) + { + // update life cycle + pbeam->t = pbeam->freq + ( pbeam->die - cl.time ); + if( pbeam->t != 0.0f ) pbeam->t = 1.0f - pbeam->freq / pbeam->t; + } } /* @@ -1401,7 +1396,7 @@ void CL_DrawBeam( BEAM *pbeam ) cl_entity_t *pStart; // HACKHACK: get brightness from head entity - pStart = CL_GetEntityByIndex( BEAMENT_ENTITY( pbeam->startEntity )); + pStart = CL_GetBeamEntityByIndex( pbeam->startEntity ); if( pStart && pStart->curstate.rendermode != kRenderNormal ) pbeam->brightness = pStart->curstate.renderamt; } @@ -1583,7 +1578,7 @@ void CL_BeamKill( int deadEntity ) { cl_entity_t *pDeadEntity; - pDeadEntity = CL_GetEntityByIndex( deadEntity ); + pDeadEntity = CL_GetBeamEntityByIndex( deadEntity ); if( !pDeadEntity ) return; CL_KillDeadBeams( pDeadEntity ); @@ -1606,8 +1601,8 @@ BEAM *CL_BeamEnts( int startEnt, int endEnt, int modelIndex, float life, float w if( CM_GetModelType( modelIndex ) != mod_sprite ) return NULL; - pStart = CL_GetEntityByIndex( BEAMENT_ENTITY( startEnt )); - pEnd = CL_GetEntityByIndex( BEAMENT_ENTITY( endEnt )); + pStart = CL_GetBeamEntityByIndex( startEnt ); + pEnd = CL_GetBeamEntityByIndex( endEnt ); // don't start temporary beams out of the PVS if( life != 0 && ( !pStart || !pStart->curstate.modelindex || !pEnd || !pEnd->curstate.modelindex )) @@ -1767,12 +1762,13 @@ BEAM *CL_BeamEntPoint( int startEnt, const vec3_t end, int modelIndex, float lif { cl_entity_t *pStart; BEAM *pBeam; + float scale; // need a valid model. if( CM_GetModelType( modelIndex ) != mod_sprite ) return NULL; - pStart = CL_GetEntityByIndex( BEAMENT_ENTITY( startEnt )); + pStart = CL_GetBeamEntityByIndex( startEnt ); // don't start temporary beams out of the PVS if( life != 0.0f && ( !pStart || !pStart->curstate.modelindex )) @@ -1781,6 +1777,11 @@ BEAM *CL_BeamEntPoint( int startEnt, const vec3_t end, int modelIndex, float lif pBeam = CL_AllocBeam(); if( !pBeam ) return NULL; + scale = max( max( r, g ), b ); + if( scale <= 1.0f ) + scale = 255.0f; + else scale = 1.0f; + pBeam->type = TE_BEAMPOINTS; pBeam->flags = FBEAM_STARTENTITY; pBeam->modelIndex = modelIndex; @@ -1793,12 +1794,12 @@ BEAM *CL_BeamEntPoint( int startEnt, const vec3_t end, int modelIndex, float lif if( life == 0.0f ) pBeam->flags |= FBEAM_FOREVER; pBeam->die += life; pBeam->width = width; - pBeam->amplitude = amplitude; - pBeam->brightness = brightness; + pBeam->amplitude = amplitude * 10; + pBeam->brightness = brightness * scale; pBeam->speed = speed; - pBeam->r = r; - pBeam->g = g; - pBeam->b = b; + pBeam->r = r * scale; + pBeam->g = g * scale; + pBeam->b = b * scale; VectorSubtract( pBeam->target, pBeam->source, pBeam->delta ); @@ -1828,8 +1829,8 @@ BEAM *CL_BeamRing( int startEnt, int endEnt, int modelIndex, float life, float w if( CM_GetModelType( modelIndex ) != mod_sprite ) return NULL; - pStart = CL_GetEntityByIndex( BEAMENT_ENTITY( startEnt )); - pEnd = CL_GetEntityByIndex( BEAMENT_ENTITY( endEnt )); + pStart = CL_GetBeamEntityByIndex( startEnt ); + pEnd = CL_GetBeamEntityByIndex( endEnt ); // don't start temporary beams out of the PVS if( life != 0 && ( !pStart || !pStart->curstate.modelindex || !pEnd || !pEnd->curstate.modelindex )) @@ -1878,7 +1879,7 @@ BEAM *CL_BeamFollow( int startEnt, int modelIndex, float life, float width, floa if( CM_GetModelType( modelIndex ) != mod_sprite ) return NULL; - pStart = CL_GetEntityByIndex( BEAMENT_ENTITY( startEnt )); + pStart = CL_GetBeamEntityByIndex( startEnt ); // don't start temporary beams out of the PVS if( life != 0.0f && ( !pStart || !pStart->curstate.modelindex )) @@ -1898,7 +1899,7 @@ BEAM *CL_BeamFollow( int startEnt, int modelIndex, float life, float width, floa pBeam->freq = cl.time; pBeam->die += life; pBeam->width = width; - pBeam->amplitude = 1.0f; // beamfollow doesn't have amplitude + pBeam->amplitude = life; // partilces lifetime pBeam->brightness = bright; pBeam->speed = 1.0f; pBeam->r = r; @@ -1910,6 +1911,20 @@ BEAM *CL_BeamFollow( int startEnt, int modelIndex, float life, float width, floa return pBeam; } +/* +============== +CL_BeamSprite + +Create a beam with sprite at the end +Valve legacy +============== +*/ +void CL_BeamSprite( const vec3_t start, const vec3_t end, int beamIndex, int spriteIndex ) +{ + CL_BeamLightning( start, end, beamIndex, 0.1f, 1.0f, 0.0f, 255, 1.0f ); + CL_DefaultSprite( end, spriteIndex, 1.0f ); +} + /* ============== CL_ParseViewBeam @@ -1986,7 +2001,7 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType ) endEnt = BF_ReadShort( msg ); modelIndex = BF_ReadShort( msg ); startFrame = BF_ReadByte( msg ); - frameRate = (float)(BF_ReadByte( msg ) * 0.1f); // FIXME: this is correct ? + frameRate = (float)(BF_ReadByte( msg ) * 0.1f); life = (float)(BF_ReadByte( msg ) * 0.1f); width = (float)(BF_ReadByte( msg ) * 0.1f); noise = (float)(BF_ReadByte( msg ) * 0.1f); @@ -2002,7 +2017,15 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType ) MsgDev( D_ERROR, "TE_BEAM is obsolete\n" ); break; case TE_BEAMSPRITE: - // FIXME: implement + start[0] = BF_ReadCoord( msg ); + start[1] = BF_ReadCoord( msg ); + start[2] = BF_ReadCoord( msg ); + end[0] = BF_ReadCoord( msg ); + end[1] = BF_ReadCoord( msg ); + end[2] = BF_ReadCoord( msg ); + modelIndex = BF_ReadShort( msg ); // beam model + startFrame = BF_ReadShort( msg ); // sprite model + CL_BeamSprite( start, end, modelIndex, startFrame ); break; case TE_BEAMTORUS: case TE_BEAMDISK: @@ -2015,7 +2038,7 @@ void CL_ParseViewBeam( sizebuf_t *msg, int beamType ) end[2] = BF_ReadCoord( msg ); modelIndex = BF_ReadShort( msg ); startFrame = BF_ReadByte( msg ); - frameRate = (float)(BF_ReadByte( msg ) * 0.1f); // FIXME: this is correct ? + frameRate = (float)(BF_ReadByte( msg ) * 0.1f); life = (float)(BF_ReadByte( msg ) * 0.1f); width = (float)BF_ReadByte( msg ); noise = (float)(BF_ReadByte( msg ) * 0.1f); diff --git a/engine/client/cl_cmds.c b/engine/client/cl_cmds.c index df32de13..e76ab711 100644 --- a/engine/client/cl_cmds.c +++ b/engine/client/cl_cmds.c @@ -271,7 +271,7 @@ void SCR_TimeRefresh_f( void ) for( i = 0; i < 128; i++ ) { cl.refdef.viewangles[1] = i / 128.0 * 360.0f; - re->RenderFrame( &cl.refdef ); + re->RenderFrame( &cl.refdef, true ); } re->EndFrame(); } @@ -282,7 +282,7 @@ void SCR_TimeRefresh_f( void ) cl.refdef.viewangles[1] = i / 128.0 * 360.0f; re->BeginFrame( true ); - re->RenderFrame( &cl.refdef ); + re->RenderFrame( &cl.refdef, true ); re->EndFrame(); } } diff --git a/engine/client/cl_demo.c b/engine/client/cl_demo.c index a3231b47..8aeab204 100644 --- a/engine/client/cl_demo.c +++ b/engine/client/cl_demo.c @@ -406,7 +406,7 @@ void CL_StopPlayback( void ) // let game known about movie state cls.state = ca_disconnected; cls.demoname[0] = '\0'; // clear demoname too - gameui.globals->demoname[0] = '\0'; + menu.globals->demoname[0] = '\0'; if( clgame.hInstance ) clgame.dllFuncs.pfnReset(); // end of demos, stop the client } @@ -423,7 +423,7 @@ void CL_StopRecord( void ) cls.demofile = NULL; cls.demorecording = false; cls.demoname[0] = '\0'; - gameui.globals->demoname[0] = '\0'; + menu.globals->demoname[0] = '\0'; } /* @@ -605,7 +605,7 @@ void CL_Record_f( void ) // write demoshot for preview Cbuf_AddText( va( "demoshot \"%s\"\n", demoname )); com.strncpy( cls.demoname, demoname, sizeof( cls.demoname )); - com.strncpy( gameui.globals->demoname, demoname, sizeof( gameui.globals->demoname )); + com.strncpy( menu.globals->demoname, demoname, sizeof( menu.globals->demoname )); CL_WriteDemoHeader( demopath ); } @@ -641,7 +641,7 @@ void CL_PlayDemo_f( void ) cls.demofile = FS_OpenEx( filename, "rb", true ); com.strncpy( cls.demoname, Cmd_Argv( 1 ), sizeof( cls.demoname )); - com.strncpy( gameui.globals->demoname, Cmd_Argv( 1 ), sizeof( gameui.globals->demoname )); + com.strncpy( menu.globals->demoname, Cmd_Argv( 1 ), sizeof( menu.globals->demoname )); Con_Close(); UI_SetActiveMenu( false ); diff --git a/engine/client/cl_frame.c b/engine/client/cl_frame.c index 17236ddf..39a5d33a 100644 --- a/engine/client/cl_frame.c +++ b/engine/client/cl_frame.c @@ -8,6 +8,7 @@ #include "net_encode.h" #include "entity_types.h" #include "cl_tent.h" +#include "dlight.h" #include "input.h" qboolean CL_IsPlayerIndex( int idx ) @@ -26,19 +27,129 @@ FRAME PARSING */ void CL_UpdateEntityFields( cl_entity_t *ent ) { - // set player state - ent->player = CL_IsPlayerIndex( ent->index ); - ent->onground = CL_GetEntityByIndex( ent->curstate.onground ); - // FIXME: this very-very temporary stuffffffff // make me lerping VectorCopy( ent->curstate.origin, ent->origin ); VectorCopy( ent->curstate.angles, ent->angles ); +} - if( ent->curstate.effects & EF_BRIGHTFIELD ) +qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ) +{ + model_t *mod; + float oldScale, oldRenderAmt; + float shellScale = 1.0f; + int result = 0; + + mod = CM_ClipHandleToModel( ent->curstate.modelindex ); + if( !mod ) return false; + + // if entity is beam add it here + // because render doesn't know how to draw beams + if( entityType == ET_BEAM ) { - CL_EntityParticles( ent ); + CL_AddCustomBeam( ent ); + return true; } + + // check for adding this entity + if( !clgame.dllFuncs.pfnAddEntity( entityType, ent, mod->name )) + return false; + + if( ent->curstate.renderfx == kRenderFxGlowShell ) + { + oldRenderAmt = ent->curstate.renderamt; + oldScale = ent->curstate.scale ? ent->curstate.scale : 1.0f; + ent->curstate.renderamt = 255; // clear amount + } + + result = re->AddRefEntity( ent, entityType, -1 ); + + if( ent->curstate.renderfx == kRenderFxGlowShell ) + { + shellScale = ( oldRenderAmt * 0.00015f ); // shellOffset + ent->curstate.scale = oldScale + shellScale; // sets new scale + ent->curstate.renderamt = 128; + + // render glowshell + result |= re->AddRefEntity( ent, entityType, cls.glowShell ); // FIXME + + // restore parms + ent->curstate.scale = oldScale; + ent->curstate.renderamt = oldRenderAmt; + } + + if( !result ) return false; + + // apply effects + if( ent->curstate.effects & EF_BRIGHTFIELD ) + CL_EntityParticles( ent ); + + // add in muzzleflash effect + if( ent->curstate.effects & EF_MUZZLEFLASH ) + { + vec3_t pos; + + if( entityType == ET_VIEWENTITY ) + ent->curstate.effects &= ~EF_MUZZLEFLASH; + + VectorCopy( ent->attachment[0], pos ); + + if(!VectorCompare( pos, ent->origin )) + { + dlight_t *dl = CL_AllocDlight( 0 ); + + VectorCopy( ent->origin, dl->origin ); + dl->die = cl.time + 0.05f; + dl->color.r = 255; + dl->color.g = 180; + dl->color.b = 64; + dl->radius = 100; + } + } + + // add light effect + if( ent->curstate.effects & EF_LIGHT ) + { + dlight_t *dl = CL_AllocDlight( 0 ); + VectorCopy( ent->origin, dl->origin ); + dl->die = cl.time + 0.001f; // die at next frame + dl->color.r = 100; + dl->color.g = 100; + dl->color.b = 100; + dl->radius = 200; + CL_RocketFlare( ent->origin ); + } + + // add dimlight + if( ent->curstate.effects & EF_DIMLIGHT ) + { + if( entityType == ET_PLAYER ) + { + CL_UpadteFlashlight( ent ); + } + else + { + dlight_t *dl = CL_AllocDlight( 0 ); + VectorCopy( ent->origin, dl->origin ); + dl->die = cl.time + 0.001f; // die at next frame + dl->color.r = 255; + dl->color.g = 255; + dl->color.b = 255; + dl->radius = Com_RandomLong( 200, 230 ); + } + } + + if( ent->curstate.effects & EF_BRIGHTLIGHT ) + { + dlight_t *dl = CL_AllocDlight( 0 ); + VectorSet( dl->origin, ent->origin[0], ent->origin[1], ent->origin[2] + 16 ); + dl->die = cl.time + 0.001f; // die at next frame + dl->color.r = 255; + dl->color.g = 255; + dl->color.b = 255; + dl->radius = Com_RandomLong( 400, 430 ); + } + return true; } /* @@ -64,6 +175,7 @@ void CL_WeaponAnim( int iAnim, int body ) // save animtime view->latched.prevanimtime = view->curstate.animtime; + view->syncbase = -0.01f; // back up to get 0'th frame animations } view->curstate.entityType = ET_VIEWENTITY; @@ -118,7 +230,8 @@ void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate ) // save current blends to right lerping from last sequence for( i = 0; i < 4; i++ ) ent->latched.prevseqblending[i] = ent->curstate.blending[i]; - ent->latched.prevsequence = ent->curstate.sequence; // save old sequence + ent->latched.prevsequence = ent->curstate.sequence; // save old sequence + ent->syncbase = -0.01f; // back up to get 0'th frame animations } if( newstate->animtime != ent->curstate.animtime ) @@ -189,12 +302,15 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t cls.next_client_entities++; frame->num_entities++; - if( ent->index <= 0 ) + if( !ent->index ) { CL_InitEntity( ent ); noInterp = true; } + // set player state + ent->player = CL_IsPlayerIndex( ent->index ); + if( state->effects & EF_NOINTERP || noInterp ) { // duplicate the current state so lerping doesn't hurt anything @@ -213,7 +329,14 @@ void CL_DeltaEntity( sizebuf_t *msg, frame_t *frame, int newnum, entity_state_t // set right current state ent->curstate = *state; - CL_LinkEdict( ent ); // relink entity + if( ent->player ) + { + clgame.dllFuncs.pfnProcessPlayerState( &cl.frame.playerstate[ent->index-1], state ); + + // fill private structure for local client + if(( ent->index - 1 ) == cl.playernum ) + cl.frame.local.playerstate = cl.frame.playerstate[ent->index-1]; + } } /* @@ -509,18 +632,18 @@ void CL_AddPacketEntities( frame_t *frame ) int e, entityType; // now recalc actual entcount - for( ; EDICT_NUM( clgame.numEntities - 1 )->index == -1; clgame.numEntities-- ); + for( ; !EDICT_NUM( clgame.numEntities - 1 )->index; clgame.numEntities-- ); clent = CL_GetLocalPlayer(); if( !clent ) return; // update client vars - clgame.dllFuncs.pfnTxferLocalOverrides( &clent->curstate, &cl.frame.clientdata ); + clgame.dllFuncs.pfnTxferLocalOverrides( &clent->curstate, &cl.frame.local.client ); for( e = 1; e < clgame.numEntities; e++ ) { ent = CL_GetEntityByIndex( e ); - if( !ent ) continue; + if( !ent || !ent->index ) continue; // entity not visible for this client if( ent->curstate.effects & EF_NODRAW ) @@ -533,21 +656,7 @@ void CL_AddPacketEntities( frame_t *frame ) entityType = ET_BEAM; else entityType = ET_NORMAL; - // if entity is beam add it here - // because render doesn't know how to draw beams - if ( entityType == ET_BEAM ) - { - CL_AddCustomBeam( ent ); - continue; - } - - if( clgame.dllFuncs.pfnAddVisibleEntity( ent, entityType )) - { - if( entityType == ET_PORTAL && !VectorCompare( ent->curstate.origin, ent->curstate.vuser1 )) - cl.render_flags |= RDF_PORTALINVIEW; - } - // NOTE: skyportal entity never added to rendering - if( entityType == ET_SKYPORTAL ) cl.render_flags |= RDF_SKYPORTALINVIEW; + CL_AddVisibleEntity( ent, entityType ); } } @@ -563,9 +672,10 @@ void CL_AddEntities( void ) if( cls.state != ca_active ) return; - cl.render_flags = 0; cl.num_custombeams = 0; + clgame.dllFuncs.CAM_Think(); + CL_AddPacketEntities( &cl.frame ); clgame.dllFuncs.pfnCreateEntities(); @@ -591,7 +701,7 @@ qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, vec3_t velocity ent = EDICT_NUM( entnum ); - if( ent->index == -1 || ent->curstate.number != entnum ) + if( !ent->index || ent->curstate.number != entnum ) { // this entity isn't visible but maybe it have baseline ? if( ent->baseline.number != entnum ) @@ -637,5 +747,6 @@ qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, vec3_t velocity void CL_ExtraUpdate( void ) { + clgame.dllFuncs.IN_Accumulate(); S_ExtraUpdate(); } \ No newline at end of file diff --git a/engine/client/cl_game.c b/engine/client/cl_game.c index 74f5aba0..de84dd72 100644 --- a/engine/client/cl_game.c +++ b/engine/client/cl_game.c @@ -19,47 +19,53 @@ #include "input.h" #include "shake.h" +#define MAX_TEXTCHANNELS 8 // must be power of two (GoldSrc uses 4 channel) +#define TEXT_MSGNAME "TextMessage%i" + +char cl_textbuffer[MAX_TEXTCHANNELS][512]; +client_textmessage_t cl_textmessage[MAX_TEXTCHANNELS]; + static dllfunc_t cdll_exports[] = { -{ "Initialize", (void **)&clgame.cdllFuncs.pfnInitialize }, -{ "HUD_VidInit", (void **)&clgame.cdllFuncs.pfnVidInit }, -{ "HUD_Init", (void **)&clgame.cdllFuncs.pfnInit }, -{ "HUD_Shutdown", (void **)&clgame.cdllFuncs.pfnShutdown }, -{ "HUD_Redraw", (void **)&clgame.cdllFuncs.pfnRedraw }, -{ "HUD_UpdateClientData", (void **)&clgame.cdllFuncs.pfnUpdateClientData }, -{ "HUD_Reset", (void **)&clgame.cdllFuncs.pfnReset }, -{ "HUD_PlayerMove", (void **)&clgame.cdllFuncs.pfnPlayerMove }, -{ "HUD_PlayerMoveInit", (void **)&clgame.cdllFuncs.pfnPlayerMoveInit }, -{ "HUD_PlayerMoveTexture", (void **)&clgame.cdllFuncs.pfnPlayerMoveTexture }, -{ "HUD_ConnectionlessPacket", (void **)&clgame.cdllFuncs.pfnConnectionlessPacket }, -{ "HUD_GetHullBounds", (void **)&clgame.cdllFuncs.pfnGetHullBounds }, -{ "HUD_Frame", (void **)&clgame.cdllFuncs.pfnFrame }, -{ "HUD_VoiceStatus", (void **)&clgame.cdllFuncs.pfnVoiceStatus }, -{ "HUD_DirectorMessage", (void **)&clgame.cdllFuncs.pfnDirectorMessage }, -{ "HUD_PostRunCmd", (void **)&clgame.cdllFuncs.pfnPostRunCmd }, -{ "HUD_Key_Event", (void **)&clgame.cdllFuncs.pfnKey_Event }, -{ "HUD_AddEntity", (void **)&clgame.cdllFuncs.pfnAddEntity }, -{ "HUD_CreateEntities", (void **)&clgame.cdllFuncs.pfnCreateEntities }, -{ "HUD_StudioEvent", (void **)&clgame.cdllFuncs.pfnStudioEvent }, -{ "HUD_TxferLocalOverrides", (void **)&clgame.cdllFuncs.pfnTxferLocalOverrides }, -{ "HUD_ProcessPlayerState", (void **)&clgame.cdllFuncs.pfnProcessPlayerState }, -{ "HUD_TxferPredictionData", (void **)&clgame.cdllFuncs.pfnTxferPredictionData }, -{ "HUD_TempEntUpdate", (void **)&clgame.cdllFuncs.pfnTempEntUpdate }, -{ "HUD_DrawNormalTriangles", (void **)&clgame.cdllFuncs.pfnDrawNormalTriangles }, -{ "HUD_DrawTransparentTriangles", (void **)&clgame.cdllFuncs.pfnDrawTransparentTriangles }, -{ "HUD_GetUserEntity", (void **)&clgame.cdllFuncs.pfnGetUserEntity }, -{ "Demo_ReadBuffer", (void **)&clgame.cdllFuncs.pfnDemo_ReadBuffer }, -{ "CAM_Think", (void **)&clgame.cdllFuncs.CAM_Think }, -{ "CL_IsThirdPerson", (void **)&clgame.cdllFuncs.CL_IsThirdPerson }, -{ "CL_CameraOffset", (void **)&clgame.cdllFuncs.CL_CameraOffset }, -{ "CL_CreateMove", (void **)&clgame.cdllFuncs.CL_CreateMove }, -{ "IN_ActivateMouse", (void **)&clgame.cdllFuncs.IN_ActivateMouse }, -{ "IN_DeactivateMouse", (void **)&clgame.cdllFuncs.IN_DeactivateMouse }, -{ "IN_MouseEvent", (void **)&clgame.cdllFuncs.IN_MouseEvent }, -{ "IN_Accumulate", (void **)&clgame.cdllFuncs.IN_Accumulate }, -{ "IN_ClearStates", (void **)&clgame.cdllFuncs.IN_ClearStates }, -{ "V_CalcRefdef", (void **)&clgame.cdllFuncs.V_CalcRefdef }, -{ "KB_Find", (void **)&clgame.cdllFuncs.KB_Find }, +{ "Initialize", (void **)&clgame.dllFuncs.pfnInitialize }, +{ "HUD_VidInit", (void **)&clgame.dllFuncs.pfnVidInit }, +{ "HUD_Init", (void **)&clgame.dllFuncs.pfnInit }, +{ "HUD_Shutdown", (void **)&clgame.dllFuncs.pfnShutdown }, +{ "HUD_Redraw", (void **)&clgame.dllFuncs.pfnRedraw }, +{ "HUD_UpdateClientData", (void **)&clgame.dllFuncs.pfnUpdateClientData }, +{ "HUD_Reset", (void **)&clgame.dllFuncs.pfnReset }, +{ "HUD_PlayerMove", (void **)&clgame.dllFuncs.pfnPlayerMove }, +{ "HUD_PlayerMoveInit", (void **)&clgame.dllFuncs.pfnPlayerMoveInit }, +{ "HUD_PlayerMoveTexture", (void **)&clgame.dllFuncs.pfnPlayerMoveTexture }, +{ "HUD_ConnectionlessPacket", (void **)&clgame.dllFuncs.pfnConnectionlessPacket }, +{ "HUD_GetHullBounds", (void **)&clgame.dllFuncs.pfnGetHullBounds }, +{ "HUD_Frame", (void **)&clgame.dllFuncs.pfnFrame }, +{ "HUD_VoiceStatus", (void **)&clgame.dllFuncs.pfnVoiceStatus }, +{ "HUD_DirectorMessage", (void **)&clgame.dllFuncs.pfnDirectorMessage }, +{ "HUD_PostRunCmd", (void **)&clgame.dllFuncs.pfnPostRunCmd }, +{ "HUD_Key_Event", (void **)&clgame.dllFuncs.pfnKey_Event }, +{ "HUD_AddEntity", (void **)&clgame.dllFuncs.pfnAddEntity }, +{ "HUD_CreateEntities", (void **)&clgame.dllFuncs.pfnCreateEntities }, +{ "HUD_StudioEvent", (void **)&clgame.dllFuncs.pfnStudioEvent }, +{ "HUD_TxferLocalOverrides", (void **)&clgame.dllFuncs.pfnTxferLocalOverrides }, +{ "HUD_ProcessPlayerState", (void **)&clgame.dllFuncs.pfnProcessPlayerState }, +{ "HUD_TxferPredictionData", (void **)&clgame.dllFuncs.pfnTxferPredictionData }, +{ "HUD_TempEntUpdate", (void **)&clgame.dllFuncs.pfnTempEntUpdate }, +{ "HUD_GetStudioModelInterface", (void **)&clgame.dllFuncs.pfnGetStudioModelInterface }, +{ "HUD_DrawNormalTriangles", (void **)&clgame.dllFuncs.pfnDrawNormalTriangles }, +{ "HUD_DrawTransparentTriangles", (void **)&clgame.dllFuncs.pfnDrawTransparentTriangles }, +{ "HUD_GetUserEntity", (void **)&clgame.dllFuncs.pfnGetUserEntity }, +{ "Demo_ReadBuffer", (void **)&clgame.dllFuncs.pfnDemo_ReadBuffer }, +{ "CAM_Think", (void **)&clgame.dllFuncs.CAM_Think }, +{ "CL_IsThirdPerson", (void **)&clgame.dllFuncs.CL_IsThirdPerson }, +{ "CL_CreateMove", (void **)&clgame.dllFuncs.CL_CreateMove }, +{ "IN_ActivateMouse", (void **)&clgame.dllFuncs.IN_ActivateMouse }, +{ "IN_DeactivateMouse", (void **)&clgame.dllFuncs.IN_DeactivateMouse }, +{ "IN_MouseEvent", (void **)&clgame.dllFuncs.IN_MouseEvent }, +{ "IN_Accumulate", (void **)&clgame.dllFuncs.IN_Accumulate }, +{ "IN_ClearStates", (void **)&clgame.dllFuncs.IN_ClearStates }, +{ "V_CalcRefdef", (void **)&clgame.dllFuncs.pfnCalcRefdef }, +{ "KB_Find", (void **)&clgame.dllFuncs.KB_Find }, { NULL, NULL } }; @@ -75,10 +81,13 @@ cl_entity_t *CL_GetEntityByIndex( int index ) if( !clgame.entities ) return NULL; - if( index < 0 || index > clgame.numEntities ) + if( index < 0 ) + return clgame.dllFuncs.pfnGetUserEntity( abs( index )); + + if( index > clgame.numEntities ) return NULL; - if( EDICT_NUM( index )->index == -1 ) + if( !EDICT_NUM( index )->index ) return NULL; return EDICT_NUM( index ); } @@ -95,6 +104,30 @@ float CL_GetServerTime( void ) return sv_time(); } +/* +==================== +CL_GetLerpFrac + +returns current lerp fraction +==================== +*/ +float CL_GetLerpFrac( void ) +{ + return cl.lerpFrac; +} + +/* +==================== +CL_IsThirdPerson + +returns true if thirdperson is enabled +==================== +*/ +qboolean CL_IsThirdPerson( void ) +{ + return cl.thirdperson; +} + /* ==================== CL_GetPlayerInfo @@ -110,6 +143,22 @@ player_info_t *CL_GetPlayerInfo( int playerIndex ) return &cl.players[playerIndex]; } +/* +==================== +CL_PointContents + +Return contents for point +==================== +*/ +int CL_PointContents( const vec3_t p ) +{ + int cont = CL_TruePointContents( p ); + + if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN ) + cont = CONTENTS_WATER; + return cont; +} + /* ==================== StudioEvent @@ -122,18 +171,6 @@ void CL_StudioEvent( struct mstudioevent_s *event, cl_entity_t *pEdict ) clgame.dllFuncs.pfnStudioEvent( event, pEdict ); } -/* -==================== -Studio_FxTransform - -apply fxtransforms for each studio bone -==================== -*/ -void CL_StudioFxTransform( cl_entity_t *ent, float transform[4][4] ) -{ - clgame.dllFuncs.pfnStudioFxTransform( ent, transform ); -} - /* ================ CL_FadeAlpha @@ -521,6 +558,14 @@ static void CL_InitTitles( const char *filename ) { size_t fileSize; byte *pMemFile; + int i; + + // initialize text messages (game_text) + for( i = 0; i < MAX_TEXTCHANNELS; i++ ) + { + cl_textmessage[i].pName = com.stralloc( clgame.mempool, va( TEXT_MSGNAME, i ), __FILE__, __LINE__ ); + cl_textmessage[i].pMessage = cl_textbuffer[i]; + } // clear out any old data that's sitting around. if( clgame.titles ) Mem_Free( clgame.titles ); @@ -535,6 +580,60 @@ static void CL_InitTitles( const char *filename ) Mem_Free( pMemFile ); } +/* +==================== +CL_ParseTextMessage + +Parse TE_TEXTMESSAGE +==================== +*/ +void CL_ParseTextMessage( sizebuf_t *msg ) +{ + static int msgindex = 0; + client_textmessage_t *text; + int channel; + + // read channel ( 0 - auto) + channel = BF_ReadByte( msg ); + + if( channel <= 0 || channel > ( MAX_TEXTCHANNELS - 1 )) + { + // invalid channel specified, use internal counter + if( channel != 0 ) MsgDev( D_ERROR, "HudText: invalid channel %i\n", channel ); + channel = msgindex; + msgindex = (msgindex + 1) & (MAX_TEXTCHANNELS - 1); + } + + // grab message channel + text = &cl_textmessage[channel]; + + text->x = (float)(BF_ReadShort( msg ) / 8192.0f); + text->y = (float)(BF_ReadShort( msg ) / 8192.0f); + text->effect = BF_ReadByte( msg ); + text->r1 = BF_ReadByte( msg ); + text->g1 = BF_ReadByte( msg ); + text->b1 = BF_ReadByte( msg ); + text->a1 = BF_ReadByte( msg ); + text->r2 = BF_ReadByte( msg ); + text->g2 = BF_ReadByte( msg ); + text->b2 = BF_ReadByte( msg ); + text->a2 = BF_ReadByte( msg ); + text->fadein = (float)(BF_ReadShort( msg ) / 256.0f ); + text->fadeout = (float)(BF_ReadShort( msg ) / 256.0f ); + text->holdtime = (float)(BF_ReadShort( msg ) / 256.0f ); + + if( text->effect == 2 ) + text->fxtime = (float)(BF_ReadShort( msg ) / 256.0f ); + else text->fxtime = 0.0f; + + // to prevent grab too long messages + com.strncpy( (char *)text->pMessage, BF_ReadString( msg ), 512 ); + + // NOTE: a "HudText" message contain only 'string' with message name, so we + // don't needs to use MSG_ routines here, just directly write msgname into netbuffer + CL_DispatchUserMessage( "HudText", com.strlen( text->pName ) + 1, (void *)text->pName ); +} + /* ==================== CL_BadMessage @@ -557,12 +656,13 @@ Render callback for studio models */ cl_entity_t *CL_GetLocalPlayer( void ) { - if( cls.state == ca_active ) + if( cls.state >= ca_connected ) { - cl_entity_t *player = EDICT_NUM( cl.playernum + 1 ); + cl_entity_t *player; - if( player ) return player; - Host_Error( "CL_GetLocalPlayer: invalid edict\n" ); + player = EDICT_NUM( cl.playernum + 1 ); + ASSERT( player != NULL ); + return player; } return NULL; } @@ -589,7 +689,7 @@ void CL_DrawCrosshair( void ) pPlayer = CL_GetLocalPlayer(); - if( cl.frame.clientdata.deadflag != DEAD_NO || cl.frame.clientdata.flags & FL_FROZEN ) + if( cl.frame.local.client.deadflag != DEAD_NO || cl.frame.local.client.flags & FL_FROZEN ) return; // any camera on @@ -909,7 +1009,7 @@ void CL_FireEvents( void ) } // delayed event! - if( ei->fire_time && ( ei->fire_time > cl_time() )) + if( ei->fire_time && ( ei->fire_time > cl.time )) continue; success = CL_FireEvent( ei ); @@ -1003,7 +1103,7 @@ void CL_QueueEvent( int flags, int index, float delay, event_args_t *args ) } ei->index = index; - ei->fire_time = delay ? (cl_time() + delay) : 0.0f; + ei->fire_time = delay ? (cl.time + delay) : 0.0f; ei->flags = flags; // copy in args event data @@ -1041,7 +1141,7 @@ void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, floa if( delay < 0.0f ) delay = 0.0f; // fixup negative delays - if( pInvoker ) invokerIndex = NUM_FOR_EDICT( pInvoker ); + invokerIndex = cl.playernum + 1; args.flags = 0; args.entindex = invokerIndex; @@ -1063,12 +1163,10 @@ void CL_PlaybackEvent( int flags, const edict_t *pInvoker, word eventindex, floa else if( invokerIndex ) { // get up some info from invoker - if( VectorIsNull( args.origin )) - VectorCopy(((cl_entity_t *)&pInvoker)->curstate.origin, args.origin ); - if( VectorIsNull( args.angles )) - VectorCopy(((cl_entity_t *)&pInvoker)->curstate.angles, args.angles ); - VectorCopy(((cl_entity_t *)&pInvoker)->curstate.velocity, args.velocity ); - args.ducking = ((cl_entity_t *)&pInvoker)->curstate.usehull; + VectorCopy( cl.data.origin, args.origin ); + VectorCopy( cl.data.viewangles, args.angles ); + VectorCopy( cl.frame.local.playerstate.velocity, args.velocity ); + args.ducking = cl.frame.local.playerstate.usehull; } CL_QueueEvent( flags, eventindex, delay, &args ); @@ -1086,12 +1184,10 @@ void CL_FreeEntity( cl_entity_t *pEdict ) ASSERT( pEdict ); // already freed ? - if( pEdict->index == -1 ) - return; + if( !pEdict->index ) return; - CL_UnlinkEdict( pEdict ); CL_KillDeadBeams( pEdict ); - pEdict->index = -1; // freed + pEdict->index = 0; // freed } void CL_InitWorld( void ) @@ -1104,25 +1200,16 @@ void CL_InitWorld( void ) ent->curstate.solid = SOLID_BSP; ent->curstate.movetype = MOVETYPE_PUSH; clgame.numEntities = 1; - - // clear physics interaction links - CL_ClearWorld (); } void CL_InitEdicts( void ) { - cl_entity_t *e; - int i; - ASSERT( clgame.entities == NULL ); CL_UPDATE_BACKUP = ( cl.maxclients == 1 ) ? SINGLEPLAYER_BACKUP : MULTIPLAYER_BACKUP; cls.num_client_entities = CL_UPDATE_BACKUP * 64; cls.packet_entities = Z_Realloc( cls.packet_entities, sizeof( entity_state_t ) * cls.num_client_entities ); clgame.entities = Mem_Alloc( clgame.mempool, sizeof( cl_entity_t ) * clgame.maxEntities ); - - for( i = 0, e = clgame.entities; i < clgame.maxEntities; i++, e++ ) - e->index = -1; // mark all entities as freed } void CL_FreeEdicts( void ) @@ -1159,21 +1246,71 @@ void CL_FreeEdicts( void ) =============================================================================== */ +static void CL_LoadHudSprite( const char *szPicName, model_t *m_pSprite, int shaderType ) +{ + ASSERT( m_pSprite != NULL ); + + // register new sprite + com.strncpy( m_pSprite->name, szPicName, sizeof( m_pSprite->name )); + m_pSprite->numtexinfo = re->RegisterShader( m_pSprite->name, shaderType ); + + if( !m_pSprite->numtexinfo ) + { + // can't loading or something + Mem_Set( m_pSprite, 0, sizeof( *m_pSprite )); + return; + } + + m_pSprite->registration_sequence = -1; // to differentiate from normal sprites + m_pSprite->type = mod_sprite; + re->GetParms( NULL, NULL, &m_pSprite->numframes, 0, m_pSprite->numtexinfo ); +} + +static shader_t CL_GetHudSpriteShader( HSPRITE hSpr ) +{ + if( hSpr <= 0 || hSpr > MAX_IMAGES ) + return 0; // bad image + + return clgame.ds.images[hSpr].numtexinfo; +} + /* ========= pfnSPR_Load ========= */ -static HSPRITE pfnSPR_Load( const char *szPicName ) +HSPRITE pfnSPR_Load( const char *szPicName ) { + int i; + if( !re ) return 0; // render not initialized if( !szPicName || !*szPicName ) { MsgDev( D_ERROR, "CL_LoadSprite: bad name!\n" ); return 0; } - return re->RegisterShader( szPicName, SHADER_SPRITE ); + + // slot 0 isn't used + for( i = 1; i < MAX_IMAGES && clgame.ds.images[i].name[0]; i++ ) + { + if( !com.strcmp( clgame.ds.images[i].name, szPicName )) + { + // refresh shader + CL_LoadHudSprite( szPicName, &clgame.ds.images[i], SHADER_SPRITE ); + return i; + } + } + + if( i == MAX_IMAGES ) + { + MsgDev( D_ERROR, "SPR_Load: can't load %s, MAX_HSPRITES limit exceeded\n", szPicName ); + return 0; + } + + // load new shader + CL_LoadHudSprite( szPicName, &clgame.ds.images[i], SHADER_SPRITE ); + return i; } /* @@ -1187,7 +1324,7 @@ static int pfnSPR_Frames( HSPRITE hPic ) int numFrames; if( !re ) return 1; - re->GetParms( NULL, NULL, &numFrames, 0, hPic ); + re->GetParms( NULL, NULL, &numFrames, 0, CL_GetHudSpriteShader( hPic )); return numFrames; } @@ -1203,7 +1340,7 @@ static int pfnSPR_Height( HSPRITE hPic, int frame ) int sprHeight; if( !re ) return 0; - re->GetParms( NULL, &sprHeight, NULL, frame, hPic ); + re->GetParms( NULL, &sprHeight, NULL, frame, CL_GetHudSpriteShader( hPic )); return sprHeight; } @@ -1219,7 +1356,7 @@ static int pfnSPR_Width( HSPRITE hPic, int frame ) int sprWidth; if( !re ) return 0; - re->GetParms( &sprWidth, NULL, NULL, frame, hPic ); + re->GetParms( &sprWidth, NULL, NULL, frame, CL_GetHudSpriteShader( hPic )); return sprWidth; } @@ -1236,7 +1373,7 @@ static void pfnSPR_Set( HSPRITE hPic, int r, int g, int b ) if( !re ) return; // render not initialized - clgame.ds.hSprite = hPic; + clgame.ds.hSprite = CL_GetHudSpriteShader( hPic ); MakeRGBA( color, r, g, b, 255 ); re->SetColor( color ); } @@ -1467,7 +1604,7 @@ static void pfnSetCrosshair( HSPRITE hspr, wrect_t rc, int r, int g, int b ) clgame.ds.rgbaCrosshair[1] = (byte)g; clgame.ds.rgbaCrosshair[2] = (byte)b; clgame.ds.rgbaCrosshair[3] = (byte)0xFF; - clgame.ds.hCrosshair = hspr; + clgame.ds.hCrosshair = CL_GetHudSpriteShader( hspr ); clgame.ds.rcCrosshair = rc; } @@ -1611,6 +1748,13 @@ static client_textmessage_t *pfnTextMessageGet( const char *pName ) { int i; + // first check internal messages + for( i = 0; i < MAX_TEXTCHANNELS; i++ ) + { + if( !com.strcmp( pName, va( TEXT_MSGNAME, i ))) + return cl_textmessage + i; + } + // find desired message for( i = 0; i < clgame.numTitles; i++ ) { @@ -1629,16 +1773,20 @@ returns drawed chachter width (in real screen pixels) */ static int pfnDrawCharacter( int x, int y, int number, int r, int g, int b ) { - number &= 255; + rgba_t color; if( !cls.creditsFont.valid ) return 0; + number &= 255; + if( number < 32 ) return 0; if( y < -clgame.scrInfo.iCharHeight ) return 0; - pfnSPR_Set( cls.creditsFont.hFontTexture, r, g, b ); + MakeRGBA( color, r, g, b, 255 ); + re->SetColor( color ); + clgame.ds.hSprite = cls.creditsFont.hFontTexture; pfnSPR_DrawAdditive( 0, x, y, &cls.creditsFont.fontRc[number] ); return clgame.scrInfo.charWidths[number]; } @@ -1759,7 +1907,7 @@ pfnPhysInfo_ValueForKey */ static const char* pfnPhysInfo_ValueForKey( const char *key ) { - return Info_ValueForKey( cl.frame.clientdata.physinfo, key ); + return Info_ValueForKey( cl.frame.local.client.physinfo, key ); } /* @@ -1782,7 +1930,7 @@ value that come from server */ static float pfnGetClientMaxspeed( void ) { - return cl.frame.clientdata.maxspeed; + return cl.frame.local.client.maxspeed; } /* @@ -1825,7 +1973,11 @@ pfnGetMousePosition */ static void pfnGetMousePosition( int *mx, int *my ) { - // FIXME: implement + POINT curpos; + + GetCursorPos( &curpos ); + if( mx ) *mx = curpos.x; + if( my ) *my = curpos.y; } /* @@ -1847,7 +1999,6 @@ int pfnIsNoClipping( void ) ============= pfnGetViewModel -can return NULL ============= */ static cl_entity_t* pfnGetViewModel( void ) @@ -1981,26 +2132,36 @@ pfnWaterEntity */ static int pfnWaterEntity( const float *rgflPos ) { - cl_entity_t *pWater, *touch[MAX_EDICTS]; - int i, num; + physent_t *pe; + hull_t *hull; + vec3_t test; + int i; if( !rgflPos ) return -1; - // grab contents from all the water entities - num = CL_AreaEdicts( rgflPos, rgflPos, touch, MAX_EDICTS, AREA_CUSTOM ); - - for( i = 0; i < num; i++ ) + for( i = 0; i < clgame.pmove->nummoveent; i++ ) { - pWater = touch[i]; + pe = &clgame.pmove->moveents[i]; - if( !pWater || pWater->index == -1 ) + if( pe->solid != SOLID_NOT ) // disabled ? continue; - if( pWater->curstate.solid != SOLID_NOT || pWater->curstate.skin == CONTENTS_NONE ) - continue; // invalid water ? + // only brushes can have special contents + if( pe->model->type != mod_brush ) + continue; - // return first valid water entity - return pWater - clgame.entities; + // check water brushes accuracy + hull = PM_HullForBsp( pe, vec3_origin, vec3_origin, test ); + + // offset the test point appropriately for this hull. + VectorSubtract( rgflPos, test, test ); + + // test hull for intersection with this model + if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY ) + continue; + + // found water entity + return pe->info; } return -1; } @@ -2170,7 +2331,7 @@ pfnLocalPlayerDucking */ int pfnLocalPlayerDucking( void ) { - return cl.frame.clientdata.bInDuck; + return cl.frame.local.client.bInDuck; } /* @@ -2329,6 +2490,20 @@ static qboolean pfnBoxVisible( const vec3_t mins, const vec3_t maxs ) return CM_BoxVisible( mins, maxs, re->GetCurrentVis()); } +/* +============= +CL_GetSpritePointer + +============= +*/ +const model_t *CL_GetSpritePointer( HSPRITE hSprite ) +{ + if( hSprite <= 0 || hSprite > MAX_IMAGES ) + return 0; // bad image + + return &clgame.ds.images[hSprite]; +} + /* ============= CL_LoadModel @@ -2348,11 +2523,11 @@ model_t *CL_LoadModel( const char *modelname, int *index ) int CL_AddEntity( int entityType, cl_entity_t *pEnt ) { - if( !re || !pEnt || pEnt->index == -1 ) + if( !re || !pEnt || !pEnt->index ) return false; // let the render reject entity without model - return re->AddRefEntity( pEnt, entityType, -1 ); + return CL_AddVisibleEntity( pEnt, entityType ); } /* @@ -2386,7 +2561,13 @@ pfnGetLevelName */ static const char *pfnGetLevelName( void ) { - return clgame.mapname; + static char mapname[64]; + + if( cls.state >= ca_connected ) + com.snprintf( mapname, sizeof( mapname ), "maps/%s.bsp", clgame.mapname ); + else mapname[0] = '\0'; // not in game + + return mapname; } /* @@ -2442,8 +2623,35 @@ pfnLoadMapSprite */ model_t *pfnLoadMapSprite( const char *filename ) { - // FIXME: implement - return NULL; + int i; + + if( !re ) return NULL; // render not initialized + if( !filename || !*filename ) + { + MsgDev( D_ERROR, "CL_LoadMapSprite: bad name!\n" ); + return 0; + } + + // slot 0 isn't used + for( i = 1; i < MAX_IMAGES && clgame.ds.images[i].name[0]; i++ ) + { + if( !com.strcmp( clgame.ds.images[i].name, filename )) + { + // refresh shader + CL_LoadHudSprite( filename, &clgame.ds.images[i], SHADER_GENERIC ); + return clgame.ds.images + i; + } + } + + if( i == MAX_IMAGES ) + { + MsgDev( D_ERROR, "LoadMapSprite: can't load %s, MAX_HSPRITES limit exceeded\n", filename ); + return 0; + } + + // load new shader + CL_LoadHudSprite( filename, &clgame.ds.images[i], SHADER_GENERIC ); + return clgame.ds.images + i; } /* @@ -2584,58 +2792,6 @@ void pfnSetMouseEnable( qboolean fEnable ) =============================================================================== */ -/* -================= -pfnDecalIndexFromName - -================= -*/ -int pfnDecalIndexFromName( const char *szDecalName ) -{ - int i; - - if( !szDecalName || !szDecalName[0] ) - return 0; - - // look through the loaded sprite name list for SpriteName - for( i = 0; i < MAX_DECALS && host.draw_decals[i+1][0]; i++ ) - { - if( !com.stricmp( szDecalName, host.draw_decals[i+1] )) - { - if( !cl.decal_index[i+1] ) - cl.decal_index[i+1] = re->RegisterShader( szDecalName, SHADER_DECAL ); - return cl.decal_index[i+1]; - } - } - return 0; // invalid decal -} - -/* -================= -pfnDecalIndex - -================= -*/ -static int pfnDecalIndex( int id ) -{ - id = bound( 0, id, MAX_DECALS - 1 ); - if( !cl.decal_index[id] ) - cl.decal_index[id] = re->RegisterShader( host.draw_decals[id], SHADER_DECAL ); - return cl.decal_index[id]; -} - -/* -================= -pfnCullBox - -================= -*/ -static int pfnCullBox( const vec3_t mins, const vec3_t maxs ) -{ - if( !re ) return false; - return re->CullBox( mins, maxs ); -} - /* ================= pfnEnvShot @@ -2676,15 +2832,16 @@ static void pfnEnvShot( const float *vieworg, const char *name, int skyshot ) /* ================= -pfnGetPaletteColor +pfnSkyCamera ================= */ -static void pfnGetPaletteColor( int colorIndex, vec3_t outColor ) +static void pfnSkyCamera( const float *vieworg, const float *viewangles, float scale, float fov ) { - if( !outColor ) return; - colorIndex = bound( 0, colorIndex, 255 ); - VectorCopy( clgame.palette[colorIndex], outColor ); + if( !re || !vieworg || !viewangles ) + return; + + re->SetSkyPortal( vieworg, viewangles, scale, fov ); } /* @@ -2702,30 +2859,17 @@ callback from renderer */ void Tri_DrawTriangles( int fTrans ) { - CL_DrawBeams( fTrans ); - - if( fTrans ) CL_DrawParticles(); - - clgame.dllFuncs.pfnDrawTriangles( fTrans ); -} - -/* -============= -TriLoadShader - -============= -*/ -shader_t TriLoadShader( const char *szShaderName, int fShaderNoMip ) -{ - if( !re ) return 0; // render not initialized - if( !szShaderName || !*szShaderName ) + if( fTrans ) { - MsgDev( D_ERROR, "Tri_LoadShader: invalid shadername (%s)\n", fShaderNoMip ? "nomip" : "generic" ); - return -1; + CL_DrawBeams( true ); + CL_DrawParticles(); + clgame.dllFuncs.pfnDrawTransparentTriangles (); + } + else + { + CL_DrawBeams( false ); + clgame.dllFuncs.pfnDrawNormalTriangles (); } - if( fShaderNoMip ) - return re->RegisterShader( szShaderName, SHADER_NOMIP ); - return re->RegisterShader( szShaderName, SHADER_GENERIC ); } /* @@ -2740,25 +2884,6 @@ void TriRenderMode( int mode ) re->RenderMode( mode ); } -shader_t TriGetSpriteFrame( int spriteIndex, int spriteFrame ) -{ - if( !re ) return 0; - return re->GetSpriteTexture( spriteIndex, spriteFrame ); -} - -/* -============= -TriBind - -bind current shader -============= -*/ -void TriBind( shader_t shader, int frame ) -{ - if( !re ) return; - re->Bind( shader, frame ); -} - /* ============= TriBegin @@ -2783,78 +2908,6 @@ void TriEnd( void ) if( re ) re->End(); } -/* -============= -TriEnable - -============= -*/ -void TriEnable( int cap ) -{ - if( !re ) return; - re->Enable( cap ); -} - -/* -============= -TriDisable - -============= -*/ -void TriDisable( int cap ) -{ - if( !re ) return; - re->Disable( cap ); -} - -/* -============= -TriVertex3f - -============= -*/ -void TriVertex3f( float x, float y, float z ) -{ - if( !re ) return; - re->Vertex3f( x, y, z ); -} - -/* -============= -TriVertex3fv - -============= -*/ -void TriVertex3fv( const float *v ) -{ - if( !re || !v ) return; - re->Vertex3f( v[0], v[1], v[2] ); -} - -/* -============= -TriNormal3f - -============= -*/ -void TriNormal3f( float x, float y, float z ) -{ - if( !re ) return; - re->Normal3f( x, y, z ); -} - -/* -============= -TriNormal3fv - -============= -*/ -void TriNormal3fv( const float *v ) -{ - if( !re || !v ) return; - re->Normal3f( v[0], v[1], v[2] ); -} - /* ============= TriColor4f @@ -2897,6 +2950,30 @@ void TriTexCoord2f( float u, float v ) re->TexCoord2f( u, v ); } +/* +============= +TriVertex3fv + +============= +*/ +void TriVertex3fv( const float *v ) +{ + if( !re || !v ) return; + re->Vertex3f( v[0], v[1], v[2] ); +} + +/* +============= +TriVertex3f + +============= +*/ +void TriVertex3f( float x, float y, float z ) +{ + if( !re ) return; + re->Vertex3f( x, y, z ); +} + /* ============= TriBrightness @@ -2905,7 +2982,10 @@ TriBrightness */ void TriBrightness( float brightness ) { - // FIXME: implement + int color; + + color = brightness * 255; + re->Color4ub( color, color, color, 255 ); } /* @@ -2922,16 +3002,28 @@ void TriCullFace( TRICULLSTYLE mode ) /* ============= -TriScreenToWorld +TriSpriteTexture -convert screen coordinates (x,y) into world (x, y, z) +bind current texture ============= */ -void TriScreenToWorld( float *screen, float *world ) +int TriSpriteTexture( model_t *pSpriteModel, int frame ) { - if( !re ) return; - re->ScreenToWorld( screen, world ); -} + shader_t shader; + + if( !re || !pSpriteModel ) + return 0; + + if( pSpriteModel->registration_sequence == -1 ) + shader = pSpriteModel->numtexinfo; + else if( pSpriteModel->type == mod_sprite && pSpriteModel->numframes ) + shader = re->GetSpriteTexture( CM_ClipModelToHandle( pSpriteModel ), frame ); + else return 0; + + re->Bind( shader, frame ); + + return 1; +} /* ============= @@ -2969,6 +3061,43 @@ void TriFog( float flFogColor[3], float flStart, float flEnd, int bOn ) if( re ) re->Fog( flFogColor, flStart, flEnd, bOn ); } +/* +============= +TriScreenToWorld + +convert screen coordinates (x,y) into world (x, y, z) +============= +*/ +void TriScreenToWorld( float *screen, float *world ) +{ + if( !re ) return; + re->ScreenToWorld( screen, world ); +} + +/* +============= +TriNormal3fv + +============= +*/ +void TriNormal3fv( const float *v ) +{ + if( !re || !v ) return; + re->Normal3f( v[0], v[1], v[2] ); +} + +/* +============= +TriNormal3f + +============= +*/ +void TriNormal3f( float x, float y, float z ) +{ + if( !re ) return; + re->Normal3f( x, y, z ); +} + /* ================= DemoApi implementation @@ -3214,31 +3343,87 @@ static triangleapi_t gTriApi = TriVertex3f, TriBrightness, TriCullFace, - TriGetSpriteFrame, + TriSpriteTexture, TriWorldToScreen, TriFog, TriScreenToWorld, - - TriLoadShader, - TriEnable, - TriDisable, - TriNormal3f, - TriNormal3fv, - TriBind, }; static efx_api_t gEfxApi = { - pfnGetPaletteColor, - pfnDecalIndex, - pfnDecalIndexFromName, + CL_AllocParticle, + CL_BlobExplosion, + CL_Blood, + CL_BloodSprite, + CL_BloodStream, + CL_BreakModel, + CL_Bubbles, + CL_BubbleTrail, + CL_BulletImpactParticles, + CL_EntityParticles, + CL_Explosion, + CL_FizzEffect, + CL_FireField, + CL_FlickerParticles, + CL_FunnelSprite, + CL_Implosion, + CL_Large_Funnel, + CL_LavaSplash, + CL_MultiGunshot, + CL_MuzzleFlash, + CL_ParticleBox, + CL_ParticleBurst, + CL_ParticleExplosion, + CL_ParticleExplosion2, + CL_ParticleLine, + CL_PlayerSprites, + CL_Projectile, + CL_RicochetSound, + CL_RicochetSprite, + CL_RocketFlare, + CL_RocketTrail, + CL_RunParticleEffect, + CL_ShowLine, + CL_SparkEffect, + CL_SparkShower, + CL_SparkStreaks, + CL_Spray, + CL_Sprite_Explode, + CL_Sprite_Smoke, + CL_Sprite_Spray, + CL_Sprite_Trail, + CL_Sprite_WallPuff, + CL_StreakSplash, + CL_TracerEffect, + CL_UserTracerParticle, + CL_TracerParticles, + CL_TeleportSplash, + CL_TempSphereModel, + CL_TempModel, + CL_DefaultSprite, + CL_TempSprite, + CL_DecalIndex, + CL_DecalIndexFromName, CL_DecalShoot, - CL_PlayerDecal, + CL_AttachTentToPlayer, + CL_KillAttachedTents, + CL_BeamCirclePoints, + CL_BeamEntPoint, + CL_BeamEnts, + CL_BeamFollow, + CL_BeamKill, + CL_BeamLightning, + CL_BeamPoints, + CL_BeamRing, CL_AllocDlight, CL_AllocElight, - CL_LightForPoint, - pfnBoxVisible, - pfnCullBox, + CL_TempEntAlloc, + CL_TempEntAllocNoModel, + CL_TempEntAllocHigh, + CL_TempEntAllocCustom, + CL_GetPackedColor, + CL_LookupColor, + CL_DecalRemoveAll, }; static event_api_t gEventApi = @@ -3363,7 +3548,7 @@ static cl_enginefunc_t gEngfuncs = pfnTraceLine, CL_LoadModel, CL_AddEntity, - CM_ClipHandleToModel, + CL_GetSpritePointer, pfnPlaySoundByNameAtLocation, pfnPrecacheEvent, CL_PlaybackEvent, @@ -3413,9 +3598,8 @@ void CL_UnloadProgs( void ) CL_FreeViewBeams(); CL_FreeParticles(); - // deinitialize game clgame.dllFuncs.pfnShutdown(); - + FS_FreeLibrary( clgame.hInstance ); Mem_FreePool( &cls.mempool ); Mem_FreePool( &clgame.mempool ); @@ -3424,7 +3608,6 @@ void CL_UnloadProgs( void ) qboolean CL_LoadProgs( const char *name ) { - static CLIENTAPI GetClientAPI; static playermove_t gpMove; const dllfunc_t *func; @@ -3446,8 +3629,7 @@ qboolean CL_LoadProgs( const char *name ) // clear exports for( func = cdll_exports; func && func->name; func++ ) *func->func = NULL; -#if 0 - // UNDONE: waiting for finalize client.dll interface + for( func = cdll_exports; func && func->name != NULL; func++ ) { // functions are cleared before all the extensions are evaluated @@ -3459,21 +3641,8 @@ qboolean CL_LoadProgs( const char *name ) return false; } } -#endif - GetClientAPI = (CLIENTAPI)FS_GetProcAddress( clgame.hInstance, "CreateAPI" ); - // FIXME: this very-very temporary stuffffffff - clgame.cdllFuncs.pfnTempEntUpdate = FS_GetProcAddress( clgame.hInstance, "HUD_TempEntUpdate" ); - - if( !GetClientAPI ) - { - FS_FreeLibrary( clgame.hInstance ); - MsgDev( D_NOTE, "CL_LoadProgs: failed to get address of CreateAPI proc\n" ); - clgame.hInstance = NULL; - return false; - } - - if( !GetClientAPI( &clgame.dllFuncs, &gEngfuncs )) + if( !clgame.dllFuncs.pfnInitialize( &gEngfuncs, CLDLL_INTERFACE_VERSION )) { FS_FreeLibrary( clgame.hInstance ); MsgDev( D_NOTE, "CL_LoadProgs: can't init client API\n" ); @@ -3481,6 +3650,16 @@ qboolean CL_LoadProgs( const char *name ) return false; } + if( !CL_InitStudioAPI( )) + { + FS_FreeLibrary( clgame.hInstance ); + MsgDev( D_NOTE, "CL_LoadProgs: can't init studio API\n" ); + clgame.hInstance = NULL; + return false; + } + + Cvar_Get( "cl_lw", "1", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" ); + clgame.maxEntities = GI->max_edicts; // merge during loading CL_InitTitles( "titles.txt" ); CL_InitParticles (); diff --git a/engine/client/cl_main.c b/engine/client/cl_main.c index 9a5c9f0d..372709fb 100644 --- a/engine/client/cl_main.c +++ b/engine/client/cl_main.c @@ -7,6 +7,7 @@ #include "client.h" #include "byteorder.h" #include "net_encode.h" +#include "cl_tent.h" #include "input.h" #define MAX_TOTAL_CMDS 16 @@ -40,7 +41,6 @@ convar_t *model; convar_t *topcolor; convar_t *bottomcolor; convar_t *rate; -convar_t *cl_lw; client_t cl; client_static_t cls; @@ -260,7 +260,6 @@ usercmd_t CL_CreateCmd( void ) { usercmd_t cmd; static double extramsec = 0; - client_data_t cdata; int ms; // send milliseconds of time to apply the move @@ -272,12 +271,17 @@ usercmd_t CL_CreateCmd( void ) Mem_Set( &cmd, 0, sizeof( cmd )); - VectorCopy( cl.frame.clientdata.origin, cdata.origin ); - VectorCopy( cl.refdef.cl_viewangles, cdata.viewangles ); - cdata.iWeaponBits = cl.frame.clientdata.weapons; - cdata.fov = cl.frame.clientdata.fov; + VectorCopy( cl.frame.local.client.origin, cl.data.origin ); + VectorCopy( cl.refdef.cl_viewangles, cl.data.viewangles ); + cl.data.iWeaponBits = cl.frame.local.client.weapons; + cl.data.fov = cl.frame.local.client.fov; - clgame.dllFuncs.pfnUpdateClientData( &cdata, cl_time( )); + clgame.dllFuncs.pfnUpdateClientData( &cl.data, cl.time ); + + // grab changes + VectorCopy( cl.data.viewangles, cl.refdef.cl_viewangles ); + cl.frame.local.client.weapons = cl.data.iWeaponBits; + cl.frame.local.client.fov = cl.data.fov; // allways dump the first ten messages, // because it may contain leftover inputs @@ -285,13 +289,13 @@ usercmd_t CL_CreateCmd( void ) if( ++cl.movemessages <= 10 ) return cmd; - clgame.dllFuncs.pfnCreateMove( &cmd, cl.time - cl.oldtime, ( cls.state == ca_active && !cl.refdef.paused )); + clgame.dllFuncs.CL_CreateMove( cl.time - cl.oldtime, &cmd, ( cls.state == ca_active && !cl.refdef.paused )); if( re ) { vec3_t color; - re->LightForPoint( cl.frame.clientdata.origin, color ); + re->LightForPoint( cl.frame.local.client.origin, color ); cmd.lightlevel = VectorAvg( color ) * 255; } @@ -1081,7 +1085,7 @@ void CL_PrepVideo( void ) { decallist_t *entry = &host.decalList[i]; cl_entity_t *pEdict = CL_GetEntityByIndex( entry->entityIndex ); - shader_t decalIndex = pfnDecalIndexFromName( entry->name ); + shader_t decalIndex = CL_DecalIndex( CL_DecalIndexFromName( entry->name )); int modelIndex = 0; if( pEdict ) modelIndex = pEdict->curstate.modelindex; @@ -1306,6 +1310,7 @@ void CL_ReadPackets( void ) else CL_ReadNetMessage(); cl.lerpFrac = CL_LerpPoint(); + cl.thirdperson = clgame.dllFuncs.CL_IsThirdPerson(); // build list of all solid entities per frame (exclude clients) CL_SetSolidEntities (); @@ -1352,7 +1357,7 @@ CL_Physinfo_f void CL_Physinfo_f( void ) { Msg( "Phys info settings:\n" ); - Info_Print( cl.frame.clientdata.physinfo ); + Info_Print( cl.frame.local.client.physinfo ); } void CL_RequestNextDownload( void ) @@ -1458,8 +1463,7 @@ void CL_InitLocal( void ) rate = Cvar_Get( "rate", "25000", CVAR_USERINFO|CVAR_ARCHIVE, "player network rate" ); userinfo = Cvar_Get( "@userinfo", "0", CVAR_READ_ONLY, "" ); // use ->modified value only cl_showfps = Cvar_Get( "cl_showfps", "1", CVAR_ARCHIVE, "show client fps" ); - cl_lw = Cvar_Get( "cl_lw", "1", CVAR_ARCHIVE|CVAR_USERINFO, "enable client weapon predicting" ); - cl_smooth = Cvar_Get ("cl_smooth", "1", 0, "smooth up stair climbing and interpolate position in multiplayer" ); + cl_smooth = Cvar_Get ("cl_smooth", "0", CVAR_ARCHIVE, "smooth up stair climbing and interpolate position in multiplayer" ); cl_cmdbackup = Cvar_Get( "cl_cmdbackup", "2", CVAR_ARCHIVE, "how many additional history commands are sent" ); cl_cmdrate = Cvar_Get( "cl_cmdrate", "30", CVAR_ARCHIVE, "Max number of command packets sent to server per second" ); cl_draw_particles = Cvar_Get( "cl_draw_particles", "1", CVAR_ARCHIVE, "Disable any particle effects" ); @@ -1555,10 +1559,10 @@ void Host_ClientFrame( void ) cl.time += host.frametime; // menu time (not paused, not clamped) - gameui.globals->time = host.realtime; - gameui.globals->frametime = host.realframetime; - gameui.globals->demoplayback = cls.demoplayback; - gameui.globals->demorecording = cls.demorecording; + menu.globals->time = host.realtime; + menu.globals->frametime = host.realframetime; + menu.globals->demoplayback = cls.demoplayback; + menu.globals->demorecording = cls.demorecording; // if in the debugger last frame, don't timeout if( host.frametime > 5.0f ) cls.netchan.last_received = Sys_DoubleTime(); @@ -1612,9 +1616,6 @@ void CL_Init( void ) Con_Init(); CL_InitLocal(); - if( !CL_LoadProgs( va( "%s/client.dll", GI->dll_path ))) - Host_Error( "CL_InitGame: can't initialize client.dll\n" ); - Host_CheckChanges (); cls.initialized = true; @@ -1641,7 +1642,9 @@ void CL_Shutdown( void ) Host_WriteOpenGLConfig (); Host_WriteConfig (); - CL_UnloadProgs (); + + IN_Shutdown (); SCR_Shutdown (); + CL_UnloadProgs (); cls.initialized = false; } \ No newline at end of file diff --git a/engine/client/cl_menu.c b/engine/client/cl_menu.c index 13fb463a..aaaf528f 100644 --- a/engine/client/cl_menu.c +++ b/engine/client/cl_menu.c @@ -1,39 +1,39 @@ //======================================================================= // Copyright XashXT Group 2010 й -// cl_menu.c - gameui dlls interaction +// cl_menu.c - menu dlls interaction //======================================================================= #include "common.h" #include "client.h" #include "const.h" -gameui_static_t gameui; +menu_static_t menu; void UI_UpdateMenu( float realtime ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnRedraw( realtime ); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnRedraw( realtime ); } void UI_KeyEvent( int key, qboolean down ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnKeyEvent( key, down ); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnKeyEvent( key, down ); } void UI_MouseMove( int x, int y ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnMouseMove( x, y ); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnMouseMove( x, y ); } void UI_SetActiveMenu( qboolean fActive ) { movie_state_t *cin_state; - if( !gameui.hInstance ) return; - gameui.drawLogo = fActive; - gameui.dllFuncs.pfnSetActiveMenu( fActive ); + if( !menu.hInstance ) return; + menu.drawLogo = fActive; + menu.dllFuncs.pfnSetActiveMenu( fActive ); if( !fActive ) { @@ -45,50 +45,50 @@ void UI_SetActiveMenu( qboolean fActive ) void UI_AddServerToList( netadr_t adr, const char *info ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnAddServerToList( adr, info ); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnAddServerToList( adr, info ); } void UI_GetCursorPos( int *pos_x, int *pos_y ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnGetCursorPos( pos_x, pos_y ); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnGetCursorPos( pos_x, pos_y ); } void UI_SetCursorPos( int pos_x, int pos_y ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnSetCursorPos( pos_x, pos_y ); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnSetCursorPos( pos_x, pos_y ); } void UI_ShowCursor( qboolean show ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnShowCursor( show ); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnShowCursor( show ); } qboolean UI_CreditsActive( void ) { - if( !gameui.hInstance ) return 0; - return gameui.dllFuncs.pfnCreditsActive(); + if( !menu.hInstance ) return 0; + return menu.dllFuncs.pfnCreditsActive(); } void UI_CharEvent( int key ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnCharEvent( key ); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnCharEvent( key ); } qboolean UI_MouseInRect( void ) { - if( !gameui.hInstance ) return 1; - return gameui.dllFuncs.pfnMouseInRect(); + if( !menu.hInstance ) return 1; + return menu.dllFuncs.pfnMouseInRect(); } qboolean UI_IsVisible( void ) { - if( !gameui.hInstance ) return 0; - return gameui.dllFuncs.pfnIsVisible(); + if( !menu.hInstance ) return 0; + return menu.dllFuncs.pfnIsVisible(); } static void UI_DrawLogo( const char *filename, float x, float y, float width, float height ) @@ -101,7 +101,7 @@ static void UI_DrawLogo( const char *filename, float x, float y, float width, fl int cin_frame; qboolean redraw = false; - if( !gameui.drawLogo ) return; + if( !menu.drawLogo ) return; cin_state = AVI_GetState( CIN_LOGO ); if( !AVI_IsActive( cin_state )) @@ -117,15 +117,15 @@ static void UI_DrawLogo( const char *filename, float x, float y, float width, fl if( FS_FileExists( path ) && !fullpath ) { MsgDev( D_ERROR, "couldn't load %s from packfile. Please extract it\n", path ); - gameui.drawLogo = false; + menu.drawLogo = false; return; } AVI_OpenVideo( cin_state, fullpath, false, false, true ); - if( !( AVI_GetVideoInfo( cin_state, &gameui.logo_xres, &gameui.logo_yres, &video_duration ))) + if( !( AVI_GetVideoInfo( cin_state, &menu.logo_xres, &menu.logo_yres, &video_duration ))) { AVI_CloseVideo( cin_state ); - gameui.drawLogo = false; + menu.drawLogo = false; return; } @@ -158,23 +158,23 @@ static void UI_DrawLogo( const char *filename, float x, float y, float width, fl redraw = true; } - re->DrawStretchRaw( x, y, width, height, gameui.logo_xres, gameui.logo_yres, cin_data, redraw ); + re->DrawStretchRaw( x, y, width, height, menu.logo_xres, menu.logo_yres, cin_data, redraw ); } static int UI_GetLogoWidth( void ) { - return gameui.logo_xres; + return menu.logo_xres; } static int UI_GetLogoHeight( void ) { - return gameui.logo_yres; + return menu.logo_yres; } void Host_Credits( void ) { - if( !gameui.hInstance ) return; - gameui.dllFuncs.pfnFinalCredits(); + if( !menu.hInstance ) return; + menu.dllFuncs.pfnFinalCredits(); } static void UI_ConvertGameInfo( GAMEINFO *out, gameinfo_t *in ) @@ -202,42 +202,42 @@ static qboolean PIC_Scissor( float *x, float *y, float *width, float *height, fl if(( width == 0 ) || ( height == 0 )) return false; - if( *x + *width <= gameui.ds.scissor_x ) + if( *x + *width <= menu.ds.scissor_x ) return false; - if( *x >= gameui.ds.scissor_x + gameui.ds.scissor_width ) + if( *x >= menu.ds.scissor_x + menu.ds.scissor_width ) return false; - if( *y + *height <= gameui.ds.scissor_y ) + if( *y + *height <= menu.ds.scissor_y ) return false; - if( *y >= gameui.ds.scissor_y + gameui.ds.scissor_height ) + if( *y >= menu.ds.scissor_y + menu.ds.scissor_height ) return false; dudx = (*u1 - *u0) / *width; dvdy = (*v1 - *v0) / *height; - if( *x < gameui.ds.scissor_x ) + if( *x < menu.ds.scissor_x ) { - *u0 += (gameui.ds.scissor_x - *x) * dudx; - *width -= gameui.ds.scissor_x - *x; - *x = gameui.ds.scissor_x; + *u0 += (menu.ds.scissor_x - *x) * dudx; + *width -= menu.ds.scissor_x - *x; + *x = menu.ds.scissor_x; } - if( *x + *width > gameui.ds.scissor_x + gameui.ds.scissor_width ) + if( *x + *width > menu.ds.scissor_x + menu.ds.scissor_width ) { - *u1 -= (*x + *width - (gameui.ds.scissor_x + gameui.ds.scissor_width)) * dudx; - *width = gameui.ds.scissor_x + gameui.ds.scissor_width - *x; + *u1 -= (*x + *width - (menu.ds.scissor_x + menu.ds.scissor_width)) * dudx; + *width = menu.ds.scissor_x + menu.ds.scissor_width - *x; } - if( *y < gameui.ds.scissor_y ) + if( *y < menu.ds.scissor_y ) { - *v0 += (gameui.ds.scissor_y - *y) * dvdy; - *height -= gameui.ds.scissor_y - *y; - *y = gameui.ds.scissor_y; + *v0 += (menu.ds.scissor_y - *y) * dvdy; + *height -= menu.ds.scissor_y - *y; + *y = menu.ds.scissor_y; } - if( *y + *height > gameui.ds.scissor_y + gameui.ds.scissor_height ) + if( *y + *height > menu.ds.scissor_y + menu.ds.scissor_height ) { - *v1 -= (*y + *height - (gameui.ds.scissor_y + gameui.ds.scissor_height)) * dvdy; - *height = gameui.ds.scissor_y + gameui.ds.scissor_height - *y; + *v1 -= (*y + *height - (menu.ds.scissor_y + menu.ds.scissor_height)) * dvdy; + *height = menu.ds.scissor_y + menu.ds.scissor_height - *y; } return true; } @@ -260,7 +260,7 @@ static void PIC_DrawGeneric( int frame, float x, float y, float width, float hei int w, h; // assume we get sizes from image - re->GetParms( &w, &h, NULL, frame, gameui.ds.hSprite ); + re->GetParms( &w, &h, NULL, frame, menu.ds.hSprite ); width = w; height = h; @@ -283,16 +283,16 @@ static void PIC_DrawGeneric( int frame, float x, float y, float width, float hei } // pass scissor test if supposed - if( gameui.ds.scissor_test && !PIC_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 )) + if( menu.ds.scissor_test && !PIC_Scissor( &x, &y, &width, &height, &s1, &t1, &s2, &t2 )) return; - re->DrawStretchPic( x, y, width, height, s1, t1, s2, t2, gameui.ds.hSprite ); + re->DrawStretchPic( x, y, width, height, s1, t1, s2, t2, menu.ds.hSprite ); re->SetColor( NULL ); } /* =============================================================================== - GameUI Builtin Functions + MainUI Builtin Functions =============================================================================== */ @@ -387,7 +387,7 @@ static void pfnPIC_Set( HIMAGE hPic, int r, int g, int b, int a ) if( !re ) return; // render not initialized - gameui.ds.hSprite = hPic; + menu.ds.hSprite = hPic; MakeRGBA( color, r, g, b, a ); re->SetColor( color ); } @@ -402,7 +402,7 @@ static void pfnPIC_Draw( int frame, int x, int y, int width, int height, const w { if( !re ) return; // render not initialized - re->SetParms( gameui.ds.hSprite, kRenderNormal, frame ); + re->SetParms( menu.ds.hSprite, kRenderNormal, frame ); PIC_DrawGeneric( frame, x, y, width, height, prc ); } @@ -416,7 +416,7 @@ static void pfnPIC_DrawTrans( int frame, int x, int y, int width, int height, co { if( !re ) return; // render not initialized - re->SetParms( gameui.ds.hSprite, kRenderTransTexture, frame ); + re->SetParms( menu.ds.hSprite, kRenderTransTexture, frame ); PIC_DrawGeneric( frame, x, y, width, height, prc ); } @@ -430,7 +430,7 @@ static void pfnPIC_DrawHoles( int frame, int x, int y, int width, int height, co { if( !re ) return; // render not initialized - re->SetParms( gameui.ds.hSprite, kRenderTransAlpha, frame ); + re->SetParms( menu.ds.hSprite, kRenderTransAlpha, frame ); PIC_DrawGeneric( frame, x, y, width, height, prc ); } @@ -444,7 +444,7 @@ static void pfnPIC_DrawAdditive( int frame, int x, int y, int width, int height, { if( !re ) return; // render not initialized - re->SetParms( gameui.ds.hSprite, kRenderTransAdd, frame ); + re->SetParms( menu.ds.hSprite, kRenderTransAdd, frame ); PIC_DrawGeneric( frame, x, y, width, height, prc ); } @@ -457,16 +457,16 @@ pfnPIC_EnableScissor static void pfnPIC_EnableScissor( int x, int y, int width, int height ) { // check bounds - x = bound( 0, x, gameui.globals->scrWidth ); - y = bound( 0, y, gameui.globals->scrHeight ); - width = bound( 0, width, gameui.globals->scrWidth - x ); - height = bound( 0, height, gameui.globals->scrHeight - y ); + x = bound( 0, x, menu.globals->scrWidth ); + y = bound( 0, y, menu.globals->scrHeight ); + width = bound( 0, width, menu.globals->scrWidth - x ); + height = bound( 0, height, menu.globals->scrHeight - y ); - gameui.ds.scissor_x = x; - gameui.ds.scissor_width = width; - gameui.ds.scissor_y = y; - gameui.ds.scissor_height = height; - gameui.ds.scissor_test = true; + menu.ds.scissor_x = x; + menu.ds.scissor_width = width; + menu.ds.scissor_y = y; + menu.ds.scissor_height = height; + menu.ds.scissor_test = true; } /* @@ -477,11 +477,11 @@ pfnPIC_DisableScissor */ static void pfnPIC_DisableScissor( void ) { - gameui.ds.scissor_x = 0; - gameui.ds.scissor_width = 0; - gameui.ds.scissor_y = 0; - gameui.ds.scissor_height = 0; - gameui.ds.scissor_test = false; + menu.ds.scissor_x = 0; + menu.ds.scissor_width = 0; + menu.ds.scissor_y = 0; + menu.ds.scissor_height = 0; + menu.ds.scissor_test = false; } /* @@ -577,8 +577,8 @@ static int pfnDrawConsoleString( int x, int y, const char *string ) int drawLen; if( !string || !*string ) return 0; // silent ignore - drawLen = Con_DrawString( x, y, string, gameui.ds.textColor ); - MakeRGBA( gameui.ds.textColor, 255, 255, 255, 255 ); + drawLen = Con_DrawString( x, y, string, menu.ds.textColor ); + MakeRGBA( menu.ds.textColor, 255, 255, 255, 255 ); return drawLen; // exclude color prexfixes } @@ -593,10 +593,10 @@ set color for anything static void pfnDrawSetTextColor( int r, int g, int b, int alpha ) { // bound color and convert to byte - gameui.ds.textColor[0] = r; - gameui.ds.textColor[1] = g; - gameui.ds.textColor[2] = b; - gameui.ds.textColor[3] = alpha; + menu.ds.textColor[0] = r; + menu.ds.textColor[1] = g; + menu.ds.textColor[2] = b; + menu.ds.textColor[3] = alpha; } /* @@ -608,7 +608,7 @@ for drawing playermodel previews */ static cl_entity_t* pfnGetPlayerModel( void ) { - return &gameui.playermodel; + return &menu.playermodel; } /* @@ -634,7 +634,8 @@ for drawing playermodel previews static void pfnRenderScene( const ref_params_t *fd ) { if( !re || !fd ) return; - re->RenderFrame( fd ); + if( fd->fov_x <= 0.0f || fd->fov_y <= 0.0f ) return; + re->RenderFrame( fd, false ); } /* @@ -681,7 +682,7 @@ pfnMemAlloc */ static void *pfnMemAlloc( size_t cb, const char *filename, const int fileline ) { - return com.malloc( gameui.mempool, cb, filename, fileline ); + return com.malloc( menu.mempool, cb, filename, fileline ); } /* @@ -705,7 +706,7 @@ static int pfnGetGameInfo( GAMEINFO *pgameinfo ) { if( !pgameinfo ) return 0; - *pgameinfo = gameui.gameInfo; + *pgameinfo = menu.gameInfo; return 1; } @@ -718,7 +719,7 @@ pfnGetGamesList static GAMEINFO **pfnGetGamesList( int *numGames ) { if( numGames ) *numGames = SI->numgames; - return gameui.modsInfo; + return menu.modsInfo; } /* @@ -970,64 +971,64 @@ static ui_enginefuncs_t gEngfuncs = void UI_UnloadProgs( void ) { - if( !gameui.hInstance ) return; + if( !menu.hInstance ) return; // deinitialize game - gameui.dllFuncs.pfnShutdown(); + menu.dllFuncs.pfnShutdown(); - FS_FreeLibrary( gameui.hInstance ); - Mem_FreePool( &gameui.mempool ); - Mem_Set( &gameui, 0, sizeof( gameui )); + FS_FreeLibrary( menu.hInstance ); + Mem_FreePool( &menu.mempool ); + Mem_Set( &menu, 0, sizeof( menu )); } qboolean UI_LoadProgs( const char *name ) { - static GAMEUIAPI GetMenuAPI; + static MENUAPI GetMenuAPI; static ui_globalvars_t gpGlobals; int i; - if( gameui.hInstance ) UI_UnloadProgs(); + if( menu.hInstance ) UI_UnloadProgs(); // setup globals - gameui.globals = &gpGlobals; + menu.globals = &gpGlobals; - gameui.mempool = Mem_AllocPool( "GameUI Pool" ); - gameui.hInstance = FS_LoadLibrary( name, false ); - if( !gameui.hInstance ) return false; + menu.mempool = Mem_AllocPool( "Menu Pool" ); + menu.hInstance = FS_LoadLibrary( name, false ); + if( !menu.hInstance ) return false; - GetMenuAPI = (GAMEUIAPI)FS_GetProcAddress( gameui.hInstance, "CreateAPI" ); + GetMenuAPI = (MENUAPI)FS_GetProcAddress( menu.hInstance, "GetMenuAPI" ); if( !GetMenuAPI ) { - FS_FreeLibrary( gameui.hInstance ); - MsgDev( D_NOTE, "UI_LoadProgs: failed to get address of CreateAPI proc\n" ); - gameui.hInstance = NULL; + FS_FreeLibrary( menu.hInstance ); + MsgDev( D_NOTE, "UI_LoadProgs: failed to get address of GetMenuAPI proc\n" ); + menu.hInstance = NULL; return false; } - if( !GetMenuAPI( &gameui.dllFuncs, &gEngfuncs, gameui.globals )) + if( !GetMenuAPI( &menu.dllFuncs, &gEngfuncs, menu.globals )) { - FS_FreeLibrary( gameui.hInstance ); + FS_FreeLibrary( menu.hInstance ); MsgDev( D_NOTE, "UI_LoadProgs: can't init client API\n" ); - gameui.hInstance = NULL; + menu.hInstance = NULL; return false; } // setup gameinfo for( i = 0; i < SI->numgames; i++ ) { - gameui.modsInfo[i] = Mem_Alloc( gameui.mempool, sizeof( GAMEINFO )); - UI_ConvertGameInfo( gameui.modsInfo[i], SI->games[i] ); + menu.modsInfo[i] = Mem_Alloc( menu.mempool, sizeof( GAMEINFO )); + UI_ConvertGameInfo( menu.modsInfo[i], SI->games[i] ); } - UI_ConvertGameInfo( &gameui.gameInfo, SI->GameInfo ); // current gameinfo + UI_ConvertGameInfo( &menu.gameInfo, SI->GameInfo ); // current gameinfo // setup globals - gameui.globals->developer = host.developer; - com.strncpy( gameui.globals->shotExt, SI->savshot_ext, sizeof( gameui.globals->shotExt )); + menu.globals->developer = host.developer; + com.strncpy( menu.globals->shotExt, SI->savshot_ext, sizeof( menu.globals->shotExt )); // initialize game - gameui.dllFuncs.pfnInit(); + menu.dllFuncs.pfnInit(); return true; } \ No newline at end of file diff --git a/engine/client/cl_parse.c b/engine/client/cl_parse.c index f36f38e2..70a2886e 100644 --- a/engine/client/cl_parse.c +++ b/engine/client/cl_parse.c @@ -429,6 +429,7 @@ void CL_ParseMovevars( sizebuf_t *msg ) re->RegisterShader( clgame.movevars.skyName, SHADER_SKY ); Mem_Copy( &clgame.oldmovevars, &clgame.movevars, sizeof( movevars_t )); + clgame.entities->curstate.scale = clgame.movevars.waveHeight; } /* @@ -451,7 +452,7 @@ void CL_ParseParticles( sizebuf_t *msg ) color = BF_ReadByte( msg ); if( count == 255 ) count = 1024; - clgame.dllFuncs.pfnParticleEffect( org, dir, color, count ); + CL_RunParticleEffect( org, dir, color, count ); } /* @@ -598,8 +599,8 @@ void CL_ParseServerData( sizebuf_t *msg ) com.strncpy( clgame.maptitle, BF_ReadString( msg ), MAX_STRING ); cl.refdef.viewentity = cl.playernum + 1; // always keep viewent an actual - gameui.globals->maxClients = cl.maxclients; - com.strncpy( gameui.globals->maptitle, clgame.maptitle, sizeof( gameui.globals->maptitle )); + menu.globals->maxClients = cl.maxclients; + com.strncpy( menu.globals->maptitle, clgame.maptitle, sizeof( menu.globals->maptitle )); // no effect for local client // merge entcount only for remote clients @@ -687,8 +688,8 @@ void CL_ParseClientData( sizebuf_t *msg ) // Fixme, do this after all packets read for this frame? cl.last_incoming_sequence = cls.netchan.incoming_sequence; - to_cd = &frame->clientdata; - to_wd = frame->weapondata; + to_cd = &frame->local.client; + to_wd = frame->local.weapondata; // clear to old value before delta parsing if( !BF_ReadOneBit( msg )) @@ -702,8 +703,8 @@ void CL_ParseClientData( sizebuf_t *msg ) { int delta_sequence = BF_ReadByte( msg ); - from_cd = &cl.frames[delta_sequence & CL_UPDATE_MASK].clientdata; - from_wd = cl.frames[delta_sequence & CL_UPDATE_MASK].weapondata; + from_cd = &cl.frames[delta_sequence & CL_UPDATE_MASK].local.client; + from_wd = cl.frames[delta_sequence & CL_UPDATE_MASK].local.weapondata; if(( delta_sequence & CL_UPDATE_MASK ) != ( cl.delta_sequence & CL_UPDATE_MASK )) MsgDev( D_WARN, "CL_ParseClientData: mismatch delta_sequence\n" ); @@ -1085,6 +1086,39 @@ void CL_ParseScreenFade( sizebuf_t *msg ) } } +/* +============== +CL_DispatchUserMessage + +Dispatch user message by engine request +============== +*/ +qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf ) +{ + int i; + + if( !pszName || !*pszName ) + return false; + + for( i = 0; i < MAX_USER_MESSAGES; i++ ) + { + // search for user message + if( !com.strcmp( clgame.msg[i].name, pszName )) + break; + } + + if( i == MAX_USER_MESSAGES ) + { + MsgDev( D_ERROR, "CL_DispatchUserMessage: bad message %s\n", pszName ); + return false; + } + + if( clgame.msg[i].func ) clgame.msg[i].func( pszName, iSize, pbuf ); + else MsgDev( D_ERROR, "CL_DispatchUserMessage: %s not hooked\n", pszName ); + + return true; +} + /* ============== CL_ParseUserMessage diff --git a/engine/client/cl_part.c b/engine/client/cl_part.c index d5d105ec..4d443324 100644 --- a/engine/client/cl_part.c +++ b/engine/client/cl_part.c @@ -258,6 +258,41 @@ particle_t *CL_AllocParticle( void (*callback)( particle_t*, float )) return p; } +static void CL_SparkTracerDraw( particle_t *p, float frametime ) +{ + float lifePerc = p->die - cl.time; + float grav = frametime * clgame.movevars.gravity * 0.05f; + float length, width; + int alpha = 255; + vec3_t delta; + + VectorScale( p->vel, p->ramp, delta ); + length = VectorLength( delta ); + width = ( length < TRACER_WIDTH ) ? length : TRACER_WIDTH; + if( lifePerc < 0.5f ) alpha = (lifePerc * 2) * 255; + + CL_DrawTracer( p->org, delta, width, clgame.palette[p->color], alpha, 0.0f, 0.8f ); + + p->vel[2] -= grav * 8; // use vox gravity + VectorMA( p->org, frametime, p->vel, p->org ); +} + +static void CL_BulletTracerDraw( particle_t *p, float frametime ) +{ + int alpha = (int)(traceralpha->value * 255); + float length, width; + vec3_t delta; + + VectorScale( p->vel, p->ramp, delta ); + length = VectorLength( delta ); + width = ( length < TRACER_WIDTH ) ? length : TRACER_WIDTH; + + // bullet tracers used particle palette + CL_DrawTracer( p->org, delta, width, clgame.palette[p->color], alpha, 0.0f, 0.8f ); + + VectorMA( p->org, frametime, p->vel, p->org ); +} + /* ================ CL_UpdateParticle @@ -283,8 +318,14 @@ void CL_UpdateParticle( particle_t *p, float ft ) break; case pt_clientcustom: if( p->callback ) + { p->callback( p, ft ); - return; + if( p->callback == CL_BulletTracerDraw ) + return; // already drawed + else if( p->callback == CL_SparkTracerDraw ) + return; // already drawed + } + break; case pt_fire: p->ramp += time1; if( p->ramp >= 6 ) p->die = -1; @@ -365,7 +406,6 @@ void CL_UpdateParticle( particle_t *p, float ft ) p->color = bound( 0, p->color, 255 ); VectorSet( color, clgame.palette[p->color][0], clgame.palette[p->color][1], clgame.palette[p->color][2] ); - re->Enable( TRI_SHADER ); re->RenderMode( kRenderTransTexture ); re->Color4ub( color[0], color[1], color[2], alpha ); @@ -384,10 +424,12 @@ void CL_UpdateParticle( particle_t *p, float ft ) re->Vertex3f( p->org[0] - right[0] - up[0], p->org[1] - right[1] - up[1], p->org[2] - right[2] - up[2] ); re->End(); - re->Disable( TRI_SHADER ); - // update position. - VectorMA( p->org, ft, p->vel, p->org ); + if( p->type != pt_clientcustom ) + { + // update position. + VectorMA( p->org, ft, p->vel, p->org ); + } } void CL_DrawParticles( void ) @@ -1031,13 +1073,27 @@ CL_BulletImpactParticles =============== */ -void CL_BulletImpactParticles( const vec3_t pos ) +void CL_BulletImpactParticles( const vec3_t org ) { particle_t *p; + vec3_t pos, dir; int i, j; // do sparks - CL_SparkShower( pos ); + // randomize position + pos[0] = org[0] + Com_RandomFloat( -2.0f, 2.0f ); + pos[1] = org[1] + Com_RandomFloat( -2.0f, 2.0f ); + pos[2] = org[2] + Com_RandomFloat( -2.0f, 2.0f ); + + // create a 8 random spakle tracers + for( i = 0; i < 8; i++ ) + { + dir[0] = Com_RandomFloat( -1.0f, 1.0f ); + dir[1] = Com_RandomFloat( -1.0f, 1.0f ); + dir[2] = Com_RandomFloat( -1.0f, 1.0f ); + + CL_SparkleTracer( pos, dir ); + } for( i = 0; i < 25; i++ ) { @@ -1045,13 +1101,14 @@ void CL_BulletImpactParticles( const vec3_t pos ) if( !p ) return; p->die += 2.0f; + p->color = 0; // black if( i & 1 ) { p->type = pt_grav; for( j = 0; j < 3; j++ ) { - p->org[j] = pos[j] + Com_RandomFloat( -2.0f, 3.0f ); + p->org[j] = org[j] + Com_RandomFloat( -2.0f, 3.0f ); p->vel[j] = Com_RandomFloat( -70.0f, 70.0f ); } } @@ -1190,7 +1247,6 @@ void CL_DrawTracer( vec3_t start, vec3_t delta, float width, rgb_t color, int al // NOTE: Gotta get the winding right so it's not backface culled // (we need to turn of backface culling for these bad boys) - re->Enable( TRI_SHADER ); re->RenderMode( kRenderTransTexture ); re->Color4ub( color[0], color[1], color[2], alpha ); @@ -1211,42 +1267,6 @@ void CL_DrawTracer( vec3_t start, vec3_t delta, float width, rgb_t color, int al TriVertex3fv( verts[0] ); re->End(); - re->Disable( TRI_SHADER ); -} - -static void CL_SparkTracerDraw( particle_t *p, float frametime ) -{ - float lifePerc = p->die - cl.time; - float grav = frametime * clgame.movevars.gravity * 0.05f; - float length, width; - int alpha = 255; - vec3_t delta; - - VectorScale( p->vel, p->ramp, delta ); - length = VectorLength( delta ); - width = ( length < TRACER_WIDTH ) ? length : TRACER_WIDTH; - if( lifePerc < 0.5f ) alpha = (lifePerc * 2) * 255; - - CL_DrawTracer( p->org, delta, width, clgame.palette[p->color], alpha, 0.0f, 0.8f ); - - p->vel[2] -= grav * 8; // use vox gravity - VectorMA( p->org, frametime, p->vel, p->org ); -} - -static void CL_BulletTracerDraw( particle_t *p, float frametime ) -{ - int alpha = (int)(traceralpha->value * 255); - float length, width; - vec3_t delta; - - VectorScale( p->vel, p->ramp, delta ); - length = VectorLength( delta ); - width = ( length < TRACER_WIDTH ) ? length : TRACER_WIDTH; - - // bullet tracers used particle palette - CL_DrawTracer( p->org, delta, width, clgame.palette[p->color], alpha, 0.0f, 0.8f ); - - VectorMA( p->org, frametime, p->vel, p->org ); } /* diff --git a/engine/client/cl_pmove.c b/engine/client/cl_pmove.c index 93f7497a..e963ee1d 100644 --- a/engine/client/cl_pmove.c +++ b/engine/client/cl_pmove.c @@ -6,6 +6,7 @@ #include "common.h" #include "client.h" #include "const.h" +#include "cl_tent.h" #include "pm_local.h" void CL_ClearPhysEnts( void ) @@ -94,27 +95,23 @@ CL_AddLinksToPmove collect solid entities ==================== */ -void CL_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t pmove_maxs ) +void CL_AddLinksToPmove( void ) { - link_t *l, *next; cl_entity_t *check; physent_t *pe; + int i, idx; - // touch linked edicts - for( l = node->solid_edicts.next; l != &node->solid_edicts; l = next ) + for( i = 0; i < cl.frame.num_entities; i++ ) { - next = l->next; - check = EDICT_FROM_AREA( l ); + idx = cls.packet_entities[(cl.frame.first_entity + i) % cls.num_client_entities].number; + check = CL_GetEntityByIndex( idx ); // don't add the world and clients here if( !check || check == &clgame.entities[0] || check->player ) continue; - if(check->curstate.solid == SOLID_BSP || check->curstate.solid == SOLID_BBOX || check->curstate.solid == SOLID_SLIDEBOX) + if( check->curstate.solid == SOLID_BSP || check->curstate.solid == SOLID_BBOX || check->curstate.solid == SOLID_SLIDEBOX ) { - if( !BoundsIntersect( pmove_mins, pmove_maxs, check->absmin, check->absmax )) - continue; - if( clgame.pmove->numphysent == MAX_PHYSENTS ) return; @@ -123,15 +120,17 @@ void CL_AddLinksToPmove( areanode_t *node, const vec3_t pmove_mins, const vec3_t if( CL_CopyEntityToPhysEnt( pe, check )) clgame.pmove->numphysent++; } - } - - // recurse down both sides - if( node->axis == -1 ) return; + else if( check->curstate.solid == SOLID_NOT && check->curstate.skin != CONTENTS_NONE ) + { + if( clgame.pmove->nummoveent >= MAX_MOVEENTS ) + continue; - if( pmove_maxs[node->axis] > node->dist ) - CL_AddLinksToPmove( node->children[0], pmove_mins, pmove_maxs ); - if( pmove_mins[node->axis] < node->dist ) - CL_AddLinksToPmove( node->children[1], pmove_mins, pmove_maxs ); + pe = &clgame.pmove->moveents[clgame.pmove->nummoveent]; + + if( CL_CopyEntityToPhysEnt( pe, check )) + clgame.pmove->nummoveent++; + } + } } /* @@ -172,6 +171,54 @@ void CL_SetSolidPlayers( int playernum ) } } +/* +============= +CL_TruePointContents + +============= +*/ +int CL_TruePointContents( const vec3_t p ) +{ + int i, contents; + hull_t *hull; + vec3_t test; + physent_t *pe; + + // sanity check + if( !p ) return CONTENTS_NONE; + + // get base contents from world + contents = PM_HullPointContents( &cl.worldmodel->hulls[0], 0, p ); + + for( i = 0; i < clgame.pmove->nummoveent; i++ ) + { + pe = &clgame.pmove->moveents[i]; + + if( pe->solid != SOLID_NOT ) // disabled ? + continue; + + // only brushes can have special contents + if( pe->model->type != mod_brush ) + continue; + + // check water brushes accuracy + hull = PM_HullForBsp( pe, vec3_origin, vec3_origin, test ); + + // offset the test point appropriately for this hull. + VectorSubtract( p, test, test ); + + // test hull for intersection with this model + if( PM_HullPointContents( hull, hull->firstclipnode, test ) == CONTENTS_EMPTY ) + continue; + + // compare contents ranking + if( RankForContents( pe->skin ) > RankForContents( contents )) + contents = pe->skin; // new content has more priority + } + + return contents; +} + static void pfnParticle( float *origin, int color, float life, int zpos, int zvel ) { vec3_t dir; @@ -185,7 +232,7 @@ static void pfnParticle( float *origin, int color, float life, int zpos, int zve // FIXME: send lifetime too VectorSet( dir, 0.0f, 0.0f, ( zpos * zvel )); - clgame.dllFuncs.pfnParticleEffect( origin, dir, color, 1 ); + CL_RunParticleEffect( origin, dir, color, 1 ); } static int pfnTestPlayerPosition( float *pos, pmtrace_t *ptrace ) @@ -271,11 +318,22 @@ static hull_t *pfnHullForBsp( physent_t *pe, float *offset ) return PM_HullForBsp( pe, mins, maxs, offset ); } -static float pfnTraceModel( physent_t *pEnt, float *start, float *end, pmtrace_t *trace ) +static float pfnTraceModel( physent_t *pEnt, float *start, float *end, trace_t *trace ) { - if( PM_TraceModel( pEnt, start, vec3_origin, vec3_origin, end, trace, PM_STUDIO_BOX )) - return trace->fraction; - return 1.0f; + pmtrace_t pmtrace; + + PM_TraceModel( pEnt, start, vec3_origin, vec3_origin, end, &pmtrace, PM_STUDIO_BOX ); + + // copy pmtrace_t to trace_t + if( trace ) + { + // NOTE: if pmtrace.h is changed is must be changed too + Mem_Copy( trace, &pmtrace, sizeof( *trace )); + trace->hitgroup = pmtrace.hitgroup; + trace->ent = NULL; + } + + return pmtrace.fraction; } static const char *pfnTraceTexture( int ground, float *vstart, float *vend ) @@ -405,7 +463,7 @@ void CL_InitClientMove( void ) clgame.pmove->PM_TraceLineEx = pfnTraceLineEx; // initalize pmove - clgame.dllFuncs.pfnPM_Init( clgame.pmove ); + clgame.dllFuncs.pfnPlayerMoveInit( clgame.pmove ); } static void PM_CheckMovingGround( clientdata_t *cd, entity_state_t *state, float frametime ) @@ -421,11 +479,6 @@ static void PM_CheckMovingGround( clientdata_t *cd, entity_state_t *state, float void CL_SetSolidEntities( void ) { - physent_t *pe; - vec3_t absmin, absmax; - cl_entity_t *touch[MAX_EDICTS]; - int i, count; - // world not initialized if( !cl.frame.valid ) return; @@ -434,33 +487,10 @@ void CL_SetSolidEntities( void ) clgame.pmove->numphysent = 0; clgame.pmove->nummoveent = 0; - for( i = 0; i < 3; i++ ) - { - absmin[i] = cl.frame.clientdata.origin[i] - 1024; - absmax[i] = cl.frame.clientdata.origin[i] + 1024; - } - CL_CopyEntityToPhysEnt( &clgame.pmove->physents[0], &clgame.entities[0] ); clgame.pmove->numphysent = 1; // always have world - CL_AddLinksToPmove( cl_areanodes, absmin, absmax ); - count = CL_AreaEdicts( absmin, absmax, touch, MAX_EDICTS, AREA_CUSTOM ); - - // build list of ladders around player - for( i = 0; i < count; i++ ) - { - if( clgame.pmove->nummoveent >= MAX_MOVEENTS ) - { - MsgDev( D_ERROR, "PM_PlayerMove: too many ladders in PVS\n" ); - break; - } - - if( touch[i] == CL_GetLocalPlayer( )) continue; - - pe = &clgame.pmove->moveents[clgame.pmove->nummoveent]; - if( CL_CopyEntityToPhysEnt( pe, touch[i] )) - clgame.pmove->nummoveent++; - } + CL_AddLinksToPmove(); } static void PM_SetupMove( playermove_t *pmove, clientdata_t *cd, entity_state_t *state, usercmd_t *ucmd ) diff --git a/engine/client/cl_pred.c b/engine/client/cl_pred.c index a0ef1f0f..e4f8f525 100644 --- a/engine/client/cl_pred.c +++ b/engine/client/cl_pred.c @@ -32,8 +32,7 @@ qboolean CL_IsPredicted( void ) void CL_PreRunCmd( cl_entity_t *clent, usercmd_t *ucmd ) { - clgame.pmove->runfuncs = false; - clgame.dllFuncs.pfnCmdStart( clent, clgame.pmove->runfuncs ); + clgame.pmove->runfuncs = (( clent->index - 1 ) == cl.playernum ) ? true : false; } /* @@ -45,9 +44,14 @@ Done after running a player command. */ void CL_PostRunCmd( cl_entity_t *clent, usercmd_t *ucmd ) { + local_state_t *from, *to; + if( !clent ) return; - clgame.pmove->runfuncs = false; // all next calls ignore footstep sounds - clgame.dllFuncs.pfnCmdEnd( clent, ucmd, cl.random_seed ); + + from = &cl.frames[cl.delta_sequence & CL_UPDATE_MASK].local; + to = &cl.frame.local; + + clgame.dllFuncs.pfnPostRunCmd( from, to, ucmd, clgame.pmove->runfuncs, cl.time, cl.random_seed ); } /* @@ -106,7 +110,7 @@ void CL_SetIdealPitch( cl_entity_t *ent ) int i, j; int step, dir, steps; - if( !( cl.frame.clientdata.flags & FL_ONGROUND )) + if( !( cl.frame.local.client.flags & FL_ONGROUND )) return; angleval = ent->angles[YAW] * M_PI * 2 / 360; @@ -116,7 +120,7 @@ void CL_SetIdealPitch( cl_entity_t *ent ) { top[0] = ent->origin[0] + cosval * (i + 3) * 12; top[1] = ent->origin[1] + sinval * (i + 3) * 12; - top[2] = ent->origin[2] + cl.frame.clientdata.view_ofs[2]; + top[2] = ent->origin[2] + cl.frame.local.client.view_ofs[2]; bottom[0] = top[0]; bottom[1] = top[1]; @@ -166,7 +170,7 @@ Sets cl.predicted_origin and cl.predicted_angles */ void CL_PredictMovement( void ) { - int frame; + int frame = 0; int ack, current; cl_entity_t *player, *viewent; clientdata_t *cd; @@ -177,7 +181,7 @@ void CL_PredictMovement( void ) player = CL_GetLocalPlayer (); viewent = CL_GetEntityByIndex( cl.refdef.viewentity ); - cd = &cl.frame.clientdata; + cd = &cl.frame.local.client; CL_SetIdealPitch( player ); @@ -205,7 +209,7 @@ void CL_PredictMovement( void ) CL_PostRunCmd( player, cmd ); return; } -#if 0 + ack = cls.netchan.incoming_acknowledged; current = cls.netchan.outgoing_sequence; @@ -216,7 +220,7 @@ void CL_PredictMovement( void ) MsgDev( D_ERROR, "CL_Predict: exceeded CMD_BACKUP\n" ); return; } - +#if 0 // setup initial pmove state // FIXME!!!!... // VectorCopy( player->v.movedir, clgame.pmove->movedir ); diff --git a/engine/client/cl_scrn.c b/engine/client/cl_scrn.c index 712b787c..53bb89bd 100644 --- a/engine/client/cl_scrn.c +++ b/engine/client/cl_scrn.c @@ -337,27 +337,28 @@ void SCR_RegisterShaders( void ) cls.fillShader = re->RegisterShader( "*white", SHADER_NOMIP ); // used for FillRGBA cls.particleShader = re->RegisterShader( "*particle", SHADER_NOMIP ); + // register gfx.wad images + cls.pauseIcon = re->RegisterShader( "gfx/paused", SHADER_NOMIP ); + cls.loadingBar = re->RegisterShader( "gfx/lambda", SHADER_NOMIP ); + cls.creditsFont.hFontTexture = re->RegisterShader( "gfx/creditsfont", SHADER_NOMIP ); + // FIXME: register new type shader 'GLOWSHELL', allow to loading sprites with this type // apply by default 'deformVertices' etc cls.glowShell = re->RegisterShader( "renderfx/glowshell", SHADER_GENERIC ); - - // register gfx.wad images - cls.pauseIcon = re->RegisterShader( "gfx/paused", SHADER_NOMIP ); // FIXME: MAKE INTRESOURCE - cls.loadingBar = re->RegisterShader( "gfx/lambda", SHADER_NOMIP ); // FIXME: MAKE INTRESOURCE - cls.creditsFont.hFontTexture = re->RegisterShader( "gfx/creditsfont", SHADER_NOMIP ); // FIXME: MAKE INTRESOURCE + cls.hChromeSprite = pfnSPR_Load( "sprites/shellchrome.spr" ); } Mem_Set( &clgame.ds, 0, sizeof( clgame.ds )); // reset a draw state - Mem_Set( &gameui.ds, 0, sizeof( gameui.ds )); // reset a draw state + Mem_Set( &menu.ds, 0, sizeof( menu.ds )); // reset a draw state Mem_Set( &clgame.centerPrint, 0, sizeof( clgame.centerPrint )); // update screen sizes for menu - gameui.globals->scrWidth = scr_width->integer; - gameui.globals->scrHeight = scr_height->integer; + menu.globals->scrWidth = scr_width->integer; + menu.globals->scrHeight = scr_height->integer; // vid_state has changed if( clgame.hInstance ) clgame.dllFuncs.pfnVidInit(); - if( gameui.hInstance ) gameui.dllFuncs.pfnVidInit(); + if( menu.hInstance ) menu.dllFuncs.pfnVidInit(); // restart console size Con_VidInit (); @@ -387,9 +388,9 @@ void SCR_Init( void ) Cmd_AddCommand( "skyname", CL_SetSky_f, "set new skybox by basename" ); Cmd_AddCommand( "viewpos", SCR_Viewpos_f, "prints current player origin" ); - if( !UI_LoadProgs( va( "%s/GameUI.dll", GI->dll_path ) )) + if( !UI_LoadProgs( va( "%s/MainUI.dll", GI->dll_path ) )) { - Msg( "^1Error: ^7can't initialize gameui.dll\n" ); // there is non fatal for us + Msg( "^1Error: ^7can't initialize MainUI.dll\n" ); // there is non fatal for us if( !host.developer ) host.developer = 1; // we need console, because menu is missing } diff --git a/engine/client/cl_studio.c b/engine/client/cl_studio.c new file mode 100644 index 00000000..878c63c3 --- /dev/null +++ b/engine/client/cl_studio.c @@ -0,0 +1,517 @@ +//======================================================================= +// Copyright XashXT Group 2010 й +// cl_studio.c - client studio utilities +//======================================================================= + +#include "common.h" +#include "client.h" +#include "byteorder.h" +#include "matrix_lib.h" +#include "const.h" +#include "r_studioint.h" +#include "studio.h" +#include "pm_local.h" + +static r_studio_interface_t *pStudioDraw; + +/* +=============== +pfnGetCurrentEntity + +=============== +*/ +static cl_entity_t *pfnGetCurrentEntity( void ) +{ + // FIXME: implement + // this is will be needs is we called StudioDrawModel or StudioDrawPlayer + return NULL; +} + +/* +=============== +pfnPlayerInfo + +=============== +*/ +static player_info_t *pfnPlayerInfo( int index ) +{ + if( index < 0 || index > cl.maxclients ) + return NULL; + return &cl.players[index]; +} + +/* +=============== +pfnGetPlayerState + +=============== +*/ +static entity_state_t *pfnGetPlayerState( int index ) +{ + if( index < 0 || index > cl.maxclients ) + return NULL; + return &cl.frame.playerstate[index]; +} + +/* +=============== +pfnGetViewEntity + +=============== +*/ +static cl_entity_t *pfnGetViewEntity( void ) +{ + return &clgame.viewent; +} + +/* +=============== +pfnGetEngineTimes + +=============== +*/ +static void pfnGetEngineTimes( int *framecount, double *current, double *old ) +{ + if( framecount ) *framecount = host.framecount; // this is will not working properly with mirros etc + if( current ) *current = cl.time; + if( old ) *old = cl.oldtime; +} + +/* +=============== +pfnGetViewInfo + +=============== +*/ +static void pfnGetViewInfo( float *origin, float *upv, float *rightv, float *forwardv ) +{ + if( origin ) VectorCopy( cl.refdef.vieworg, origin ); + if( upv ) VectorCopy( cl.refdef.up, upv ); + if( rightv ) VectorCopy( cl.refdef.right, rightv ); + if( forwardv ) VectorCopy( cl.refdef.forward, forwardv ); +} + +/* +=============== +pfnGetChromeSprite + +=============== +*/ +static model_t *pfnGetChromeSprite( void ) +{ + if( cls.hChromeSprite <= 0 || cls.hChromeSprite > MAX_IMAGES ) + return NULL; // bad sprite + return &clgame.ds.images[cls.hChromeSprite]; +} + +/* +=============== +pfnGetModelCounters + +=============== +*/ +static void pfnGetModelCounters( int **s, int **a ) +{ + static int studio_count, studio_drawn; + + // FIXME: implement + *s = &studio_count; + *a = &studio_drawn; +} + +/* +=============== +pfnGetAliasScale + +Software scales not used in Xash3D +=============== +*/ +static void pfnGetAliasScale( float *x, float *y ) +{ + if( x ) *x = 0.0f; + if( y ) *y = 0.0f; +} + +/* +=============== +pfnStudioGetBoneTransform + +=============== +*/ +static float ****pfnStudioGetBoneTransform( void ) +{ + // FIXME: implement + return NULL; +} + +/* +=============== +pfnStudioGetLightTransform + +=============== +*/ +static float ****pfnStudioGetLightTransform( void ) +{ + // FIXME: implement + return NULL; +} + +/* +=============== +pfnStudioGetAliasTransform + +=============== +*/ +static float ***pfnStudioGetAliasTransform( void ) +{ + // FIXME: implement + return NULL; +} + +/* +=============== +pfnStudioGetRotationMatrix + +=============== +*/ +static float ***pfnStudioGetRotationMatrix( void ) +{ + // FIXME: implement + return NULL; +} + +/* +=============== +pfnStudioSetupModel + +=============== +*/ +static void pfnStudioSetupModel( int bodypart, void **ppbodypart, void **ppsubmodel ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioCheckBBox + +=============== +*/ +static int pfnStudioCheckBBox( void ) +{ + // FIXME: implement + return false; +} + +/* +=============== +pfnStudioDynamicLight + +=============== +*/ +static void pfnStudioDynamicLight( struct cl_entity_s *ent, struct alight_s *plight ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioEntityLight + +=============== +*/ +static void pfnStudioEntityLight( struct alight_s *plight ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioSetupLighting + +=============== +*/ +static void pfnStudioSetupLighting( struct alight_s *plighting ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioDrawPoints + +=============== +*/ +static void pfnStudioDrawPoints( void ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioDrawHulls + +=============== +*/ +static void pfnStudioDrawHulls( void ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioDrawAbsBBox + +=============== +*/ +static void pfnStudioDrawAbsBBox( void ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioDrawBones + +=============== +*/ +static void pfnStudioDrawBones( void ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioSetupSkin + +=============== +*/ +static void pfnStudioSetupSkin( void *ptexturehdr, int index ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioSetRemapColors + +=============== +*/ +static void pfnStudioSetRemapColors( int top, int bottom ) +{ + // FIXME: implement +} + +/* +=============== +pfnSetupPlayerModel + +=============== +*/ +static model_t *pfnSetupPlayerModel( int index ) +{ + player_info_t *info; + string modelpath; + int modelIndex; + + if( index < 0 || index > cl.maxclients ) + return NULL; // bad client ? + + info = &cl.players[index]; + + com.snprintf( modelpath, sizeof( modelpath ), "models/player/%s/%s.mdl", info->model, info->model ); + modelIndex = CL_FindModelIndex( modelpath ); + + return CM_ClipHandleToModel( modelIndex ); +} + +/* +=============== +pfnStudioClientEvents + +=============== +*/ +static void pfnStudioClientEvents( void ) +{ + // FIXME: implement +} + +/* +=============== +pfnGetForceFaceFlags + +=============== +*/ +static int pfnGetForceFaceFlags( void ) +{ + // FIXME: implement + return 0; +} + +/* +=============== +pfnSetForceFaceFlags + +=============== +*/ +static void pfnSetForceFaceFlags( int flags ) +{ + // FIXME: implement +} + +/* +=============== +pfnStudioSetHeader + +=============== +*/ +static void pfnStudioSetHeader( void *header ) +{ + // FIXME: implement +} + +/* +=============== +pfnSetRenderModel + +=============== +*/ +static void pfnSetRenderModel( model_t *model ) +{ + // FIXME: implement +} + +/* +=============== +pfnSetupRenderer + +=============== +*/ +static void pfnSetupRenderer( int rendermode ) +{ + // FIXME: implement +} + +/* +=============== +pfnRestoreRenderer + +=============== +*/ +static void pfnRestoreRenderer( void ) +{ + // FIXME: implement +} + +/* +=============== +pfnSetChromeOrigin + +=============== +*/ +static void pfnSetChromeOrigin( void ) +{ + // FIXME: implement +} + +/* +=============== +pfnIsHardware + +Xash3D is always works in hadrware mode +=============== +*/ +static int pfnIsHardware( void ) +{ + return true; +} + +/* +=============== +pfnStudioDrawShadow + +=============== +*/ +static void pfnStudioDrawShadow( void ) +{ + // in GoldSrc shadow call is dsiabled with 'return' at start of the function + // some mods used a hack with calling DrawShadow ahead of 'return' + // this code is for HL compatibility. + return; + + // FIXME: implement + MsgDev( D_INFO, "GL_StudioDrawShadow()\n" ); // just a debug +} + +/* +=============== +pfnSetRenderMode + +=============== +*/ +static void pfnSetRenderMode( int mode ) +{ + // FIXME: implement +} + +static engine_studio_api_t gStudioAPI = +{ + Mod_Calloc, + Mod_CacheCheck, + Mod_LoadCacheFile, + CM_ModForName, + Mod_Extradata, + CM_ClipHandleToModel, + pfnGetCurrentEntity, + pfnPlayerInfo, + pfnGetPlayerState, + pfnGetViewEntity, + pfnGetEngineTimes, + pfnCVarGetPointer, + pfnGetViewInfo, + pfnGetChromeSprite, + pfnGetModelCounters, + pfnGetAliasScale, + pfnStudioGetBoneTransform, + pfnStudioGetLightTransform, + pfnStudioGetAliasTransform, + pfnStudioGetRotationMatrix, + pfnStudioSetupModel, + pfnStudioCheckBBox, + pfnStudioDynamicLight, + pfnStudioEntityLight, + pfnStudioSetupLighting, + pfnStudioDrawPoints, + pfnStudioDrawHulls, + pfnStudioDrawAbsBBox, + pfnStudioDrawBones, + pfnStudioSetupSkin, + pfnStudioSetRemapColors, + pfnSetupPlayerModel, + pfnStudioClientEvents, + pfnGetForceFaceFlags, + pfnSetForceFaceFlags, + pfnStudioSetHeader, + pfnSetRenderModel, + pfnSetupRenderer, + pfnRestoreRenderer, + pfnSetChromeOrigin, + pfnIsHardware, + pfnStudioDrawShadow, + pfnSetRenderMode, + +}; + +/* +=============== +CL_InitStudioAPI + +Initialize client studio +=============== +*/ +qboolean CL_InitStudioAPI( void ) +{ + pStudioDraw = NULL; // clear previous API + + return clgame.dllFuncs.pfnGetStudioModelInterface( STUDIO_INTERFACE_VERSION, &pStudioDraw, &gStudioAPI ); +} \ No newline at end of file diff --git a/engine/client/cl_tent.c b/engine/client/cl_tent.c index 47c3d92d..e576c627 100644 --- a/engine/client/cl_tent.c +++ b/engine/client/cl_tent.c @@ -300,9 +300,7 @@ void CL_AddTempEnts( void ) double ft = cl.time - cl.oldtime; float gravity = clgame.movevars.gravity; - if( !clgame.cdllFuncs.pfnTempEntUpdate ) return; - - clgame.cdllFuncs.pfnTempEntUpdate( ft, cl.time, gravity, &cl_free_tents, &cl_active_tents, + clgame.dllFuncs.pfnTempEntUpdate( ft, cl.time, gravity, &cl_free_tents, &cl_active_tents, CL_TEntAddEntity, CL_TEntPlaySound ); // callbacks } @@ -367,14 +365,14 @@ TEMPENTITY *CL_TempEntAllocHigh( const vec3_t org, model_t *pmodel ) pTemp = cl_free_tents; cl_free_tents = pTemp->next; - pTemp->next = cl_active_tents; - cl_active_tents = pTemp; - - CL_TempEntAlloc( org, pmodel ); + CL_PrepareTEnt( pTemp, pmodel ); pTemp->priority = TENTPRIORITY_HIGH; if( org ) VectorCopy( org, pTemp->entity.origin ); + pTemp->next = cl_active_tents; + cl_active_tents = pTemp; + return pTemp; } @@ -822,9 +820,9 @@ void CL_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int model Mod_GetFrames( modelIndex, &frameCount ); pTemp->entity.curstate.rendermode = kRenderTransTexture; pTemp->entity.curstate.renderfx = kRenderFxClampMinScale; - pTemp->entity.curstate.scale = Com_RandomFloat(( size / 25.0f), ( size / 35.0f )); + pTemp->entity.curstate.scale = Com_RandomFloat(( size / 25.0f ), ( size / 35.0f )); pTemp->flags = FTENT_SPRANIMATE; - + pTemp->entity.curstate.rendercolor.r = clgame.palette[colorIndex][0]; pTemp->entity.curstate.rendercolor.g = clgame.palette[colorIndex][1]; pTemp->entity.curstate.rendercolor.b = clgame.palette[colorIndex][2]; @@ -849,14 +847,16 @@ void CL_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int model pTemp = CL_TempEntAllocHigh( org, CM_ClipHandleToModel( modelIndex2 )); if( !pTemp ) return; - pTemp->flags = FTENT_SPRANIMATE|FTENT_COLLIDEWORLD|FTENT_SLOWGRAVITY; - + pTemp->flags = FTENT_SPRANIMATELOOP|FTENT_COLLIDEWORLD|FTENT_SLOWGRAVITY; + + pTemp->entity.curstate.rendermode = kRenderTransTexture; + pTemp->entity.curstate.renderfx = kRenderFxClampMinScale; + pTemp->entity.curstate.scale = Com_RandomFloat(( size / 25.0f), ( size / 35.0f )); pTemp->entity.curstate.rendercolor.r = clgame.palette[colorIndex][0]; pTemp->entity.curstate.rendercolor.g = clgame.palette[colorIndex][1]; pTemp->entity.curstate.rendercolor.b = clgame.palette[colorIndex][2]; pTemp->entity.curstate.framerate = frameCount * 4; // Finish in 0.250 seconds - // play the whole thing once - pTemp->die = cl.time + (frameCount / pTemp->entity.curstate.framerate) + 5.0f; + pTemp->die = cl.time + Com_RandomFloat( 4.0f, 16.0f ); pTemp->entity.angles[2] = Com_RandomLong( 0, 360 ); pTemp->bounceFactor = 0; @@ -865,7 +865,7 @@ void CL_BloodSprite( const vec3_t org, int colorIndex, int modelIndex, int model dir[1] = forward[1] + Com_RandomFloat( -0.3f, 0.3f ); dir[2] = forward[2] + Com_RandomFloat( -0.3f, 0.3f ); - VectorScale( dir, Com_RandomFloat( 4.0f * size, 40.0f * size ), pTemp->entity.baseline.origin ); + VectorScale( dir, Com_RandomFloat( 4.0f * size, 16.0f * size ), pTemp->entity.baseline.origin ); pTemp->entity.baseline.origin[2] += Com_RandomFloat( 4.0f, 16.0f ) * size; } } @@ -1405,7 +1405,7 @@ CL_StreakSplash Create a streak tracers =============== */ -void CL_StreakSplash( const vec3_t pos, const vec3_t dir, int color, int count, int speed, int velMin, int velMax ) +void CL_StreakSplash( const vec3_t pos, const vec3_t dir, int color, int count, float speed, int velMin, int velMax ) { int i; @@ -1643,16 +1643,17 @@ handle temp-entity messages */ void CL_ParseTempEntity( sizebuf_t *msg ) { - sizebuf_t buf; - byte pbuf[256]; - TEMPENTITY *pTemp; - int iSize = BF_ReadByte( msg ); - int type, color, count, flags; - int decalIndex, modelIndex, entityIndex; - float scale, life, frameRate, vel, random; - float brightness; - vec3_t pos, pos2; - dlight_t *dl; + sizebuf_t buf; + byte pbuf[256]; + int iSize = BF_ReadByte( msg ); + int type, color, count, flags; + int decalIndex, modelIndex, entityIndex; + float scale, life, frameRate, vel, random; + float brightness, r, g, b; + vec3_t pos, pos2, ang; + TEMPENTITY *pTemp; + cl_entity_t *pEnt; + dlight_t *dl; // parse user message into buffer BF_ReadBytes( msg, pbuf, iSize ); @@ -1851,14 +1852,273 @@ void CL_ParseTempEntity( sizebuf_t *msg ) dl->decay = BF_ReadCoord( &buf ); break; case TE_TEXTMESSAGE: + CL_ParseTextMessage( &buf ); + break; + case TE_LINE: + case TE_BOX: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + life = (float)(BF_ReadShort( &buf ) * 0.1f); + r = BF_ReadByte( &buf ); + g = BF_ReadByte( &buf ); + b = BF_ReadByte( &buf ); + if( type == TE_LINE ) CL_ParticleLine( pos, pos2, r, g, b, life ); + else CL_ParticleBox( pos, pos2, r, g, b, life ); + break; + case TE_LARGEFUNNEL: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + modelIndex = BF_ReadShort( &buf ); + flags = BF_ReadShort( &buf ); + CL_FunnelSprite( pos, modelIndex, flags ); + break; + case TE_BLOODSTREAM: + case TE_BLOOD: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + color = BF_ReadByte( &buf ); + vel = (float)BF_ReadByte( &buf ); + if( type == TE_BLOOD ) CL_Blood( pos, pos2, color, vel ); + else CL_BloodStream( pos, pos2, color, vel ); + break; + case TE_SHOWLINE: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + CL_ShowLine( pos, pos2 ); + break; + case TE_DECAL: + case TE_DECALHIGH: + case TE_WORLDDECAL: + case TE_WORLDDECALHIGH: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + decalIndex = BF_ReadByte( &buf ); + if( type == TE_DECAL || type == TE_DECALHIGH ) + entityIndex = BF_ReadShort( &buf ); + else entityIndex = 0; + if( type == TE_DECALHIGH || type == TE_WORLDDECALHIGH ) + decalIndex += 256; + pEnt = CL_GetEntityByIndex( entityIndex ); + modelIndex = (pEnt) ? pEnt->curstate.modelindex : 0; + CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, pos, 0 ); + break; + case TE_FIZZ: + entityIndex = BF_ReadShort( &buf ); + modelIndex = BF_ReadShort( &buf ); + scale = BF_ReadByte( &buf ); // same as density + pEnt = CL_GetEntityByIndex( entityIndex ); + CL_FizzEffect( pEnt, modelIndex, scale ); + break; + case TE_MODEL: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + VectorSet( ang, 0.0f, BF_ReadAngle( &buf ), 0.0f ); // yaw angle + modelIndex = BF_ReadShort( &buf ); + flags = BF_ReadByte( &buf ); // sound flags + life = (float)(BF_ReadByte( &buf ) * 0.1f); + CL_TempModel( pos, pos2, ang, life, modelIndex, flags ); + break; + case TE_EXPLODEMODEL: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + vel = BF_ReadCoord( &buf ); + modelIndex = BF_ReadShort( &buf ); + count = BF_ReadShort( &buf ); + life = (float)(BF_ReadByte( &buf ) * 0.1f); + CL_TempSphereModel( pos, vel, life, count, modelIndex ); + break; + case TE_BREAKMODEL: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + ang[0] = BF_ReadCoord( &buf ); + ang[1] = BF_ReadCoord( &buf ); + ang[2] = BF_ReadCoord( &buf ); + random = (float)BF_ReadByte( &buf ); + modelIndex = BF_ReadShort( &buf ); + count = BF_ReadByte( &buf ); + life = (float)(BF_ReadByte( &buf ) * 0.1f); + flags = BF_ReadByte( &buf ); + CL_BreakModel( pos, pos2, ang, random, life, count, modelIndex, (char)flags ); + break; + case TE_GUNSHOTDECAL: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + entityIndex = BF_ReadShort( &buf ); + decalIndex = BF_ReadByte( &buf ); + pEnt = CL_GetEntityByIndex( entityIndex ); + modelIndex = (pEnt) ? pEnt->curstate.modelindex : 0; + CL_DecalShoot( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, pos, 0 ); + CL_RicochetSound( pos ); + break; + case TE_SPRAY: + case TE_SPRITE_SPRAY: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + modelIndex = BF_ReadShort( &buf ); + count = BF_ReadByte( &buf ); + vel = (float)BF_ReadByte( &buf ); + random = (float)BF_ReadByte( &buf ); + if( type == TE_SPRAY ) + { + flags = BF_ReadByte( &buf ); // rendermode + CL_Spray( pos, pos2, modelIndex, count, vel, random, flags ); + } + else CL_Sprite_Spray( pos, pos2, modelIndex, count, vel, random ); + break; + case TE_ARMOR_RICOCHET: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + scale = (float)(BF_ReadByte( &buf ) * 0.1f); + modelIndex = CL_FindModelIndex( "sprites/richo1.spr" ); + CL_RicochetSprite( pos, CM_ClipHandleToModel( modelIndex ), 0.0f, scale ); + CL_RicochetSound( pos ); + break; + case TE_PLAYERDECAL: + color = BF_ReadByte( &buf ); // playernum + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + entityIndex = BF_ReadShort( &buf ); + decalIndex = BF_ReadByte( &buf ); + CL_PlayerDecal( CL_DecalIndex( decalIndex ), entityIndex, pos, NULL ); + break; + case TE_BUBBLES: + case TE_BUBBLETRAIL: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + scale = BF_ReadCoord( &buf ); // water height + modelIndex = BF_ReadShort( &buf ); + count = BF_ReadByte( &buf ); + vel = BF_ReadCoord( &buf ); + if( type == TE_BUBBLES ) CL_Bubbles( pos, pos2, scale, modelIndex, count, vel ); + else CL_BubbleTrail( pos, pos2, scale, modelIndex, count, vel ); + break; + case TE_BLOODSPRITE: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + modelIndex = BF_ReadShort( &buf ); // sprite #1 + decalIndex = BF_ReadShort( &buf ); // sprite #2 + color = BF_ReadByte( &buf ); + scale = (float)BF_ReadByte( &buf ); + CL_BloodSprite( pos, color, modelIndex, decalIndex, scale ); + break; + case TE_PROJECTILE: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + modelIndex = BF_ReadShort( &buf ); + life = (float)(BF_ReadByte( &buf ) * 0.1f); + color = BF_ReadByte( &buf ); // playernum + CL_Projectile( pos, pos2, modelIndex, life, color, NULL ); + break; + case TE_PLAYERSPRITES: + color = BF_ReadByte( &buf ); // playernum + modelIndex = BF_ReadShort( &buf ); + count = BF_ReadByte( &buf ); + random = (float)BF_ReadByte( &buf ); + CL_PlayerSprites( color, modelIndex, count, random ); + break; + case TE_PARTICLEBURST: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + scale = (float)BF_ReadShort( &buf ); + color = BF_ReadByte( &buf ); + life = (float)(BF_ReadByte( &buf ) * 0.1f); + CL_ParticleBurst( pos, scale, color, life ); + break; + case TE_FIREFIELD: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + scale = (float)BF_ReadShort( &buf ); + modelIndex = BF_ReadShort( &buf ); + count = BF_ReadByte( &buf ); + flags = BF_ReadByte( &buf ); + life = (float)(BF_ReadByte( &buf ) * 0.1f); + CL_FireField( pos, scale, modelIndex, count, flags, life ); + break; + case TE_PLAYERATTACHMENT: + color = BF_ReadByte( &buf ); // playernum + scale = BF_ReadCoord( &buf ); // height + modelIndex = BF_ReadShort( &buf ); + life = (float)(BF_ReadShort( &buf ) * 0.1f); + CL_AttachTentToPlayer( color, modelIndex, scale, life ); + break; + case TE_KILLPLAYERATTACHMENTS: + color = BF_ReadByte( &buf ); // playernum + CL_KillAttachedTents( color ); + break; + case TE_MULTIGUNSHOT: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + ang[0] = BF_ReadCoord( &buf ) * 0.01f; + ang[1] = BF_ReadCoord( &buf ) * 0.01f; + ang[2] = 0.0f; + count = BF_ReadByte( &buf ); + decalIndex = BF_ReadByte( &buf ); + CL_MultiGunshot( pos, pos2, ang, count, 1, &decalIndex ); + break; + case TE_USERTRACER: + pos[0] = BF_ReadCoord( &buf ); + pos[1] = BF_ReadCoord( &buf ); + pos[2] = BF_ReadCoord( &buf ); + pos2[0] = BF_ReadCoord( &buf ); + pos2[1] = BF_ReadCoord( &buf ); + pos2[2] = BF_ReadCoord( &buf ); + life = (float)(BF_ReadByte( &buf ) * 0.1f); + color = BF_ReadByte( &buf ); + scale = (float)(BF_ReadByte( &buf ) * 0.1f); + CL_UserTracerParticle( pos, pos2, life, color, scale, 0, NULL ); break; default: - clgame.dllFuncs.pfnTempEntityMessage( iSize, pbuf ); + MsgDev( D_ERROR, "ParseTempEntity: illegible te_message %i\n", type ); break; } // throw warning - if( BF_CheckOverflow( &buf )) MsgDev( D_WARN, "ParseTempEntity: bad message\n" ); + if( BF_CheckOverflow( &buf )) MsgDev( D_WARN, "ParseTempEntity: overflow te_message\n" ); } @@ -2068,6 +2328,74 @@ void CL_AddDLights( void ) } } +/* +================ +CL_UpadteFlashlight + +update client flashlight +================ +*/ +void CL_UpadteFlashlight( cl_entity_t *pEnt ) +{ + vec3_t vecSrc, vecEnd, vecPos; + vec3_t forward, view_ofs; + pmtrace_t trace; + dlight_t *dl; + + if(( pEnt->index - 1 ) == cl.playernum ) + { + // get the predicted angles + AngleVectors( cl.refdef.cl_viewangles, forward, NULL, NULL ); + } + else + { + vec3_t v_angle; + + // restore viewangles from angles + v_angle[PITCH] = -pEnt->angles[PITCH] * 3; + v_angle[YAW] = pEnt->angles[YAW]; + v_angle[ROLL] = 0; // no roll + + AngleVectors( v_angle, forward, NULL, NULL ); + } + + VectorClear( view_ofs ); + + // FIXME: grab viewheight from other place + view_ofs[2] = 28.0f; + + if( pEnt->player ) + { + if(( pEnt->index - 1 ) == cl.playernum ) + { + VectorCopy( cl.predicted_viewofs, view_ofs ); + } + else if( pEnt->curstate.usehull == 1 ) + { + // FIXME: grab ducked viewheight from other place + view_ofs[2] = 12.0f; + } + } + + VectorAdd( pEnt->origin, view_ofs, vecSrc ); + VectorMA( vecSrc, 512.0f, forward, vecEnd ); + + trace = PM_PlayerTrace( clgame.pmove, vecSrc, vecEnd, PM_TRACELINE_PHYSENTSONLY, 2, -1, NULL ); + + if( trace.fraction != 1.0f ) + VectorMA( trace.endpos, -16.0f, trace.plane.normal, vecPos ); + else VectorCopy( trace.endpos, vecPos ); + + // update flashlight endpos + dl = CL_AllocDlight( pEnt->index ); + VectorCopy( vecPos, dl->origin ); + dl->die = cl.time + 0.001f; // die on next frame + dl->color.r = 255; + dl->color.g = 255; + dl->color.b = 255; + dl->radius = 96; +} + /* ================ CL_TestLights @@ -2136,9 +2464,11 @@ void CL_PlayerDecal( HSPRITE hDecal, int entityIndex, float *pos, byte *color ) { cl_entity_t *pEnt; int modelIndex = 0; + rgb_t _clr = { 255, 255, 255 }; pEnt = CL_GetEntityByIndex( entityIndex ); if( pEnt ) modelIndex = pEnt->curstate.modelindex; + if( !color ) color = _clr; if( re ) re->DecalShoot( hDecal, entityIndex, modelIndex, pos, NULL, FDECAL_CUSTOM, color, 0.0f, 0.0f ); } diff --git a/engine/client/cl_tent.h b/engine/client/cl_tent.h index 41a9f7d2..f4202245 100644 --- a/engine/client/cl_tent.h +++ b/engine/client/cl_tent.h @@ -10,6 +10,7 @@ #define SPARK_ELECTRIC_MAXSPEED 100.0f // EfxAPI +void CL_DrawTracer( vec3_t start, vec3_t delta, float width, rgb_t color, int alpha, float startV, float endV ); struct particle_s *CL_AllocParticle( void (*callback)( struct particle_s*, float )); void CL_Explosion( vec3_t pos, int model, float scale, float framerate, int flags ); void CL_ParticleExplosion( const vec3_t org ); @@ -32,6 +33,9 @@ void CL_StreakTracer( const vec3_t pos, const vec3_t velocity, int colorIndex ); void CL_TracerEffect( const vec3_t start, const vec3_t end ); void CL_UserTracerParticle( float *org, float *vel, float life, int colorIndex, float length, byte deathcontext, void (*deathfunc)( struct particle_s* )); struct particle_s *CL_TracerParticles( float *org, float *vel, float life ); +void CL_ParticleLine( const vec3_t start, const vec3_t end, byte r, byte g, byte b, float life ); +void CL_ParticleBox( const vec3_t mins, const vec3_t maxs, byte r, byte g, byte b, float life ); +void CL_ShowLine( const vec3_t start, const vec3_t end ); void CL_BulletImpactParticles( const vec3_t pos ); void CL_SparkShower( const vec3_t org ); struct tempent_s *CL_TempEntAlloc( const vec3_t org, model_t *pmodel ); @@ -59,7 +63,7 @@ void CL_Sprite_Trail( int type, const vec3_t vecStart, const vec3_t vecEnd, int void CL_FunnelSprite( const vec3_t pos, int spriteIndex, int flags ); void CL_Large_Funnel( const vec3_t pos, int flags ); void CL_SparkEffect( const vec3_t pos, int count, int velocityMin, int velocityMax ); -void CL_StreakSplash( const vec3_t pos, const vec3_t dir, int color, int count, int speed, int velMin, int velMax ); +void CL_StreakSplash( const vec3_t pos, const vec3_t dir, int color, int count, float speed, int velMin, int velMax ); void CL_SparkStreaks( const vec3_t pos, int count, int velocityMin, int velocityMax ); void CL_Projectile( const vec3_t origin, const vec3_t velocity, int modelIndex, int life, int owner, void (*hitcallback)( struct tempent_s*, struct pmtrace_s* )); void CL_TempSphereModel( const vec3_t pos, float speed, float life, int count, int modelIndex ); @@ -70,6 +74,7 @@ void CL_Sprite_WallPuff( struct tempent_s *pTemp, float scale ); void CL_RicochetSound( const vec3_t pos ); struct dlight_s *CL_AllocDlight( int key ); struct dlight_s *CL_AllocElight( int key ); +void CL_UpadteFlashlight( cl_entity_t *pEnt ); void CL_DecalShoot( HSPRITE hDecal, int entityIndex, int modelIndex, float *pos, int flags ); void CL_DecalRemoveAll( int textureIndex ); int CL_DecalIndexFromName( const char *name ); diff --git a/engine/client/cl_view.c b/engine/client/cl_view.c index 7d557992..5556250f 100644 --- a/engine/client/cl_view.c +++ b/engine/client/cl_view.c @@ -20,6 +20,22 @@ void V_ClearScene( void ) if( re ) re->ClearScene(); } +float V_CalcFov( float fov_x, float width, float height ) +{ + float x, half_fov_y; + + // check to avoid division by zero + if( fov_x < 1 || fov_x > 179 ) + { + MsgDev( D_ERROR, "V_CalcFov: invalid fov %g!\n", fov_x ); + fov_x = 90; + } + + x = width / com.tan( DEG2RAD( fov_x ) * 0.5f ); + half_fov_y = atan( height / x ); + return RAD2DEG( half_fov_y ) * 2; +} + /* =============== V_SetupRefDef @@ -33,23 +49,22 @@ void V_SetupRefDef( void ) clent = CL_GetLocalPlayer (); - VectorCopy( cl.frame.clientdata.punchangle, cl.refdef.punchangle ); - clgame.viewent.curstate.modelindex = cl.frame.clientdata.viewmodel; + VectorCopy( cl.frame.local.client.punchangle, cl.refdef.punchangle ); + clgame.viewent.curstate.modelindex = cl.frame.local.client.viewmodel; cl.refdef.movevars = &clgame.movevars; - cl.refdef.onground = ( cl.frame.clientdata.flags & FL_ONGROUND ) ? 1 : 0; - cl.refdef.health = cl.frame.clientdata.health; - cl.refdef.lerpfrac = cl.lerpFrac; - cl.refdef.num_entities = clgame.numEntities; + cl.refdef.onground = ( cl.frame.local.client.flags & FL_ONGROUND ) ? 1 : 0; + cl.refdef.health = cl.frame.local.client.health; + cl.refdef.playernum = cl.playernum; cl.refdef.max_entities = clgame.maxEntities; cl.refdef.maxclients = cl.maxclients; cl.refdef.time = cl_time(); cl.refdef.frametime = cl.time - cl.oldtime; cl.refdef.demoplayback = cls.demoplayback; cl.refdef.smoothing = cl_smooth->integer; - cl.refdef.waterlevel = cl.frame.clientdata.waterlevel; - cl.refdef.flags = cl.render_flags; - cl.refdef.viewsize = 120; // FIXME if you can + cl.refdef.waterlevel = cl.frame.local.client.waterlevel; + cl.refdef.viewsize = 120; // FIXME if you can + cl.refdef.hardware = true; // always true cl.refdef.nextView = 0; // setup default viewport @@ -57,6 +72,10 @@ void V_SetupRefDef( void ) cl.refdef.viewport[2] = scr_width->integer; cl.refdef.viewport[3] = scr_height->integer; + // calc FOV + cl.refdef.fov_x = cl.data.fov; // this is a final fov value + cl.refdef.fov_y = V_CalcFov( cl.refdef.fov_x, cl.refdef.viewport[2], cl.refdef.viewport[3] ); + // calculate the origin if( CL_IsPredicted( ) && !cl.refdef.demoplayback ) { @@ -74,8 +93,8 @@ void V_SetupRefDef( void ) else { VectorCopy( clent->origin, cl.refdef.simorg ); - VectorCopy( cl.frame.clientdata.view_ofs, cl.refdef.viewheight ); - VectorCopy( cl.frame.clientdata.velocity, cl.refdef.simvel ); + VectorCopy( cl.frame.local.client.view_ofs, cl.refdef.viewheight ); + VectorCopy( cl.frame.local.client.velocity, cl.refdef.simvel ); } } @@ -89,9 +108,9 @@ apply pre-calculated values void V_AddViewModel( void ) { if( cl.refdef.nextView ) return; // add viewmodel only at firstperson pass - if( !cl.frame.valid || cl.refdef.paused ) return; + if( !cl.frame.valid || cl.refdef.paused || cl.thirdperson ) return; - clgame.dllFuncs.pfnAddVisibleEntity( &clgame.viewent, ET_VIEWENTITY ); + CL_AddVisibleEntity( &clgame.viewent, ET_VIEWENTITY ); } /* @@ -107,7 +126,7 @@ void V_CalcRefDef( void ) { clgame.dllFuncs.pfnCalcRefdef( &cl.refdef ); V_AddViewModel(); - re->RenderFrame( &cl.refdef ); + re->RenderFrame( &cl.refdef, true ); } while( cl.refdef.nextView ); } diff --git a/engine/client/cl_world.c b/engine/client/cl_world.c deleted file mode 100644 index 533eeb9e..00000000 --- a/engine/client/cl_world.c +++ /dev/null @@ -1,299 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2009 й -// cl_world.c - world query functions -//======================================================================= - -#include "common.h" -#include "client.h" -#include "const.h" -#include "pm_defs.h" - -areanode_t cl_areanodes[AREA_NODES]; -int cl_numareanodes; - -/* -=============== -CL_CreateAreaNode - -builds a uniformly subdivided tree for the given world size -=============== -*/ -areanode_t *CL_CreateAreaNode( int depth, vec3_t mins, vec3_t maxs ) -{ - areanode_t *anode; - vec3_t size; - vec3_t mins1, maxs1; - vec3_t mins2, maxs2; - - anode = &cl_areanodes[cl_numareanodes++]; - - ClearLink( &anode->trigger_edicts ); - ClearLink( &anode->solid_edicts ); - ClearLink( &anode->water_edicts ); - - if( depth == AREA_DEPTH ) - { - anode->axis = -1; - anode->children[0] = anode->children[1] = NULL; - return anode; - } - - VectorSubtract( maxs, mins, size ); - if( size[0] > size[1] ) - anode->axis = 0; - else anode->axis = 1; - - anode->dist = 0.5f * ( maxs[anode->axis] + mins[anode->axis] ); - VectorCopy( mins, mins1 ); - VectorCopy( mins, mins2 ); - VectorCopy( maxs, maxs1 ); - VectorCopy( maxs, maxs2 ); - - maxs1[anode->axis] = mins2[anode->axis] = anode->dist; - anode->children[0] = CL_CreateAreaNode( depth+1, mins2, maxs2 ); - anode->children[1] = CL_CreateAreaNode( depth+1, mins1, maxs1 ); - - return anode; -} - -/* -=============== -CL_ClearWorld - -=============== -*/ -void CL_ClearWorld( void ) -{ - Mem_Set( cl_areanodes, 0, sizeof( cl_areanodes )); - cl_numareanodes = 0; - - CL_CreateAreaNode( 0, cl.worldmodel->mins, cl.worldmodel->maxs ); -} - -/* -=============== -CL_UnlinkEdict -=============== -*/ -void CL_UnlinkEdict( cl_entity_t *ent ) -{ - // not linked in anywhere - if( !ent->area.prev ) - return; - - RemoveLink( &ent->area ); - ent->area.prev = NULL; - ent->area.next = NULL; -} - -void CL_SetAbsBbox( cl_entity_t *ent ) -{ - if (( ent->curstate.solid == SOLID_BSP ) && !VectorIsNull( ent->angles )) - { - // expand for rotation - float max = 0, v; - int i; - - for ( i = 0; i < 3; i++ ) - { - v = fabs( ent->curstate.mins[i] ); - if ( v > max ) max = v; - v = fabs( ent->curstate.maxs[i] ); - if ( v > max ) max = v; - } - - for ( i = 0; i < 3; i++ ) - { - ent->absmin[i] = ent->origin[i] - max; - ent->absmax[i] = ent->origin[i] + max; - } - } - else - { - VectorAdd( ent->origin, ent->curstate.mins, ent->absmin ); - VectorAdd( ent->origin, ent->curstate.maxs, ent->absmax ); - } - - ent->absmin[0] -= 1; - ent->absmin[1] -= 1; - ent->absmin[2] -= 1; - ent->absmax[0] += 1; - ent->absmax[1] += 1; - ent->absmax[2] += 1; -} - -/* -=============== -CL_LinkEntity -=============== -*/ -void CL_LinkEdict( cl_entity_t *ent ) -{ - areanode_t *node; - - if( !ent ) return; - if( ent->area.prev ) CL_UnlinkEdict( ent ); // unlink from old position - if( ent->index <= 0 ) return; - - // set the abs box - CL_SetAbsBbox( ent ); - - // ignore not solid bodies - if( ent->curstate.solid == SOLID_NOT && ent->curstate.skin == CONTENTS_NONE ) - return; - - // find the first node that the ent's box crosses - node = cl_areanodes; - - while( 1 ) - { - if( node->axis == -1 ) break; - if( ent->absmin[node->axis] > node->dist ) - node = node->children[0]; - else if( ent->absmax[node->axis] < node->dist ) - node = node->children[1]; - else break; // crosses the node - } - - // link it in - if( ent->curstate.solid == SOLID_TRIGGER ) - InsertLinkBefore( &ent->area, &node->trigger_edicts ); - else if( ent->curstate.solid == SOLID_NOT && ent->curstate.skin != CONTENTS_NONE ) - InsertLinkBefore (&ent->area, &node->water_edicts ); - else InsertLinkBefore (&ent->area, &node->solid_edicts ); -} - -/* -============================================================================ - -AREA QUERY - -Fills in a list of all entities who's absmin / absmax intersects the given -bounds. This does NOT mean that they actually touch in the case of bmodels. -============================================================================ -*/ -/* -==================== -CL_AreaEdicts_r -==================== -*/ -void CL_AreaEdicts_r( areanode_t *node, area_t *ap ) -{ - link_t *l, *next, *start; - cl_entity_t *check; - int count = 0; - - // touch linked edicts - if( ap->type == AREA_SOLID ) - start = &node->solid_edicts; - else if( ap->type == AREA_TRIGGERS ) - start = &node->trigger_edicts; - else start = &node->water_edicts; - - for( l = start->next; l != start; l = next ) - { - next = l->next; - check = EDICT_FROM_AREA( l ); - if( !check ) continue; - - if( check->curstate.solid == SOLID_NOT && check->curstate.skin == CONTENTS_NONE ) - continue; // deactivated - if( !BoundsIntersect( check->absmin, check->absmax, ap->mins, ap->maxs )) - continue; // not touching - - if( ap->count == ap->maxcount ) - { - MsgDev( D_WARN, "CL_AreaEdicts: maxcount hit\n" ); - return; - } - - ap->list[ap->count] = check; - ap->count++; - } - - if( node->axis == -1 ) return; // terminal node - - // recurse down both sides - if( ap->maxs[node->axis] > node->dist ) CL_AreaEdicts_r( node->children[0], ap ); - if( ap->mins[node->axis] < node->dist ) CL_AreaEdicts_r( node->children[1], ap ); -} - -/* -================ -CL_AreaEdicts -================ -*/ -int CL_AreaEdicts( const vec3_t mins, const vec3_t maxs, cl_entity_t **list, int maxcount, int areatype ) -{ - area_t ap; - - ap.mins = mins; - ap.maxs = maxs; - ap.list = list; - ap.count = 0; - ap.maxcount = maxcount; - ap.type = areatype; - - CL_AreaEdicts_r( cl_areanodes, &ap ); - - return ap.count; -} - -/* -============= -CL_PointContents - -============= -*/ -int CL_TruePointContents( const vec3_t p ) -{ - int i, num, contents; - cl_entity_t *hit, *touch[MAX_EDICTS]; - - // sanity check - if( !p ) return CONTENTS_NONE; - - // get base contents from world - contents = CM_PointContents( p ); - - if( contents != CONTENTS_EMPTY ) - return contents; // have some world contents - - // check contents from all the solid entities - num = CL_AreaEdicts( p, p, touch, MAX_EDICTS, AREA_SOLID ); - - for( i = 0; i < num; i++ ) - { - hit = touch[i]; - - if( hit->curstate.solid != SOLID_BSP ) - continue; // monsters, players - - // solid entity found - return CONTENTS_SOLID; - } - - // check contents from all the custom entities - num = CL_AreaEdicts( p, p, touch, MAX_EDICTS, AREA_CUSTOM ); - - for( i = 0; i < num; i++ ) - { - hit = touch[i]; - - if( hit->curstate.solid != SOLID_NOT || hit->curstate.skin == CONTENTS_NONE ) - continue; // invalid water ? - - // custom contents found - return hit->curstate.skin; - } - return contents; -} - -int CL_PointContents( const vec3_t p ) -{ - int cont = CL_TruePointContents( p ); - - if( cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN ) - cont = CONTENTS_WATER; - return cont; -} \ No newline at end of file diff --git a/engine/client/client.h b/engine/client/client.h index bd491e32..4c18e1d0 100644 --- a/engine/client/client.h +++ b/engine/client/client.h @@ -8,7 +8,7 @@ #include "mathlib.h" #include "cdll_int.h" -#include "gameui_api.h" +#include "menu_int.h" #include "cl_entity.h" #include "com_model.h" #include "cm_local.h" @@ -21,6 +21,7 @@ #define MAX_DEMOS 32 #define MAX_MOVIES 8 +#define MAX_IMAGES 256 // HSPRITE pics #define EDICT_FROM_AREA( l ) STRUCT_FROM_LINK( l, cl_entity_t, area ) #define NUM_FOR_EDICT(e) ((int)((cl_entity_t *)(e) - clgame.entities)) @@ -36,8 +37,8 @@ typedef struct frame_s double latency; double time; // server timestamp - clientdata_t clientdata; // message received that reflects performing - weapon_data_t weapondata[32]; + local_state_t local; // local client state + entity_state_t playerstate[MAX_CLIENTS]; int num_entities; int first_entity; // into the circular cl_packet_entities[] @@ -77,9 +78,12 @@ typedef struct int last_incoming_sequence; qboolean force_send_usercmd; + qboolean thirdperson; uint checksum; // for catching cheater maps + client_data_t data; // some clientdata holds + frame_t frame; // received from server int surpressCount; // number of messages rate supressed frame_t frames[MULTIPLAYER_BACKUP]; // alloced on svc_serverdata @@ -91,7 +95,6 @@ typedef struct double oldtime; // previous cl.time, time-oldtime is used // to decay light values and smooth step ups - int render_flags; // clearing at end of frame float lerpFrac; // interpolation value ref_params_t refdef; // shared refdef @@ -197,15 +200,17 @@ typedef struct typedef struct { - HSPRITE hFontTexture; // handle to texture shader + shader_t hFontTexture; // handle to texture shader wrect_t fontRc[256]; // rectangles qboolean valid; // rectangles are valid } cl_font_t; typedef struct { + model_t images[MAX_IMAGES]; // conatin handle to spriteshader etc + // temp handle - HSPRITE hSprite; + shader_t hSprite; // scissor test int scissor_x; @@ -218,7 +223,7 @@ typedef struct rgba_t textColor; // crosshair members - HSPRITE hCrosshair; + shader_t hCrosshair; wrect_t rcCrosshair; rgba_t rgbaCrosshair; byte gammaTable[256]; @@ -274,27 +279,26 @@ typedef struct void (*pfnProcessPlayerState)( entity_state_t *dst, const entity_state_t *src ); void (*pfnTxferPredictionData)( entity_state_t *ps, const entity_state_t *pps, clientdata_t *pcd, const clientdata_t *ppcd, weapon_data_t *wd, const weapon_data_t *pwd ); void (*pfnTempEntUpdate)( double frametime, double client_time, double cl_gravity, struct tempent_s **ppTempEntFree, struct tempent_s **ppTempEntActive, int ( *Callback_AddVisibleEntity )( cl_entity_t *pEntity ), void ( *Callback_TempEntPlaySound )( struct tempent_s *pTemp, float damp )); + int (*pfnGetStudioModelInterface)( int version, struct r_studio_interface_s **ppinterface, struct engine_studio_api_s *pstudio ); void (*pfnDrawNormalTriangles)( void ); void (*pfnDrawTransparentTriangles)( void ); - cl_entity_t (*pfnGetUserEntity)( int index ); - void *(*KB_Find)( const char *name ); // returns kbutton_t. Probably Xash3D doesn't need for it - void (*CAM_Think)( void ); // camera stuff (QW issues) + cl_entity_t *(*pfnGetUserEntity)( int index ); + void *(*KB_Find)( const char *name ); + void (*CAM_Think)( void ); // camera stuff int (*CL_IsThirdPerson)( void ); - void (*CL_CameraOffset)( float *ofs ); void (*CL_CreateMove)( float frametime, usercmd_t *cmd, int active ); void (*IN_ActivateMouse)( void ); void (*IN_DeactivateMouse)( void ); void (*IN_MouseEvent)( int mstate ); void (*IN_Accumulate)( void ); void (*IN_ClearStates)( void ); - void (*V_CalcRefdef)( ref_params_t *pparams ); -} CDLL_FUNCTIONS; + void (*pfnCalcRefdef)( ref_params_t *pparams ); +} HUD_FUNCTIONS; typedef struct { void *hInstance; // pointer to client.dll HUD_FUNCTIONS dllFuncs; // dll exported funcs - CDLL_FUNCTIONS cdllFuncs; // dll exported funcs (under construction) byte *mempool; // client edicts pool string mapname; // map name string maptitle; // display map title @@ -342,14 +346,14 @@ typedef struct draw_stuff_t ds; // draw2d stuff (hud, weaponmenu etc) GAMEINFO gameInfo; // current gameInfo - GAMEINFO *modsInfo[MAX_MODS]; // simplified gameInfo for GameUI + GAMEINFO *modsInfo[MAX_MODS]; // simplified gameInfo for MainUI ui_globalvars_t *globals; qboolean drawLogo; // set to TRUE if logo.avi missed or corrupted long logo_xres; long logo_yres; -} gameui_static_t; +} menu_static_t; typedef struct { @@ -384,6 +388,7 @@ typedef struct shader_t pauseIcon; // draw 'paused' when game in-pause shader_t loadingBar; // 'loading' progress bar shader_t glowShell; // for renderFxGlowShell + HSPRITE hChromeSprite; // this is a really HudSprite handle, not shader_t! cl_font_t creditsFont; // shared creditsfont int num_client_entities; // cl.maxclients * CL_UPDATE_BACKUP * MAX_PACKET_ENTITIES @@ -424,7 +429,7 @@ typedef struct extern client_t cl; extern client_static_t cls; extern clgame_static_t clgame; -extern gameui_static_t gameui; +extern menu_static_t menu; extern render_exp_t *re; // @@ -512,6 +517,7 @@ void CL_UnloadProgs( void ); qboolean CL_LoadProgs( const char *name ); void CL_ParseUserMessage( sizebuf_t *msg, int svc_num ); void CL_LinkUserMessage( char *pszName, const int svc_num, int iSize ); +void CL_ParseTextMessage( sizebuf_t *msg ); void CL_DrawHUD( int state ); void CL_InitEdicts( void ); void CL_FreeEdicts( void ); @@ -523,6 +529,7 @@ void CL_SetEventIndex( const char *szEvName, int ev_index ); void CL_TextMessageParse( byte *pMemFile, int fileSize ); int pfnDecalIndexFromName( const char *szDecalName ); int CL_FindModelIndex( const char *m ); +HSPRITE pfnSPR_Load( const char *szPicName ); void *VGui_GetPanel( void ); void VGui_ViewportPaintBackground( int extents[4] ); @@ -540,6 +547,7 @@ _inline cl_entity_t *CL_EDICT_NUM( int n, const char *file, const int line ) extern const char *svc_strings[256]; void CL_ParseServerMessage( sizebuf_t *msg ); void CL_ParseTempEntity( sizebuf_t *msg ); +qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf ); void CL_RunBackgroundTrack( void ); void CL_Download_f( void ); @@ -573,11 +581,19 @@ void CL_InitClientMove( void ); void CL_PredictMovement( void ); void CL_CheckPredictionError( void ); qboolean CL_IsPredicted( void ); +int CL_TruePointContents( const vec3_t p ); +int CL_PointContents( const vec3_t p ); + +// +// cl_studio.c +// +qboolean CL_InitStudioAPI( void ); // // cl_frame.c // void CL_ParsePacketEntities( sizebuf_t *msg, qboolean delta ); +qboolean CL_AddVisibleEntity( cl_entity_t *ent, int entityType ); void CL_UpdateStudioVars( cl_entity_t *ent, entity_state_t *newstate ); qboolean CL_GetEntitySpatialization( int ent, vec3_t origin, vec3_t velocity ); qboolean CL_IsPlayerIndex( int idx ); @@ -660,16 +676,4 @@ void SCR_RunCinematic( void ); void SCR_StopCinematic( void ); void CL_PlayVideo_f( void ); -// -// cl_world.c -// -extern areanode_t cl_areanodes[]; - -void CL_ClearWorld( void ); -void CL_UnlinkEdict( cl_entity_t *ent ); -void CL_LinkEdict( cl_entity_t *ent ); -int CL_AreaEdicts( const vec3_t mins, const vec3_t maxs, cl_entity_t **list, int maxcount, int areatype ); -int CL_TruePointContents( const vec3_t p ); -int CL_PointContents( const vec3_t p ); - #endif//CLIENT_H \ No newline at end of file diff --git a/engine/common/cm_local.h b/engine/common/cm_local.h index 989a5034..8ec6ec16 100644 --- a/engine/common/cm_local.h +++ b/engine/common/cm_local.h @@ -43,6 +43,8 @@ typedef struct clipmap_s vec3_t hull_sizes[4]; // hull sizes + byte *studiopool; // cache for submodels + script_t *entityscript; // only actual for world } clipmap_t; @@ -81,9 +83,14 @@ void Mod_GetBounds( int handle, vec3_t mins, vec3_t maxs ); void Mod_GetFrames( int handle, int *numFrames ); modtype_t CM_GetModelType( int handle ); model_t *CM_ClipHandleToModel( int handle ); +int CM_ClipModelToHandle( const model_t *pmodel ); void CM_BeginRegistration ( const char *name, qboolean clientload, uint *checksum ); +model_t *CM_ModForName( const char *name, qboolean world ); qboolean CM_RegisterModel( const char *name, int index ); -void *Mod_Extradata( int handle ); void CM_EndRegistration( void ); +void *Mod_Calloc( int number, size_t size ); +void *Mod_CacheCheck( struct cache_user_s *c ); +void Mod_LoadCacheFile( const char *path, struct cache_user_s *cu ); +void *Mod_Extradata( model_t *mod ); #endif//CM_LOCAL_H \ No newline at end of file diff --git a/engine/common/cm_model.c b/engine/common/cm_model.c index 270d87f9..c9d9300c 100644 --- a/engine/common/cm_model.c +++ b/engine/common/cm_model.c @@ -82,13 +82,13 @@ void CM_SetupHulls( float mins[4][3], float maxs[4][3] ) CM_StudioBodyVariations ================ */ -static int CM_StudioBodyVariations( int handle ) +static int CM_StudioBodyVariations( model_t *mod ) { studiohdr_t *pstudiohdr; mstudiobodyparts_t *pbodypart; int i, count; - pstudiohdr = (studiohdr_t *)Mod_Extradata( handle ); + pstudiohdr = (studiohdr_t *)Mod_Extradata( mod ); if( !pstudiohdr ) return 0; count = 1; @@ -129,6 +129,8 @@ qboolean CM_InitPhysics( void ) { cm_novis = Cvar_Get( "cm_novis", "0", 0, "force to ignore server visibility" ); + cm.studiopool = Mem_AllocPool( "Studio Cache" ); + Mem_Set( cm.nullrow, 0xFF, MAX_MAP_LEAFS / 8 ); return true; } @@ -139,6 +141,8 @@ void CM_FreePhysics( void ) for( i = 0; i < cm_nummodels; i++ ) CM_FreeModel( &cm_models[i] ); + + Mem_FreePool( &cm.studiopool ); } /* @@ -667,7 +671,9 @@ static void BSP_LoadEntityString( dlump_t *l ) byte *in; in = (void *)(mod_base + l->fileofs); - cm.entityscript = Com_OpenScript( LUMP_ENTITIES, in, l->filelen ); + loadmodel->entities = Mem_Alloc( loadmodel->mempool, l->filelen ); + Mem_Copy( loadmodel->entities, mod_base + l->fileofs, l->filelen ); + cm.entityscript = Com_OpenScript( "entities", in, l->filelen ); } /* @@ -918,7 +924,7 @@ static void CM_SpriteModel( model_t *mod, byte *buffer ) loadmodel->maxs[2] = phdr->bounds[1] / 2; } -static model_t *CM_ModForName( const char *name, qboolean world ) +model_t *CM_ModForName( const char *name, qboolean world ) { byte *buf; model_t *mod; @@ -969,7 +975,8 @@ static model_t *CM_ModForName( const char *name, qboolean world ) buf = FS_LoadFile( name, &size ); if( !buf ) { - MsgDev( D_ERROR, "CM_LoadModel: %s couldn't load\n", name ); + if( world ) Host_Error( "Mod_ForName: %s couldn't load\n", name ); + else MsgDev( D_ERROR, "Mod_ForName: %s couldn't load\n", name ); return NULL; } @@ -1022,6 +1029,9 @@ static void CM_FreeWorld( void ) cm.entityscript = NULL; } worldmodel = NULL; + + // purge all submodels + Mem_EmptyPool( cm.studiopool ); } /* @@ -1101,17 +1111,20 @@ model_t *CM_ClipHandleToModel( int handle ) } /* -=================== -Mod_Extradata -=================== +================== +CM_ClipHandleToModel +================== */ -void *Mod_Extradata( int handle ) +int CM_ClipModelToHandle( const model_t *pmodel ) { - model_t *mod = CM_ClipHandleToModel( handle ); + int i; - if( mod && mod->type == mod_studio ) - return mod->extradata; - return NULL; + if( !pmodel ) return 0; + + for( i = 0; i < MAX_MODELS; i++ ) + if( sv_models[i] == pmodel ) + return i; + return 0; } /* @@ -1133,7 +1146,7 @@ void Mod_GetFrames( int handle, int *numFrames ) if( mod->type == mod_sprite ) *numFrames = mod->numframes; else if( mod->type == mod_studio ) - *numFrames = CM_StudioBodyVariations( handle ); + *numFrames = CM_StudioBodyVariations( mod ); if( *numFrames < 1 ) *numFrames = 1; } @@ -1184,4 +1197,72 @@ qboolean CM_RegisterModel( const char *name, int index ) sv_models[index] = mod; return ( mod != NULL ); +} + +/* +=============== +Mod_Calloc + +=============== +*/ +void *Mod_Calloc( int number, size_t size ) +{ + if( number <= 0 || size <= 0 ) return NULL; + return Mem_Alloc( cm.studiopool, number * size ); +} + +/* +=============== +Mod_CacheCheck + +=============== +*/ +void *Mod_CacheCheck( cache_user_t *c ) +{ + return Cache_Check( cm.studiopool, c ); +} + +/* +=============== +Mod_LoadCacheFile + +=============== +*/ +void Mod_LoadCacheFile( const char *path, cache_user_t *cu ) +{ + byte *buf; + string filepath; + size_t i, size; + + ASSERT( cu != NULL ); + + if( !path || !path[0] ) return; + + // replace all '\' with '/' + for( i = ( path[0] == '/' ||path[0] == '\\' ), size = 0; path[i] && ( size < sizeof( filepath )-1 ); i++ ) + { + if( path[i] == '\\' ) filepath[size++] = '/'; + else filepath[size++] = path[i]; + } + + if( !size ) return; + filepath[size] = 0; + + buf = FS_LoadFile( filepath, &size ); + cu->data = Mem_Alloc( cm.studiopool, size ); + Mem_Copy( cu->data, buf, size ); + Mem_Free( buf ); +} + +/* +=============== +Mod_Extradata + +=============== +*/ +void *Mod_Extradata( model_t *mod ) +{ + if( mod && mod->type == mod_studio ) + return mod->extradata; + return NULL; } \ No newline at end of file diff --git a/engine/common/common.h b/engine/common/common.h index 5062e0c0..c2263bbe 100644 --- a/engine/common/common.h +++ b/engine/common/common.h @@ -276,13 +276,14 @@ movie_state_t *AVI_GetState( int num ); // shared calls qboolean CL_IsInGame( void ); qboolean CL_IsInMenu( void ); +qboolean CL_IsThirdPerson( void ); float CL_GetServerTime( void ); +float CL_GetLerpFrac( void ); void CL_CharEvent( int key ); void Tri_DrawTriangles( int fTrans ); int CL_PointContents( const vec3_t point ); char *COM_ParseFile( char *data, char *token ); byte *COM_LoadFile( const char *filename, int usehunk, int *pLength ); -void CL_StudioFxTransform( struct cl_entity_s *ent, float transform[4][4] ); qboolean CL_GetEntitySpatialization( int entnum, vec3_t origin, vec3_t velocity ); void CL_StudioEvent( struct mstudioevent_s *event, struct cl_entity_s *ent ); qboolean CL_GetComment( const char *demoname, char *comment ); @@ -296,6 +297,7 @@ struct player_info_s *CL_GetPlayerInfo( int playerIndex ); void CL_ExtraUpdate( void ); int CL_GetMaxClients( void ); qboolean CL_IsPlaybackDemo( void ); +qboolean CL_LoadProgs( const char *name ); qboolean SV_GetComment( const char *savename, char *comment ); qboolean SV_NewGame( const char *mapName, qboolean loadGame ); void SV_SysError( const char *error_string ); diff --git a/engine/common/con_utils.c b/engine/common/con_utils.c index ff4371f7..bc2fed1e 100644 --- a/engine/common/con_utils.c +++ b/engine/common/con_utils.c @@ -8,6 +8,7 @@ #include "byteorder.h" #include "const.h" #include "bspfile.h" +#include "../cl_dll/kbutton.h" #ifdef _DEBUG void DBG_AssertFunction( qboolean fExpr, const char* szExpr, const char* szFile, int szLine, const char* szMessage ) @@ -908,6 +909,7 @@ Writes key bindings and archived cvars to config.cfg void Host_WriteConfig( void ) { file_t *f; + kbutton_t *mlook, *jlook; if( !cls.initialized ) return; @@ -920,6 +922,16 @@ void Host_WriteConfig( void ) FS_Printf( f, "//=======================================================================\n" ); Key_WriteBindings( f ); Cmd_WriteVariables( f ); + + mlook = (kbutton_t *)clgame.dllFuncs.KB_Find( "in_mlook" ); + jlook = (kbutton_t *)clgame.dllFuncs.KB_Find( "in_jlook" ); + + if( mlook && ( mlook->state & 1 )) + FS_Printf( f, "+mlook\n" ); + + if( jlook && ( jlook->state & 1 )) + FS_Printf( f, "+jlook\n" ); + FS_Close( f ); } else MsgDev( D_ERROR, "Couldn't write config.cfg.\n" ); diff --git a/engine/common/console.c b/engine/common/console.c index c5632d98..7f5abd35 100644 --- a/engine/common/console.c +++ b/engine/common/console.c @@ -1554,7 +1554,7 @@ void Con_Close( void ) ========= Con_DefaultColor -called from GameUI +called from MainUI ========= */ void Con_DefaultColor( int r, int g, int b ) diff --git a/engine/common/host.c b/engine/common/host.c index 0b0e6cac..5a332274 100644 --- a/engine/common/host.c +++ b/engine/common/host.c @@ -126,7 +126,6 @@ qboolean Host_InitRender( void ) // studio callbacks ri.UpdateScreen = SCR_UpdateScreen; ri.StudioEvent = CL_StudioEvent; - ri.StudioFxTransform = CL_StudioFxTransform; ri.ShowCollision = Host_DrawDebugCollision; ri.GetClientEdict = CL_GetEntityByIndex; ri.GetPlayerInfo = CL_GetPlayerInfo; @@ -134,6 +133,8 @@ qboolean Host_InitRender( void ) ri.GetMaxClients = CL_GetMaxClients; ri.DrawTriangles = Tri_DrawTriangles; ri.ExtraUpdate = CL_ExtraUpdate; + ri.GetLerpFrac = CL_GetLerpFrac; + ri.IsThirdPerson = CL_IsThirdPerson; ri.WndProc = IN_WndProc; Sys_LoadLibrary( host_video->string, &render_dll ); @@ -429,7 +430,7 @@ void Host_InitDecals( void ) } if( t ) Mem_Free( t ); - MsgDev( D_INFO, "InitDecals: %i decals\n", num_decals ); + MsgDev( D_NOTE, "InitDecals: %i decals\n", num_decals ); } /* @@ -813,7 +814,6 @@ void Host_InitCommon( const int argc, const char **argv ) void Host_FreeCommon( void ) { - IN_Shutdown(); Netchan_Shutdown(); Mem_FreePool( &host.mempool ); } @@ -833,6 +833,10 @@ void Host_Init( const int argc, const char **argv ) if( host.type != HOST_DEDICATED ) { + // NOTE: client.dll must be loaded first to get mlook state from congig.cfg + if( !CL_LoadProgs( va( "%s/client.dll", GI->dll_path ))) + Host_Error( "CL_InitGame: can't initialize client.dll\n" ); + // get the user configuration Cbuf_AddText( "exec config.cfg\n" ); Cbuf_Execute(); diff --git a/engine/common/input.c b/engine/common/input.c index 41e5ca3c..0f391535 100644 --- a/engine/common/input.c +++ b/engine/common/input.c @@ -150,6 +150,26 @@ static qboolean IN_CursorInRect( void ) return true; } +/* +=========== +IN_ToggleClientMouse + +Called when key_dest is changed +=========== +*/ +void IN_ToggleClientMouse( int newstate, int oldstate ) +{ + if( newstate == oldstate ) return; + + if( oldstate == key_game ) + { + clgame.dllFuncs.IN_DeactivateMouse(); + } + else if( newstate == key_game ) + { + clgame.dllFuncs.IN_ActivateMouse(); + } +} /* =========== @@ -213,7 +233,11 @@ void IN_ActivateMouse( void ) if( in_mouseactive ) return; in_mouseactive = true; - if( in_mouseparmsvalid ) + if( CL_IsInGame( )) + { + clgame.dllFuncs.IN_ActivateMouse(); + } + else if( in_mouseparmsvalid ) in_restore_spi = SystemParametersInfo( SPI_SETMOUSE, 0, in_newmouseparms, 0 ); width = GetSystemMetrics( SM_CXSCREEN ); @@ -246,7 +270,11 @@ void IN_DeactivateMouse( void ) if( !in_mouseinitialized || !in_mouseactive ) return; - if( in_restore_spi ) + if( CL_IsInGame( )) + { + clgame.dllFuncs.IN_DeactivateMouse(); + } + else if( in_restore_spi ) SystemParametersInfo( SPI_SETMOUSE, 0, in_originalmouseparms, 0 ); in_mouseactive = false; @@ -265,7 +293,7 @@ void IN_MouseMove( void ) POINT current_pos; int mx, my; - if( !in_mouseinitialized || !in_mouseactive || in_mouse_suspended ) + if( !in_mouseinitialized || !in_mouseactive || in_mouse_suspended || CL_IsInGame( )) return; // find mouse movement @@ -292,6 +320,12 @@ void IN_MouseEvent( int mstate ) if( !in_mouseinitialized || !in_mouseactive ) return; + if( CL_IsInGame( )) + { + clgame.dllFuncs.IN_MouseEvent( mstate ); + return; + } + // perform button actions for( i = 0; i < in_mouse_buttons; i++ ) { @@ -440,6 +474,7 @@ long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam ) wnd_caption = GetSystemMetrics( SM_CYCAPTION ) + WND_BORDER; S_Activate(( host.state == HOST_FRAME ) ? true : false, host.hWnd ); Key_ClearStates(); // FIXME!!! + clgame.dllFuncs.IN_ClearStates(); if( host.state == HOST_FRAME ) { diff --git a/engine/common/input.h b/engine/common/input.h index 1affedb8..a7c02844 100644 --- a/engine/common/input.h +++ b/engine/common/input.h @@ -25,6 +25,7 @@ void IN_Shutdown( void ); void IN_MouseEvent( int mstate ); void IN_ActivateMouse( void ); void IN_DeactivateMouse( void ); +void IN_ToggleClientMouse( int newstate, int oldstate ); long IN_WndProc( void *hWnd, uint uMsg, uint wParam, long lParam ); #endif//INPUT_H \ No newline at end of file diff --git a/engine/common/keys.c b/engine/common/keys.c index eca1a9ee..3f107046 100644 --- a/engine/common/keys.c +++ b/engine/common/keys.c @@ -634,6 +634,8 @@ Key_SetKeyDest */ void Key_SetKeyDest( int key_dest ) { + IN_ToggleClientMouse( key_dest, cls.key_dest ); + switch( key_dest ) { case key_game: @@ -705,9 +707,4 @@ void CL_MouseEvent( int mx, int my ) // if the menu is visible, move the menu cursor UI_MouseMove( mx, my ); } - else if( cls.key_dest != key_console && CL_Active( )) - { - // otherwise passed into client.dll - clgame.dllFuncs.pfnMouseEvent( mx, my ); - } } \ No newline at end of file diff --git a/engine/common/net_buffer.h b/engine/common/net_buffer.h index 574f0acd..fba517b9 100644 --- a/engine/common/net_buffer.h +++ b/engine/common/net_buffer.h @@ -40,7 +40,8 @@ typedef struct #define BF_ReadBitAngles BF_ReadBitVec3Coord #define BF_ReadString( bf ) BF_ReadStringExt( bf, false ) #define BF_ReadStringLine( bf ) BF_ReadStringExt( bf, true ) -#define BF_ReadCoord( bf ) (float)(BF_ReadShort( bf ) * (1.0f / 8.0f )) +#define BF_ReadCoord( bf ) (float)(BF_ReadShort( bf ) * ( 1.0f / 8.0f )) +#define BF_ReadAngle( bf ) (float)(BF_ReadChar( bf ) * ( 360.0f / 256.0f )) #define BF_Init( bf, name, data, bytes ) BF_InitExt( bf, name, data, bytes, -1 ) // common functions diff --git a/engine/common/net_encode.c b/engine/common/net_encode.c index 4b498878..7a5b763d 100644 --- a/engine/common/net_encode.c +++ b/engine/common/net_encode.c @@ -776,7 +776,7 @@ void Delta_Init( void ) Delta_AddField( "movevars_t", "stepsize", DT_FLOAT|DT_SIGNED, 16, 16.0f, 1.0f ); Delta_AddField( "movevars_t", "maxvelocity", DT_FLOAT|DT_SIGNED, 16, 8.0f, 1.0f ); Delta_AddField( "movevars_t", "zmax", DT_FLOAT|DT_SIGNED, 16, 1.0f, 1.0f ); // no fractional part - Delta_AddField( "movevars_t", "waveHeight", DT_FLOAT|DT_SIGNED, 16, 1.0f, 16.0f ); + Delta_AddField( "movevars_t", "waveHeight", DT_FLOAT|DT_SIGNED, 16, 16.0f, 8.0f ); Delta_AddField( "movevars_t", "skyName", DT_STRING, 1, 1.0f, 1.0f ); Delta_AddField( "movevars_t", "footsteps", DT_INTEGER, 1, 1.0f, 1.0f ); Delta_AddField( "movevars_t", "rollangle", DT_FLOAT|DT_SIGNED, 16, 32.0f, 1.0f ); diff --git a/engine/common/world.c b/engine/common/world.c index 257820be..072688c4 100644 --- a/engine/common/world.c +++ b/engine/common/world.c @@ -93,19 +93,19 @@ void World_MoveBounds( const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_ trace_t World_CombineTraces( trace_t *cliptrace, trace_t *trace, edict_t *touch ) { - if( trace->fAllSolid || trace->fStartSolid || trace->flFraction < cliptrace->flFraction ) + if( trace->allsolid || trace->startsolid || trace->fraction < cliptrace->fraction ) { - trace->pHit = touch; + trace->ent = touch; - if( cliptrace->fStartSolid ) + if( cliptrace->startsolid ) { *cliptrace = *trace; - cliptrace->fStartSolid = true; + cliptrace->startsolid = true; } else *cliptrace = *trace; } - else if( trace->fStartSolid ) - cliptrace->fStartSolid = true; + else if( trace->startsolid ) + cliptrace->startsolid = true; return *cliptrace; } diff --git a/engine/eiface.h b/engine/eiface.h index e4bad869..4ab78b66 100644 --- a/engine/eiface.h +++ b/engine/eiface.h @@ -351,7 +351,6 @@ typedef enum _fieldtypes FIELD_TIME, // a floating point time (these are fixed up automatically too!) FIELD_MODELNAME, // Engine string that is a model name (needs precache) FIELD_SOUNDNAME, // Engine string that is a sound name (needs precache) - FIELD_WEAPONTIME, // Custom field for predicted and normal weapons FIELD_TYPECOUNT, // MUST BE LAST } FIELDTYPE; diff --git a/engine/engine.dsp b/engine/engine.dsp index 436e6987..c251358d 100644 --- a/engine/engine.dsp +++ b/engine/engine.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "common" /I "server" /I "client" /I "uimenu" /I "../public" /I "../common" /I "../game_shared" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "common" /I "server" /I "client" /I "uimenu" /I "../public" /I "../common" /I "../game_shared" /I "../pm_shared" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -61,8 +61,8 @@ TargetDir=\Xash3D\src_main\temp\engine\!release InputPath=\Xash3D\src_main\temp\engine\!release\engine.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\engine.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\engine.dll "D:\Xash3D\bin\engine.dll" +"D:\Xash3D\engine.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\engine.dll "D:\Xash3D\engine.dll" # End Custom Build @@ -80,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "common" /I "server" /I "client" /I "uimenu" /I "../public" /I "../common" /I "../game_shared" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "common" /I "server" /I "client" /I "uimenu" /I "../public" /I "../common" /I "../game_shared" /I "../pm_shared" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 @@ -98,8 +98,8 @@ TargetDir=\Xash3D\src_main\temp\engine\!debug InputPath=\Xash3D\src_main\temp\engine\!debug\engine.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\engine.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\engine.dll "D:\Xash3D\bin\engine.dll" +"D:\Xash3D\engine.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\engine.dll "D:\Xash3D\engine.dll" # End Custom Build @@ -170,6 +170,10 @@ SOURCE=.\client\cl_scrn.c # End Source File # Begin Source File +SOURCE=.\client\cl_studio.c +# End Source File +# Begin Source File + SOURCE=.\client\cl_tent.c # End Source File # Begin Source File @@ -182,10 +186,6 @@ SOURCE=.\client\cl_view.c # End Source File # Begin Source File -SOURCE=.\client\cl_world.c -# End Source File -# Begin Source File - SOURCE=.\common\cm_model.c # End Source File # Begin Source File diff --git a/common/gameui_api.h b/engine/menu_int.h similarity index 93% rename from common/gameui_api.h rename to engine/menu_int.h index 905e8e6f..eb922787 100644 --- a/common/gameui_api.h +++ b/engine/menu_int.h @@ -1,15 +1,15 @@ //======================================================================= // Copyright XashXT Group 2010 й -// gameui_api.h - interface between engine and gameui +// menu_int.h - interface between engine and menu //======================================================================= -#ifndef GAMEUI_API_H -#define GAMEUI_API_H +#ifndef MENU_INT_H +#define MENU_INT_H #include "cvardef.h" #include "gameinfo.h" #include "wrect.h" -typedef int HIMAGE; // handle to a graphic +typedef int HIMAGE; // handle to a graphic typedef struct ui_globalvars_s { @@ -164,6 +164,6 @@ typedef struct void (*pfnFinalCredits)( void ); // show credits + game end } UI_FUNCTIONS; -typedef int (*GAMEUIAPI)( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* engfuncs, ui_globalvars_t *pGlobals ); +typedef int (*MENUAPI)( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* engfuncs, ui_globalvars_t *pGlobals ); -#endif//GAMEUI_API_H \ No newline at end of file +#endif//MENU_INT_H \ No newline at end of file diff --git a/engine/server/server.h b/engine/server/server.h index 55f49856..f5291b63 100644 --- a/engine/server/server.h +++ b/engine/server/server.h @@ -411,7 +411,6 @@ void SV_ActivateServer( void ); void SV_DeactivateServer( void ); void SV_LevelInit( const char *pMapName, char const *pOldLevel, char const *pLandmarkName, qboolean loadGame ); qboolean SV_SpawnServer( const char *server, const char *startspot ); -int SV_FindIndex( const char *name, int start, int end, qboolean create ); // // sv_phys.c @@ -493,7 +492,6 @@ edict_t *SV_AllocEdict( void ); void SV_FreeEdict( edict_t *pEdict ); void SV_InitEdict( edict_t *pEdict ); const char *SV_ClassName( const edict_t *e ); -void SV_ConfigString( int index, const char *val ); void SV_SetModel( edict_t *ent, const char *name ); void SV_CopyTraceToGlobal( trace_t *trace ); void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max ); @@ -542,6 +540,7 @@ void SV_LoadAdjacentEnts( const char *pOldLevel, const char *pLandmarkName ); // sv_studio.c // void SV_InitStudioHull( void ); +qboolean SV_InitStudioAPI( void ); qboolean SV_StudioExtractBbox( model_t *mod, int sequence, float *mins, float *maxs ); void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang ); trace_t SV_TraceHitbox( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t maxs, const vec3_t end ); diff --git a/engine/server/sv_game.c b/engine/server/sv_game.c index 69992933..ceb865d2 100644 --- a/engine/server/sv_game.c +++ b/engine/server/sv_game.c @@ -100,17 +100,17 @@ void SV_SetMinMaxSize( edict_t *e, const float *min, const float *max ) void SV_CopyTraceToGlobal( trace_t *trace ) { - svgame.globals->trace_allsolid = trace->fAllSolid; - svgame.globals->trace_startsolid = trace->fStartSolid; - svgame.globals->trace_fraction = trace->flFraction; - svgame.globals->trace_plane_dist = trace->flPlaneDist; - svgame.globals->trace_ent = trace->pHit; + svgame.globals->trace_allsolid = trace->allsolid; + svgame.globals->trace_startsolid = trace->startsolid; + svgame.globals->trace_fraction = trace->fraction; + svgame.globals->trace_plane_dist = trace->plane.dist; + svgame.globals->trace_ent = trace->ent; svgame.globals->trace_flags = 0; - svgame.globals->trace_inopen = trace->fInOpen; - svgame.globals->trace_inwater = trace->fInWater; - VectorCopy( trace->vecEndPos, svgame.globals->trace_endpos ); - VectorCopy( trace->vecPlaneNormal, svgame.globals->trace_plane_normal ); - svgame.globals->trace_hitgroup = trace->iHitgroup; + svgame.globals->trace_inopen = trace->inopen; + svgame.globals->trace_inwater = trace->inwater; + VectorCopy( trace->endpos, svgame.globals->trace_endpos ); + VectorCopy( trace->plane.normal, svgame.globals->trace_plane_normal ); + svgame.globals->trace_hitgroup = trace->hitgroup; } void SV_SetModel( edict_t *ent, const char *name ) @@ -170,23 +170,27 @@ float SV_AngleMod( float ideal, float current, float speed ) return anglemod( current + move ); } -void SV_ConfigString( int index, const char *val ) +/* +============= +SV_ConvertTrace + +convert trace_t to TraceResult +============= +*/ +void SV_ConvertTrace( TraceResult *dst, trace_t *src ) { - if( index < 0 || index >= MAX_CONFIGSTRINGS ) - Host_Error( "SV_ConfigString: bad index %i value %s\n", index, val ); + ASSERT( src != NULL && dst != NULL ); - if( !val || !*val ) val = ""; - - // change the string in sv - com.strcpy( sv.configstrings[index], val ); - - if( sv.state != ss_loading ) - { - // send the update to everyone - BF_WriteByte( &sv.reliable_datagram, svc_configstring ); - BF_WriteShort( &sv.reliable_datagram, index ); - BF_WriteString( &sv.reliable_datagram, val ); - } + dst->fAllSolid = src->allsolid; + dst->fStartSolid = src->startsolid; + dst->fInOpen = src->inopen; + dst->fInWater = src->inwater; + dst->flFraction = src->fraction; + VectorCopy( src->endpos, dst->vecEndPos ); + dst->flPlaneDist = src->plane.dist; + VectorCopy( src->plane.normal, dst->vecPlaneNormal ); + dst->pHit = src->ent; + dst->iHitgroup = src->hitgroup; } /* @@ -1410,15 +1414,15 @@ int pfnDropToFloor( edict_t* e ) trace = SV_Move( e->v.origin, e->v.mins, e->v.maxs, end, MOVE_NORMAL, e ); - if( trace.flFraction == 1.0f || trace.fAllSolid ) + if( trace.fraction == 1.0f || trace.allsolid ) { return false; } - VectorCopy( trace.vecEndPos, e->v.origin ); + VectorCopy( trace.endpos, e->v.origin ); SV_LinkEdict( e, false ); e->v.flags |= FL_ONGROUND; - e->v.groundentity = trace.pHit; + e->v.groundentity = trace.ent; return true; } @@ -1759,14 +1763,17 @@ pfnTraceLine */ static void pfnTraceLine( const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ) { + trace_t trace; + if( !ptr ) return; if( svgame.globals->trace_flags & 1 ) fNoMonsters |= FMOVE_SIMPLEBOX; svgame.globals->trace_flags = 0; - *ptr = SV_Move( v1, vec3_origin, vec3_origin, v2, fNoMonsters, pentToSkip ); - SV_CopyTraceToGlobal( ptr ); + trace = SV_Move( v1, vec3_origin, vec3_origin, v2, fNoMonsters, pentToSkip ); + SV_ConvertTrace( ptr, &trace ); + SV_CopyTraceToGlobal( &trace ); } /* @@ -1777,6 +1784,8 @@ pfnTraceToss */ static void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr ) { + trace_t trace; + if( !ptr ) return; if( !SV_IsValidEdict( pent )) @@ -1785,8 +1794,9 @@ static void pfnTraceToss( edict_t* pent, edict_t* pentToIgnore, TraceResult *ptr return; } - *ptr = SV_MoveToss( pent, pentToIgnore ); - SV_CopyTraceToGlobal( ptr ); + trace = SV_MoveToss( pent, pentToIgnore ); + SV_ConvertTrace( ptr, &trace ); + SV_CopyTraceToGlobal( &trace ); } /* @@ -1797,14 +1807,17 @@ pfnTraceHull */ static void pfnTraceHull( const float *v1, const float *v2, int fNoMonsters, int hullNumber, edict_t *pentToSkip, TraceResult *ptr ) { + trace_t trace; + if( !ptr ) return; if( svgame.globals->trace_flags & 1 ) fNoMonsters |= FMOVE_SIMPLEBOX; svgame.globals->trace_flags = 0; - *ptr = SV_MoveHull( v1, hullNumber, v2, fNoMonsters, pentToSkip ); - SV_CopyTraceToGlobal( ptr ); + trace = SV_MoveHull( v1, hullNumber, v2, fNoMonsters, pentToSkip ); + SV_ConvertTrace( ptr, &trace ); + SV_CopyTraceToGlobal( &trace ); } /* @@ -1815,7 +1828,7 @@ pfnTraceMonsterHull */ static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v2, int fNoMonsters, edict_t *pentToSkip, TraceResult *ptr ) { - trace_t result; + trace_t trace; if( !SV_IsValidEdict( pEdict )) { @@ -1827,14 +1840,14 @@ static int pfnTraceMonsterHull( edict_t *pEdict, const float *v1, const float *v fNoMonsters |= FMOVE_SIMPLEBOX; svgame.globals->trace_flags = 0; - result = SV_Move( v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip ); + trace = SV_Move( v1, pEdict->v.mins, pEdict->v.maxs, v2, fNoMonsters, pentToSkip ); if( ptr ) { - SV_CopyTraceToGlobal( ptr ); - *ptr = result; + SV_ConvertTrace( ptr, &trace ); + SV_CopyTraceToGlobal( &trace ); } - if( result.fAllSolid || result.flFraction != 1.0f ) + if( trace.allsolid || trace.fraction != 1.0f ) return true; return false; } @@ -1848,6 +1861,7 @@ pfnTraceModel static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edict_t *pent, TraceResult *ptr ) { float *mins, *maxs; + trace_t trace; if( !ptr ) return; @@ -1861,8 +1875,9 @@ static void pfnTraceModel( const float *v1, const float *v2, int hullNumber, edi mins = sv.worldmodel->hulls[hullNumber].clip_mins; maxs = sv.worldmodel->hulls[hullNumber].clip_maxs; - *ptr = SV_TraceHull( pent, hullNumber, v1, mins, maxs, v2 ); - SV_CopyTraceToGlobal( ptr ); + trace = SV_TraceHull( pent, hullNumber, v1, mins, maxs, v2 ); + SV_ConvertTrace( ptr, &trace ); + SV_CopyTraceToGlobal( &trace ); } /* @@ -1940,7 +1955,7 @@ void pfnGetAimVector( edict_t* ent, float speed, float *rgflReturn ) VectorMA( start, 2048, dir, end ); tr = SV_Move( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent ); - if( tr.pHit && (tr.pHit->v.takedamage == DAMAGE_AIM && fNoFriendlyFire || ent->v.team <= 0 || ent->v.team != tr.pHit->v.team )) + if( tr.ent && (tr.ent->v.takedamage == DAMAGE_AIM && fNoFriendlyFire || ent->v.team <= 0 || ent->v.team != tr.ent->v.team )) { VectorCopy( svgame.globals->v_forward, rgflReturn ); return; @@ -1965,7 +1980,7 @@ void pfnGetAimVector( edict_t* ent, float speed, float *rgflReturn ) dist = DotProduct( dir, svgame.globals->v_forward ); if( dist < bestdist ) continue; // to far to turn tr = SV_Move( start, vec3_origin, vec3_origin, end, MOVE_NORMAL, ent ); - if( tr.pHit == check ) + if( tr.ent == check ) { // can shoot at this one bestdist = dist; @@ -2682,9 +2697,12 @@ returns pointer to a studiomodel */ static void *pfnGetModelPtr( edict_t* pEdict ) { + model_t *mod; + if( !pEdict || pEdict->free ) return NULL; - return Mod_Extradata( pEdict->v.modelindex ); + mod = CM_ClipHandleToModel( pEdict->v.modelindex ); + return Mod_Extradata( mod ); } /* @@ -3892,7 +3910,7 @@ qboolean pfnVoice_GetClientListening( int iReceiver, int iSender ) return false; } - return ((svs.clients[iSender].listeners & ( 1 << iReceiver )) != 0 ); + return ((svs.clients[iSender-1].listeners & ( 1 << iReceiver )) != 0 ); } /* @@ -3915,11 +3933,11 @@ qboolean pfnVoice_SetClientListening( int iReceiver, int iSender, qboolean bList if( bListen ) { - svs.clients[iSender].listeners |= (1 << iReceiver); + svs.clients[iSender-1].listeners |= (1 << iReceiver); } else { - svs.clients[iSender].listeners &= ~(1 << iReceiver); + svs.clients[iSender-1].listeners &= ~(1 << iReceiver); } return true; } @@ -4416,6 +4434,14 @@ qboolean SV_LoadProgs( const char *name ) } } + if( !SV_InitStudioAPI( )) + { + FS_FreeLibrary( svgame.hInstance ); + MsgDev( D_ERROR, "SV_LoadProgs: couldn't get studio API\n" ); + svgame.hInstance = NULL; + return false; + } + svgame.globals->pStringBase = ""; // setup string base svgame.globals->maxEntities = GI->max_edicts; diff --git a/engine/server/sv_move.c b/engine/server/sv_move.c index 27847a97..35e68a18 100644 --- a/engine/server/sv_move.c +++ b/engine/server/sv_move.c @@ -61,9 +61,9 @@ realcheck: trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_WORLDONLY, ent ); else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent ); - if( trace.flFraction == 1.0f ) + if( trace.fraction == 1.0f ) return false; - mid = bottom = trace.vecEndPos[2]; + mid = bottom = trace.endpos[2]; // the corners must be within 16 of the midpoint for( x = 0; x <= 1; x++ ) @@ -77,9 +77,9 @@ realcheck: trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_WORLDONLY, ent ); else trace = SV_Move( start, vec3_origin, vec3_origin, stop, MOVE_NORMAL, ent ); - if( trace.flFraction != 1.0f && trace.vecEndPos[2] > bottom ) - bottom = trace.vecEndPos[2]; - if( trace.flFraction == 1.0f || mid - trace.vecEndPos[2] > svgame.movevars.stepsize ) + if( trace.fraction != 1.0f && trace.endpos[2] > bottom ) + bottom = trace.endpos[2]; + if( trace.fraction == 1.0f || mid - trace.endpos[2] > svgame.movevars.stepsize ) return false; } } @@ -141,18 +141,18 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink ) trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, neworg, MOVE_NORMAL, ent ); - if( trace.flFraction == 1.0f ) + if( trace.fraction == 1.0f ) { svs.groupmask = ent->v.groupinfo; // that move takes us out of the water. // apparently though, it's okay to travel into solids, lava, sky, etc :) - if(( ent->v.flags & FL_SWIM ) && SV_PointContents( trace.vecEndPos ) == CONTENTS_EMPTY ) + if(( ent->v.flags & FL_SWIM ) && SV_PointContents( trace.endpos ) == CONTENTS_EMPTY ) { return 0; } - VectorCopy( trace.vecEndPos, ent->v.origin ); + VectorCopy( trace.endpos, ent->v.origin ); if( relink != 0 ) { @@ -177,19 +177,19 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink ) end[2] -= dz * 2.0f; trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); - if( trace.fAllSolid != 0 ) + if( trace.allsolid != 0 ) return 0; - if( trace.fStartSolid != 0 ) + if( trace.startsolid != 0 ) { neworg[2] -= dz; trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); - if( trace.fAllSolid != 0 || trace.fStartSolid != 0 ) + if( trace.allsolid != 0 || trace.startsolid != 0 ) return 0; } - if( trace.flFraction == 1.0f ) + if( trace.fraction == 1.0f ) { if( ent->v.flags & FL_PARTIALGROUND ) { @@ -205,7 +205,7 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink ) } else { - VectorCopy( trace.vecEndPos, ent->v.origin ); + VectorCopy( trace.endpos, ent->v.origin ); if( SV_CheckBottom( ent, MOVE_NORMAL ) == 0 ) { @@ -226,7 +226,7 @@ qboolean SV_MoveStep( edict_t *ent, vec3_t move, qboolean relink ) if( ent->v.flags & FL_PARTIALGROUND ) ent->v.flags &= ~FL_PARTIALGROUND; - ent->v.groundentity = trace.pHit; + ent->v.groundentity = trace.ent; if( relink != 0 ) { @@ -255,19 +255,19 @@ qboolean SV_MoveTest( edict_t *ent, vec3_t move, qboolean relink ) trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent ); - if( trace.fAllSolid != 0 ) + if( trace.allsolid != 0 ) return 0; - if( trace.fStartSolid != 0 ) + if( trace.startsolid != 0 ) { neworg[2] -= temp; trace = SV_Move( neworg, ent->v.mins, ent->v.maxs, end, MOVE_WORLDONLY, ent ); - if( trace.fAllSolid != 0 || trace.fStartSolid != 0 ) + if( trace.allsolid != 0 || trace.startsolid != 0 ) return 0; } - if( trace.flFraction == 1.0f ) + if( trace.fraction == 1.0f ) { if( ent->v.flags & FL_PARTIALGROUND ) { @@ -283,7 +283,7 @@ qboolean SV_MoveTest( edict_t *ent, vec3_t move, qboolean relink ) } else { - VectorCopy( trace.vecEndPos, ent->v.origin ); + VectorCopy( trace.endpos, ent->v.origin ); if( SV_CheckBottom( ent, MOVE_WORLDONLY ) == 0 ) { @@ -304,7 +304,7 @@ qboolean SV_MoveTest( edict_t *ent, vec3_t move, qboolean relink ) if( ent->v.flags & FL_PARTIALGROUND ) ent->v.flags &= ~FL_PARTIALGROUND; - ent->v.groundentity = trace.pHit; + ent->v.groundentity = trace.ent; if( relink != 0 ) { diff --git a/engine/server/sv_phys.c b/engine/server/sv_phys.c index 0eef007a..eab089d7 100644 --- a/engine/server/sv_phys.c +++ b/engine/server/sv_phys.c @@ -167,7 +167,7 @@ Two entities have touched, so run their touch functions */ void SV_Impact( edict_t *e1, trace_t *trace ) { - edict_t *e2 = trace->pHit; + edict_t *e2 = trace->ent; // custom user filter if( svgame.dllFuncs2.pfnShouldCollide ) @@ -387,40 +387,40 @@ int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace ) VectorMA( ent->v.origin, time_left, ent->v.velocity, end ); trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent ); - allFraction += trace.flFraction; + allFraction += trace.fraction; - if( trace.fAllSolid ) + if( trace.allsolid ) { // entity is trapped in another solid VectorClear( ent->v.velocity ); return 4; } - if( trace.flFraction > 0.0f ) + if( trace.fraction > 0.0f ) { // actually covered some distance - VectorCopy( trace.vecEndPos, ent->v.origin ); + VectorCopy( trace.endpos, ent->v.origin ); VectorCopy( ent->v.velocity, original_velocity ); numplanes = 0; } - if( trace.flFraction == 1.0f ) + if( trace.fraction == 1.0f ) break; // moved the entire distance - if( !trace.pHit ) - MsgDev( D_ERROR, "SV_FlyMove: trace.pHit == NULL\n" ); + if( !trace.ent ) + MsgDev( D_ERROR, "SV_FlyMove: trace.ent == NULL\n" ); - if( trace.vecPlaneNormal[2] > 0.7f ) + if( trace.plane.normal[2] > 0.7f ) { blocked |= 1; // floor - if( trace.pHit->v.solid == SOLID_BSP ) + if( trace.ent->v.solid == SOLID_BSP ) { ent->v.flags |= FL_ONGROUND; - ent->v.groundentity = trace.pHit; + ent->v.groundentity = trace.ent; } } - if( trace.vecPlaneNormal[2] == 0.0f ) + if( trace.plane.normal[2] == 0.0f ) { blocked |= 2; // step if( steptrace ) *steptrace = trace; // save for player extrafriction @@ -432,7 +432,7 @@ int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace ) // break if removed by the impact function if( ent->free ) break; - time_left -= time_left * trace.flFraction; + time_left -= time_left * trace.fraction; // clipped to another plane if( numplanes >= MAX_CLIP_PLANES ) @@ -442,7 +442,7 @@ int SV_FlyMove( edict_t *ent, float time, trace_t *steptrace ) break; } - VectorCopy( trace.vecPlaneNormal, planes[numplanes] ); + VectorCopy( trace.plane.normal, planes[numplanes] ); numplanes++; // modify original_velocity so it parallels all of the clip planes @@ -564,9 +564,9 @@ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int else type = MOVE_NORMAL; trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, end, type, ent ); - if( !trace.fAllSolid && !trace.fStartSolid ) + if( !trace.allsolid && !trace.startsolid ) { - VectorCopy( trace.vecEndPos, ent->v.origin ); + VectorCopy( trace.endpos, ent->v.origin ); SV_LinkEdict( ent, true ); if( apush[YAW] && ent->v.flags & FL_CLIENT && ( cl = SV_ClientFromEdict( ent, true )) != NULL ) @@ -578,14 +578,14 @@ trace_t SV_PushEntity( edict_t *ent, const vec3_t lpush, const vec3_t apush, int // don't rotate pushables! if( ent->v.movetype != MOVETYPE_PUSHSTEP ) { - ent->v.angles[YAW] += trace.flFraction * apush[YAW]; + ent->v.angles[YAW] += trace.fraction * apush[YAW]; } } if( blocked ) *blocked = !VectorCompare( ent->v.origin, end ); // can't move full distance // so we can run impact function afterwards. - if( trace.pHit ) SV_Impact( ent, &trace ); + if( trace.ent ) SV_Impact( ent, &trace ); return trace; } @@ -1177,19 +1177,19 @@ void SV_Physics_Toss( edict_t *ent ) SV_CheckVelocity( ent ); // make sure what we don't collide with like entity (e.g. gib with gib) - if( trace.fAllSolid && SV_IsValidEdict( trace.pHit ) && trace.pHit->v.movetype != ent->v.movetype ) + if( trace.allsolid && SV_IsValidEdict( trace.ent ) && trace.ent->v.movetype != ent->v.movetype ) { // entity is trapped in another solid - if( trace.vecPlaneNormal[2] > 0.7f ) + if( trace.plane.normal[2] > 0.7f ) { - ent->v.groundentity = trace.pHit; + ent->v.groundentity = trace.ent; ent->v.flags |= FL_ONGROUND; } VectorClear( ent->v.velocity ); return; } - if( trace.flFraction == 1.0f ) + if( trace.fraction == 1.0f ) { SV_CheckWater( ent ); return; @@ -1201,10 +1201,10 @@ void SV_Physics_Toss( edict_t *ent ) backoff = 2.0f; else backoff = 1.0f; - SV_ClipVelocity( ent->v.velocity, trace.vecPlaneNormal, ent->v.velocity, backoff ); + SV_ClipVelocity( ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff ); // stop if on ground - if( trace.vecPlaneNormal[2] > 0.7f ) + if( trace.plane.normal[2] > 0.7f ) { float vel; @@ -1212,7 +1212,7 @@ void SV_Physics_Toss( edict_t *ent ) if( ent->v.velocity[2] < sv_gravity->value * sv_frametime( )) { // we're rolling on the ground, add static friction. - ent->v.groundentity = trace.pHit; + ent->v.groundentity = trace.ent; ent->v.flags |= FL_ONGROUND; ent->v.velocity[2] = 0.0f; } @@ -1222,12 +1222,12 @@ void SV_Physics_Toss( edict_t *ent ) if( vel < 900 || ( ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE )) { ent->v.flags |= FL_ONGROUND; - ent->v.groundentity = trace.pHit; + ent->v.groundentity = trace.ent; VectorClear( ent->v.velocity ); // avelocity clearing in server.dll } else { - VectorScale( ent->v.velocity, (1.0f - trace.flFraction) * sv_frametime() * 0.9f, move ); + VectorScale( ent->v.velocity, (1.0f - trace.fraction) * sv_frametime() * 0.9f, move ); trace = SV_PushEntity( ent, move, vec3_origin, NULL ); if( ent->free ) return; } @@ -1390,10 +1390,10 @@ void SV_Physics_Step( edict_t *ent ) trace = SV_Move( point, vec3_origin, vec3_origin, point, MOVE_NORMAL, ent ); - if( trace.fStartSolid ) + if( trace.startsolid ) { ent->v.flags |= FL_ONGROUND; - ent->v.groundentity = trace.pHit; + ent->v.groundentity = trace.ent; ent->v.friction = 1.0f; break; } @@ -1412,7 +1412,7 @@ void SV_Physics_Step( edict_t *ent ) { // check monster with another monster intersect (e.g. tentacle damage) trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent ); - pHit = trace.pHit; + pHit = trace.ent; if( SV_IsValidEdict( pHit ) && pHit->v.flags & FL_MONSTER && pHit->v.deadflag == DEAD_NO ) SV_Impact( ent, &trace ); @@ -1459,7 +1459,7 @@ static void SV_Physics_Client( edict_t *ent ) // check client colliding with monster (e.g. tentacle damage) trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent ); - pHit = trace.pHit; + pHit = trace.ent; if( SV_IsValidEdict( pHit ) && pHit->v.flags & FL_MONSTER && pHit->v.deadflag == DEAD_NO ) SV_Impact( ent, &trace ); diff --git a/engine/server/sv_pmove.c b/engine/server/sv_pmove.c index 5473178a..7d039b3c 100644 --- a/engine/server/sv_pmove.c +++ b/engine/server/sv_pmove.c @@ -327,37 +327,22 @@ static hull_t *pfnHullForBsp( physent_t *pe, float *offset ) return PM_HullForBsp( pe, mins, maxs, offset ); } -static float pfnTraceModel( physent_t *pEnt, float *start, float *end, void *rawTrace ) +static float pfnTraceModel( physent_t *pEnt, float *start, float *end, trace_t *trace ) { - trace_t *result; - pmtrace_t trace; + pmtrace_t pmtrace; - PM_TraceModel( pEnt, start, vec3_origin, vec3_origin, end, &trace, PM_STUDIO_BOX ); + PM_TraceModel( pEnt, start, vec3_origin, vec3_origin, end, &pmtrace, PM_STUDIO_BOX ); - // copy pmtrace_t to rawTrace - if( rawTrace ) + // copy pmtrace_t to trace_t + if( trace ) { - // NOTE: in original HL stupid fucking coders declared three different traces: - // TraceResult, trace_t and pmtrace_t. In Xash3D trace_t is equal TraceResult - // but in HL this is has some differences: plane.dist and plane.normal are swapped. - // don't forget about it - result = (trace_t *)rawTrace; - - result->fAllSolid = trace.allsolid; - result->fStartSolid = trace.startsolid; - result->fInOpen = trace.inopen; - result->fInWater = trace.inwater; - result->flFraction = trace.fraction; - VectorCopy( result->vecEndPos, trace.endpos ); - result->flPlaneDist = trace.plane.normal[0]; - result->vecPlaneNormal[0] = trace.plane.normal[1]; - result->vecPlaneNormal[1] = trace.plane.normal[2]; - result->vecPlaneNormal[2] = trace.plane.dist; - result->iHitgroup = trace.hitgroup; - result->pHit = NULL; // no acess to edicts from pm_* code + // NOTE: if pmtrace.h is changed is must be changed too + Mem_Copy( trace, &pmtrace, sizeof( *trace )); + trace->hitgroup = pmtrace.hitgroup; + trace->ent = NULL; } - return trace.fraction; + return pmtrace.fraction; } static const char *pfnTraceTexture( int ground, float *vstart, float *vend ) diff --git a/engine/server/sv_save.c b/engine/server/sv_save.c index e9dfd26e..e96eec1b 100644 --- a/engine/server/sv_save.c +++ b/engine/server/sv_save.c @@ -403,19 +403,19 @@ void ReapplyDecal( SAVERESTOREDATA *pSaveData, decallist_t *entry, qboolean adja tr = SV_Move( testspot, vec3_origin, vec3_origin, testend, MOVE_NOMONSTERS, NULL ); - if( tr.flFraction != 1.0f && !tr.fAllSolid ) + if( tr.fraction != 1.0f && !tr.allsolid ) { // check impact plane normal - float dot = DotProduct( entry->impactPlaneNormal, tr.vecPlaneNormal ); + float dot = DotProduct( entry->impactPlaneNormal, tr.plane.normal ); if( dot >= 0.95f ) { - entityIndex = pfnIndexOfEdict( tr.pHit ); + entityIndex = pfnIndexOfEdict( tr.ent ); if( entityIndex > 0 ) - modelIndex = tr.pHit->v.modelindex; + modelIndex = tr.ent->v.modelindex; // FIXME: probably some rotating or moving objects can't receive decal properly - SV_CreateDecal( tr.vecEndPos, decalIndex, entityIndex, modelIndex, flags ); + SV_CreateDecal( tr.endpos, decalIndex, entityIndex, modelIndex, flags ); } } } diff --git a/engine/server/sv_studio.c b/engine/server/sv_studio.c index 1129279c..e310c733 100644 --- a/engine/server/sv_studio.c +++ b/engine/server/sv_studio.c @@ -8,17 +8,21 @@ #include "common.h" #include "server.h" #include "studio.h" +#include "r_studioint.h" #include "matrix_lib.h" -static studiohdr_t *sv_studiohdr; -static mplane_t sv_hitboxplanes[6]; // there a temp hitbox -static matrix4x4 sv_studiomatrix; -static matrix4x4 sv_studiobones[MAXSTUDIOBONES]; -typedef qboolean (*pfnHitboxTrace)( trace_t *trace ); -static vec3_t trace_startmins, trace_endmins; -static vec3_t trace_startmaxs, trace_endmaxs; -static vec3_t trace_absmins, trace_absmaxs; -static float trace_realfraction; +typedef int (*STUDIOAPI)( int, sv_blending_interface_t*, server_studio_api_t*, matrix4x4, matrix4x4[MAXSTUDIOBONES] ); + +static studiohdr_t *sv_studiohdr; +static mplane_t sv_hitboxplanes[6]; // there a temp hitbox +static matrix4x4 sv_studiomatrix; +static matrix4x4 sv_studiobones[MAXSTUDIOBONES]; +typedef qboolean (*pfnHitboxTrace)( trace_t *trace ); +static vec3_t trace_startmins, trace_endmins; +static vec3_t trace_startmaxs, trace_endmaxs; +static vec3_t trace_absmins, trace_absmaxs; +static float trace_realfraction; +static sv_blending_interface_t *pBlendAPI; /* ==================== @@ -316,12 +320,12 @@ StudioCalcRotations ==================== */ -static void SV_StudioCalcRotations( edict_t *ent, float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) +static void SV_StudioCalcRotations( const edict_t *ent, int boneused[], int numbones, const byte *pcontroller, float pos[][3], vec4_t *q, mstudioseqdesc_t *pseqdesc, mstudioanim_t *panim, float f ) { - int i, frame; + int i, j, frame; mstudiobone_t *pbone; float adj[MAXSTUDIOCONTROLLERS]; - float s, dadt = 1.0f; // noInterp + float s; if( f > pseqdesc->numframes - 1 ) f = 0; @@ -334,12 +338,13 @@ static void SV_StudioCalcRotations( edict_t *ent, float pos[][3], vec4_t *q, mst // add in programtic controllers pbone = (mstudiobone_t *)((byte *)sv_studiohdr + sv_studiohdr->boneindex); - SV_StudioCalcBoneAdj( dadt, adj, ent->v.controller, ent->v.controller ); + SV_StudioCalcBoneAdj( 1.0f, adj, pcontroller, pcontroller ); - for( i = 0; i < sv_studiohdr->numbones; i++, pbone++, panim++ ) + for( j = numbones - 1; j >= 0; j-- ) { - SV_StudioCalcBoneQuaterion( frame, s, pbone, panim, adj, q[i] ); - SV_StudioCalcBonePosition( frame, s, pbone, panim, adj, pos[i] ); + i = boneused[j]; + SV_StudioCalcBoneQuaterion( frame, s, &pbone[i], &panim[i], adj, q[i] ); + SV_StudioCalcBonePosition( frame, s, &pbone[i], &panim[i], adj, pos[i] ); } if( pseqdesc->motiontype & STUDIO_X ) pos[pseqdesc->motionbone][0] = 0.0f; @@ -359,13 +364,13 @@ StudioEstimateFrame ==================== */ -static float SV_StudioEstimateFrame( edict_t *ent, mstudioseqdesc_t *pseqdesc ) +static float SV_StudioEstimateFrame( float frame, mstudioseqdesc_t *pseqdesc ) { double f; if( pseqdesc->numframes <= 1 ) f = 0; - else f = (ent->v.frame * ( pseqdesc->numframes - 1 )) / 256.0; + else f = ( frame * ( pseqdesc->numframes - 1 )) / 256.0; if( pseqdesc->flags & STUDIO_LOOPING ) { @@ -459,17 +464,20 @@ static mstudioanim_t *SV_StudioGetAnim( model_t *m_pSubModel, mstudioseqdesc_t * /* ==================== StudioSetupBones + +NOTE: pEdict is unused ==================== */ -static void SV_StudioSetupBones( edict_t *ent ) +static void SV_StudioSetupBones( model_t *pModel, float frame, int sequence, const vec3_t angles, const vec3_t origin, + const byte *pcontroller, const byte *pblending, int iBone, const edict_t *pEdict ) { - int i; + int i, j, numbones; + int boneused[MAXSTUDIOBONES]; double f; mstudiobone_t *pbones; mstudioseqdesc_t *pseqdesc; mstudioanim_t *panim; - model_t *m_pModel; static float pos[MAXSTUDIOBONES][3]; static vec4_t q[MAXSTUDIOBONES]; @@ -482,15 +490,38 @@ static void SV_StudioSetupBones( edict_t *ent ) static float pos4[MAXSTUDIOBONES][3]; static vec4_t q4[MAXSTUDIOBONES]; - m_pModel = CM_ClipHandleToModel( ent->v.modelindex ); + if( sequence >= sv_studiohdr->numseq ) sequence = 0; + pseqdesc = (mstudioseqdesc_t *)((byte *)sv_studiohdr + sv_studiohdr->seqindex) + sequence; + pbones = (mstudiobone_t *)((byte *)sv_studiohdr + sv_studiohdr->boneindex); - if( ent->v.sequence >= sv_studiohdr->numseq ) ent->v.sequence = 0; - pseqdesc = (mstudioseqdesc_t *)((byte *)sv_studiohdr + sv_studiohdr->seqindex) + ent->v.sequence; + if( iBone < -1 || iBone >= sv_studiohdr->numbones ) + { + iBone = 0; + } - f = SV_StudioEstimateFrame( ent, pseqdesc ); + numbones = 0; - panim = SV_StudioGetAnim( m_pModel, pseqdesc ); - SV_StudioCalcRotations( ent, pos, q, pseqdesc, panim, f ); + if( iBone == -1 ) + { + numbones = sv_studiohdr->numbones; + for( i = 0; i < sv_studiohdr->numbones; i++ ) + { + boneused[(numbones - i) - 1] = i; + } + } + else + { + for( i = iBone; i != -1; i = pbones[i].parent ) + { + boneused[numbones] = i; + numbones++; + } + } + + f = SV_StudioEstimateFrame( frame, pseqdesc ); + + panim = SV_StudioGetAnim( pModel, pseqdesc ); + SV_StudioCalcRotations( pEdict, boneused, numbones, pcontroller, pos, q, pseqdesc, panim, f ); if( pseqdesc->numblends > 1 ) { @@ -498,32 +529,31 @@ static void SV_StudioSetupBones( edict_t *ent ) float dadt = 1.0f; panim += sv_studiohdr->numbones; - SV_StudioCalcRotations( ent, pos2, q2, pseqdesc, panim, f ); + SV_StudioCalcRotations( pEdict, boneused, numbones, pcontroller, pos2, q2, pseqdesc, panim, f ); - s = (ent->v.blending[0] * dadt + ent->v.blending[0] * ( 1.0f - dadt )) / 255.0f; + s = (float)pblending[0] / 255.0f; SV_StudioSlerpBones( q, pos, q2, pos2, s ); if( pseqdesc->numblends == 4 ) { panim += sv_studiohdr->numbones; - SV_StudioCalcRotations( ent, pos3, q3, pseqdesc, panim, f ); + SV_StudioCalcRotations( pEdict, boneused, numbones, pcontroller, pos3, q3, pseqdesc, panim, f ); panim += sv_studiohdr->numbones; - SV_StudioCalcRotations( ent, pos4, q4, pseqdesc, panim, f ); + SV_StudioCalcRotations( pEdict, boneused, numbones, pcontroller, pos4, q4, pseqdesc, panim, f ); - s = ( ent->v.blending[0] * dadt + ent->v.blending[0] * ( 1.0f - dadt )) / 255.0f; + s = (float)pblending[0] / 255.0f; SV_StudioSlerpBones( q3, pos3, q4, pos4, s ); - s = ( ent->v.blending[1] * dadt + ent->v.blending[1] * ( 1.0f - dadt )) / 255.0f; + s = (float)pblending[1] / 255.0f; SV_StudioSlerpBones( q, pos, q3, pos3, s ); } } - pbones = (mstudiobone_t *)((byte *)sv_studiohdr + sv_studiohdr->boneindex); - - for( i = 0; i < sv_studiohdr->numbones; i++ ) + for( j = numbones - 1; j >= 0; j-- ) { + i = boneused[j]; Matrix4x4_FromOriginQuat( bonematrix, pos[i][0], pos[i][1], pos[i][2], q[i][0], q[i][1], q[i][2], q[i][3] ); if( pbones[i].parent == -1 ) Matrix4x4_ConcatTransforms( sv_studiobones[i], sv_studiomatrix, bonematrix ); @@ -533,65 +563,21 @@ static void SV_StudioSetupBones( edict_t *ent ) /* ==================== -StudioCalcAttachments +StudioSetupModel ==================== */ -static qboolean SV_StudioCalcAttachments( edict_t *e, int iAttachment, float *org, float *ang ) +static qboolean SV_StudioSetupModel( edict_t *ent, int iBone ) { - int i; - mstudioattachment_t *pAtt; - vec3_t axis[3]; - vec3_t localOrg, localAng; - void *hdr = Mod_Extradata( e->v.modelindex ); - - if( !hdr ) return false; - - sv_studiohdr = (studiohdr_t *)hdr; - if( sv_studiohdr->numattachments <= 0 ) - return false; - - SV_StudioSetUpTransform( e ); - SV_StudioSetupBones( e ); - - if( sv_studiohdr->numattachments > MAXSTUDIOATTACHMENTS ) - { - sv_studiohdr->numattachments = MAXSTUDIOATTACHMENTS; // reduce it - MsgDev( D_WARN, "SV_StudioCalcAttahments: too many attachments on %s\n", sv_studiohdr->name ); - } - - iAttachment = bound( 0, iAttachment, sv_studiohdr->numattachments ); - - // calculate attachment points - pAtt = (mstudioattachment_t *)((byte *)sv_studiohdr + sv_studiohdr->attachmentindex); - - for( i = 0; i < sv_studiohdr->numattachments; i++ ) - { - if( i == iAttachment ) - { - // compute pos and angles - Matrix4x4_VectorTransform( sv_studiobones[pAtt[i].bone], pAtt[i].org, localOrg ); - Matrix4x4_VectorTransform( sv_studiobones[pAtt[i].bone], pAtt[i].vectors[0], axis[0] ); - Matrix4x4_VectorTransform( sv_studiobones[pAtt[i].bone], pAtt[i].vectors[1], axis[1] ); - Matrix4x4_VectorTransform( sv_studiobones[pAtt[i].bone], pAtt[i].vectors[2], axis[2] ); - Matrix3x3_ToAngles( axis, localAng, true ); // FIXME: dll's uses FLU ? - if( org ) VectorCopy( localOrg, org ); - if( ang ) VectorCopy( localAng, ang ); - break; // done - } - } - return true; -} - -static qboolean SV_StudioSetupModel( edict_t *ent ) -{ - void *hdr = Mod_Extradata( ent->v.modelindex ); + model_t *mod = CM_ClipHandleToModel( ent->v.modelindex ); + void *hdr = Mod_Extradata( mod ); if( !hdr ) return false; sv_studiohdr = (studiohdr_t *)hdr; SV_StudioSetUpTransform( ent ); - SV_StudioSetupBones( ent ); + pBlendAPI->SV_StudioSetupBones( mod, ent->v.frame, ent->v.sequence, ent->v.angles, ent->v.origin, + ent->v.controller, ent->v.blending, iBone, ent ); return true; } @@ -686,8 +672,8 @@ static qboolean SV_StudioTestToHitbox( trace_t *trace ) } // inside this hitbox - trace->flFraction = trace_realfraction = 0; - trace->fStartSolid = trace->fAllSolid = true; + trace->fraction = trace_realfraction = 0; + trace->startsolid = trace->allsolid = true; return true; } @@ -802,8 +788,8 @@ static qboolean SV_StudioClipToHitbox( trace_t *trace ) if( !startout ) { // original point was inside hitbox - trace->fStartSolid = true; - if( !getout ) trace->fAllSolid = true; + trace->startsolid = true; + if( !getout ) trace->allsolid = true; return true; } @@ -814,9 +800,9 @@ static qboolean SV_StudioClipToHitbox( trace_t *trace ) if( enterfrac < 0 ) enterfrac = 0; trace_realfraction = enterfrac; - trace->flFraction = enterfrac - DIST_EPSILON * distfrac; - VectorCopy( clipplane->normal, trace->vecPlaneNormal ); - trace->flPlaneDist = clipplane->dist; + trace->fraction = enterfrac - DIST_EPSILON * distfrac; + VectorCopy( clipplane->normal, trace->plane.normal ); + trace->plane.dist = clipplane->dist; return true; } } @@ -881,14 +867,14 @@ trace_t SV_TraceHitbox( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t ma // assume we didn't hit anything Mem_Set( &trace, 0, sizeof( trace_t )); - VectorCopy( end, trace.vecEndPos ); - trace.flFraction = trace_realfraction = 1.0f; - trace.iHitgroup = -1; + VectorCopy( end, trace.endpos ); + trace.fraction = trace_realfraction = 1.0f; + trace.hitgroup = -1; if( !SV_StudioIntersect( ent, start, mins, maxs, end )) return trace; - if( !SV_StudioSetupModel( ent )) + if( !SV_StudioSetupModel( ent, -1 )) // all bones used return trace; if( VectorCompare( start, end )) @@ -916,10 +902,10 @@ trace_t SV_TraceHitbox( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t ma if( TraceHitbox( &trace )) { outBone = phitbox->bone; - trace.iHitgroup = phitbox->group; + trace.hitgroup = phitbox->group; } - if( trace.fAllSolid ) + if( trace.allsolid ) break; } @@ -928,40 +914,102 @@ trace_t SV_TraceHitbox( edict_t *ent, const vec3_t start, vec3_t mins, vec3_t ma { vec3_t temp; - trace.pHit = ent; - VectorCopy( trace.vecPlaneNormal, temp ); - trace.flFraction = bound( 0, trace.flFraction, 1.0f ); - VectorLerp( start, trace.flFraction, end, trace.vecEndPos ); - Matrix4x4_TransformPositivePlane( sv_studiobones[outBone], temp, trace.flPlaneDist, trace.vecPlaneNormal, &trace.flPlaneDist ); + trace.ent = ent; + VectorCopy( trace.plane.normal, temp ); + trace.fraction = bound( 0, trace.fraction, 1.0f ); + VectorLerp( start, trace.fraction, end, trace.endpos ); + Matrix4x4_TransformPositivePlane( sv_studiobones[outBone], temp, trace.plane.dist, trace.plane.normal, &trace.plane.dist ); } return trace; } void SV_StudioGetAttachment( edict_t *e, int iAttachment, float *org, float *ang ) { - if( !SV_StudioCalcAttachments( e, iAttachment, org, ang )) - { - // reset attachments - if( org ) VectorCopy( e->v.origin, org ); - if( ang ) VectorCopy( e->v.angles, ang ); + mstudioattachment_t *pAtt; + vec3_t axis[3], bonepos; + vec3_t localOrg, localAng; + void *hdr; + + hdr = Mod_Extradata( CM_ClipHandleToModel( e->v.modelindex )); + if( !hdr ) return; + + sv_studiohdr = (studiohdr_t *)hdr; + if( sv_studiohdr->numattachments <= 0 ) return; + + if( sv_studiohdr->numattachments > MAXSTUDIOATTACHMENTS ) + { + sv_studiohdr->numattachments = MAXSTUDIOATTACHMENTS; // reduce it + MsgDev( D_WARN, "SV_StudioGetAttahment: too many attachments on %s\n", sv_studiohdr->name ); } + + iAttachment = bound( 0, iAttachment, sv_studiohdr->numattachments ); + + // calculate attachment origin and angles + pAtt = (mstudioattachment_t *)((byte *)sv_studiohdr + sv_studiohdr->attachmentindex); + + SV_StudioSetupModel( e, pAtt[iAttachment].bone ); + + // compute pos and angles + Matrix4x4_VectorTransform( sv_studiobones[pAtt[iAttachment].bone], pAtt[iAttachment].org, localOrg ); + Matrix4x4_OriginFromMatrix( sv_studiobones[pAtt[iAttachment].bone], bonepos ); + VectorSubtract( localOrg, bonepos, axis[0] ); // make forward + VectorNormalizeFast( axis[0] ); + VectorVectors( axis[0], axis[1], axis[2] ); // make right and up + Matrix3x3_ToAngles( axis, localAng, false ); // FIXME: dll's uses FLU ? + + if( org ) VectorCopy( localOrg, org ); + if( ang ) VectorCopy( localAng, ang ); } void SV_GetBonePosition( edict_t *e, int iBone, float *org, float *ang ) { matrix3x3 axis; - if( !SV_StudioSetupModel( e ) || sv_studiohdr->numbones <= 0 ) - { - // reset bones - if( org ) VectorCopy( e->v.origin, org ); - if( ang ) VectorCopy( e->v.angles, ang ); + if( !SV_StudioSetupModel( e, iBone ) || sv_studiohdr->numbones <= 0 ) return; - } iBone = bound( 0, iBone, sv_studiohdr->numbones ); Matrix3x3_FromMatrix4x4( axis, sv_studiobones[iBone] ); if( org ) Matrix4x4_OriginFromMatrix( sv_studiobones[iBone], org ); if( ang ) Matrix3x3_ToAngles( axis, ang, true ); +} + +static sv_blending_interface_t gBlendAPI = +{ + SV_BLENDING_INTERFACE_VERSION, + SV_StudioSetupBones, +}; + +static server_studio_api_t gStudioAPI = +{ + Mod_Calloc, + Mod_CacheCheck, + Mod_LoadCacheFile, + Mod_Extradata, +}; + +/* +=============== +SV_InitStudioAPI + +Initialize server studio (blending interface) +=============== +*/ +qboolean SV_InitStudioAPI( void ) +{ + static STUDIOAPI pBlendIface; + + pBlendAPI = &gBlendAPI; + + pBlendIface = (STUDIOAPI)FS_GetProcAddress( svgame.hInstance, "Server_GetBlendingInterface" ); + if( pBlendIface && pBlendIface( SV_BLENDING_INTERFACE_VERSION, pBlendAPI, &gStudioAPI, sv_studiomatrix, sv_studiobones )) + return true; + + // NOTE: we always return true even if game interface was not correct + // because SetupBones is used for hitbox tracing on the server-side + // just restore pointer to builtin function + pBlendAPI = &gBlendAPI; + + return true; } \ No newline at end of file diff --git a/engine/server/sv_world.c b/engine/server/sv_world.c index 7a4ffd80..936d4ffe 100644 --- a/engine/server/sv_world.c +++ b/engine/server/sv_world.c @@ -751,7 +751,7 @@ qboolean SV_TestEntityPosition( edict_t *ent ) trace = SV_Move( ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, MOVE_NORMAL, ent ); - return trace.fStartSolid; + return trace.startsolid; } /* @@ -795,12 +795,12 @@ qboolean SV_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec { if( num != CONTENTS_SOLID ) { - trace->fAllSolid = false; + trace->allsolid = false; if( num == CONTENTS_EMPTY ) - trace->fInOpen = true; - else trace->fInWater = true; + trace->inopen = true; + else trace->inwater = true; } - else trace->fStartSolid = true; + else trace->startsolid = true; return true; // empty } @@ -849,7 +849,7 @@ qboolean SV_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec return SV_RecursiveHullCheck (hull, node->children[side^1], midf, p2f, mid, p2, trace); } - if( trace->fAllSolid ) + if( trace->allsolid ) return false; // never got out of the solid area //================== @@ -857,13 +857,13 @@ qboolean SV_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec //================== if( !side ) { - VectorCopy( plane->normal, trace->vecPlaneNormal ); - trace->flPlaneDist = plane->dist; + VectorCopy( plane->normal, trace->plane.normal ); + trace->plane.dist = plane->dist; } else { - VectorNegate( plane->normal, trace->vecPlaneNormal ); - trace->flPlaneDist = -plane->dist; + VectorNegate( plane->normal, trace->plane.normal ); + trace->plane.dist = -plane->dist; } while( SV_HullPointContents( hull, hull->firstclipnode, mid ) == CONTENTS_SOLID ) @@ -873,8 +873,8 @@ qboolean SV_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec if( frac < 0.0f ) { - trace->flFraction = midf; - VectorCopy( mid, trace->vecEndPos ); + trace->fraction = midf; + VectorCopy( mid, trace->endpos ); MsgDev( D_WARN, "trace backed up 0.0\n" ); return false; } @@ -883,8 +883,8 @@ qboolean SV_RecursiveHullCheck( hull_t *hull, int num, float p1f, float p2f, vec VectorLerp( p1, frac, p2, mid ); } - trace->flFraction = midf; - VectorCopy( mid, trace->vecEndPos ); + trace->fraction = midf; + VectorCopy( mid, trace->endpos ); return false; } @@ -907,10 +907,10 @@ trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins // fill in a default trace Mem_Set( &trace, 0, sizeof( trace_t )); - VectorCopy( end, trace.vecEndPos ); - trace.flFraction = 1.0f; - trace.fAllSolid = true; - trace.iHitgroup = -1; + VectorCopy( end, trace.endpos ); + trace.fraction = 1.0f; + trace.allsolid = true; + trace.hitgroup = -1; // get the clipping hull hull = SV_HullForEntity( ent, hullNum, mins, maxs, offset ); @@ -948,29 +948,29 @@ trace_t SV_TraceHull( edict_t *ent, int hullNum, const vec3_t start, vec3_t mins // rotate endpos back to world frame of reference if( ent->v.solid == SOLID_BSP && !VectorIsNull( ent->v.angles )) { - if( trace.flFraction != 1.0f ) + if( trace.fraction != 1.0f ) { // compute endpos - VectorLerp( start, trace.flFraction, end, trace.vecEndPos ); + VectorLerp( start, trace.fraction, end, trace.endpos ); - VectorCopy( trace.vecPlaneNormal, temp ); - Matrix4x4_TransformPositivePlane( matrix, temp, trace.flPlaneDist, - trace.vecPlaneNormal, &trace.flPlaneDist ); + VectorCopy( trace.plane.normal, temp ); + Matrix4x4_TransformPositivePlane( matrix, temp, trace.plane.dist, + trace.plane.normal, &trace.plane.dist ); } } else { // special case for non-rotated bmodels // fix trace up by the offset - if( trace.flFraction != 1.0f ) - VectorAdd( trace.vecEndPos, offset, trace.vecEndPos ); + if( trace.fraction != 1.0f ) + VectorAdd( trace.endpos, offset, trace.endpos ); - trace.flPlaneDist = DotProduct( trace.vecEndPos, trace.vecPlaneNormal ); + trace.plane.dist = DotProduct( trace.endpos, trace.plane.normal ); } // did we clip the move? - if( trace.flFraction < 1.0f || trace.fStartSolid ) - trace.pHit = ent; + if( trace.fraction < 1.0f || trace.startsolid ) + trace.ent = ent; return trace; } @@ -1177,7 +1177,7 @@ static void SV_ClipToLinks( areanode_t *node, moveclip_t *clip ) } // might intersect, so do an exact clip - if( clip->trace.fAllSolid ) return; + if( clip->trace.allsolid ) return; traceHitbox = false; @@ -1362,8 +1362,8 @@ trace_t SV_MoveToss( edict_t *tossent, edict_t *ignore ) VectorScale( tossent->v.velocity, 0.05f, move ); VectorAdd( tossent->v.origin, move, end ); trace = SV_Move( tossent->v.origin, tossent->v.mins, tossent->v.maxs, end, MOVE_NORMAL, tossent ); - VectorCopy( trace.vecEndPos, tossent->v.origin ); - if( trace.flFraction < 1.0f ) break; + VectorCopy( trace.endpos, tossent->v.origin ); + if( trace.fraction < 1.0f ) break; } VectorCopy( original_origin, tossent->v.origin ); diff --git a/game_launch/game.cpp b/game_launch/game.cpp index 257b0bb4..3f51fd43 100644 --- a/game_launch/game.cpp +++ b/game_launch/game.cpp @@ -35,7 +35,7 @@ int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdL { HINSTANCE hmain; - if(( hmain = LoadLibrary( "bin\\launch.dll" )) == NULL ) + if(( hmain = LoadLibrary( "launch.dll" )) == NULL ) { Sys_Error( "Unable to load the launch.dll" ); } diff --git a/game_shared/bitvec.h b/game_shared/bitvec.h new file mode 100644 index 00000000..0271a117 --- /dev/null +++ b/game_shared/bitvec.h @@ -0,0 +1,179 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef BITVEC_H +#define BITVEC_H +#ifdef _WIN32 +#pragma once +#endif + + +#include + + +class CBitVecAccessor +{ +public: + CBitVecAccessor(unsigned long *pDWords, int iBit); + + void operator=(int val); + operator unsigned long(); + +private: + unsigned long *m_pDWords; + int m_iBit; +}; + + +// CBitVec allows you to store a list of bits and do operations on them like they were +// an atomic type. +template +class CBitVec +{ +public: + + CBitVec(); + + // Set all values to the specified value (0 or 1..) + void Init(int val = 0); + + // Access the bits like an array. + CBitVecAccessor operator[](int i); + + // Operations on other bit vectors. + CBitVec& operator=(CBitVec const &other); + bool operator==(CBitVec const &other); + bool operator!=(CBitVec const &other); + + // Get underlying dword representations of the bits. + int GetNumDWords(); + unsigned long GetDWord(int i); + void SetDWord(int i, unsigned long val); + + int GetNumBits(); + +private: + + enum {NUM_DWORDS = NUM_BITS/32 + !!(NUM_BITS & 31)}; + unsigned long m_DWords[NUM_DWORDS]; +}; + + + +// ------------------------------------------------------------------------ // +// CBitVecAccessor inlines. +// ------------------------------------------------------------------------ // + +inline CBitVecAccessor::CBitVecAccessor(unsigned long *pDWords, int iBit) +{ + m_pDWords = pDWords; + m_iBit = iBit; +} + + +inline void CBitVecAccessor::operator=(int val) +{ + if(val) + m_pDWords[m_iBit >> 5] |= (1 << (m_iBit & 31)); + else + m_pDWords[m_iBit >> 5] &= ~(unsigned long)(1 << (m_iBit & 31)); +} + +inline CBitVecAccessor::operator unsigned long() +{ + return m_pDWords[m_iBit >> 5] & (1 << (m_iBit & 31)); +} + + + +// ------------------------------------------------------------------------ // +// CBitVec inlines. +// ------------------------------------------------------------------------ // + +template +inline int CBitVec::GetNumBits() +{ + return NUM_BITS; +} + + +template +inline CBitVec::CBitVec() +{ + for(int i=0; i < NUM_DWORDS; i++) + m_DWords[i] = 0; +} + + +template +inline void CBitVec::Init(int val) +{ + for(int i=0; i < GetNumBits(); i++) + { + (*this)[i] = val; + } +} + + +template +inline CBitVec& CBitVec::operator=(CBitVec const &other) +{ + memcpy(m_DWords, other.m_DWords, sizeof(m_DWords)); + return *this; +} + + +template +inline CBitVecAccessor CBitVec::operator[](int i) +{ + assert(i >= 0 && i < GetNumBits()); + return CBitVecAccessor(m_DWords, i); +} + + +template +inline bool CBitVec::operator==(CBitVec const &other) +{ + for(int i=0; i < NUM_DWORDS; i++) + if(m_DWords[i] != other.m_DWords[i]) + return false; + + return true; +} + + +template +inline bool CBitVec::operator!=(CBitVec const &other) +{ + return !(*this == other); +} + + +template +inline int CBitVec::GetNumDWords() +{ + return NUM_DWORDS; +} + +template +inline unsigned long CBitVec::GetDWord(int i) +{ + assert(i >= 0 && i < NUM_DWORDS); + return m_DWords[i]; +} + + +template +inline void CBitVec::SetDWord(int i, unsigned long val) +{ + assert(i >= 0 && i < NUM_DWORDS); + m_DWords[i] = val; +} + + +#endif // BITVEC_H + diff --git a/game_shared/pm_debug.cpp b/game_shared/pm_debug.cpp deleted file mode 100644 index d9d097db..00000000 --- a/game_shared/pm_debug.cpp +++ /dev/null @@ -1,320 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include "mathlib.h" -#include "const.h" -#include "usercmd.h" -#include "pm_defs.h" -#include "pm_shared.h" -#include "pm_movevars.h" -#include "pm_debug.h" - -#include - -#pragma warning(disable : 4244) -#pragma warning(disable : 4305) - -extern playermove_t *pmove; - -// Expand debugging BBOX particle hulls by this many units. -#define BOX_GAP 0.0f - -static int PM_boxpnt[6][4] = -{ - { 0, 4, 6, 2 }, // +X - { 0, 1, 5, 4 }, // +Y - { 0, 2, 3, 1 }, // +Z - { 7, 5, 1, 3 }, // -X - { 7, 3, 2, 6 }, // -Y - { 7, 6, 4, 5 }, // -Z -}; - -void PM_ShowClipBox( void ) -{ -#if defined( _DEBUG ) - vec3_t org; - vec3_t offset = { 0, 0, 0 }; - - if ( !pmove->runfuncs ) - return; - - // More debugging, draw the particle bbox for player and for the entity we are looking directly at. - // aslo prints entity info to the console overlay. - //if ( !pmove->server ) - // return; - - // Draw entity in center of view - // Also draws the normal to the clip plane that intersects our movement ray. Leaves a particle - // trail at the intersection point. - PM_ViewEntity(); - - VectorCopy( pmove->origin, org ); - - if ( pmove->server ) - { - VectorAdd( org, offset, org ); - } - else - { - VectorSubtract( org, offset, org ); - } - - // Show our BBOX in particles. - PM_DrawBBox( pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], org, pmove->server ? 132 : 0, 0.1 ); - - PM_ParticleLine( org, org, pmove->server ? 132 : 0, 0.1, 5.0 ); -/* - { - int i; - for ( i = 0; i < pmove->numphysent; i++ ) - { - if ( pmove->physents[ i ].info >= 1 && pmove->physents[ i ].info <= 4 ) - { - PM_DrawBBox( pmove->player_mins[pmove->usehull], pmove->player_maxs[pmove->usehull], pmove->physents[i].origin, 132, 0.1 ); - } - } - } -*/ -#endif -} - -/* -=============== -PM_ParticleLine(vec3_t start, vec3_t end, int color, float life) - -================ -*/ -void PM_ParticleLine(vec3_t start, vec3_t end, int pcolor, float life, float vert) -{ - float linestep = 2.0f; - float curdist; - float len; - vec3_t curpos; - vec3_t diff; - int i; - // Determine distance; - - VectorSubtract(end, start, diff); - - len = VectorNormalize(diff); - - curdist = 0; - while (curdist <= len) - { - for (i = 0; i < 3; i++) - curpos[i] = start[i] + curdist * diff[i]; - - pmove->PM_Particle( curpos, pcolor, life, 0, vert); - curdist += linestep; - } - -} - -/* -================ -PM_DrawRectangle(vec3_t tl, vec3_t br) - -================ -*/ -void PM_DrawRectangle(vec3_t tl, vec3_t bl, vec3_t tr, vec3_t br, int pcolor, float life) -{ - PM_ParticleLine(tl, bl, pcolor, life, 0); - PM_ParticleLine(bl, br, pcolor, life, 0); - PM_ParticleLine(br, tr, pcolor, life, 0); - PM_ParticleLine(tr, tl, pcolor, life, 0); -} - -/* -================ -PM_DrawPhysEntBBox(int num) - -================ -*/ -void PM_DrawPhysEntBBox(int num, int pcolor, float life) -{ - physent_t *pe; - vec3_t org; - int j; - vec3_t tmp; - vec3_t p[8]; - float gap = BOX_GAP; - vec3_t modelmins, modelmaxs; - - if (num >= pmove->numphysent || - num <= 0) - return; - - pe = &pmove->physents[num]; - - if (pe->model) - { - VectorCopy(pe->origin, org); - - pmove->PM_GetModelBounds( pe->model, modelmins, modelmaxs ); - for (j = 0; j < 8; j++) - { - tmp[0] = (j & 1) ? modelmins[0] - gap : modelmaxs[0] + gap; - tmp[1] = (j & 2) ? modelmins[1] - gap : modelmaxs[1] + gap; - tmp[2] = (j & 4) ? modelmins[2] - gap : modelmaxs[2] + gap; - - VectorCopy(tmp, p[j]); - } - - // If the bbox should be rotated, do that - if (pe->angles[0] || pe->angles[1] || pe->angles[2]) - { - vec3_t forward, right, up; - - AngleVectorsTranspose(pe->angles, forward, right, up); - for (j = 0; j < 8; j++) - { - VectorCopy(p[j], tmp); - p[j][0] = DotProduct ( tmp, forward ); - p[j][1] = DotProduct ( tmp, right ); - p[j][2] = DotProduct ( tmp, up ); - } - } - - // Offset by entity origin, if any. - for (j = 0; j < 8; j++) - VectorAdd(p[j], org, p[j]); - - for (j = 0; j < 6; j++) - { - PM_DrawRectangle( - p[PM_boxpnt[j][1]], - p[PM_boxpnt[j][0]], - p[PM_boxpnt[j][2]], - p[PM_boxpnt[j][3]], - pcolor, life); - } - } - else - { - for (j = 0; j < 8; j++) - { - tmp[0] = (j & 1) ? pe->mins[0] : pe->maxs[0]; - tmp[1] = (j & 2) ? pe->mins[1] : pe->maxs[1]; - tmp[2] = (j & 4) ? pe->mins[2] : pe->maxs[2]; - - VectorAdd(tmp, pe->origin, tmp); - VectorCopy(tmp, p[j]); - } - - for (j = 0; j < 6; j++) - { - PM_DrawRectangle( - p[PM_boxpnt[j][1]], - p[PM_boxpnt[j][0]], - p[PM_boxpnt[j][2]], - p[PM_boxpnt[j][3]], - pcolor, life); - } - - } -} - -/* -================ -PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life) - -================ -*/ -void PM_DrawBBox(vec3_t mins, vec3_t maxs, vec3_t origin, int pcolor, float life) -{ - int j; - - vec3_t tmp; - vec3_t p[8]; - float gap = BOX_GAP; - - for (j = 0; j < 8; j++) - { - tmp[0] = (j & 1) ? mins[0] - gap : maxs[0] + gap; - tmp[1] = (j & 2) ? mins[1] - gap : maxs[1] + gap ; - tmp[2] = (j & 4) ? mins[2] - gap : maxs[2] + gap ; - - VectorAdd(tmp, origin, tmp); - VectorCopy(tmp, p[j]); - } - - for (j = 0; j < 6; j++) - { - PM_DrawRectangle( - p[PM_boxpnt[j][1]], - p[PM_boxpnt[j][0]], - p[PM_boxpnt[j][2]], - p[PM_boxpnt[j][3]], - pcolor, life); - } -} - - -#ifndef DEDICATED - -/* -================ -PM_ViewEntity - -Shows a particle trail from player to entity in crosshair. -Shows particles at that entities bbox - -Tries to shoot a ray out by about 128 units. -================ -*/ -void PM_ViewEntity( void ) -{ - vec3_t forward, right, up; - float raydist = 256.0f; - vec3_t origin; - vec3_t end; - int i; - pmtrace_t trace; - int pcolor = 77; - float fup; - -#if 0 - if ( !pm_showclip.value ) - return; -#endif - - AngleVectors (pmove->angles, forward, right, up); // Determine movement angles - - VectorCopy( pmove->origin, origin); - - fup = 0.5*( pmove->player_mins[pmove->usehull][2] + pmove->player_maxs[pmove->usehull][2] ); - fup += pmove->view_ofs[2]; - fup -= 4; - - for (i = 0; i < 3; i++) - { - end[i] = origin[i] + raydist * forward[i]; - } - - trace = pmove->PM_PlayerTrace( origin, end, PM_STUDIO_BOX, -1 ); - - if (trace.ent > 0) // Not the world - { - pcolor = 111; - } - - // Draw the hull or bbox. - if (trace.ent > 0) - { - PM_DrawPhysEntBBox(trace.ent, pcolor, 0.3f); - } -} - -#endif diff --git a/game_shared/pm_defs.h b/game_shared/pm_defs.h deleted file mode 100644 index da878e78..00000000 --- a/game_shared/pm_defs.h +++ /dev/null @@ -1,219 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#ifndef PM_DEFS_H -#define PM_DEFS_H - -#define MAX_PHYSENTS 600 // Must have room for all entities in the world. -#define MAX_MOVEENTS 64 -#define MAX_CLIP_PLANES 5 - -#define PM_NORMAL 0x00000000 -#define PM_STUDIO_IGNORE 0x00000001 // Skip studio models -#define PM_STUDIO_BOX 0x00000002 // Use boxes for non-complex studio models (even in traceline) -#define PM_GLASS_IGNORE 0x00000004 // Ignore entities with non-normal rendermode -#define PM_WORLD_ONLY 0x00000008 // Only trace against the world - -// Values for flags parameter of PM_TraceLine -#define PM_TRACELINE_PHYSENTSONLY 0 -#define PM_TRACELINE_ANYVISIBLE 1 - -#include "pm_info.h" - -// PM_PlayerTrace results. -#include "pmtrace.h" - - -#include "usercmd.h" - -// physent_t -typedef struct physent_s -{ - char name[32]; // Name of model, or "player" or "world". - int player; - vec3_t origin; // Model's origin in world coordinates. - struct model_s *model; // only for bsp models - struct model_s *studiomodel; // SOLID_BBOX, but studio clip intersections. - vec3_t mins, maxs; // only for non-bsp models - int info; // For client or server to use to identify (index into edicts or cl_entities) - vec3_t angles; // rotated entities need this info for hull testing to work. - - int solid; // Triggers and func_door type WATER brushes are SOLID_NOT - int skin; // BSP Contents for such things like fun_door water brushes. - int rendermode; // So we can ignore glass - - // Complex collision detection. - float frame; - int sequence; - byte controller[4]; - byte blending[2]; - - int movetype; - int takedamage; - int blooddecal; - int team; - int classnumber; - - // For mods - int iuser1; - int iuser2; - int iuser3; - int iuser4; - float fuser1; - float fuser2; - float fuser3; - float fuser4; - vec3_t vuser1; - vec3_t vuser2; - vec3_t vuser3; - vec3_t vuser4; -} physent_t; - -typedef struct playermove_s -{ - int player_index; // So we don't try to run the PM_CheckStuck nudging too quickly. - qboolean server; // For debugging, are we running physics code on server side? - - qboolean multiplayer; // 1 == multiplayer server - float time; // realtime on host, for reckoning duck timing - float frametime; // Duration of this frame - - vec3_t forward, right, up; // Vectors for angles - - // player state - vec3_t origin; // Movement origin. - vec3_t angles; // Movement view angles. - vec3_t oldangles; // Angles before movement view angles were looked at. - vec3_t velocity; // Current movement direction. - vec3_t movedir; // For waterjumping, a forced forward velocity so we can fly over lip of ledge. - vec3_t basevelocity; // Velocity of the conveyor we are standing, e.g. - - // For ducking/dead - vec3_t view_ofs; // Our eye position. - float flDuckTime; // Time we started duck - qboolean bInDuck; // In process of ducking or ducked already? - - // For walking/falling - int flTimeStepSound; // Next time we can play a step sound - int iStepLeft; - - float flFallVelocity; - vec3_t punchangle; - - float flSwimTime; - float flNextPrimaryAttack; - - int effects; // MUZZLE FLASH, e.g. - - int flags; // FL_ONGROUND, FL_DUCKING, etc. - int usehull; // 0 = regular player hull, 1 = ducked player hull, 2 = point hull - float gravity; // Our current gravity and friction. - float friction; - int oldbuttons; // Buttons last usercmd - float waterjumptime; // Amount of time left in jumping out of water cycle. - qboolean dead; // Are we a dead player? - int deadflag; - int spectator; // Should we use spectator physics model? - int movetype; // Our movement type, NOCLIP, WALK, FLY - - int onground; - int waterlevel; - int watertype; - int oldwaterlevel; - - char sztexturename[256]; - char chtexturetype; - - float maxspeed; - float clientmaxspeed; // Player specific maxspeed - - // For mods - int iuser1; - int iuser2; - int iuser3; - int iuser4; - float fuser1; - float fuser2; - float fuser3; - float fuser4; - vec3_t vuser1; - vec3_t vuser2; - vec3_t vuser3; - vec3_t vuser4; - - // world state - - // Number of entities to clip against. - int numphysent; - physent_t physents[MAX_PHYSENTS]; - - // Number of momvement entities (ladders) - int nummoveent; - // just a list of ladders - physent_t moveents[MAX_MOVEENTS]; - - // All things being rendered, for tracing against things you don't actually collide with - int numvisent; - physent_t visents[MAX_PHYSENTS]; - - // input to run through physics. - usercmd_t cmd; - - // Trace results for objects we collided with. - int numtouch; - pmtrace_t touchindex[MAX_PHYSENTS]; - - char physinfo[MAX_PHYSINFO_STRING]; // Physics info string - - struct movevars_s *movevars; - vec3_t player_mins[4]; - vec3_t player_maxs[4]; - - // Common functions - const char *(*PM_Info_ValueForKey) ( const char *s, const char *key ); - void (*PM_Particle)( float *origin, int color, float life, int zpos, int zvel ); - int (*PM_TestPlayerPosition)( float *pos, pmtrace_t *ptrace ); - void (*Con_NPrintf)( int idx, char *fmt, ... ); - void (*Con_DPrintf)( char *fmt, ... ); - void (*Con_Printf)( char *fmt, ... ); - double (*Sys_FloatTime)( void ); - void (*PM_StuckTouch)( int hitent, pmtrace_t *ptraceresult ); - int (*PM_PointContents)( float *p, int *truecontents /*filled in if this is non-null*/ ); - int (*PM_TruePointContents)( float *p ); - int (*PM_HullPointContents)( struct hull_s *hull, int num, float *p ); - pmtrace_t (*PM_PlayerTrace)( float *start, float *end, int traceFlags, int ignore_pe ); - struct pmtrace_s *(*PM_TraceLine)( float *start, float *end, int flags, int usehulll, int ignore_pe ); - long (*RandomLong)( long lLow, long lHigh ); - float (*RandomFloat)( float flLow, float flHigh ); - int (*PM_GetModelType)( struct model_s *mod ); - void (*PM_GetModelBounds)( struct model_s *mod, float *mins, float *maxs ); - void *(*PM_HullForBsp)( physent_t *pe, float *offset ); - float (*PM_TraceModel)( physent_t *pEnt, float *start, float *end, void *raw_trace ); - int (*COM_FileSize)( char *filename ); - byte *(*COM_LoadFile)( char *path, int usehunk, int *pLength ); - void (*COM_FreeFile)( void *buffer ); - char *(*memfgets)( byte *pMemFile, int fileSize, int *pFilePos, char *pBuffer, int bufferSize ); - - // Functions - // Run functions for this frame? - qboolean runfuncs; - void (*PM_PlaySound)( int channel, const char *sample, float volume, float attenuation, int fFlags, int pitch ); - const char *(*PM_TraceTexture)( int ground, float *vstart, float *vend ); - void (*PM_PlaybackEventFull)( int flags, int clientindex, unsigned short eventindex, float delay, float *origin, float *angles, float fparam1, float fparam2, int iparam1, int iparam2, int bparam1, int bparam2 ); - pmtrace_t (*PM_PlayerTraceEx) (float *start, float *end, int traceFlags, int (*pfnIgnore)( physent_t *pe )); - int (*PM_TestPlayerPositionEx) (float *pos, pmtrace_t *ptrace, int (*pfnIgnore)( physent_t *pe )); - struct pmtrace_s *(*PM_TraceLineEx)( float *start, float *end, int flags, int usehulll, int (*pfnIgnore)( physent_t *pe )); -} playermove_t; -#endif//PM_DEFS_H \ No newline at end of file diff --git a/game_shared/pm_info.h b/game_shared/pm_info.h deleted file mode 100644 index 9eb173a5..00000000 --- a/game_shared/pm_info.h +++ /dev/null @@ -1,10 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2010 й -// pm_info.h - physics info string definition -//======================================================================= -#ifndef PM_INFO_H -#define PM_INFO_H - -#define MAX_PHYSINFO_STRING 256 - -#endif // PM_INFO_H \ No newline at end of file diff --git a/game_shared/pm_materials.h b/game_shared/pm_materials.h deleted file mode 100644 index 73048c76..00000000 --- a/game_shared/pm_materials.h +++ /dev/null @@ -1,22 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2009 й -// pm_materials.h - defined texture types -//======================================================================= -#ifndef PM_MATERIALS_H -#define PM_MATERIALS_H - -#define CBTEXTURENAMEMAX 13 // only load first n chars of name - -#define CHAR_TEX_CONCRETE 'C' // texture types -#define CHAR_TEX_METAL 'M' -#define CHAR_TEX_DIRT 'D' -#define CHAR_TEX_VENT 'V' -#define CHAR_TEX_GRATE 'G' -#define CHAR_TEX_TILE 'T' -#define CHAR_TEX_SLOSH 'S' -#define CHAR_TEX_WOOD 'W' -#define CHAR_TEX_COMPUTER 'P' -#define CHAR_TEX_GLASS 'Y' -#define CHAR_TEX_FLESH 'F' - -#endif//PM_MATERIALS_H \ No newline at end of file diff --git a/game_shared/pm_math.cpp b/game_shared/pm_math.cpp deleted file mode 100644 index 28e0d72d..00000000 --- a/game_shared/pm_math.cpp +++ /dev/null @@ -1,416 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ -// pm_math.c -- math primitives - -#include "mathlib.h" -#include "const.h" -#include - -// up / down -#define PITCH 0 -// left / right -#define YAW 1 -// fall over -#define ROLL 2 - -#pragma warning(disable : 4244) - -vec3_t vec3_origin = {0,0,0}; -int nanmask = 255<<23; - -void AngleVectors (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - if (forward) - { - forward[0] = cp*cy; - forward[1] = cp*sy; - forward[2] = -sp; - } - if (right) - { - right[0] = (-1*sr*sp*cy+-1*cr*-sy); - right[1] = (-1*sr*sp*sy+-1*cr*cy); - right[2] = -1*sr*cp; - } - if (up) - { - up[0] = (cr*sp*cy+-sr*-sy); - up[1] = (cr*sp*sy+-sr*cy); - up[2] = cr*cp; - } -} - -void AngleVectorsTranspose (const vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - if (forward) - { - forward[0] = cp*cy; - forward[1] = (sr*sp*cy+cr*-sy); - forward[2] = (cr*sp*cy+-sr*-sy); - } - if (right) - { - right[0] = cp*sy; - right[1] = (sr*sp*sy+cr*cy); - right[2] = (cr*sp*sy+-sr*cy); - } - if (up) - { - up[0] = -sp; - up[1] = sr*cp; - up[2] = cr*cp; - } -} - - -void AngleMatrix (const vec3_t angles, float (*matrix)[4] ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - // matrix = (YAW * PITCH) * ROLL - matrix[0][0] = cp*cy; - matrix[1][0] = cp*sy; - matrix[2][0] = -sp; - matrix[0][1] = sr*sp*cy+cr*-sy; - matrix[1][1] = sr*sp*sy+cr*cy; - matrix[2][1] = sr*cp; - matrix[0][2] = (cr*sp*cy+-sr*-sy); - matrix[1][2] = (cr*sp*sy+-sr*cy); - matrix[2][2] = cr*cp; - matrix[0][3] = 0.0; - matrix[1][3] = 0.0; - matrix[2][3] = 0.0; -} - -void AngleIMatrix (const vec3_t angles, float matrix[3][4] ) -{ - float angle; - float sr, sp, sy, cr, cp, cy; - - angle = angles[YAW] * (M_PI*2 / 360); - sy = sin(angle); - cy = cos(angle); - angle = angles[PITCH] * (M_PI*2 / 360); - sp = sin(angle); - cp = cos(angle); - angle = angles[ROLL] * (M_PI*2 / 360); - sr = sin(angle); - cr = cos(angle); - - // matrix = (YAW * PITCH) * ROLL - matrix[0][0] = cp*cy; - matrix[0][1] = cp*sy; - matrix[0][2] = -sp; - matrix[1][0] = sr*sp*cy+cr*-sy; - matrix[1][1] = sr*sp*sy+cr*cy; - matrix[1][2] = sr*cp; - matrix[2][0] = (cr*sp*cy+-sr*-sy); - matrix[2][1] = (cr*sp*sy+-sr*cy); - matrix[2][2] = cr*cp; - matrix[0][3] = 0.0; - matrix[1][3] = 0.0; - matrix[2][3] = 0.0; -} - -void NormalizeAngles( float *angles ) -{ - int i; - // Normalize angles - for ( i = 0; i < 3; i++ ) - { - if ( angles[i] > 180.0 ) - { - angles[i] -= 360.0; - } - else if ( angles[i] < -180.0 ) - { - angles[i] += 360.0; - } - } -} - -/* -=================== -InterpolateAngles - -Interpolate Euler angles. -FIXME: Use Quaternions to avoid discontinuities -Frac is 0.0 to 1.0 ( i.e., should probably be clamped, but doesn't have to be ) -=================== -*/ -void InterpolateAngles( float *start, float *end, float *output, float frac ) -{ - int i; - float ang1, ang2; - float d; - - NormalizeAngles( start ); - NormalizeAngles( end ); - - for ( i = 0 ; i < 3 ; i++ ) - { - ang1 = start[i]; - ang2 = end[i]; - - d = ang2 - ang1; - if ( d > 180 ) - { - d -= 360; - } - else if ( d < -180 ) - { - d += 360; - } - - output[i] = ang1 + d * frac; - } - - NormalizeAngles( output ); -} - - -/* -=================== -AngleBetweenVectors - -=================== -*/ -float AngleBetweenVectors( const vec3_t v1, const vec3_t v2 ) -{ - float angle; - float l1 = Length( v1 ); - float l2 = Length( v2 ); - - if ( !l1 || !l2 ) - return 0.0f; - - angle = acos( DotProduct( v1, v2 ) ) / (l1*l2); - angle = ( angle * 180.0f ) / M_PI; - - return angle; -} - - -void VectorTransform (const vec3_t in1, float in2[3][4], vec3_t out) -{ - out[0] = DotProduct(in1, in2[0]) + in2[0][3]; - out[1] = DotProduct(in1, in2[1]) + in2[1][3]; - out[2] = DotProduct(in1, in2[2]) + in2[2][3]; -} - - -int VectorCompare (const vec3_t v1, const vec3_t v2) -{ - int i; - - for (i=0 ; i<3 ; i++) - if (v1[i] != v2[i]) - return 0; - - return 1; -} - -void VectorMA (const vec3_t veca, float scale, const vec3_t vecb, vec3_t vecc) -{ - vecc[0] = veca[0] + scale*vecb[0]; - vecc[1] = veca[1] + scale*vecb[1]; - vecc[2] = veca[2] + scale*vecb[2]; -} - - -vec_t _DotProduct (vec3_t v1, vec3_t v2) -{ - return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; -} - -void _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out) -{ - out[0] = veca[0]-vecb[0]; - out[1] = veca[1]-vecb[1]; - out[2] = veca[2]-vecb[2]; -} - -void _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out) -{ - out[0] = veca[0]+vecb[0]; - out[1] = veca[1]+vecb[1]; - out[2] = veca[2]+vecb[2]; -} - -void _VectorCopy (vec3_t in, vec3_t out) -{ - out[0] = in[0]; - out[1] = in[1]; - out[2] = in[2]; -} - -void CrossProduct (const vec3_t v1, const vec3_t v2, vec3_t cross) -{ - cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; - cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; - cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; -} - -double sqrt(double x); - -float Length(const vec3_t v) -{ - int i; - float length = 0.0f; - - for (i=0 ; i< 3 ; i++) - length += v[i]*v[i]; - length = sqrt (length); // FIXME - - return length; -} - -float Distance(const vec3_t v1, const vec3_t v2) -{ - vec3_t d; - VectorSubtract(v2,v1,d); - return Length(d); -} - -float VectorNormalize (vec3_t v) -{ - float length, ilength; - - length = v[0]*v[0] + v[1]*v[1] + v[2]*v[2]; - length = sqrt (length); // FIXME - - if (length) - { - ilength = 1/length; - v[0] *= ilength; - v[1] *= ilength; - v[2] *= ilength; - } - - return length; - -} - -void VectorInverse (vec3_t v) -{ - v[0] = -v[0]; - v[1] = -v[1]; - v[2] = -v[2]; -} - -void VectorScale (const vec3_t in, vec_t scale, vec3_t out) -{ - out[0] = in[0]*scale; - out[1] = in[1]*scale; - out[2] = in[2]*scale; -} - - -int Q_log2(int val) -{ - int answer=0; - while (val>>=1) - answer++; - return answer; -} - -void VectorMatrix( vec3_t forward, vec3_t right, vec3_t up) -{ - vec3_t tmp; - - if (forward[0] == 0 && forward[1] == 0) - { - right[0] = 1; - right[1] = 0; - right[2] = 0; - up[0] = -forward[2]; - up[1] = 0; - up[2] = 0; - return; - } - - tmp[0] = 0; tmp[1] = 0; tmp[2] = 1.0; - CrossProduct( forward, tmp, right ); - VectorNormalize( right ); - CrossProduct( right, forward, up ); - VectorNormalize( up ); -} - - -void VectorAngles( const vec3_t forward, vec3_t angles ) -{ - float tmp, yaw, pitch; - - if (forward[1] == 0 && forward[0] == 0) - { - yaw = 0; - if (forward[2] > 0) - pitch = 90; - else - pitch = 270; - } - else - { - yaw = (atan2(forward[1], forward[0]) * 180 / M_PI); - if (yaw < 0) - yaw += 360; - - tmp = sqrt (forward[0]*forward[0] + forward[1]*forward[1]); - pitch = (atan2(forward[2], tmp) * 180 / M_PI); - if (pitch < 0) - pitch += 360; - } - - angles[0] = pitch; - angles[1] = yaw; - angles[2] = 0; -} diff --git a/game_shared/pm_movevars.h b/game_shared/pm_movevars.h deleted file mode 100644 index 9e7d59e1..00000000 --- a/game_shared/pm_movevars.h +++ /dev/null @@ -1,38 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2008 й -// pm_movevars.h - shared movement variables -//======================================================================= -#ifndef PM_MOVEVARS_H -#define PM_MOVEVARS_H - -typedef struct movevars_s -{ - float gravity; // Gravity for map - float stopspeed; // Deceleration when not moving - float maxspeed; // Max allowed speed - float spectatormaxspeed; - float accelerate; // Acceleration factor - float airaccelerate; // Same for when in open air - float wateraccelerate; // Same for when in water - float friction; - float edgefriction; // Extra friction near dropofs - float waterfriction; // Less in water - float entgravity; // 1.0 - float bounce; // Wall bounce value. 1.0 - float stepsize; // sv_stepsize; - float maxvelocity; // maximum server velocity. - float zmax; // Max z-buffer range (for GL) - float waveHeight; // Water wave height (for GL) - qboolean footsteps; // Play footstep sounds - char skyName[32]; // Name of the sky map - float rollangle; - float rollspeed; - float skycolor_r; // Sky color - float skycolor_g; // - float skycolor_b; // - float skyvec_x; // Sky vector - float skyvec_y; // - float skyvec_z; // -} movevars_t; - -#endif//PM_MOVEVARS_H \ No newline at end of file diff --git a/game_shared/pm_shared.cpp b/game_shared/pm_shared.cpp deleted file mode 100644 index 656d17bc..00000000 --- a/game_shared/pm_shared.cpp +++ /dev/null @@ -1,3324 +0,0 @@ -/*** -* -* Copyright (c) 1996-2002, Valve LLC. All rights reserved. -* -* This product contains software technology licensed from Id -* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. -* All Rights Reserved. -* -* Use, distribution, and modification of this source code and/or resulting -* object code is restricted to non-commercial enhancements to products from -* Valve LLC. All other use, distribution, or modification is prohibited -* without written permission from Valve LLC. -* -****/ - -#include -#include -#include "mathlib.h" -#include "const.h" -#include "usercmd.h" -#include "pm_defs.h" -#include "pm_shared.h" -#include "pm_movevars.h" -#include "com_model.h" -#include "pm_debug.h" -#include // NULL -#include // sqrt -#include // strcpy -#include // atoi -#include // isspace - -#ifdef CLIENT_DLL - // Spectator Mode - int iJumpSpectator; - float vJumpOrigin[3]; - float vJumpAngles[3]; -#endif - -static int pm_shared_initialized = 0; - -#pragma warning( disable : 4305 ) - -playermove_t *pmove = NULL; - -// Ducking time -#define TIME_TO_DUCK 0.4 -#define VEC_DUCK_HULL_MIN -18 -#define VEC_DUCK_HULL_MAX 18 -#define VEC_DUCK_VIEW 12 -#define PM_DEAD_VIEWHEIGHT -8 -#define MAX_CLIMB_SPEED 200 -#define STUCK_MOVEUP 1 -#define STUCK_MOVEDOWN -1 -#define VEC_HULL_MIN -36 -#define VEC_HULL_MAX 36 -#define VEC_VIEW 28 -#define STOP_EPSILON 0.1 - -#define CTEXTURESMAX 512 // max number of textures loaded -#define CBTEXTURENAMEMAX 13 // only load first n chars of name - -#define CHAR_TEX_CONCRETE 'C' // texture types -#define CHAR_TEX_METAL 'M' -#define CHAR_TEX_DIRT 'D' -#define CHAR_TEX_VENT 'V' -#define CHAR_TEX_GRATE 'G' -#define CHAR_TEX_TILE 'T' -#define CHAR_TEX_SLOSH 'S' -#define CHAR_TEX_WOOD 'W' -#define CHAR_TEX_COMPUTER 'P' -#define CHAR_TEX_GLASS 'Y' -#define CHAR_TEX_FLESH 'F' - -#define STEP_CONCRETE 0 // default step sound -#define STEP_METAL 1 // metal floor -#define STEP_DIRT 2 // dirt, sand, rock -#define STEP_VENT 3 // ventillation duct -#define STEP_GRATE 4 // metal grating -#define STEP_TILE 5 // floor tiles -#define STEP_SLOSH 6 // shallow liquid puddle -#define STEP_WADE 7 // wading in liquid -#define STEP_LADDER 8 // climbing ladder - -#define PLAYER_FATAL_FALL_SPEED 1024// approx 60 feet -#define PLAYER_MAX_SAFE_FALL_SPEED 580// approx 20 feet -#define DAMAGE_FOR_FALL_SPEED (float) 100 / ( PLAYER_FATAL_FALL_SPEED - PLAYER_MAX_SAFE_FALL_SPEED )// damage per unit per second. -#define PLAYER_MIN_BOUNCE_SPEED 200 -#define PLAYER_FALL_PUNCH_THRESHHOLD (float)350 // won't punch player's screen/make scrape noise unless player falling at least this fast. - -#define PLAYER_LONGJUMP_SPEED 350 // how fast we longjump - -// double to float warning -#pragma warning(disable : 4244) -#define max(a, b) (((a) > (b)) ? (a) : (b)) -#define min(a, b) (((a) < (b)) ? (a) : (b)) -// up / down -#define PITCH 0 -// left / right -#define YAW 1 -// fall over -#define ROLL 2 - -#define MAX_CLIENTS 32 - -#define CONTENTS_CURRENT_0 -9 -#define CONTENTS_CURRENT_90 -10 -#define CONTENTS_CURRENT_180 -11 -#define CONTENTS_CURRENT_270 -12 -#define CONTENTS_CURRENT_UP -13 -#define CONTENTS_CURRENT_DOWN -14 - -#define CONTENTS_TRANSLUCENT -15 - -static vec3_t rgv3tStuckTable[54]; -static int rgStuckLast[MAX_CLIENTS][2]; - -// Texture names -static int gcTextures = 0; -static char grgszTextureName[CTEXTURESMAX][CBTEXTURENAMEMAX]; -static char grgchTextureType[CTEXTURESMAX]; - -int g_onladder = 0; - -void PM_SwapTextures( int i, int j ) -{ - char chTemp; - char szTemp[ CBTEXTURENAMEMAX ]; - - strcpy( szTemp, grgszTextureName[ i ] ); - chTemp = grgchTextureType[ i ]; - - strcpy( grgszTextureName[ i ], grgszTextureName[ j ] ); - grgchTextureType[ i ] = grgchTextureType[ j ]; - - strcpy( grgszTextureName[ j ], szTemp ); - grgchTextureType[ j ] = chTemp; -} - -void PM_SortTextures( void ) -{ - // Bubble sort, yuck, but this only occurs at startup and it's only 512 elements... - // - int i, j; - - for ( i = 0 ; i < gcTextures; i++ ) - { - for ( j = i + 1; j < gcTextures; j++ ) - { - if ( stricmp( grgszTextureName[ i ], grgszTextureName[ j ] ) > 0 ) - { - // Swap - // - PM_SwapTextures( i, j ); - } - } - } -} - -void PM_InitTextureTypes() -{ - char buffer[512]; - int i, j; - byte *pMemFile; - int fileSize, filePos; - static int bTextureTypeInit = FALSE; - - if ( bTextureTypeInit ) - return; - - memset(&(grgszTextureName[0][0]), 0, CTEXTURESMAX * CBTEXTURENAMEMAX); - memset(grgchTextureType, 0, CTEXTURESMAX); - - gcTextures = 0; - memset(buffer, 0, 512); - - pMemFile = pmove->COM_LoadFile( "sound/materials.txt", 5, &fileSize ); - if ( !pMemFile ) - return; - - filePos = 0; - // for each line in the file... - while ( pmove->memfgets( pMemFile, fileSize, &filePos, buffer, 511 ) != NULL && (gcTextures < CTEXTURESMAX) ) - { - // skip whitespace - i = 0; - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // skip comment lines - if (buffer[i] == '/' || !isalpha(buffer[i])) - continue; - - // get texture type - grgchTextureType[gcTextures] = toupper(buffer[i++]); - - // skip whitespace - while(buffer[i] && isspace(buffer[i])) - i++; - - if (!buffer[i]) - continue; - - // get sentence name - j = i; - while (buffer[j] && !isspace(buffer[j])) - j++; - - if (!buffer[j]) - continue; - - // null-terminate name and save in sentences array - j = min (j, CBTEXTURENAMEMAX-1+i); - buffer[j] = 0; - strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); - } - - // Must use engine to free since we are in a .dll - pmove->COM_FreeFile ( pMemFile ); - - PM_SortTextures(); - - bTextureTypeInit = TRUE; -} - -char PM_FindTextureType( char *name ) -{ - int left, right, pivot; - int val; - - assert( pm_shared_initialized ); - - left = 0; - right = gcTextures - 1; - - while ( left <= right ) - { - pivot = ( left + right ) / 2; - - val = strnicmp( name, grgszTextureName[ pivot ], CBTEXTURENAMEMAX-1 ); - if ( val == 0 ) - { - return grgchTextureType[ pivot ]; - } - else if ( val > 0 ) - { - left = pivot + 1; - } - else if ( val < 0 ) - { - right = pivot - 1; - } - } - - return CHAR_TEX_CONCRETE; -} - -void PM_PlayStepSound( int step, float fvol ) -{ - static int iSkipStep = 0; - int irand; - vec3_t hvel; - - pmove->iStepLeft = !pmove->iStepLeft; - - if ( !pmove->runfuncs ) - { - return; - } - - irand = pmove->RandomLong(0,1) + ( pmove->iStepLeft * 2 ); - - // FIXME mp_footsteps needs to be a movevar - if ( pmove->multiplayer && !pmove->movevars->footsteps ) - return; - - VectorCopy( pmove->velocity, hvel ); - hvel[2] = 0.0; - - if ( pmove->multiplayer && ( !g_onladder && Length( hvel ) <= 220 ) ) - return; - - // irand - 0,1 for right foot, 2,3 for left foot - // used to alternate left and right foot - // FIXME, move to player state - - switch (step) - { - default: - case STEP_CONCRETE: - switch (irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_step4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_METAL: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_metal4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_DIRT: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_dirt4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_VENT: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_duct4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_GRATE: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_grate4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_TILE: - if ( !pmove->RandomLong(0,4) ) - irand = 4; - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 4: pmove->PM_PlaySound( CHAN_BODY, "player/pl_tile5.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_SLOSH: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_slosh4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_WADE: - if ( iSkipStep == 0 ) - { - iSkipStep++; - break; - } - - if ( iSkipStep++ == 3 ) - { - iSkipStep = 0; - } - - switch (irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - case STEP_LADDER: - switch(irand) - { - // right foot - case 0: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder1.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 1: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder3.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - // left foot - case 2: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder2.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - case 3: pmove->PM_PlaySound( CHAN_BODY, "player/pl_ladder4.wav", fvol, ATTN_NORM, 0, PITCH_NORM ); break; - } - break; - } -} - -int PM_MapTextureTypeStepType(char chTextureType) -{ - switch (chTextureType) - { - default: - case CHAR_TEX_CONCRETE: return STEP_CONCRETE; - case CHAR_TEX_METAL: return STEP_METAL; - case CHAR_TEX_DIRT: return STEP_DIRT; - case CHAR_TEX_VENT: return STEP_VENT; - case CHAR_TEX_GRATE: return STEP_GRATE; - case CHAR_TEX_TILE: return STEP_TILE; - case CHAR_TEX_SLOSH: return STEP_SLOSH; - } -} - -/* -==================== -PM_CatagorizeTextureType - -Determine texture info for the texture we are standing on. -==================== -*/ -void PM_CatagorizeTextureType( void ) -{ - vec3_t start, end; - const char *pTextureName; - - VectorCopy( pmove->origin, start ); - VectorCopy( pmove->origin, end ); - - // Straight down - end[2] -= 64; - - // Fill in default values, just in case. - pmove->sztexturename[0] = '\0'; - pmove->chtexturetype = CHAR_TEX_CONCRETE; - - pTextureName = pmove->PM_TraceTexture( pmove->onground, start, end ); - if ( !pTextureName ) - return; - - // strip leading '-0' or '+0~' or '{' or '!' - if (*pTextureName == '-' || *pTextureName == '+') - pTextureName += 2; - - if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') - pTextureName++; - // '}}' - - strcpy( pmove->sztexturename, pTextureName); - pmove->sztexturename[ CBTEXTURENAMEMAX - 1 ] = 0; - - // get texture type - pmove->chtexturetype = PM_FindTextureType( pmove->sztexturename ); -} - -void PM_UpdateStepSound( void ) -{ - int fWalking; - float fvol; - vec3_t knee; - vec3_t feet; - vec3_t center; - float height; - float speed; - float velrun; - float velwalk; - float flduck; - int fLadder; - int step; - - if ( pmove->flTimeStepSound > 0 ) - return; - - if ( pmove->flags & FL_FROZEN ) - return; - - PM_CatagorizeTextureType(); - - speed = Length( pmove->velocity ); - - // determine if we are on a ladder - fLadder = ( pmove->movetype == MOVETYPE_FLY );// IsOnLadder(); - - // UNDONE: need defined numbers for run, walk, crouch, crouch run velocities!!!! - if ( ( pmove->flags & FL_DUCKING) || fLadder ) - { - velwalk = 60; // These constants should be based on cl_movespeedkey * cl_forwardspeed somehow - velrun = 80; // UNDONE: Move walking to server - flduck = 100; - } - else - { - velwalk = 120; - velrun = 210; - flduck = 0; - } - - // If we're on a ladder or on the ground, and we're moving fast enough, - // play step sound. Also, if pmove->flTimeStepSound is zero, get the new - // sound right away - we just started moving in new level. - if ( (fLadder || ( pmove->onground != -1 ) ) && - ( Length( pmove->velocity ) > 0.0 ) && - ( speed >= velwalk || !pmove->flTimeStepSound ) ) - { - fWalking = speed < velrun; - - VectorCopy( pmove->origin, center ); - VectorCopy( pmove->origin, knee ); - VectorCopy( pmove->origin, feet ); - - height = pmove->player_maxs[ pmove->usehull ][ 2 ] - pmove->player_mins[ pmove->usehull ][ 2 ]; - - knee[2] = pmove->origin[2] - 0.3 * height; - feet[2] = pmove->origin[2] - 0.5 * height; - - // find out what we're stepping in or on... - if (fLadder) - { - step = STEP_LADDER; - fvol = 0.35; - pmove->flTimeStepSound = 350; - } - else if ( pmove->PM_PointContents ( knee, NULL ) == CONTENTS_WATER ) - { - step = STEP_WADE; - fvol = 0.65; - pmove->flTimeStepSound = 600; - } - else if ( pmove->PM_PointContents ( feet, NULL ) == CONTENTS_WATER ) - { - step = STEP_SLOSH; - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - } - else - { - // find texture under player, if different from current texture, - // get material type - step = PM_MapTextureTypeStepType( pmove->chtexturetype ); - - switch ( pmove->chtexturetype ) - { - default: - case CHAR_TEX_CONCRETE: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_METAL: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_DIRT: - fvol = fWalking ? 0.25 : 0.55; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_VENT: - fvol = fWalking ? 0.4 : 0.7; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_GRATE: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_TILE: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - - case CHAR_TEX_SLOSH: - fvol = fWalking ? 0.2 : 0.5; - pmove->flTimeStepSound = fWalking ? 400 : 300; - break; - } - } - - pmove->flTimeStepSound += flduck; // slower step time if ducking - - // play the sound - // 35% volume if ducking - if ( pmove->flags & FL_DUCKING ) - { - fvol *= 0.35; - } - - PM_PlayStepSound( step, fvol ); - } -} - -/* -================ -PM_AddToTouched - -Add's the trace result to touch list, if contact is not already in list. -================ -*/ -int PM_AddToTouched(pmtrace_t tr, vec3_t impactvelocity) -{ - int i; - - for (i = 0; i < pmove->numtouch; i++) - { - if (pmove->touchindex[i].ent == tr.ent) - break; - } - if (i != pmove->numtouch) // Already in list. - return FALSE; - - VectorCopy( impactvelocity, tr.deltavelocity ); - - if (pmove->numtouch >= MAX_PHYSENTS) - pmove->Con_DPrintf("Too many entities were touched!\n"); - - pmove->touchindex[pmove->numtouch++] = tr; - return TRUE; -} - -/* -================ -PM_CheckVelocity - -See if the player has a bogus velocity value. -================ -*/ -void PM_CheckVelocity () -{ - int i; - -// -// bound velocity -// - for (i=0 ; i<3 ; i++) - { - // See if it's bogus. - if (IS_NAN(pmove->velocity[i])) - { - pmove->Con_Printf ("PM Got a NaN velocity %i\n", i); - pmove->velocity[i] = 0; - } - if (IS_NAN(pmove->origin[i])) - { - pmove->Con_Printf ("PM Got a NaN origin on %i\n", i); - pmove->origin[i] = 0; - } - - // Bound it. - if (pmove->velocity[i] > pmove->movevars->maxvelocity) - { - pmove->Con_DPrintf ("PM Got a velocity too high on %i\n", i); - pmove->velocity[i] = pmove->movevars->maxvelocity; - } - else if (pmove->velocity[i] < -pmove->movevars->maxvelocity) - { - pmove->Con_DPrintf ("PM Got a velocity too low on %i\n", i); - pmove->velocity[i] = -pmove->movevars->maxvelocity; - } - } -} - -/* -================== -PM_ClipVelocity - -Slide off of the impacting object -returns the blocked flags: -0x01 == floor -0x02 == step / wall -================== -*/ -int PM_ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce) -{ - float backoff; - float change; - float angle; - int i, blocked; - - angle = normal[ 2 ]; - - blocked = 0x00; // Assume unblocked. - if (angle > 0) // If the plane that is blocking us has a positive z component, then assume it's a floor. - blocked |= 0x01; // - if (!angle) // If the plane has no Z, it is vertical (wall/step) - blocked |= 0x02; // - - // Determine how far along plane to slide based on incoming direction. - // Scale by overbounce factor. - backoff = DotProduct (in, normal) * overbounce; - - for (i=0 ; i<3 ; i++) - { - change = normal[i]*backoff; - out[i] = in[i] - change; - // If out velocity is too small, zero it out. - if (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON) - out[i] = 0; - } - - // Return blocking flags. - return blocked; -} - -void PM_AddCorrectGravity () -{ - float ent_gravity; - - if ( pmove->waterjumptime ) - return; - - if (pmove->gravity) - ent_gravity = pmove->gravity; - else - ent_gravity = 1.0; - - // Add gravity so they'll be in the correct position during movement - // yes, this 0.5 looks wrong, but it's not. - pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * 0.5 * pmove->frametime ); - pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime; - pmove->basevelocity[2] = 0; - - PM_CheckVelocity(); -} - - -void PM_FixupGravityVelocity () -{ - float ent_gravity; - - if ( pmove->waterjumptime ) - return; - - if (pmove->gravity) - ent_gravity = pmove->gravity; - else - ent_gravity = 1.0; - - // Get the correct velocity for the end of the dt - pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * pmove->frametime * 0.5 ); - - PM_CheckVelocity(); -} - -/* -============ -PM_FlyMove - -The basic solid body movement clip that slides along multiple planes -============ -*/ -int PM_FlyMove (void) -{ - int bumpcount, numbumps; - vec3_t dir; - float d; - int numplanes; - vec3_t planes[MAX_CLIP_PLANES]; - vec3_t primal_velocity, original_velocity; - vec3_t new_velocity; - int i, j; - pmtrace_t trace; - vec3_t end; - float time_left, allFraction; - int blocked; - - numbumps = 4; // Bump up to four times - - blocked = 0; // Assume not blocked - numplanes = 0; // and not sliding along any planes - VectorCopy (pmove->velocity, original_velocity); // Store original velocity - VectorCopy (pmove->velocity, primal_velocity); - - allFraction = 0; - time_left = pmove->frametime; // Total time for this movement operation. - - for (bumpcount=0 ; bumpcountvelocity[0] && !pmove->velocity[1] && !pmove->velocity[2]) - break; - - // Assume we can move all the way from the current origin to the - // end point. - for (i=0 ; i<3 ; i++) - end[i] = pmove->origin[i] + time_left * pmove->velocity[i]; - - // See if we can make it from origin to end point. - trace = pmove->PM_PlayerTrace (pmove->origin, end, PM_NORMAL, -1 ); - - allFraction += trace.fraction; - // If we started in a solid object, or we were in solid space - // the whole way, zero out our velocity and return that we - // are blocked by floor and wall. - if (trace.allsolid) - { // entity is trapped in another solid - VectorCopy (vec3_origin, pmove->velocity); - //ConDPrintf("Trapped 4\n"); - return 4; - } - - // If we moved some portion of the total distance, then - // copy the end position into the pmove->origin and - // zero the plane counter. - if (trace.fraction > 0) - { // actually covered some distance - VectorCopy (trace.endpos, pmove->origin); - VectorCopy (pmove->velocity, original_velocity); - numplanes = 0; - } - - // If we covered the entire distance, we are done - // and can return. - if (trace.fraction == 1) - break; // moved the entire distance - - //if (!trace.ent) - // Sys_Error ("PM_PlayerTrace: !trace.ent"); - - // Save entity that blocked us (since fraction was < 1.0) - // for contact - // Add it if it's not already in the list!!! - PM_AddToTouched(trace, pmove->velocity); - - // If the plane we hit has a high z component in the normal, then - // it's probably a floor - if (trace.plane.normal[2] > 0.7) - { - blocked |= 1; // floor - } - // If the plane has a zero z component in the normal, then it's a - // step or wall - if (!trace.plane.normal[2]) - { - blocked |= 2; // step / wall - //ConDPrintf("Blocked by %i\n", trace.ent); - } - - // Reduce amount of pmove->frametime left by total time left * fraction - // that we covered. - time_left -= time_left * trace.fraction; - - // Did we run out of planes to clip against? - if (numplanes >= MAX_CLIP_PLANES) - { // this shouldn't really happen - // Stop our movement if so. - VectorCopy (vec3_origin, pmove->velocity); - //ConDPrintf("Too many planes 4\n"); - - break; - } - - // Set up next clipping plane - VectorCopy (trace.plane.normal, planes[numplanes]); - numplanes++; -// - -// modify original_velocity so it parallels all of the clip planes -// - if ( pmove->movetype == MOVETYPE_WALK && - ((pmove->onground == -1) || (pmove->friction != 1)) ) // relfect player velocity - { - for ( i = 0; i < numplanes; i++ ) - { - if ( planes[i][2] > 0.7 ) - {// floor or slope - PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1 ); - VectorCopy( new_velocity, original_velocity ); - } - else - PM_ClipVelocity( original_velocity, planes[i], new_velocity, 1.0 + pmove->movevars->bounce * (1-pmove->friction) ); - } - - VectorCopy( new_velocity, pmove->velocity ); - VectorCopy( new_velocity, original_velocity ); - } - else - { - for (i=0 ; ivelocity, - 1); - for (j=0 ; jvelocity, planes[j]) < 0) - break; // not ok - } - if (j == numplanes) // Didn't have to clip, so we're ok - break; - } - - // Did we go all the way through plane set - if (i != numplanes) - { // go along this plane - // pmove->velocity is set in clipping call, no need to set again. - ; - } - else - { // go along the crease - if (numplanes != 2) - { - //ConPrintf ("clip velocity, numplanes == %i\n",numplanes); - VectorCopy (vec3_origin, pmove->velocity); - //ConDPrintf("Trapped 4\n"); - - break; - } - CrossProduct (planes[0], planes[1], dir); - d = DotProduct (dir, pmove->velocity); - VectorScale (dir, d, pmove->velocity ); - } - - // - // if original velocity is against the original velocity, stop dead - // to avoid tiny occilations in sloping corners - // - if (DotProduct (pmove->velocity, primal_velocity) <= 0) - { - //ConDPrintf("Back\n"); - VectorCopy (vec3_origin, pmove->velocity); - break; - } - } - } - - if ( allFraction == 0 ) - { - VectorCopy (vec3_origin, pmove->velocity); -// pmove->Con_DPrintf( "Don't stick\n" ); - } - - return blocked; -} - -/* -============== -PM_Accelerate -============== -*/ -void PM_Accelerate (vec3_t wishdir, float wishspeed, float accel) -{ - int i; - float addspeed, accelspeed, currentspeed; - - // Dead player's don't accelerate - if (pmove->dead) - return; - - // If waterjumping, don't accelerate - if (pmove->waterjumptime) - return; - - // See if we are changing direction a bit - currentspeed = DotProduct (pmove->velocity, wishdir); - - // Reduce wishspeed by the amount of veer. - addspeed = wishspeed - currentspeed; - - // If not going to add any speed, done. - if (addspeed <= 0) - return; - - // Determine amount of accleration. - accelspeed = accel * pmove->frametime * wishspeed * pmove->friction; - - // Cap at addspeed - if (accelspeed > addspeed) - accelspeed = addspeed; - - // Adjust velocity. - for (i=0 ; i<3 ; i++) - { - pmove->velocity[i] += accelspeed * wishdir[i]; - } -} - -/* -===================== -PM_WalkMove - -Only used by players. Moves along the ground when player is a MOVETYPE_WALK. -====================== -*/ -void PM_WalkMove () -{ - int clip; - int oldonground; - int i; - - vec3_t wishvel; - float spd; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - - vec3_t dest, start; - vec3_t original, originalvel; - vec3_t down, downvel; - float downdist, updist; - - pmtrace_t trace; - - // Copy movement amounts - fmove = pmove->cmd.forwardmove; - smove = pmove->cmd.sidemove; - - // Zero out z components of movement vectors - pmove->forward[2] = 0; - pmove->right[2] = 0; - - VectorNormalize (pmove->forward); // Normalize remainder of vectors. - VectorNormalize (pmove->right); // - - for (i=0 ; i<2 ; i++) // Determine x and y parts of velocity - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; - - wishvel[2] = 0; // Zero out z part of velocity - - VectorCopy (wishvel, wishdir); // Determine maginitude of speed of move - wishspeed = VectorNormalize(wishdir); - -// -// Clamp to server defined max speed -// - if (wishspeed > pmove->maxspeed) - { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); - wishspeed = pmove->maxspeed; - } - - // Set pmove velocity - pmove->velocity[2] = 0; - PM_Accelerate (wishdir, wishspeed, pmove->movevars->accelerate); - pmove->velocity[2] = 0; - - // Add in any base velocity to the current velocity. - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity ); - - spd = Length( pmove->velocity ); - - if (spd < 1.0f) - { - VectorClear( pmove->velocity ); - return; - } - - // If we are not moving, do nothing - //if (!pmove->velocity[0] && !pmove->velocity[1] && !pmove->velocity[2]) - // return; - - oldonground = pmove->onground; - -// first try just moving to the destination - dest[0] = pmove->origin[0] + pmove->velocity[0]*pmove->frametime; - dest[1] = pmove->origin[1] + pmove->velocity[1]*pmove->frametime; - dest[2] = pmove->origin[2]; - - // first try moving directly to the next spot - VectorCopy (dest, start); - trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); - // If we made it all the way, then copy trace end - // as new player position. - if (trace.fraction == 1) - { - VectorCopy (trace.endpos, pmove->origin); - return; - } - - if (oldonground == -1 && // Don't walk up stairs if not on ground. - pmove->waterlevel == 0) - return; - - if (pmove->waterjumptime) // If we are jumping out of water, don't do anything more. - return; - - // Try sliding forward both on ground and up 16 pixels - // take the move that goes farthest - VectorCopy (pmove->origin, original); // Save out original pos & - VectorCopy (pmove->velocity, originalvel); // velocity. - - // Slide move - clip = PM_FlyMove (); - - // Copy the results out - VectorCopy (pmove->origin , down); - VectorCopy (pmove->velocity, downvel); - - // Reset original values. - VectorCopy (original, pmove->origin); - - VectorCopy (originalvel, pmove->velocity); - - // Start out up one stair height - VectorCopy (pmove->origin, dest); - dest[2] += pmove->movevars->stepsize; - - trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); - // If we started okay and made it part of the way at least, - // copy the results to the movement start position and then - // run another move try. - if (!trace.startsolid && !trace.allsolid) - { - VectorCopy (trace.endpos, pmove->origin); - } - -// slide move the rest of the way. - clip = PM_FlyMove (); - -// Now try going back down from the end point -// press down the stepheight - VectorCopy (pmove->origin, dest); - dest[2] -= pmove->movevars->stepsize; - - trace = pmove->PM_PlayerTrace (pmove->origin, dest, PM_NORMAL, -1 ); - - // If we are not on the ground any more then - // use the original movement attempt - if ( trace.plane.normal[2] < 0.7) - goto usedown; - // If the trace ended up in empty space, copy the end - // over to the origin. - if (!trace.startsolid && !trace.allsolid) - { - VectorCopy (trace.endpos, pmove->origin); - } - // Copy this origion to up. - VectorCopy (pmove->origin, pmove->up); - - // decide which one went farther - downdist = (down[0] - original[0])*(down[0] - original[0]) - + (down[1] - original[1])*(down[1] - original[1]); - updist = (pmove->up[0] - original[0])*(pmove->up[0] - original[0]) - + (pmove->up[1] - original[1])*(pmove->up[1] - original[1]); - - if (downdist > updist) - { -usedown: - VectorCopy (down , pmove->origin); - VectorCopy (downvel, pmove->velocity); - } else // copy z value from slide move - pmove->velocity[2] = downvel[2]; - -} - -/* -================== -PM_Friction - -Handles both ground friction and water friction -================== -*/ -void PM_Friction (void) -{ - float *vel; - float speed, newspeed, control; - float friction; - float drop; - vec3_t newvel; - - // If we are in water jump cycle, don't apply friction - if (pmove->waterjumptime) - return; - - // Get velocity - vel = pmove->velocity; - - // Calculate speed - speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1] + vel[2]*vel[2]); - - // If too slow, return - if (speed < 0.1f) - { - return; - } - - drop = 0; - -// apply ground friction - if (pmove->onground != -1) // On an entity that is the ground - { - vec3_t start, stop; - pmtrace_t trace; - - start[0] = stop[0] = pmove->origin[0] + vel[0]/speed*16; - start[1] = stop[1] = pmove->origin[1] + vel[1]/speed*16; - start[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2]; - stop[2] = start[2] - 34; - - trace = pmove->PM_PlayerTrace (start, stop, PM_NORMAL, -1 ); - - if (trace.fraction == 1.0) - friction = pmove->movevars->friction*pmove->movevars->edgefriction; - else - friction = pmove->movevars->friction; - - // Grab friction value. - //friction = pmove->movevars->friction; - - friction *= pmove->friction; // player friction? - - // Bleed off some speed, but if we have less than the bleed - // threshhold, bleed the theshold amount. - control = (speed < pmove->movevars->stopspeed) ? - pmove->movevars->stopspeed : speed; - // Add the amount to t'he drop amount. - drop += control*friction*pmove->frametime; - } - -// apply water friction -// if (pmove->waterlevel) -// drop += speed * pmove->movevars->waterfriction * waterlevel * pmove->frametime; - -// scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - - // Determine proportion of old speed we are using. - newspeed /= speed; - - // Adjust velocity according to proportion. - newvel[0] = vel[0] * newspeed; - newvel[1] = vel[1] * newspeed; - newvel[2] = vel[2] * newspeed; - - VectorCopy( newvel, pmove->velocity ); -} - -void PM_AirAccelerate (vec3_t wishdir, float wishspeed, float accel) -{ - int i; - float addspeed, accelspeed, currentspeed, wishspd = wishspeed; - - if (pmove->dead) - return; - if (pmove->waterjumptime) - return; - - // Cap speed - //wishspd = VectorNormalize (pmove->wishveloc); - - if (wishspd > 30) - wishspd = 30; - // Determine veer amount - currentspeed = DotProduct (pmove->velocity, wishdir); - // See how much to add - addspeed = wishspd - currentspeed; - // If not adding any, done. - if (addspeed <= 0) - return; - // Determine acceleration speed after acceleration - - accelspeed = accel * wishspeed * pmove->frametime * pmove->friction; - // Cap it - if (accelspeed > addspeed) - accelspeed = addspeed; - - // Adjust pmove vel. - for (i=0 ; i<3 ; i++) - { - pmove->velocity[i] += accelspeed*wishdir[i]; - } -} - -/* -=================== -PM_WaterMove - -=================== -*/ -void PM_WaterMove (void) -{ - int i; - vec3_t wishvel; - float wishspeed; - vec3_t wishdir; - vec3_t start, dest; - vec3_t temp; - pmtrace_t trace; - - float speed, newspeed, addspeed, accelspeed; - -// -// user intentions -// - for (i=0 ; i<3 ; i++) - wishvel[i] = pmove->forward[i]*pmove->cmd.forwardmove + pmove->right[i]*pmove->cmd.sidemove; - - // Sinking after no other movement occurs - if (!pmove->cmd.forwardmove && !pmove->cmd.sidemove && !pmove->cmd.upmove) - wishvel[2] -= 60; // drift towards bottom - else // Go straight up by upmove amount. - wishvel[2] += pmove->cmd.upmove; - - // Copy it over and determine speed - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // Cap speed. - if (wishspeed > pmove->maxspeed) - { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); - wishspeed = pmove->maxspeed; - } - // Slow us down a bit. - wishspeed *= 0.8; - - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); -// Water friction - VectorCopy(pmove->velocity, temp); - speed = VectorNormalize(temp); - if (speed) - { - newspeed = speed - pmove->frametime * speed * pmove->movevars->friction * pmove->friction; - - if (newspeed < 0) - newspeed = 0; - VectorScale (pmove->velocity, newspeed/speed, pmove->velocity); - } - else - newspeed = 0; - -// -// water acceleration -// - if ( wishspeed < 0.1f ) - { - return; - } - - addspeed = wishspeed - newspeed; - if (addspeed > 0) - { - - VectorNormalize(wishvel); - accelspeed = pmove->movevars->accelerate * wishspeed * pmove->frametime * pmove->friction; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i = 0; i < 3; i++) - pmove->velocity[i] += accelspeed * wishvel[i]; - } - -// Now move -// assume it is a stair or a slope, so press down from stepheight above - VectorMA (pmove->origin, pmove->frametime, pmove->velocity, dest); - VectorCopy (dest, start); - start[2] += pmove->movevars->stepsize + 1; - trace = pmove->PM_PlayerTrace (start, dest, PM_NORMAL, -1 ); - if (!trace.startsolid && !trace.allsolid) // FIXME: check steep slope? - { // walked up the step, so just keep result and exit - VectorCopy (trace.endpos, pmove->origin); - return; - } - - // Try moving straight along out normal path. - PM_FlyMove (); -} - - -/* -=================== -PM_AirMove - -=================== -*/ -void PM_AirMove (void) -{ - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - - // Copy movement amounts - fmove = pmove->cmd.forwardmove; - smove = pmove->cmd.sidemove; - - // Zero out z components of movement vectors - pmove->forward[2] = 0; - pmove->right[2] = 0; - // Renormalize - VectorNormalize (pmove->forward); - VectorNormalize (pmove->right); - - // Determine x and y parts of velocity - for (i=0 ; i<2 ; i++) - { - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; - } - // Zero out z part of velocity - wishvel[2] = 0; - - // Determine maginitude of speed of move - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // Clamp to server defined max speed - if (wishspeed > pmove->maxspeed) - { - VectorScale (wishvel, pmove->maxspeed/wishspeed, wishvel); - wishspeed = pmove->maxspeed; - } - - PM_AirAccelerate (wishdir, wishspeed, pmove->movevars->airaccelerate); - - // Add in any base velocity to the current velocity. - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity ); - - PM_FlyMove (); -} - -int PM_InWater( void ) -{ - return ( pmove->waterlevel > 1 ); -} - -/* -============= -PM_CheckWater - -Sets pmove->waterlevel and pmove->watertype values. -============= -*/ -int PM_CheckWater () -{ - vec3_t point; - int cont; - int TRUEcont; - float height; - float heightover2; - - // Pick a spot just above the players feet. - point[0] = pmove->origin[0] + (pmove->player_mins[pmove->usehull][0] + pmove->player_maxs[pmove->usehull][0]) * 0.5; - point[1] = pmove->origin[1] + (pmove->player_mins[pmove->usehull][1] + pmove->player_maxs[pmove->usehull][1]) * 0.5; - point[2] = pmove->origin[2] + pmove->player_mins[pmove->usehull][2] + 1; - - // Assume that we are not in water at all. - pmove->waterlevel = 0; - pmove->watertype = CONTENTS_EMPTY; - - // Grab point contents. - cont = pmove->PM_PointContents (point, &TRUEcont ); - // Are we under water? (not solid and not empty?) - if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) - { - // Set water type - pmove->watertype = cont; - - // We are at least at level one - pmove->waterlevel = 1; - - height = (pmove->player_mins[pmove->usehull][2] + pmove->player_maxs[pmove->usehull][2]); - heightover2 = height * 0.5; - - // Now check a point that is at the player hull midpoint. - point[2] = pmove->origin[2] + heightover2; - cont = pmove->PM_PointContents (point, NULL ); - // If that point is also under water... - if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) - { - // Set a higher water level. - pmove->waterlevel = 2; - - // Now check the eye position. (view_ofs is relative to the origin) - point[2] = pmove->origin[2] + pmove->view_ofs[2]; - - cont = pmove->PM_PointContents (point, NULL ); - if (cont <= CONTENTS_WATER && cont > CONTENTS_TRANSLUCENT ) - pmove->waterlevel = 3; // In over our eyes - } - - // Adjust velocity based on water current, if any. - if ( ( TRUEcont <= CONTENTS_CURRENT_0 ) && - ( TRUEcont >= CONTENTS_CURRENT_DOWN ) ) - { - // The deeper we are, the stronger the current. - static vec3_t current_table[] = - { - {1, 0, 0}, {0, 1, 0}, {-1, 0, 0}, - {0, -1, 0}, {0, 0, 1}, {0, 0, -1} - }; - - VectorMA (pmove->basevelocity, 50.0*pmove->waterlevel, current_table[CONTENTS_CURRENT_0 - TRUEcont], pmove->basevelocity); - } - } - - return pmove->waterlevel > 1; -} - -/* -============= -PM_CatagorizePosition -============= -*/ -void PM_CatagorizePosition (void) -{ - vec3_t point; - pmtrace_t tr; - -// if the player hull point one unit down is solid, the player -// is on ground - -// see if standing on something solid - - // Doing this before we move may introduce a potential latency in water detection, but - // doing it after can get us stuck on the bottom in water if the amount we move up - // is less than the 1 pixel 'threshold' we're about to snap to. Also, we'll call - // this several times per frame, so we really need to avoid sticking to the bottom of - // water on each call, and the converse case will correct itself if called twice. - PM_CheckWater(); - - point[0] = pmove->origin[0]; - point[1] = pmove->origin[1]; - point[2] = pmove->origin[2] - 2; - - if (pmove->velocity[2] > 180) // Shooting up really fast. Definitely not on ground. - { - pmove->onground = -1; - } - else - { - // Try and move down. - tr = pmove->PM_PlayerTrace (pmove->origin, point, PM_NORMAL, -1 ); - // If we hit a steep plane, we are not on ground - if ( tr.plane.normal[2] < 0.7) - pmove->onground = -1; // too steep - else - pmove->onground = tr.ent; // Otherwise, point to index of ent under us. - - // If we are on something... - if (pmove->onground != -1) - { - // Then we are not in water jump sequence - pmove->waterjumptime = 0; - // If we could make the move, drop us down that 1 pixel - if (pmove->waterlevel < 2 && !tr.startsolid && !tr.allsolid) - VectorCopy (tr.endpos, pmove->origin); - } - - // Standing on an entity other than the world - if (tr.ent > 0) // So signal that we are touching something. - { - PM_AddToTouched(tr, pmove->velocity); - } - } -} - -/* -================= -PM_GetRandomStuckOffsets - -When a player is stuck, it's costly to try and unstick them -Grab a test offset for the player based on a passed in index -================= -*/ -int PM_GetRandomStuckOffsets(int nIndex, int server, vec3_t offset) -{ - // Last time we did a full - int idx; - idx = rgStuckLast[nIndex][server]++; - - VectorCopy(rgv3tStuckTable[idx % 54], offset); - - return (idx % 54); -} - -void PM_ResetStuckOffsets(int nIndex, int server) -{ - rgStuckLast[nIndex][server] = 0; -} - -/* -================= -NudgePosition - -If pmove->origin is in a solid position, -try nudging slightly on all axis to -allow for the cut precision of the net coordinates -================= -*/ -#define PM_CHECKSTUCK_MINTIME 0.05 // Don't check again too quickly. - -int PM_CheckStuck (void) -{ - vec3_t base; - vec3_t offset; - vec3_t test; - int hitent; - int idx; - float fTime; - int i; - pmtrace_t traceresult; - - static float rgStuckCheckTime[MAX_CLIENTS][2]; // Last time we did a full - - // If position is okay, exit - hitent = pmove->PM_TestPlayerPosition (pmove->origin, &traceresult ); - if (hitent == -1 ) - { - PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - return 0; - } - - VectorCopy (pmove->origin, base); - - // - // Deal with precision error in network. - // - if (!pmove->server) - { - // World or BSP model - if ( ( hitent == 0 ) || - ( pmove->physents[hitent].model != NULL ) ) - { - int nReps = 0; - PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - do - { - i = PM_GetRandomStuckOffsets(pmove->player_index, pmove->server, offset); - - VectorAdd(base, offset, test); - if (pmove->PM_TestPlayerPosition (test, &traceresult ) == -1) - { - PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - - VectorCopy ( test, pmove->origin ); - return 0; - } - nReps++; - } while (nReps < 54); - } - } - - // Only an issue on the client. - - if (pmove->server) - idx = 0; - else - idx = 1; - - fTime = pmove->Sys_FloatTime(); - // Too soon? - if (rgStuckCheckTime[pmove->player_index][idx] >= - ( fTime - PM_CHECKSTUCK_MINTIME ) ) - { - return 1; - } - rgStuckCheckTime[pmove->player_index][idx] = fTime; - - pmove->PM_StuckTouch( hitent, &traceresult ); - - i = PM_GetRandomStuckOffsets(pmove->player_index, pmove->server, offset); - - VectorAdd(base, offset, test); - if ( ( hitent = pmove->PM_TestPlayerPosition ( test, NULL ) ) == -1 ) - { - //ConDPrintf("Nudged\n"); - - PM_ResetStuckOffsets( pmove->player_index, pmove->server ); - - if (i >= 27) - VectorCopy ( test, pmove->origin ); - - return 0; - } - - // If player is flailing while stuck in another player ( should never happen ), then see - // if we can't "unstick" them forceably. - if ( pmove->cmd.buttons & ( IN_JUMP | IN_DUCK | IN_ATTACK ) && ( pmove->physents[ hitent ].player != 0 ) ) - { - float x, y, z; - float xystep = 8.0; - float zstep = 18.0; - float xyminmax = xystep; - float zminmax = 4 * zstep; - - for ( z = 0; z <= zminmax; z += zstep ) - { - for ( x = -xyminmax; x <= xyminmax; x += xystep ) - { - for ( y = -xyminmax; y <= xyminmax; y += xystep ) - { - VectorCopy( base, test ); - test[0] += x; - test[1] += y; - test[2] += z; - - if ( pmove->PM_TestPlayerPosition ( test, NULL ) == -1 ) - { - VectorCopy( test, pmove->origin ); - return 0; - } - } - } - } - } - - //VectorCopy (base, pmove->origin); - - return 1; -} - -/* -=============== -PM_SpectatorMove -=============== -*/ -void PM_SpectatorMove (void) -{ - float speed, drop, friction, control, newspeed; - //float accel; - float currentspeed, addspeed, accelspeed; - int i; - vec3_t wishvel; - float fmove, smove; - vec3_t wishdir; - float wishspeed; - // this routine keeps track of the spectators psoition - // there a two different main move types : track player or moce freely (OBS_ROAMING) - // doesn't need excate track position, only to generate PVS, so just copy - // targets position and real view position is calculated on client (saves server CPU) - - if ( pmove->iuser1 == OBS_ROAMING) - { - -#ifdef CLIENT_DLL - // jump only in roaming mode - if ( iJumpSpectator ) - { - VectorCopy( vJumpOrigin, pmove->origin ); - VectorCopy( vJumpAngles, pmove->angles ); - VectorCopy( vec3_origin, pmove->velocity ); - iJumpSpectator = 0; - return; - } - #endif - // Move around in normal spectator method - - speed = Length (pmove->velocity); - if (speed < 1) - { - VectorCopy (vec3_origin, pmove->velocity) - } - else - { - drop = 0; - - friction = pmove->movevars->friction*1.5; // extra friction - control = speed < pmove->movevars->stopspeed ? pmove->movevars->stopspeed : speed; - drop += control*friction*pmove->frametime; - - // scale the velocity - newspeed = speed - drop; - if (newspeed < 0) - newspeed = 0; - newspeed /= speed; - - VectorScale (pmove->velocity, newspeed, pmove->velocity); - } - - // accelerate - fmove = pmove->cmd.forwardmove; - smove = pmove->cmd.sidemove; - - VectorNormalize (pmove->forward); - VectorNormalize (pmove->right); - - for (i=0 ; i<3 ; i++) - { - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; - } - wishvel[2] += pmove->cmd.upmove; - - VectorCopy (wishvel, wishdir); - wishspeed = VectorNormalize(wishdir); - - // - // clamp to server defined max speed - // - if (wishspeed > pmove->movevars->spectatormaxspeed) - { - VectorScale (wishvel, pmove->movevars->spectatormaxspeed/wishspeed, wishvel); - wishspeed = pmove->movevars->spectatormaxspeed; - } - - currentspeed = DotProduct(pmove->velocity, wishdir); - addspeed = wishspeed - currentspeed; - if (addspeed <= 0) - return; - - accelspeed = pmove->movevars->accelerate*pmove->frametime*wishspeed; - if (accelspeed > addspeed) - accelspeed = addspeed; - - for (i=0 ; i<3 ; i++) - pmove->velocity[i] += accelspeed*wishdir[i]; - - // move - VectorMA (pmove->origin, pmove->frametime, pmove->velocity, pmove->origin); - } - else - { - // all other modes just track some kind of target, so spectator PVS = target PVS - - int target; - - // no valid target ? - if ( pmove->iuser2 <= 0) - return; - - // Find the client this player's targeting - for (target = 0; target < pmove->numphysent; target++) - { - if ( pmove->physents[target].info == pmove->iuser2 ) - break; - } - - if (target == pmove->numphysent) - return; - - // use targets position as own origin for PVS - VectorCopy( pmove->physents[target].angles, pmove->angles ); - VectorCopy( pmove->physents[target].origin, pmove->origin ); - - // no velocity - VectorCopy( vec3_origin, pmove->velocity ); - } -} - -/* -================== -PM_SplineFraction - -Use for ease-in, ease-out style interpolation (accel/decel) -Used by ducking code. -================== -*/ -float PM_SplineFraction( float value, float scale ) -{ - float valueSquared; - - value = scale * value; - valueSquared = value * value; - - // Nice little ease-in, ease-out spline-like curve - return 3 * valueSquared - 2 * valueSquared * value; -} - -void PM_FixPlayerCrouchStuck( int direction ) -{ - int hitent; - int i; - vec3_t test; - - hitent = pmove->PM_TestPlayerPosition ( pmove->origin, NULL ); - if (hitent == -1 ) - return; - - VectorCopy( pmove->origin, test ); - for ( i = 0; i < 36; i++ ) - { - pmove->origin[2] += direction; - hitent = pmove->PM_TestPlayerPosition ( pmove->origin, NULL ); - if (hitent == -1 ) - return; - } - - VectorCopy( test, pmove->origin ); // Failed -} - -void PM_UnDuck( void ) -{ - int i; - pmtrace_t trace; - vec3_t newOrigin; - - VectorCopy( pmove->origin, newOrigin ); - - if ( pmove->onground != -1 ) - { - 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 ); - - if ( !trace.startsolid ) - { - pmove->usehull = 0; - - // Oh, no, changing hulls stuck us into something, try unsticking downward first. - trace = pmove->PM_PlayerTrace( newOrigin, newOrigin, PM_NORMAL, -1 ); - if ( trace.startsolid ) - { - // See if we are stuck? If so, stay ducked with the duck hull until we have a clear spot - //ConPrintf( "unstick got stuck\n" ); - pmove->usehull = 1; - return; - } - - pmove->flags &= ~FL_DUCKING; - pmove->bInDuck = FALSE; - pmove->view_ofs[2] = VEC_VIEW; - pmove->flDuckTime = 0; - - VectorCopy( newOrigin, pmove->origin ); - - // Recatagorize position since ducking can change origin - PM_CatagorizePosition(); - } -} - -void PM_Duck( void ) -{ - int i; - float time; - float duckFraction; - - int buttonsChanged = ( pmove->oldbuttons ^ pmove->cmd.buttons ); // These buttons have changed this frame - int nButtonPressed = buttonsChanged & pmove->cmd.buttons; // The changed ones still down are "pressed" - - int duckchange = buttonsChanged & IN_DUCK ? 1 : 0; - int duckpressed = nButtonPressed & IN_DUCK ? 1 : 0; - - if ( pmove->cmd.buttons & IN_DUCK ) - { - pmove->oldbuttons |= IN_DUCK; - } - else - { - pmove->oldbuttons &= ~IN_DUCK; - } - - // Prevent ducking if the iuser3 variable is set - if ( pmove->iuser3 || pmove->dead ) - { - // Try to unduck - if ( pmove->flags & FL_DUCKING ) - { - PM_UnDuck(); - } - return; - } - - if ( pmove->flags & FL_DUCKING ) - { - pmove->cmd.forwardmove *= 0.333; - pmove->cmd.sidemove *= 0.333; - pmove->cmd.upmove *= 0.333; - } - - if ( ( pmove->cmd.buttons & IN_DUCK ) || ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) - { - if ( pmove->cmd.buttons & IN_DUCK ) - { - if ( (nButtonPressed & IN_DUCK ) && !( pmove->flags & FL_DUCKING ) ) - { - // Use 1 second so super long jump will work - pmove->flDuckTime = 1000; - pmove->bInDuck = TRUE; - } - - time = max( 0.0, ( 1.0 - (float)pmove->flDuckTime / 1000.0 ) ); - - if ( pmove->bInDuck ) - { - // Finish ducking immediately if duck time is over or not on ground - if ( ( (float)pmove->flDuckTime / 1000.0 <= ( 1.0 - TIME_TO_DUCK ) ) || - ( pmove->onground == -1 ) ) - { - pmove->usehull = 1; - pmove->view_ofs[2] = VEC_DUCK_VIEW; - pmove->flags |= FL_DUCKING; - pmove->bInDuck = FALSE; - - // HACKHACK - Fudge for collision bug - no time to fix this properly - if ( pmove->onground != -1 ) - { - for ( i = 0; i < 3; i++ ) - { - pmove->origin[i] -= ( pmove->player_mins[1][i] - pmove->player_mins[0][i] ); - } - // See if we are stuck? - PM_FixPlayerCrouchStuck( STUCK_MOVEUP ); - - // Recatagorize position since ducking can change origin - PM_CatagorizePosition(); - } - } - else - { - float fMore = (VEC_DUCK_HULL_MIN - VEC_HULL_MIN); - - // Calc parametric time - duckFraction = PM_SplineFraction( time, (1.0/TIME_TO_DUCK) ); - pmove->view_ofs[2] = ((VEC_DUCK_VIEW - fMore ) * duckFraction) + (VEC_VIEW * (1-duckFraction)); - } - } - } - else - { - // Try to unduck - PM_UnDuck(); - } - } -} - -void PM_LadderMove( physent_t *pLadder ) -{ - vec3_t ladderCenter; - pmtrace_t trace; - int onFloor; - vec3_t floor; - vec3_t modelmins, modelmaxs; - - if ( pmove->movetype == MOVETYPE_NOCLIP ) - return; - - pmove->PM_GetModelBounds( pLadder->model, modelmins, modelmaxs ); - - VectorAdd( modelmins, modelmaxs, ladderCenter ); - VectorScale( ladderCenter, 0.5, ladderCenter ); - VectorAdd( ladderCenter, pLadder->origin, ladderCenter ); // allow for ladders moving around - - pmove->movetype = MOVETYPE_FLY; - - // On ladder, convert movement to be relative to the ladder - - VectorCopy( pmove->origin, floor ); - floor[2] += pmove->player_mins[pmove->usehull][2] - 1; - - if ( pmove->PM_PointContents( floor, NULL ) == CONTENTS_SOLID ) - onFloor = TRUE; - else - onFloor = FALSE; - - pmove->gravity = 0; - pmove->PM_TraceModel( pLadder, pmove->origin, ladderCenter, &trace ); - - if ( trace.fraction != 1.0 ) - { - float forward = 0, right = 0; - vec3_t vpn, v_right; - - AngleVectors( pmove->angles, vpn, v_right, NULL ); - if ( pmove->cmd.buttons & IN_BACK ) - forward -= MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_FORWARD ) - forward += MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_MOVELEFT ) - right -= MAX_CLIMB_SPEED; - if ( pmove->cmd.buttons & IN_MOVERIGHT ) - right += MAX_CLIMB_SPEED; - - if ( pmove->cmd.buttons & IN_JUMP ) - { - pmove->movetype = MOVETYPE_WALK; - VectorScale( trace.plane.normal, 270, pmove->velocity ); - } - else - { - if ( forward != 0 || right != 0 ) - { - vec3_t velocity, perp, cross, lateral, tmp; - float normal; - - //ALERT(at_console, "pev %.2f %.2f %.2f - ", - // pev->velocity.x, pev->velocity.y, pev->velocity.z); - // Calculate player's intended velocity - //Vector velocity = (forward * gpGlobals->v_forward) + (right * gpGlobals->v_right); - VectorScale( vpn, forward, velocity ); - VectorMA( velocity, right, v_right, velocity ); - - - // Perpendicular in the ladder plane - // Vector perp = CrossProduct( Vector(0,0,1), trace.vecPlaneNormal ); - // perp = perp.Normalize(); - VectorClear( tmp ); - tmp[2] = 1; - CrossProduct( tmp, trace.plane.normal, perp ); - VectorNormalize( perp ); - - - // decompose velocity into ladder plane - normal = DotProduct( velocity, trace.plane.normal ); - // This is the velocity into the face of the ladder - VectorScale( trace.plane.normal, normal, cross ); - - - // This is the player's additional velocity - VectorSubtract( velocity, cross, lateral ); - - // This turns the velocity into the face of the ladder into velocity that - // is roughly vertically perpendicular to the face of the ladder. - // NOTE: It IS possible to face up and move down or face down and move up - // because the velocity is a sum of the directional velocity and the converted - // velocity through the face of the ladder -- by design. - CrossProduct( trace.plane.normal, perp, tmp ); - VectorMA( lateral, -normal, tmp, pmove->velocity ); - if ( onFloor && normal > 0 ) // On ground moving away from the ladder - { - VectorMA( pmove->velocity, MAX_CLIMB_SPEED, trace.plane.normal, pmove->velocity ); - } - //pev->velocity = lateral - (CrossProduct( trace.vecPlaneNormal, perp ) * normal); - } - else - { - VectorClear( pmove->velocity ); - } - } - } -} - -physent_t *PM_Ladder( void ) -{ - int i; - physent_t *pe; - hull_t *hull; - int num; - vec3_t test; - - for ( i = 0; i < pmove->nummoveent; i++ ) - { - pe = &pmove->moveents[i]; - - if ( pe->model && (modtype_t)pmove->PM_GetModelType( pe->model ) == mod_brush && pe->skin == CONTENTS_LADDER ) - { - - hull = (hull_t *)pmove->PM_HullForBsp( pe, test ); - num = hull->firstclipnode; - - // Offset the test point appropriately for this hull. - VectorSubtract ( pmove->origin, test, test); - - // Test the player's hull for intersection with this model - if ( pmove->PM_HullPointContents (hull, num, test) == CONTENTS_EMPTY) - continue; - - return pe; - } - } - - return NULL; -} - - - -void PM_WaterJump (void) -{ - if ( pmove->waterjumptime > 10000 ) - { - pmove->waterjumptime = 10000; - } - - if ( !pmove->waterjumptime ) - return; - - pmove->waterjumptime -= pmove->cmd.msec; - if ( pmove->waterjumptime < 0 || - !pmove->waterlevel ) - { - pmove->waterjumptime = 0; - pmove->flags &= ~FL_WATERJUMP; - } - - pmove->velocity[0] = pmove->movedir[0]; - pmove->velocity[1] = pmove->movedir[1]; -} - -/* -============ -PM_AddGravity - -============ -*/ -void PM_AddGravity () -{ - float ent_gravity; - - if (pmove->gravity) - ent_gravity = pmove->gravity; - else - ent_gravity = 1.0; - - // Add gravity incorrectly - pmove->velocity[2] -= (ent_gravity * pmove->movevars->gravity * pmove->frametime ); - pmove->velocity[2] += pmove->basevelocity[2] * pmove->frametime; - pmove->basevelocity[2] = 0; - PM_CheckVelocity(); -} -/* -============ -PM_PushEntity - -Does not change the entities velocity at all -============ -*/ -pmtrace_t PM_PushEntity (vec3_t push) -{ - pmtrace_t trace; - vec3_t end; - - VectorAdd (pmove->origin, push, end); - - trace = pmove->PM_PlayerTrace (pmove->origin, end, PM_NORMAL, -1 ); - - VectorCopy (trace.endpos, pmove->origin); - - // So we can run impact function afterwards. - if (trace.fraction < 1.0 && - !trace.allsolid) - { - PM_AddToTouched(trace, pmove->velocity); - } - - return trace; -} - -/* -============ -PM_Physics_Toss() - -Dead player flying through air., e.g. -============ -*/ -void PM_Physics_Toss() -{ - pmtrace_t trace; - vec3_t move; - float backoff; - - PM_CheckWater(); - - if (pmove->velocity[2] > 0) - pmove->onground = -1; - - // If on ground and not moving, return. - if ( pmove->onground != -1 ) - { - if (VectorCompare(pmove->basevelocity, vec3_origin) && - VectorCompare(pmove->velocity, vec3_origin)) - return; - } - - PM_CheckVelocity (); - -// add gravity - if ( pmove->movetype != MOVETYPE_FLY && - pmove->movetype != MOVETYPE_BOUNCEMISSILE && - pmove->movetype != MOVETYPE_FLYMISSILE ) - PM_AddGravity (); - -// move origin - // Base velocity is not properly accounted for since this entity will move again after the bounce without - // taking it into account - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); - - PM_CheckVelocity(); - VectorScale (pmove->velocity, pmove->frametime, move); - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); - - trace = PM_PushEntity (move); // Should this clear basevelocity - - PM_CheckVelocity(); - - if (trace.allsolid) - { - // entity is trapped in another solid - pmove->onground = trace.ent; - VectorCopy (vec3_origin, pmove->velocity); - return; - } - - if (trace.fraction == 1) - { - PM_CheckWater(); - return; - } - - - if (pmove->movetype == MOVETYPE_BOUNCE) - backoff = 2.0 - pmove->friction; - else if (pmove->movetype == MOVETYPE_BOUNCEMISSILE) - backoff = 2.0; - else - backoff = 1; - - PM_ClipVelocity (pmove->velocity, trace.plane.normal, pmove->velocity, backoff); - - // stop if on ground - if (trace.plane.normal[2] > 0.7) - { - float vel; - vec3_t base; - - VectorClear( base ); - if (pmove->velocity[2] < pmove->movevars->gravity * pmove->frametime) - { - // we're rolling on the ground, add static friction. - pmove->onground = trace.ent; - pmove->velocity[2] = 0; - } - - vel = DotProduct( pmove->velocity, pmove->velocity ); - - // ConDPrintf("%f %f: %.0f %.0f %.0f\n", vel, trace.fraction, ent->velocity[0], ent->velocity[1], ent->velocity[2] ); - - if (vel < (30 * 30) || (pmove->movetype != MOVETYPE_BOUNCE && pmove->movetype != MOVETYPE_BOUNCEMISSILE)) - { - pmove->onground = trace.ent; - VectorCopy (vec3_origin, pmove->velocity); - } - else - { - VectorScale (pmove->velocity, (1.0 - trace.fraction) * pmove->frametime * 0.9, move); - trace = PM_PushEntity (move); - } - VectorSubtract( pmove->velocity, base, pmove->velocity ) - } - -// check for in water - PM_CheckWater(); -} - -/* -==================== -PM_NoClip - -==================== -*/ -void PM_NoClip() -{ - int i; - vec3_t wishvel; - float fmove, smove; -// float currentspeed, addspeed, accelspeed; - - // Copy movement amounts - fmove = pmove->cmd.forwardmove; - smove = pmove->cmd.sidemove; - - VectorNormalize ( pmove->forward ); - VectorNormalize ( pmove->right ); - - for (i=0 ; i<3 ; i++) // Determine x and y parts of velocity - { - wishvel[i] = pmove->forward[i]*fmove + pmove->right[i]*smove; - } - wishvel[2] += pmove->cmd.upmove; - - VectorMA (pmove->origin, pmove->frametime, wishvel, pmove->origin); - - // Zero out the velocity so that we don't accumulate a huge downward velocity from - // gravity, etc. - VectorClear( pmove->velocity ); - -} - -// Only allow bunny jumping up to 1.7x server / player maxspeed setting -#define BUNNYJUMP_MAX_SPEED_FACTOR 1.7f - -//----------------------------------------------------------------------------- -// Purpose: Corrects bunny jumping ( where player initiates a bunny jump before other -// movement logic runs, thus making onground == -1 thus making PM_Friction get skipped and -// running PM_AirMove, which doesn't crop velocity to maxspeed like the ground / other -// movement logic does. -//----------------------------------------------------------------------------- -void PM_PreventMegaBunnyJumping( void ) -{ - // Current player speed - float spd; - // If we have to crop, apply this cropping fraction to velocity - float fraction; - // Speed at which bunny jumping is limited - float maxscaledspeed; - - maxscaledspeed = BUNNYJUMP_MAX_SPEED_FACTOR * pmove->maxspeed; - - // Don't divide by zero - if ( maxscaledspeed <= 0.0f ) - return; - - spd = Length( pmove->velocity ); - - if ( spd <= maxscaledspeed ) - return; - - fraction = ( maxscaledspeed / spd ) * 0.65; //Returns the modifier for the velocity - - VectorScale( pmove->velocity, fraction, pmove->velocity ); //Crop it down!. -} - -/* -============= -PM_Jump -============= -*/ -void PM_Jump (void) -{ - int i; - int tfc = FALSE; - - int cansuperjump = FALSE; - - if (pmove->dead) - { - pmove->oldbuttons |= IN_JUMP ; // don't jump again until released - return; - } - - tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? TRUE : FALSE; - - // Spy that's feigning death cannot jump - if ( tfc && - ( pmove->deadflag == ( DEAD_DISCARDBODY + 1 ) ) ) - { - return; - } - - // See if we are waterjumping. If so, decrement count and return. - if ( pmove->waterjumptime ) - { - pmove->waterjumptime -= pmove->cmd.msec; - if (pmove->waterjumptime < 0) - { - pmove->waterjumptime = 0; - } - return; - } - - // If we are in the water most of the way... - if (pmove->waterlevel >= 2) - { // swimming, not jumping - pmove->onground = -1; - - if (pmove->watertype == CONTENTS_WATER) // We move up a certain amount - pmove->velocity[2] = 100; - else if (pmove->watertype == CONTENTS_SLIME) - pmove->velocity[2] = 80; - else // LAVA - pmove->velocity[2] = 50; - - // play swiming sound - if ( pmove->flSwimTime <= 0 ) - { - // Don't play sound again for 1 second - pmove->flSwimTime = 1000; - switch ( pmove->RandomLong( 0, 3 ) ) - { - case 0: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 1: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 2: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 3: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - } - } - - return; - } - - // No more effect - if ( pmove->onground == -1 ) - { - // Flag that we jumped. - // HACK HACK HACK - // Remove this when the game .dll no longer does physics code!!!! - pmove->oldbuttons |= IN_JUMP; // don't jump again until released - return; // in air, so no effect - } - - if ( pmove->oldbuttons & IN_JUMP ) - return; // don't pogo stick - - // In the air now. - pmove->onground = -1; - - PM_PreventMegaBunnyJumping(); - - if ( tfc ) - { - pmove->PM_PlaySound( CHAN_BODY, "player/plyrjmp8.wav", 0.5, ATTN_NORM, 0, PITCH_NORM ); - } - else - { - PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), 1.0 ); - } - - // See if user can super long jump? - cansuperjump = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "slj" ) ) == 1 ? TRUE : FALSE; - - // Acclerate upward - // If we are ducking... - if ( ( pmove->bInDuck ) || ( pmove->flags & FL_DUCKING ) ) - { - // Adjust for super long jump module - // UNDONE -- note this should be based on forward angles, not current velocity. - if ( cansuperjump && - ( pmove->cmd.buttons & IN_DUCK ) && - ( pmove->flDuckTime > 0 ) && - Length( pmove->velocity ) > 50 ) - { - pmove->punchangle[0] = -5; - - for (i =0; i < 2; i++) - { - pmove->velocity[i] = pmove->forward[i] * PLAYER_LONGJUMP_SPEED * 1.6; - } - - pmove->velocity[2] = sqrt(2 * 800 * 56.0); - } - else - { - pmove->velocity[2] = sqrt(2 * 800 * 45.0); - } - } - else - { - pmove->velocity[2] = sqrt(2 * 800 * 45.0); - } - - // Decay it for simulation - PM_FixupGravityVelocity(); - - // Flag that we jumped. - pmove->oldbuttons |= IN_JUMP; // don't jump again until released -} - -/* -============= -PM_CheckWaterJump -============= -*/ -#define WJ_HEIGHT 8 -void PM_CheckWaterJump (void) -{ - vec3_t vecStart, vecEnd; - vec3_t flatforward; - vec3_t flatvelocity; - float curspeed; - pmtrace_t tr; - int savehull; - - // Already water jumping. - if ( pmove->waterjumptime ) - return; - - // Don't hop out if we just jumped in - if ( pmove->velocity[2] < -180 ) - return; // only hop out if we are moving up - - // See if we are backing up - flatvelocity[0] = pmove->velocity[0]; - flatvelocity[1] = pmove->velocity[1]; - flatvelocity[2] = 0; - - // Must be moving - curspeed = VectorNormalize( flatvelocity ); - - // see if near an edge - flatforward[0] = pmove->forward[0]; - flatforward[1] = pmove->forward[1]; - flatforward[2] = 0; - VectorNormalize (flatforward); - - // Are we backing into water from steps or something? If so, don't pop forward - if ( curspeed != 0.0 && ( DotProduct( flatvelocity, flatforward ) < 0.0 ) ) - return; - - VectorCopy( pmove->origin, vecStart ); - vecStart[2] += WJ_HEIGHT; - - VectorMA ( vecStart, 24, flatforward, vecEnd ); - - // Trace, this trace should use the point sized collision hull - savehull = pmove->usehull; - pmove->usehull = 2; - tr = pmove->PM_PlayerTrace( vecStart, vecEnd, PM_NORMAL, -1 ); - if ( tr.fraction < 1.0 && fabs( tr.plane.normal[2] ) < 0.1f ) // Facing a near vertical wall? - { - vecStart[2] += pmove->player_maxs[ savehull ][2] - WJ_HEIGHT; - VectorMA( vecStart, 24, flatforward, vecEnd ); - VectorMA( vec3_origin, -50, tr.plane.normal, pmove->movedir ); - - tr = pmove->PM_PlayerTrace( vecStart, vecEnd, PM_NORMAL, -1 ); - if ( tr.fraction == 1.0 ) - { - pmove->waterjumptime = 2000; - pmove->velocity[2] = 225; - pmove->oldbuttons |= IN_JUMP; - pmove->flags |= FL_WATERJUMP; - } - } - - // Reset the collision hull - pmove->usehull = savehull; -} - -void PM_CheckFalling( void ) -{ - if ( pmove->onground != -1 && - !pmove->dead && - pmove->flFallVelocity >= PLAYER_FALL_PUNCH_THRESHHOLD ) - { - float fvol = 0.5; - - if ( pmove->waterlevel > 0 ) - { - } - else if ( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED ) - { - // NOTE: In the original game dll , there were no breaks after these cases, causing the first one to - // cascade into the second - //switch ( RandomLong(0,1) ) - //{ - //case 0: - //pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - //break; - //case 1: - pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - // break; - //} - fvol = 1.0; - } - else if ( pmove->flFallVelocity > PLAYER_MAX_SAFE_FALL_SPEED / 2 ) - { - int tfc = FALSE; - tfc = atoi( pmove->PM_Info_ValueForKey( pmove->physinfo, "tfc" ) ) == 1 ? TRUE : FALSE; - - if ( tfc ) - { - pmove->PM_PlaySound( CHAN_VOICE, "player/pl_fallpain3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - } - - fvol = 0.85; - } - else if ( pmove->flFallVelocity < PLAYER_MIN_BOUNCE_SPEED ) - { - fvol = 0; - } - - if ( fvol > 0.0 ) - { - // Play landing step right away - pmove->flTimeStepSound = 0; - - PM_UpdateStepSound(); - - // play step sound for current texture - PM_PlayStepSound( PM_MapTextureTypeStepType( pmove->chtexturetype ), fvol ); - - // Knock the screen around a little bit, temporary effect - pmove->punchangle[ 2 ] = pmove->flFallVelocity * 0.013; // punch z axis - - if ( pmove->punchangle[ 0 ] > 8 ) - { - pmove->punchangle[ 0 ] = 8; - } - } - } - - if ( pmove->onground != -1 ) - { - pmove->flFallVelocity = 0; - } -} - -/* -================= -PM_PlayWaterSounds - -================= -*/ -void PM_PlayWaterSounds( void ) -{ - // Did we enter or leave water? - if ( ( pmove->oldwaterlevel == 0 && pmove->waterlevel != 0 ) || - ( pmove->oldwaterlevel != 0 && pmove->waterlevel == 0 ) ) - { - switch ( pmove->RandomLong(0,3) ) - { - case 0: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade1.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 1: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade2.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 2: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade3.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - case 3: - pmove->PM_PlaySound( CHAN_BODY, "player/pl_wade4.wav", 1, ATTN_NORM, 0, PITCH_NORM ); - break; - } - } -} - -/* -=============== -PM_CalcRoll - -=============== -*/ -float PM_CalcRoll (vec3_t angles, vec3_t velocity, float rollangle, float rollspeed ) -{ - float sign; - float side; - float value; - vec3_t forward, right, up; - - AngleVectors (angles, forward, right, up); - - side = DotProduct (velocity, right); - - sign = side < 0 ? -1 : 1; - - side = fabs(side); - - value = rollangle; - - if (side < rollspeed) - { - side = side * value / rollspeed; - } - else - { - side = value; - } - - return side * sign; -} - -/* -============= -PM_DropPunchAngle - -============= -*/ -void PM_DropPunchAngle ( vec3_t punchangle ) -{ - float len; - - len = VectorNormalize ( punchangle ); - len -= (10.0 + len * 0.5) * pmove->frametime; - len = max( len, 0.0 ); - VectorScale ( punchangle, len, punchangle); -} - -/* -============== -PM_CheckParamters - -============== -*/ -void PM_CheckParamters( void ) -{ - float spd; - float maxspeed; - vec3_t v_angle; - - spd = ( pmove->cmd.forwardmove * pmove->cmd.forwardmove ) + - ( pmove->cmd.sidemove * pmove->cmd.sidemove ) + - ( pmove->cmd.upmove * pmove->cmd.upmove ); - spd = sqrt( spd ); - - maxspeed = pmove->clientmaxspeed; //atof( pmove->PM_Info_ValueForKey( pmove->physinfo, "maxspd" ) ); - if ( maxspeed != 0.0 ) - { - pmove->maxspeed = min( maxspeed, pmove->maxspeed ); - } - - if ( ( spd != 0.0 ) && - ( spd > pmove->maxspeed ) ) - { - float fRatio = pmove->maxspeed / spd; - pmove->cmd.forwardmove *= fRatio; - pmove->cmd.sidemove *= fRatio; - pmove->cmd.upmove *= fRatio; - } - - if ( pmove->flags & FL_FROZEN || pmove->flags & FL_ONTRAIN || pmove->dead ) - { - pmove->cmd.forwardmove = 0; - pmove->cmd.sidemove = 0; - pmove->cmd.upmove = 0; - - // clearing IN_JUMP flag when frozen - if( pmove->flags & FL_FROZEN ) - pmove->cmd.buttons = 0; - } - - - PM_DropPunchAngle( pmove->punchangle ); - - // Take angles from command. - if ( !pmove->dead ) - { - VectorCopy ( pmove->cmd.viewangles, v_angle ); - VectorAdd( v_angle, pmove->punchangle, v_angle ); - - // Set up view angles. - pmove->angles[ROLL] = PM_CalcRoll ( v_angle, pmove->velocity, pmove->movevars->rollangle, pmove->movevars->rollspeed )*4; - pmove->angles[PITCH] = v_angle[PITCH]; - pmove->angles[YAW] = v_angle[YAW]; - } - else - { - VectorCopy( pmove->oldangles, pmove->angles ); - } - - // Set dead player view_offset - if ( pmove->dead ) - { - pmove->view_ofs[2] = PM_DEAD_VIEWHEIGHT; - } - - // Adjust client view angles to match values used on server. - if (pmove->angles[YAW] > 180.0f) - { - pmove->angles[YAW] -= 360.0f; - } - -} - -void PM_ReduceTimers( void ) -{ - if ( pmove->flTimeStepSound > 0 ) - { - pmove->flTimeStepSound -= pmove->cmd.msec; - if ( pmove->flTimeStepSound < 0 ) - { - pmove->flTimeStepSound = 0; - } - } - if ( pmove->flDuckTime > 0 ) - { - pmove->flDuckTime -= pmove->cmd.msec; - if ( pmove->flDuckTime < 0 ) - { - pmove->flDuckTime = 0; - } - } - if ( pmove->flSwimTime > 0 ) - { - pmove->flSwimTime -= pmove->cmd.msec; - if ( pmove->flSwimTime < 0 ) - { - pmove->flSwimTime = 0; - } - } -} - -/* -============= -PlayerMove - -Returns with origin, angles, and velocity modified in place. - -Numtouch and touchindex[] will be set if any of the physents -were contacted during the move. -============= -*/ -void PM_PlayerMove ( int server ) -{ - physent_t *pLadder = NULL; - - // Are we running server code? - pmove->server = server; - - // Adjust speeds etc. - PM_CheckParamters(); - - // Assume we don't touch anything - pmove->numtouch = 0; - - // # of msec to apply movement - pmove->frametime = pmove->cmd.msec * 0.001; - - PM_ReduceTimers(); - - // Convert view angles to vectors - AngleVectors (pmove->angles, pmove->forward, pmove->right, pmove->up); - - // PM_ShowClipBox(); - - // Special handling for spectator and observers. (iuser1 is set if the player's in observer mode) - if ( pmove->spectator || pmove->iuser1 > 0 ) - { - PM_SpectatorMove(); - PM_CatagorizePosition(); - return; - } - - // Always try and unstick us unless we are in NOCLIP mode - if ( pmove->movetype != MOVETYPE_NOCLIP && pmove->movetype != MOVETYPE_NONE ) - { - if ( PM_CheckStuck() ) - { - return; // Can't move, we're stuck - } - } - - // Now that we are "unstuck", see where we are ( waterlevel and type, pmove->onground ). - PM_CatagorizePosition(); - - // Store off the starting water level - pmove->oldwaterlevel = pmove->waterlevel; - - // If we are not on ground, store off how fast we are moving down - if ( pmove->onground == -1 ) - { - pmove->flFallVelocity = -pmove->velocity[2]; - } - - g_onladder = 0; - // Don't run ladder code if dead or on a train - if ( !pmove->dead && !(pmove->flags & FL_ONTRAIN) ) - { - pLadder = PM_Ladder(); - if ( pLadder ) - { - g_onladder = 1; - } - } - - PM_UpdateStepSound(); - - PM_Duck(); - - // Don't run ladder code if dead or on a train - if ( !pmove->dead && !(pmove->flags & FL_ONTRAIN) ) - { - if ( pLadder ) - { - PM_LadderMove( pLadder ); - } - else if ( pmove->movetype != MOVETYPE_WALK && - pmove->movetype != MOVETYPE_NOCLIP ) - { - // Clear ladder stuff unless player is noclipping - // it will be set immediately again next frame if necessary - pmove->movetype = MOVETYPE_WALK; - } - } - - // Slow down, I'm pulling it! (a box maybe) but only when I'm standing on ground - if ( ( pmove->onground != -1 ) && ( pmove->cmd.buttons & IN_USE) ) - { - VectorScale( pmove->velocity, 0.3, pmove->velocity ); - } - - // Handle movement - switch ( pmove->movetype ) - { - default: - pmove->Con_DPrintf("Bogus pmove player movetype %i on (%i) 0=cl 1=sv\n", pmove->movetype, pmove->server); - break; - - case MOVETYPE_NONE: - break; - - case MOVETYPE_NOCLIP: - PM_NoClip(); - break; - - case MOVETYPE_TOSS: - case MOVETYPE_BOUNCE: - PM_Physics_Toss(); - break; - - case MOVETYPE_FLY: - - PM_CheckWater(); - - // Was jump button pressed? - // If so, set velocity to 270 away from ladder. This is currently wrong. - // Also, set MOVE_TYPE to walk, too. - if ( pmove->cmd.buttons & IN_JUMP ) - { - if ( !pLadder ) - { - PM_Jump (); - } - } - else - { - pmove->oldbuttons &= ~IN_JUMP; - } - - // Perform the move accounting for any base velocity. - VectorAdd (pmove->velocity, pmove->basevelocity, pmove->velocity); - PM_FlyMove (); - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); - break; - - case MOVETYPE_WALK: - if ( !PM_InWater() ) - { - PM_AddCorrectGravity(); - } - - // If we are leaping out of the water, just update the counters. - if ( pmove->waterjumptime ) - { - PM_WaterJump(); - PM_FlyMove(); - - // Make sure waterlevel is set correctly - PM_CheckWater(); - return; - } - - // If we are swimming in the water, see if we are nudging against a place we can jump up out - // of, and, if so, start out jump. Otherwise, if we are not moving up, then reset jump timer to 0 - if ( pmove->waterlevel >= 2 ) - { - if ( pmove->waterlevel == 2 ) - { - PM_CheckWaterJump(); - } - - // If we are falling again, then we must not trying to jump out of water any more. - if ( pmove->velocity[2] < 0 && pmove->waterjumptime ) - { - pmove->waterjumptime = 0; - } - - // Was jump button pressed? - if (pmove->cmd.buttons & IN_JUMP) - { - PM_Jump (); - } - else - { - pmove->oldbuttons &= ~IN_JUMP; - } - - // Perform regular water movement - PM_WaterMove(); - - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity); - - // Get a final position - PM_CatagorizePosition(); - } - else - - // Not underwater - { - // Was jump button pressed? - if ( pmove->cmd.buttons & IN_JUMP ) - { - if ( !pLadder ) - { - PM_Jump (); - } - } - else - { - pmove->oldbuttons &= ~IN_JUMP; - } - - // Fricion is handled before we add in any base velocity. That way, if we are on a conveyor, - // we don't slow when standing still, relative to the conveyor. - if ( pmove->onground != -1 ) - { - pmove->velocity[2] = 0.0; - PM_Friction(); - } - - // Make sure velocity is valid. - PM_CheckVelocity(); - - // Are we on ground now - if ( pmove->onground != -1 ) - { - PM_WalkMove(); - } - else - { - PM_AirMove(); // Take into account movement when in air. - } - - // Set final flags. - PM_CatagorizePosition(); - - // Now pull the base velocity back out. - // Base velocity is set if you are on a moving object, like - // a conveyor (or maybe another monster?) - VectorSubtract (pmove->velocity, pmove->basevelocity, pmove->velocity ); - - // Make sure velocity is valid. - PM_CheckVelocity(); - - // Add any remaining gravitational component. - if ( !PM_InWater() ) - { - PM_FixupGravityVelocity(); - } - - // If we are on ground, no downward velocity. - if ( pmove->onground != -1 ) - { - pmove->velocity[2] = 0; - } - - // See if we landed on the ground with enough force to play - // a landing sound. - PM_CheckFalling(); - } - - // Did we enter or leave the water? - PM_PlayWaterSounds(); - break; - } -} - -void PM_CreateStuckTable( void ) -{ - float x, y, z; - int idx; - int i; - float zi[3]; - - memset(rgv3tStuckTable, 0, 54 * sizeof(vec3_t)); - - idx = 0; - // Little Moves. - x = y = 0; - // Z moves - for (z = -0.125 ; z <= 0.125 ; z += 0.125) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - x = z = 0; - // Y moves - for (y = -0.125 ; y <= 0.125 ; y += 0.125) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - y = z = 0; - // X moves - for (x = -0.125 ; x <= 0.125 ; x += 0.125) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - - // Remaining multi axis nudges. - for ( x = - 0.125; x <= 0.125; x += 0.250 ) - { - for ( y = - 0.125; y <= 0.125; y += 0.250 ) - { - for ( z = - 0.125; z <= 0.125; z += 0.250 ) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - } - } - - // Big Moves. - x = y = 0; - zi[0] = 0.0f; - zi[1] = 1.0f; - zi[2] = 6.0f; - - for (i = 0; i < 3; i++) - { - // Z moves - z = zi[i]; - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - - x = z = 0; - - // Y moves - for (y = -2.0f ; y <= 2.0f ; y += 2.0) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - y = z = 0; - // X moves - for (x = -2.0f ; x <= 2.0f ; x += 2.0f) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - - // Remaining multi axis nudges. - for (i = 0 ; i < 3; i++) - { - z = zi[i]; - - for (x = -2.0f ; x <= 2.0f ; x += 2.0f) - { - for (y = -2.0f ; y <= 2.0f ; y += 2.0) - { - rgv3tStuckTable[idx][0] = x; - rgv3tStuckTable[idx][1] = y; - rgv3tStuckTable[idx][2] = z; - idx++; - } - } - } -} - - - -/* -This modume implements the shared player physics code between any particular game and -the engine. The same PM_Move routine is built into the game .dll and the client .dll and is -invoked by each side as appropriate. There should be no distinction, internally, between server -and client. This will ensure that prediction behaves appropriately. -*/ - -void PM_Move ( struct playermove_s *ppmove, int server ) -{ - assert( pm_shared_initialized ); - - pmove = ppmove; - - PM_PlayerMove( ( server != 0 ) ? TRUE : FALSE ); - - if ( pmove->onground != -1 ) - { - pmove->flags |= FL_ONGROUND; - } - else - { - pmove->flags &= ~FL_ONGROUND; - } - - // In single player, reset friction after each movement to FrictionModifier Triggers work still. - if ( !pmove->multiplayer && ( pmove->movetype == MOVETYPE_WALK ) ) - { - pmove->friction = 1.0f; - } -} - -int PM_GetVisEntInfo( int ent ) -{ - if ( ent >= 0 && ent <= pmove->numvisent ) - { - return pmove->visents[ ent ].info; - } - return -1; -} - -int PM_GetPhysEntInfo( int ent ) -{ - if ( ent >= 0 && ent <= pmove->numphysent) - { - return pmove->physents[ ent ].info; - } - return -1; -} - -int PM_FindPhysEntByIndex( int index ) -{ - int i; - - if ( index >= 0 && index <= pmove->numphysent) - { - for( i = 0; i < pmove->numphysent; i++ ) - { - if( pmove->physents[i].info == index ) - return i; - } - } - return -1; -} - -void PM_Init( struct playermove_s *ppmove ) -{ - assert( !pm_shared_initialized ); - - pmove = ppmove; - - PM_CreateStuckTable(); - PM_InitTextureTypes(); - - pm_shared_initialized = 1; -} diff --git a/game_shared/pm_shared.h b/game_shared/pm_shared.h deleted file mode 100644 index cf5230d9..00000000 --- a/game_shared/pm_shared.h +++ /dev/null @@ -1,21 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2009 й -// pm_shared.h - pmove general interface -//======================================================================= -#ifndef PM_SHARED_H -#define PM_SHARED_H - -void PM_Init( struct playermove_s *ppmove ); -void PM_Move( struct playermove_s *ppmove, int server ); -char PM_FindTextureType( char *name ); - -// spectator Movement modes (stored in pev->iuser1, so the physics code can get at them) -#define OBS_NONE 0 -#define OBS_CHASE_LOCKED 1 -#define OBS_CHASE_FREE 2 -#define OBS_ROAMING 3 -#define OBS_IN_EYE 4 -#define OBS_MAP_FREE 5 -#define OBS_MAP_CHASE 6 - -#endif//PM_SHARED_H \ No newline at end of file diff --git a/game_shared/vector.h b/game_shared/vector.h deleted file mode 100644 index 63609024..00000000 --- a/game_shared/vector.h +++ /dev/null @@ -1,272 +0,0 @@ -//======================================================================= -// Copyright (C) Shambler Team 2005 -// vector.h - shared vector operations -//======================================================================= -#ifndef VECTOR_H -#define VECTOR_H - -#include -#include -#include -#include - -#pragma warning( disable : 4244 ) // int or float down-conversion -#define bound( min, num, max ) ((num) >= (min) ? ((num) < (max) ? (num) : (max)) : (min)) - -#ifndef M_PI -#define M_PI (float)3.14159265358979323846 -#endif - -inline unsigned long& FloatBits( vec_t& f ) { return *reinterpret_cast(&f); } -inline unsigned long const& FloatBits( vec_t const& f ) { return *reinterpret_cast(&f); } -inline vec_t BitsToFloat( unsigned long i ) { return *reinterpret_cast(&i); } -inline bool IsFinite( vec_t f ) { return ((FloatBits(f) & 0x7F800000) != 0x7F800000); } -inline unsigned long FloatAbsBits( vec_t f ) { return FloatBits(f) & 0x7FFFFFFF; } -inline float FloatMakeNegative( vec_t f ) { return BitsToFloat( FloatBits(f) | 0x80000000 ); } -inline float FloatMakePositive( vec_t f ) { return BitsToFloat( FloatBits(f) & 0x7FFFFFFF ); } - -inline void SinCos (float angle, float *sine, float *cosine) -{ - __asm { - push ecx - fld dword ptr angle - fsincos - mov ecx, dword ptr[cosine] - fstp dword ptr [ecx] - mov ecx, dword ptr[sine] - fstp dword ptr [ecx] - pop ecx - } -} - -//========================================================= -// 2DVector - used for many pathfinding and many other -// operations that are treated as planar rather than 3d. -//========================================================= -class Vector2D -{ -public: - inline Vector2D(void) { } - inline Vector2D(float X, float Y) { x = X; y = Y; } - inline Vector2D operator+(const Vector2D& v) const { return Vector2D(x+v.x, y+v.y); } - inline Vector2D operator-(const Vector2D& v) const { return Vector2D(x-v.x, y-v.y); } - inline Vector2D operator*(float fl) const { return Vector2D(x*fl, y*fl); } - inline Vector2D operator/(float fl) const { return Vector2D(x/fl, y/fl); } - inline float Length(void) const { return sqrt(x*x + y*y ); } - inline Vector2D Normalize ( void ) const - { - Vector2D vec2; - - float flLen = Length(); - if ( flLen == 0 ) - { - return Vector2D( 0, 0 ); - } - else - { - flLen = 1 / flLen; - return Vector2D( x * flLen, y * flLen ); - } - } - vec_t x, y; -}; - -#define nanmask (255<<23) -#define IS_NAN(x) (((*(int *)&x)&nanmask)==nanmask) -#define Q_rint(x) ((x) > 0 ? (int)((x) + 0.5) : (int)((x) - 0.5)) - -inline float DotProduct(const Vector2D& a, const Vector2D& b) { return( a.x*b.x + a.y*b.y ); } -inline Vector2D operator*(float fl, const Vector2D& v) { return v * fl; } - -//========================================================= -// 3D Vector -//========================================================= -class Vector // same data-layout as engine's vec3_t, -{ // which is a vec_t[3] -public: - // Construction/destruction - inline Vector( void ) { } - inline Vector(float X, float Y, float Z) { x = X; y = Y; z = Z; } - inline Vector(const Vector& v) { x = v.x; y = v.y; z = v.z; } - inline Vector(float *rgfl) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } - inline Vector(const float *rgfl) { x = rgfl[0]; y = rgfl[1]; z = rgfl[2]; } - - // Initialization - void Init(vec_t ix=0.0f, vec_t iy=0.0f, vec_t iz=0.0f){ x = ix; y = iy; z = iz; } - - // Operators - inline Vector operator-(void) const { return Vector(-x,-y,-z); } - inline int operator==(const Vector& v) const { return x==v.x && y==v.y && z==v.z; } - inline int operator!=(const Vector& v) const { return !(*this==v); } - inline Vector operator+(const Vector& v) const { return Vector(x+v.x, y+v.y, z+v.z); } - inline Vector operator-(const Vector& v) const { return Vector(x-v.x, y-v.y, z-v.z); } - inline Vector operator*(float fl) const { return Vector(x*fl, y*fl, z*fl); } - inline Vector operator/(float fl) const { return Vector(x/fl, y/fl, z/fl); } - - _forceinline Vector& operator+=(const Vector &v) - { - x+=v.x; y+=v.y; z += v.z; - return *this; - } - _forceinline Vector& operator-=(const Vector &v) - { - x-=v.x; y-=v.y; z -= v.z; - return *this; - } - _forceinline Vector& operator*=(const Vector &v) - { - x *= v.x; y *= v.y; z *= v.z; - return *this; - } - _forceinline Vector& operator*=(float s) - { - x *= s; y *= s; z *= s; - return *this; - } - _forceinline Vector& operator/=(const Vector &v) - { - x /= v.x; y /= v.y; z /= v.z; - return *this; - } - _forceinline Vector& operator/=(float s) - { - float oofl = 1.0f / s; - x *= oofl; y *= oofl; z *= oofl; - return *this; - } - _forceinline Vector& fixangle(void) - { - if(!IS_NAN(x)) - { - while ( x < 0 ) x += 360; - while ( x > 360 ) x -= 360; - } - if(!IS_NAN(y)) - { - while ( y < 0 ) y += 360; - while ( y > 360 ) y -= 360; - } - if(!IS_NAN(z)) - { - while ( z < 0 ) z += 360; - while ( z > 360 ) z -= 360; - } - return *this; - } - _forceinline Vector MA( float scale, const Vector &start, const Vector &direction ) - { - x = start.x + scale * direction.x; - y = start.y + scale * direction.y; - z = start.z + scale * direction.z; - - return *this; - } - - // methods - inline void CopyToArray(float* rgfl) const { rgfl[0] = x, rgfl[1] = y, rgfl[2] = z; } - inline float Length(void) const { return (float)sqrt(x*x + y*y + z*z); } - operator float *() { return &x; } // Vectors will now automatically convert to float * when needed - operator const float *() const { return &x; } // Vectors will now automatically convert to float * when needed - - // array access... - vec_t operator[](int i) const { return ((vec_t*)this)[i];} - vec_t& operator[](int i) { return ((vec_t*)this)[i];} - - inline Vector Normalize(void) const - { - float flLen = Length(); - - if( flLen == 0 ) return Vector( 0, 0, 1 ); // ???? - flLen = 1.0f / flLen; - - return Vector( x * flLen, y * flLen, z * flLen ); - } - vec_t Dot(Vector const& vOther) const - { - return(x*vOther.x+y*vOther.y+z*vOther.z); - } - vec_t Distance( Vector const &vOther) const - { - return sqrt((x - vOther.x) * (x - vOther.x) + (y - vOther.y) * (y - vOther.y) + (z - vOther.z) * (z - vOther.z)); - } - Vector Cross(const Vector &vOther) const - { - return Vector(y*vOther.z - z*vOther.y, z*vOther.x - x*vOther.z, x*vOther.y - y*vOther.x); - } - inline Vector2D Make2D ( void ) const - { - Vector2D Vec2; - Vec2.x = x; - Vec2.y = y; - return Vec2; - } - inline float Length2D(void) const { return (float)sqrt(x*x + y*y); } - - inline Vector Min(const Vector &vOther) const - { - return Vector(x < vOther.x ? x : vOther.x, y < vOther.y ? y : vOther.y, z < vOther.z ? z : vOther.z); - } - - inline Vector Max(const Vector &vOther) const - { - return Vector(x > vOther.x ? x : vOther.x, y > vOther.y ? y : vOther.y, z > vOther.z ? z : vOther.z); - } - - inline bool IsValid() const - { - return IsFinite(x) && IsFinite(y) && IsFinite(z); - } - - // members - vec_t x, y, z; -}; - -inline Vector operator*(float fl, const Vector& v) { return v * fl; } -inline float DotProduct(const Vector& a, const Vector& b) { return(a.x*b.x+a.y*b.y+a.z*b.z); } -inline Vector CrossProduct(const Vector& a, const Vector& b) { return Vector( a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x ); } -inline void VectorNormalizeFast( Vector &v ) -{ - // FLT_EPSILON is added to the radius to eliminate the possibility of divide by zero. - float iradius = 1.f / ( sqrtf( v.x * v.x + v.y * v.y + v.z * v.z ) + FLT_EPSILON ); - - v.x *= iradius; - v.y *= iradius; - v.z *= iradius; -} -#define vec3_t Vector - -//========================================================= -// 4D Vector - for matrix operations -//========================================================= -class Vector4D -{ -public: - // Members - vec_t x, y, z, w; - - // Construction/destruction - Vector4D(void){} - Vector4D(vec_t X, vec_t Y, vec_t Z, vec_t W) { x = X; y = Y; z = Z; w = W;} - Vector4D(double X, double Y, double Z, double W) { x = (double)X; y = (double)Y; z = (double)Z; w = (double)W;} - Vector4D(const float *pFloat) { x = pFloat[0]; y = pFloat[1]; z = pFloat[2]; w = pFloat[3];} - - // array access... - vec_t operator[](int i) const { return ((vec_t*)this)[i];} - vec_t& operator[](int i) { return ((vec_t*)this)[i];} - - // equality - bool operator==(const Vector4D& src) const{ return(src.x == x) && (src.y == y) && (src.z == z) && (src.w == w);} - bool operator!=(const Vector4D& src) const{ return(src.x != x) || (src.y != y) || (src.z != z) || (src.w != w);} - - // arithmetic operations - Vector4D& operator+=(const Vector4D &v){ x+=v.x; y+=v.y; z += v.z; return *this;} - Vector4D& operator-=(const Vector4D &v){ x-=v.x; y-=v.y; z -= v.z; return *this;} - Vector4D operator+ (const Vector4D &v)const {Vector4D res; res.x = x + v.x; res.y = y + v.y; res.z = z + v.z; res.w = w; return res;} - Vector4D operator- (const Vector4D &v)const {Vector4D res; res.x = x - v.x; res.y = y - v.y; res.z = z - v.z; res.w = w; return res;} - Vector4D operator* (const Vector4D &v)const {Vector4D res; res.x = y * v.z - z * v.y; res.y = z * v.x - x * v.z; res.z = x * v.y - y * v.x; res.w = w; return res;} - float operator% (const Vector4D &v)const { return (x * v.x + y * v.y + z * v.z); } - Vector4D Scale( float scale)const {Vector4D res; res.x = x * scale; res.y = y * scale; res.z = z * scale; res.w = w;return res; } - Vector4D CompProduct (const Vector4D &v)const {Vector4D res; res.x = x * v.x; res.y = y * v.y; res.z = z * v.z; res.w = w; return res;} -}; - -#endif \ No newline at end of file diff --git a/game_shared/vgui_checkbutton2.cpp b/game_shared/vgui_checkbutton2.cpp new file mode 100644 index 00000000..511853f8 --- /dev/null +++ b/game_shared/vgui_checkbutton2.cpp @@ -0,0 +1,197 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include "vgui_checkbutton2.h" +#include "vgui_loadtga.h" + + +#define EXTRA_X 5 + + +using namespace vgui; + + + +CCheckButton2::CCheckButton2() : + m_Label(""), + m_pChecked(NULL), + m_pUnchecked(NULL), + m_pHandler(NULL), + m_CheckboxPanel(NULL) +{ + m_bOwnImages = false; + m_bChecked = false; + m_pChecked = m_pUnchecked = NULL; + m_bCheckboxLeft = true; + + m_Label.setParent(this); + m_Label.setFgColor(255,255,255,0); + m_Label.setBgColor(0,0,0,255); // background is not drawn and foreground is white + m_Label.addInputSignal(this); + + m_CheckboxPanel.setParent(this); + m_CheckboxPanel.addInputSignal(this); + + setPaintBackgroundEnabled(false); +} + + +CCheckButton2::~CCheckButton2() +{ + DeleteImages(); +} + + +void CCheckButton2::SetImages(char const *pChecked, char const *pUnchecked) +{ + DeleteImages(); + + m_pChecked = vgui_LoadTGA(pChecked); + m_pUnchecked = vgui_LoadTGA(pUnchecked); + m_bOwnImages = true; + + SetupControls(); +} + + +void CCheckButton2::SetImages(Image *pChecked, Image *pUnchecked) +{ + DeleteImages(); + + m_pChecked = pChecked; + m_pUnchecked = pUnchecked; + m_bOwnImages = false; + + SetupControls(); +} + + +void CCheckButton2::DeleteImages() +{ + if(m_bOwnImages) + { + delete m_pChecked; + delete m_pUnchecked; + } + + m_pChecked = NULL; + m_pUnchecked = NULL; + m_bOwnImages = false; + + SetupControls(); +} + + +void CCheckButton2::SetCheckboxLeft(bool bLeftAlign) +{ + m_bCheckboxLeft = bLeftAlign; + SetupControls(); +} + + +bool CCheckButton2::GetCheckboxLeft() +{ + return m_bCheckboxLeft; +} + + +void CCheckButton2::SetText(char const *pText, ...) +{ + char str[512]; + + va_list marker; + va_start(marker, pText); + _vsnprintf(str, sizeof(str), pText, marker); + va_end(marker); + + m_Label.setText(str); + SetupControls(); +} + + +void CCheckButton2::SetTextColor(int r, int g, int b, int a) +{ + m_Label.setFgColor(r, g, b, a); + repaint(); +} + + +void CCheckButton2::SetHandler(ICheckButton2Handler *pHandler) +{ + m_pHandler = pHandler; +} + + +bool CCheckButton2::IsChecked() +{ + return m_bChecked; +} + + +void CCheckButton2::SetChecked(bool bChecked) +{ + m_bChecked = bChecked; + SetupControls(); +} + + +void CCheckButton2::internalMousePressed(MouseCode code) +{ + m_bChecked = !m_bChecked; + + if(m_pHandler) + m_pHandler->StateChanged(this); + + SetupControls(); +} + + +void CCheckButton2::SetupControls() +{ + // Initialize the checkbutton bitmap. + Image *pBitmap = m_bChecked ? m_pChecked : m_pUnchecked; + + Panel *controls[2] = {&m_CheckboxPanel, &m_Label}; + int controlSizes[2][2]; + + controlSizes[0][0] = controlSizes[0][1] = 0; + if(pBitmap) + pBitmap->getSize(controlSizes[0][0], controlSizes[0][1]); + + m_CheckboxPanel.setImage(pBitmap); + m_CheckboxPanel.setSize(controlSizes[0][0], controlSizes[0][1]); + + + // Get the label's size. + m_Label.getSize(controlSizes[1][0], controlSizes[1][1]); + m_Label.setContentAlignment(Label::a_west); + + + // Position the controls. + int iLeftControl = !m_bCheckboxLeft; + int iBiggestY = controlSizes[0][1] > controlSizes[1][0] ? 0 : 1; + controls[iLeftControl]->setPos(0, (controlSizes[iBiggestY][1] - controlSizes[iLeftControl][1]) / 2); + controls[!iLeftControl]->setPos(controlSizes[iLeftControl][0] + EXTRA_X, (controlSizes[iBiggestY][1] - controlSizes[!iLeftControl][1]) / 2); + + + // Fit this control to the sizes of the subcontrols. + setSize(controlSizes[0][0] + controlSizes[1][0] + EXTRA_X, (controlSizes[0][1] > controlSizes[1][1]) ? controlSizes[0][1] : controlSizes[1][1]); + repaint(); +} + + +void CCheckButton2::mousePressed(MouseCode code, Panel *panel) +{ + internalMousePressed(code); +} + + + + + diff --git a/game_shared/vgui_checkbutton2.h b/game_shared/vgui_checkbutton2.h new file mode 100644 index 00000000..8f985d9f --- /dev/null +++ b/game_shared/vgui_checkbutton2.h @@ -0,0 +1,101 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_CHECKBUTTON2_H +#define VGUI_CHECKBUTTON2_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_label.h" +#include "vgui_imagepanel.h" +#include "vgui_defaultinputsignal.h" + + +namespace vgui +{ + + +class CCheckButton2; + + +class ICheckButton2Handler +{ +public: + virtual void StateChanged(CCheckButton2 *pButton) = 0; +}; + + +// VGUI checkbox class. +// - Provides access to the checkbox images. +// - Provides an easy callback mechanism for state changes. +// - Default background is invisible, and default text color is white. +class CCheckButton2 : public Panel, public CDefaultInputSignal +{ +public: + + CCheckButton2(); + ~CCheckButton2(); + + // Initialize the button with these. + void SetImages(char const *pChecked, char const *pUnchecked); + void SetImages(Image *pChecked, Image *pUnchecked); // If you use this, the button will never delete the images. + void DeleteImages(); + + // The checkbox can be to the left or the right of the text (default is left). + void SetCheckboxLeft(bool bLeftAlign); + bool GetCheckboxLeft(); + + // Set the label text. + void SetText(char const *pText, ...); + void SetTextColor(int r, int g, int b, int a); + + // You can register for change notification here. + void SetHandler(ICheckButton2Handler *pHandler); + + // Get/set the check state. + bool IsChecked(); + void SetChecked(bool bChecked); + + + +// Panel overrides. +public: + + virtual void internalMousePressed(MouseCode code); + + +protected: + + void SetupControls(); + + +// InputSignal overrides. +protected: + virtual void mousePressed(MouseCode code,Panel* panel); + + +public: + ICheckButton2Handler *m_pHandler; + + bool m_bCheckboxLeft; + Label m_Label; + ImagePanel m_CheckboxPanel; + + Image *m_pChecked; + Image *m_pUnchecked; + bool m_bOwnImages; + + bool m_bChecked; +}; + + +} + + +#endif // VGUI_CHECKBUTTON2_H diff --git a/game_shared/vgui_defaultinputsignal.h b/game_shared/vgui_defaultinputsignal.h new file mode 100644 index 00000000..94dae8df --- /dev/null +++ b/game_shared/vgui_defaultinputsignal.h @@ -0,0 +1,39 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_DEFAULTINPUTSIGNAL_H +#define VGUI_DEFAULTINPUTSIGNAL_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_inputsignal.h" + + +namespace vgui +{ + // This class derives from vgui::InputSignal and implements empty defaults for all of its functions. + class CDefaultInputSignal : public vgui::InputSignal + { + public: + virtual void cursorMoved(int x,int y,Panel* panel) {} + virtual void cursorEntered(Panel* panel) {} + virtual void cursorExited(Panel* panel) {} + virtual void mousePressed(MouseCode code,Panel* panel) {} + virtual void mouseDoublePressed(MouseCode code,Panel* panel) {} + virtual void mouseReleased(MouseCode code,Panel* panel) {} + virtual void mouseWheeled(int delta,Panel* panel) {} + virtual void keyPressed(KeyCode code,Panel* panel) {} + virtual void keyTyped(KeyCode code,Panel* panel) {} + virtual void keyReleased(KeyCode code,Panel* panel) {} + virtual void keyFocusTicked(Panel* panel) {} + }; +} + + +#endif // VGUI_DEFAULTINPUTSIGNAL_H diff --git a/game_shared/vgui_grid.cpp b/game_shared/vgui_grid.cpp new file mode 100644 index 00000000..00e9d699 --- /dev/null +++ b/game_shared/vgui_grid.cpp @@ -0,0 +1,398 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include "vgui_grid.h" + + +using namespace vgui; + + +#define AssertCheck(expr, msg) \ + if(!(expr))\ + {\ + assert(!msg);\ + return 0;\ + } + + + +// ------------------------------------------------------------------------------ // +// CGrid::CGridEntry. +// ------------------------------------------------------------------------------ // + +CGrid::CGridEntry::CGridEntry() +{ + m_pPanel = NULL; + m_bUnderline = false; +} + +CGrid::CGridEntry::~CGridEntry() +{ +} + + +// ------------------------------------------------------------------------------ // +// CGrid. +// ------------------------------------------------------------------------------ // + +CGrid::CGrid() +{ + Clear(); +} + + +CGrid::~CGrid() +{ + Term(); +} + + +bool CGrid::SetDimensions(int xCols, int yRows) +{ + Term(); + + m_GridEntries = new CGridEntry[xCols * yRows]; + m_Widths = new int[xCols*2 + yRows*2]; + m_Heights = m_Widths + xCols; + m_ColOffsets = m_Heights + yRows; + m_RowOffsets = m_ColOffsets + xCols; + + if(!m_GridEntries || !m_Widths) + { + Term(); + return false; + } + + memset(m_Widths, 0, sizeof(int) * (xCols*2 + yRows*2)); + + m_xCols = xCols; + m_yRows = yRows; + return true; +} + + +void CGrid::Term() +{ + delete [] m_GridEntries; + delete [] m_Widths; + Clear(); +} + + +Panel* CGrid::GetEntry(int x, int y) +{ + return GridEntry(x, y)->m_pPanel; +} + + +bool CGrid::SetEntry(int x, int y, Panel *pPanel) +{ + CGridEntry *pEntry = GridEntry(x, y); + if(!pEntry) + return false; + + if(pEntry->m_pPanel) + pEntry->m_pPanel->setParent(NULL); + + pEntry->m_pPanel = pPanel; + if(pPanel) + pPanel->setParent(this); + + m_bDirty = true; + return true; +} + + +int CGrid::GetXSpacing() +{ + return m_xSpacing; +} + + +int CGrid::GetYSpacing() +{ + return m_ySpacing; +} + + +void CGrid::SetSpacing(int xSpacing, int ySpacing) +{ + if(xSpacing != m_xSpacing) + { + m_xSpacing = xSpacing; + CalcColOffsets(0); + m_bDirty = true; + } + + if(ySpacing != m_ySpacing) + { + m_ySpacing = ySpacing; + CalcRowOffsets(0); + m_bDirty = true; + } +} + + +bool CGrid::SetColumnWidth(int iColumn, int width) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::SetColumnWidth : invalid location specified"); + m_Widths[iColumn] = width; + CalcColOffsets(iColumn+1); + m_bDirty = true; + return true; +} + + +bool CGrid::SetRowHeight(int iRow, int height) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::SetColumnWidth : invalid location specified"); + m_Heights[iRow] = height; + CalcRowOffsets(iRow+1); + m_bDirty = true; + return true; +} + + +int CGrid::GetColumnWidth(int iColumn) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::GetColumnWidth: invalid location specified"); + return m_Widths[iColumn]; +} + + +int CGrid::GetRowHeight(int iRow) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::GetRowHeight: invalid location specified"); + return m_Heights[iRow]; +} + + +int CGrid::CalcFitColumnWidth(int iColumn) +{ + AssertCheck(iColumn >= 0 && iColumn < m_xCols, "CGrid::CalcFitColumnWidth: invalid location specified"); + + int maxSize = 0; + for(int i=0; i < m_yRows; i++) + { + Panel *pPanel = GridEntry(iColumn, i)->m_pPanel; + if(!pPanel) + continue; + + int w, h; + pPanel->getSize(w,h); + if(w > maxSize) + maxSize = w; + } + + return maxSize; +} + + +int CGrid::CalcFitRowHeight(int iRow) +{ + AssertCheck(iRow >= 0 && iRow < m_yRows, "CGrid::CalcFitRowHeight: invalid location specified"); + + int maxSize = 0; + for(int i=0; i < m_xCols; i++) + { + Panel *pPanel = GridEntry(i, iRow)->m_pPanel; + if(!pPanel) + continue; + + int w, h; + pPanel->getSize(w,h); + if(h > maxSize) + maxSize = h; + } + + return maxSize; +} + + +void CGrid::AutoSetRowHeights() +{ + for(int i=0; i < m_yRows; i++) + SetRowHeight(i, CalcFitRowHeight(i)); +} + + +bool CGrid::GetEntryBox( + int col, int row, int &x, int &y, int &w, int &h) +{ + AssertCheck(col >= 0 && col < m_xCols && row >= 0 && row < m_yRows, "CGrid::GetEntryBox: invalid location specified"); + + x = m_ColOffsets[col]; + w = m_Widths[col]; + + y = m_RowOffsets[row]; + h = m_Heights[row]; + return true; +} + + +bool CGrid::CopyColumnWidths(CGrid *pOther) +{ + if(!pOther || pOther->m_xCols != m_xCols) + return false; + + for(int i=0; i < m_xCols; i++) + m_Widths[i] = pOther->m_Widths[i]; + + CalcColOffsets(0); + m_bDirty = true; + return true; +} + + +void CGrid::RepositionContents() +{ + for(int x=0; x < m_xCols; x++) + { + for(int y=0; y < m_yRows; y++) + { + Panel *pPanel = GridEntry(x,y)->m_pPanel; + if(!pPanel) + continue; + + pPanel->setBounds( + m_ColOffsets[x], + m_RowOffsets[y], + m_Widths[x], + m_Heights[y]); + } + } + + m_bDirty = false; +} + + +int CGrid::CalcDrawHeight() +{ + if(m_yRows > 0) + { + return m_RowOffsets[m_yRows-1] + m_Heights[m_yRows - 1] + m_ySpacing; + } + else + { + return 0; + } +} + + +void CGrid::paint() +{ + if(m_bDirty) + RepositionContents(); + + Panel::paint(); + + // walk the grid looking for underlined rows + int x = 0, y = 0; + for (int row = 0; row < m_yRows; row++) + { + CGridEntry *cell = GridEntry(0, row); + + y += cell->m_pPanel->getTall() + m_ySpacing; + if (cell->m_bUnderline) + { + drawSetColor(cell->m_UnderlineColor[0], cell->m_UnderlineColor[1], cell->m_UnderlineColor[2], cell->m_UnderlineColor[3]); + drawFilledRect(0, y - (cell->m_iUnderlineOffset + 1), getWide(), y - cell->m_iUnderlineOffset); + } + } +} + +void CGrid::paintBackground() +{ + Panel::paintBackground(); +} + +//----------------------------------------------------------------------------- +// Purpose: sets underline color for a particular row +//----------------------------------------------------------------------------- +void CGrid::SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a) +{ + CGridEntry *cell = GridEntry(0, row); + cell->m_bUnderline = enabled; + if (enabled) + { + cell->m_iUnderlineOffset = offset; + cell->m_UnderlineColor[0] = r; + cell->m_UnderlineColor[1] = g; + cell->m_UnderlineColor[2] = b; + cell->m_UnderlineColor[3] = a; + } +} + +void CGrid::Clear() +{ + m_xCols = m_yRows = 0; + m_Widths = NULL; + m_GridEntries = NULL; + m_xSpacing = m_ySpacing = 0; + m_bDirty = false; +} + + +CGrid::CGridEntry* CGrid::GridEntry(int x, int y) +{ + AssertCheck(x >= 0 && x < m_xCols && y >= 0 && y < m_yRows, "CGrid::GridEntry: invalid location specified"); + return &m_GridEntries[y*m_xCols + x]; +} + + +void CGrid::CalcColOffsets(int iStart) +{ + int cur = m_xSpacing; + if(iStart != 0) + cur += m_ColOffsets[iStart-1] + m_Widths[iStart-1]; + + for(int i=iStart; i < m_xCols; i++) + { + m_ColOffsets[i] = cur; + cur += m_Widths[i] + m_xSpacing; + } +} + + +void CGrid::CalcRowOffsets(int iStart) +{ + int cur = m_ySpacing; + if(iStart != 0) + cur += m_RowOffsets[iStart-1]; + + for(int i=iStart; i < m_yRows; i++) + { + m_RowOffsets[i] = cur; + cur += m_Heights[i] + m_ySpacing; + } +} + +bool CGrid::getCellAtPoint(int worldX, int worldY, int &row, int &col) +{ + row = -1; col = -1; + for(int x=0; x < m_xCols; x++) + { + for(int y=0; y < m_yRows; y++) + { + Panel *pPanel = GridEntry(x,y)->m_pPanel; + if (!pPanel) + continue; + + if (pPanel->isWithin(worldX, worldY)) + { + col = x; + row = y; + return true; + } + } + } + + return false; +} + + diff --git a/game_shared/vgui_grid.h b/game_shared/vgui_grid.h new file mode 100644 index 00000000..472f5094 --- /dev/null +++ b/game_shared/vgui_grid.h @@ -0,0 +1,122 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_GRID_H +#define VGUI_GRID_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_panel.h" + + +namespace vgui +{ + +// The grid control simply manages a grid of panels. You can adjust column sizes and spacings and +// configure and fill the panels however you want. +// To use this control, call SetDimensions, SetSpacing and fill the controls. +class CGrid : public Panel +{ +public: + CGrid(); + virtual ~CGrid(); + + bool SetDimensions(int xCols, int yRows); // Set how many columns and rows in the grid. + void Term(); + + Panel* GetEntry(int x, int y); // Get the panel associated with a grid entry. + bool SetEntry(int x, int y, Panel *pPanel); + + int GetXSpacing(); + int GetYSpacing(); + void SetSpacing(int xSpacing, int ySpacing); // Set spacing between rows and columns. + + bool SetColumnWidth(int iColumn, int width); // Set a column's width. + bool SetRowHeight(int iRow, int height); // Set a row's height. + + int GetColumnWidth(int iColumn); + int GetRowHeight(int iRow); + + int CalcFitColumnWidth(int iColumn); // Returns the maximum width of all panels in the column. + int CalcFitRowHeight(int iRow); // Returns the maximum height of all panels in the row. + + int CalcDrawHeight(); // Returns how many pixels high the grid control should be + // for all of its contents to be visible (based on its row heights + // and y spacing). + + void AutoSetRowHeights(); // Just does SetRowHeight(iRow, CalcFitRowHeight(iRow)) for all rows. + + bool GetEntryBox( // Returns the bounding box for the specified entry. + int col, int row, int &x, int &y, int &w, int &h); + + bool CopyColumnWidths(CGrid *pOther); // Copy the column widths from the other grid. Fails if the + // column count is different. + + void RepositionContents(); // Sets the size and position of all the grid entries based + // on current spacings and row/column widths. + // You usually only want to call this while setting up the control + // if you want to get the position or dimensions of the child + // controls. This will set them. + + void SetRowUnderline(int row, bool enabled, int offset, int r, int g, int b, int a); // sets underline color for a particular row + + // returns the true if found, false otherwise + bool getCellAtPoint(int worldX, int worldY, int &row, int &col); + +// Panel overrides. +public: + + virtual void paint(); + virtual void paintBackground(); + +protected: + + class CGridEntry + { + public: + CGridEntry(); + ~CGridEntry(); + + Panel *m_pPanel; + + bool m_bUnderline; + short m_UnderlineColor[4]; + int m_iUnderlineOffset; + }; + + void Clear(); + CGridEntry* GridEntry(int x, int y); + + void CalcColOffsets(int iStart); + void CalcRowOffsets(int iStart); + + +protected: + + bool m_bDirty; // Set when controls will need to be repositioned. + + int m_xCols; + int m_yRows; + + int m_xSpacing; + int m_ySpacing; + + int *m_Widths; + int *m_Heights; + int *m_ColOffsets; + int *m_RowOffsets; + + CGridEntry *m_GridEntries; + +}; + +}; + + +#endif // VGUI_GRID_H diff --git a/game_shared/vgui_helpers.cpp b/game_shared/vgui_helpers.cpp new file mode 100644 index 00000000..fbcfeb5e --- /dev/null +++ b/game_shared/vgui_helpers.cpp @@ -0,0 +1,45 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_helpers.h" + + +using namespace vgui; + + +void AlignPanel(Panel *pChild, Panel *pParent, int alignment) +{ + int w, h, cw, ch; + pParent->getSize(w, h); + pChild->getSize(cw, ch); + + int xCenter = (w - cw) / 2; + int yCenter = (h - ch) / 2; + + if(alignment == Label::a_west) + pChild->setPos(0, yCenter); + else if(alignment == Label::a_northwest) + pChild->setPos(0,0); + else if(alignment == Label::a_north) + pChild->setPos(xCenter, 0); + else if(alignment == Label::a_northeast) + pChild->setPos(w - cw, 0); + else if(alignment == Label::a_east) + pChild->setPos(w - cw, yCenter); + else if(alignment == Label::a_southeast) + pChild->setPos(w - cw, h - ch); + else if(alignment == Label::a_south) + pChild->setPos(xCenter, h - ch); + else if(alignment == Label::a_southwest) + pChild->setPos(0, h - ch); + else if(alignment == Label::a_center) + pChild->setPos(xCenter, yCenter); +} + + + + diff --git a/game_shared/vgui_helpers.h b/game_shared/vgui_helpers.h new file mode 100644 index 00000000..f9ee45e8 --- /dev/null +++ b/game_shared/vgui_helpers.h @@ -0,0 +1,31 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_HELPERS_H +#define VGUI_HELPERS_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "vgui_panel.h" +#include "vgui_label.h" + + +inline int PanelTop(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y;} +inline int PanelLeft(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x;} +inline int PanelRight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return x+w;} +inline int PanelBottom(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return y+h;} +inline int PanelWidth(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return w;} +inline int PanelHeight(vgui::Panel *pPanel) {int x,y,w,h; pPanel->getBounds(x,y,w,h); return h;} + +// Places child at the requested position inside pParent. iAlignment is from Label::Alignment. +void AlignPanel(vgui::Panel *pChild, vgui::Panel *pParent, int alignment); + + +#endif // VGUI_HELPERS_H + diff --git a/game_shared/vgui_listbox.cpp b/game_shared/vgui_listbox.cpp new file mode 100644 index 00000000..972091e0 --- /dev/null +++ b/game_shared/vgui_listbox.cpp @@ -0,0 +1,207 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "vgui_listbox.h" + + + +using namespace vgui; + + +CListBox::CListBox() : Panel(0, 0, 0, 0), + m_ItemsPanel(0,0,0,0), + m_ScrollBar(0, 0, 0, 0, true), + m_Slider(0, 0, 10, 40, true) +{ + m_Signal.m_pListBox = this; + + m_ItemsPanel.setParent(this); + m_ItemsPanel.setBgColor(0,0,0,255); + + m_Slider.setRangeWindow(50); + m_Slider.setRangeWindowEnabled(true); + + m_ScrollBar.setParent(this); + m_ScrollBar.addIntChangeSignal(&m_Signal); + m_ScrollBar.setSlider(&m_Slider); + m_ScrollBar.setButtonPressedScrollValue(1); + + m_Items.m_pNext = m_Items.m_pPrev = &m_Items; + m_ItemOffset = 0; + m_iScrollMax = -1; +} + +CListBox::~CListBox() +{ + Term(); +} + +void CListBox::Init() +{ + Term(); +} + +void CListBox::Term() +{ + m_ItemOffset = 0; + + // Free the LBItems. + LBItem *pNext; + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pNext) + { + pItem->m_pPanel->setParent(NULL); // detach the panel from us + pNext = pItem->m_pNext; + delete pItem; + } + m_Items.m_pPrev = m_Items.m_pNext = &m_Items; +} + +void CListBox::AddItem(Panel* panel) +{ + // Add the item. + LBItem *pItem = new LBItem; + if(!pItem) + return; + + pItem->m_pPanel = panel; + pItem->m_pPanel->setParent(&m_ItemsPanel); + + pItem->m_pPrev = m_Items.m_pPrev; + pItem->m_pNext = &m_Items; + pItem->m_pNext->m_pPrev = pItem->m_pPrev->m_pNext = pItem; + + m_ScrollBar.setRange(0, GetScrollMax()); + m_Slider.setRangeWindow(50); + m_Slider.setRangeWindowEnabled(true); + + InternalLayout(); +} + +int CListBox::GetNumItems() +{ + int count=0; + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) + ++count; + + return count; +} + +int CListBox::GetItemWidth() +{ + int wide, tall; + m_ItemsPanel.getSize(wide, tall); + return wide; +} + +int CListBox::GetScrollPos() +{ + return m_ItemOffset; +} + +void CListBox::SetScrollPos(int pos) +{ + int maxItems = GetScrollMax(); + if(maxItems < 0) + return; + + m_ItemOffset = (pos < 0) ? 0 : ((pos > maxItems) ? maxItems : pos); + InternalLayout(); +} + +void CListBox::setPos(int x, int y) +{ + Panel::setPos(x, y); + InternalLayout(); +} + +void CListBox::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + InternalLayout(); +} + +void CListBox::setPixelScroll(int value) +{ + m_ItemOffset = m_ScrollBar.getValue(); + InternalLayout(); +} + +void CListBox::InternalLayout() +{ + int x, y, wide, tall; + getBounds(x, y, wide, tall); + + // Reposition the main panel and the scrollbar. + m_ItemsPanel.setBounds(0, 0, wide-15, tall); + m_ScrollBar.setBounds(wide-15, 0, 15, tall); + + bool bNeedScrollbar = false; + + // Reposition the items. + int curItem = 0; + int curY = 0; + int maxItem = GetScrollMax(); + for(LBItem *pItem=m_Items.m_pNext; pItem != &m_Items; pItem=pItem->m_pNext) + { + if(curItem < m_ItemOffset) + { + pItem->m_pPanel->setVisible(false); + bNeedScrollbar = true; + } + else if (curItem >= maxItem) + { + // item is past the end of the items we care about + pItem->m_pPanel->setVisible(false); + } + else + { + pItem->m_pPanel->setVisible(true); + + int itemWidth, itemHeight; + pItem->m_pPanel->getSize(itemWidth, itemHeight); + + // Don't change the item's height but change its width to fit the listbox. + pItem->m_pPanel->setBounds(0, curY, wide, itemHeight); + + curY += itemHeight; + + if (curY > tall) + { + bNeedScrollbar = true; + } + } + + ++curItem; + } + + m_ScrollBar.setVisible(bNeedScrollbar); + + repaint(); +} + +void CListBox::paintBackground() +{ +} + +void CListBox::SetScrollRange(int maxScroll) +{ + m_iScrollMax = maxScroll; + m_ScrollBar.setRange(0, maxScroll); + InternalLayout(); +} + +int CListBox::GetScrollMax() +{ + if (m_iScrollMax < 0) + { + return GetNumItems() - 1; + } + + return m_iScrollMax; +} + + diff --git a/game_shared/vgui_listbox.h b/game_shared/vgui_listbox.h new file mode 100644 index 00000000..a48acef4 --- /dev/null +++ b/game_shared/vgui_listbox.h @@ -0,0 +1,115 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_LISTBOX_H +#define VOICE_LISTBOX_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "VGUI_Panel.h" +#include "VGUI_IntChangeSignal.h" + +#include "VGUI_Slider2.h" +#include "VGUI_ScrollBar2.h" + + +namespace vgui +{ + +// Listbox class used by voice code. Based off of vgui's list panel but with some modifications: +// - This listbox clips its child items to its rectangle. +// - You can access things like the scrollbar and find out the item width. +// - The scrollbar scrolls one element at a time and the range is correct. + +// Note: this listbox does not provide notification when items are +class CListBox : public Panel +{ +public: + + CListBox(); + ~CListBox(); + + void Init(); + void Term(); + + // Add an item to the listbox. This automatically sets the item's parent to the listbox + // and resizes the item's width to fit within the listbox. + void AddItem(Panel *pPanel); + + // Get the number of items currently in the listbox. + int GetNumItems(); + + // Get the width that listbox items will be set to (this changes if you resize the listbox). + int GetItemWidth(); + + // Get/set the scrollbar position (position says which element is at the top of the listbox). + int GetScrollPos(); + void SetScrollPos(int pos); + + // sets the last item the listbox should scroll to + // scroll to GetNumItems() if not set + void SetScrollRange(int maxScroll); + + // returns the maximum value the scrollbar can scroll to + int GetScrollMax(); + +// vgui overrides. +public: + + virtual void setPos(int x, int y); + virtual void setSize(int wide,int tall); + virtual void setPixelScroll(int value); + virtual void paintBackground(); + + +protected: + + class LBItem + { + public: + Panel *m_pPanel; + LBItem *m_pPrev, *m_pNext; + }; + + class ListBoxSignal : public IntChangeSignal + { + public: + void intChanged(int value,Panel* panel) + { + m_pListBox->setPixelScroll(-value); + } + + vgui::CListBox *m_pListBox; + }; + + +protected: + + void InternalLayout(); + + +protected: + + // All the items.. + LBItem m_Items; + + Panel m_ItemsPanel; + + int m_ItemOffset; // where we're scrolled to + Slider2 m_Slider; + ScrollBar2 m_ScrollBar; + ListBoxSignal m_Signal; + + int m_iScrollMax; +}; + +} + + +#endif // VOICE_LISTBOX_H diff --git a/game_shared/vgui_loadtga.cpp b/game_shared/vgui_loadtga.cpp new file mode 100644 index 00000000..d7e1f5e9 --- /dev/null +++ b/game_shared/vgui_loadtga.cpp @@ -0,0 +1,93 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "../cl_dll/wrect.h" +#include "../cl_dll/cl_dll.h" +#include "vgui.h" +#include "vgui_loadtga.h" +#include "vgui_inputstream.h" + + +// ---------------------------------------------------------------------- // +// Helper class for loading tga files. +// ---------------------------------------------------------------------- // +class MemoryInputStream : public vgui::InputStream +{ +public: + MemoryInputStream() + { + m_pData = NULL; + m_DataLen = m_ReadPos = 0; + } + + virtual void seekStart(bool& success) {m_ReadPos=0; success=true;} + virtual void seekRelative(int count,bool& success) {m_ReadPos+=count; success=true;} + virtual void seekEnd(bool& success) {m_ReadPos=m_DataLen; success=true;} + virtual int getAvailable(bool& success) {success=false; return 0;} // This is what vgui does for files... + + virtual uchar readUChar(bool& success) + { + if(m_ReadPos>=0 && m_ReadPos +#include +#include +#include + +using namespace vgui; + + +namespace +{ +class FooDefaultScrollBarIntChangeSignal : public IntChangeSignal +{ +public: + FooDefaultScrollBarIntChangeSignal(ScrollBar2* scrollBar) + { + _scrollBar=scrollBar; + } + virtual void intChanged(int value,Panel* panel) + { + _scrollBar->fireIntChangeSignal(); + } +protected: + ScrollBar2* _scrollBar; +}; + +class FooDefaultButtonSignal : public ActionSignal +{ +public: + ScrollBar2* _scrollBar; + int _buttonIndex; +public: + FooDefaultButtonSignal(ScrollBar2* scrollBar,int buttonIndex) + { + _scrollBar=scrollBar; + _buttonIndex=buttonIndex; + } +public: + virtual void actionPerformed(Panel* panel) + { + _scrollBar->doButtonPressed(_buttonIndex); + } +}; + +} + +//----------------------------------------------------------------------------- +// Purpose: Default scrollbar button +// Draws in new scoreboard style +//----------------------------------------------------------------------------- +class ScrollBarButton : public Button +{ +private: + LineBorder m_Border; + +public: + ScrollBarButton(const char *filename, int x, int y, int wide, int tall) : m_Border(Color(60, 60, 60, 0)), Button("", x, y, wide, tall) + { + Image *image = vgui_LoadTGA(filename); + if (image) + { + image->setColor(Color(140, 140, 140, 0)); + setImage(image); + } + + setBorder(&m_Border); + } + + virtual void paintBackground() + { + int wide,tall; + getPaintSize(wide,tall); + + // fill the background + drawSetColor(0, 0, 0, 0); + drawFilledRect(0, 0, wide, tall); + } +}; + + + + +//----------------------------------------------------------------------------- +// Purpose: Constructor +// Input : x - +// y - +// wide - +// tall - +// vertical - +//----------------------------------------------------------------------------- +ScrollBar2::ScrollBar2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) +{ + _slider=null; + _button[0]=null; + _button[1]=null; + + if(vertical) + { + setSlider(new Slider2(0,wide-1,wide,(tall-(wide*2))+2,true)); + setButton(new ScrollBarButton("gfx/vgui/arrowup.tga",0,0,wide,wide),0); + setButton(new ScrollBarButton("gfx/vgui/arrowdown.tga",0,tall-wide,wide,wide),1); + } + else + { + // untested code + setSlider(new Slider2(tall,0,wide-(tall*2),tall,false)); + setButton(new ScrollBarButton("gfx/vgui/320_arrowlt.tga",0,0,tall+1,tall+1),0); + setButton(new ScrollBarButton("gfx/vgui/320_arrowrt.tga",wide-tall,0,tall+1,tall+1),1); + } + + setPaintBorderEnabled(true); + setPaintBackgroundEnabled(true); + setPaintEnabled(true); + setButtonPressedScrollValue(15); + + validate(); + } + +void ScrollBar2::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + + if(_slider==null) + { + return; + } + + if(_button[0]==null) + { + return; + } + + if(_button[1]==null) + { + return; + } + + getPaintSize(wide,tall); + + if(_slider->isVertical()) + { + _slider->setBounds(0,wide,wide,tall-(wide*2)); + //_slider->setBounds(0,0,wide,tall); + _button[0]->setBounds(0,0,wide,wide); + _button[1]->setBounds(0,tall-wide,wide,wide); + } + else + { + _slider->setBounds(tall,0,wide-(tall*2),tall); + //_slider->setBounds(0,0,wide,tall); + _button[0]->setBounds(0,0,tall,tall); + _button[1]->setBounds((wide-tall),0,tall,tall); + } +} + +void ScrollBar2::performLayout() +{ +} + +void ScrollBar2::setValue(int value) +{ + _slider->setValue(value); +} + +int ScrollBar2::getValue() +{ + return _slider->getValue(); +} + +void ScrollBar2::addIntChangeSignal(IntChangeSignal* s) +{ + _intChangeSignalDar.putElement(s); + _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); +} + +void ScrollBar2::setRange(int min,int max) +{ + _slider->setRange(min,max); +} + +void ScrollBar2::fireIntChangeSignal() +{ + for(int i=0;i<_intChangeSignalDar.getCount();i++) + { + _intChangeSignalDar[i]->intChanged(_slider->getValue(),this); + } +} + +bool ScrollBar2::isVertical() +{ + return _slider->isVertical(); +} + +bool ScrollBar2::hasFullRange() +{ + return _slider->hasFullRange(); +} + +//LEAK: new and old slider will leak +void ScrollBar2::setButton(Button* button,int index) +{ + if(_button[index]!=null) + { + removeChild(_button[index]); + } + _button[index]=button; + addChild(_button[index]); + + _button[index]->addActionSignal(new FooDefaultButtonSignal(this,index)); + + validate(); + + //_button[index]->setVisible(false); +} + +Button* ScrollBar2::getButton(int index) +{ + return _button[index]; +} + +//LEAK: new and old slider will leak +void ScrollBar2::setSlider(Slider2 *slider) +{ + if(_slider!=null) + { + removeChild(_slider); + } + _slider=slider; + addChild(_slider); + + _slider->addIntChangeSignal(new FooDefaultScrollBarIntChangeSignal(this)); + + validate(); +} + +Slider2 *ScrollBar2::getSlider() +{ + return _slider; +} + +void ScrollBar2::doButtonPressed(int buttonIndex) +{ + if(buttonIndex==0) + { + _slider->setValue(_slider->getValue()-_buttonPressedScrollValue); + } + else + { + _slider->setValue(_slider->getValue()+_buttonPressedScrollValue); + } + +} + +void ScrollBar2::setButtonPressedScrollValue(int value) +{ + _buttonPressedScrollValue=value; +} + +void ScrollBar2::setRangeWindow(int rangeWindow) +{ + _slider->setRangeWindow(rangeWindow); +} + +void ScrollBar2::setRangeWindowEnabled(bool state) +{ + _slider->setRangeWindowEnabled(state); +} + +void ScrollBar2::validate() +{ + if(_slider!=null) + { + int buttonOffset=0; + + for(int i=0;i<2;i++) + { + if(_button[i]!=null) + { + if(_button[i]->isVisible()) + { + if(_slider->isVertical()) + { + buttonOffset+=_button[i]->getTall(); + } + else + { + buttonOffset+=_button[i]->getWide(); + } + } + } + } + + _slider->setButtonOffset(buttonOffset); + } + + int wide,tall; + getSize(wide,tall); + setSize(wide,tall); +} diff --git a/game_shared/vgui_scrollbar2.h b/game_shared/vgui_scrollbar2.h new file mode 100644 index 00000000..b9dfea6d --- /dev/null +++ b/game_shared/vgui_scrollbar2.h @@ -0,0 +1,62 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SCROLLBAR2_H +#define VGUI_SCROLLBAR2_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +class IntChangeSignal; +class Button; +class Slider2; + +//----------------------------------------------------------------------------- +// Purpose: Hacked up version of the vgui scrollbar +//----------------------------------------------------------------------------- +class VGUIAPI ScrollBar2 : public Panel +{ +public: + ScrollBar2(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual bool isVertical(); + virtual bool hasFullRange(); + virtual void setButton(Button *button,int index); + virtual Button* getButton(int index); + virtual void setSlider(Slider2 *slider); + virtual Slider2 *getSlider(); + virtual void doButtonPressed(int buttonIndex); + virtual void setButtonPressedScrollValue(int value); + virtual void validate(); +public: //bullshit public + virtual void fireIntChangeSignal(); +protected: + virtual void performLayout(); +protected: + Button* _button[2]; + Slider2 *_slider; + Dar _intChangeSignalDar; + int _buttonPressedScrollValue; +}; + +} + +#endif // VGUI_SCROLLBAR2_H diff --git a/game_shared/vgui_slider2.cpp b/game_shared/vgui_slider2.cpp new file mode 100644 index 00000000..7a220b5b --- /dev/null +++ b/game_shared/vgui_slider2.cpp @@ -0,0 +1,436 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: New version of the slider bar +// +// $NoKeywords: $ +//============================================================================= + +#include "VGUI_Slider2.h" + +#include +#include +#include +#include + +using namespace vgui; + +namespace +{ +class FooDefaultSliderSignal : public InputSignal +{ +private: + Slider2* _slider; +public: + FooDefaultSliderSignal(Slider2* slider) + { + _slider=slider; + } +public: + void cursorMoved(int x,int y,Panel* panel) + { + _slider->privateCursorMoved(x,y,panel); + } + void cursorEntered(Panel* panel){} + void cursorExited(Panel* panel){} + void mouseDoublePressed(MouseCode code,Panel* panel){} + void mousePressed(MouseCode code,Panel* panel) + { + _slider->privateMousePressed(code,panel); + } + void mouseReleased(MouseCode code,Panel* panel) + { + _slider->privateMouseReleased(code,panel); + } + void mouseWheeled(int delta,Panel* panel){} + void keyPressed(KeyCode code,Panel* panel){} + void keyTyped(KeyCode code,Panel* panel){} + void keyReleased(KeyCode code,Panel* panel){} + void keyFocusTicked(Panel* panel){} +}; +} + +Slider2::Slider2(int x,int y,int wide,int tall,bool vertical) : Panel(x,y,wide,tall) +{ + _vertical=vertical; + _dragging=false; + _value=0; + _range[0]=0; + _range[1]=299; + _rangeWindow=0; + _rangeWindowEnabled=false; + _buttonOffset=0; + recomputeNobPosFromValue(); + addInputSignal(new FooDefaultSliderSignal(this)); +} + +void Slider2::setSize(int wide,int tall) +{ + Panel::setSize(wide,tall); + recomputeNobPosFromValue(); +} + +bool Slider2::isVertical() +{ + return _vertical; +} + +void Slider2::setValue(int value) +{ + int oldValue=_value; + + if(value<_range[0]) + { + value=_range[0]; + } + + if(value>_range[1]) + { + value=_range[1]; + } + + _value=value; + recomputeNobPosFromValue(); + + if(_value!=oldValue) + { + fireIntChangeSignal(); + } +} + +int Slider2::getValue() +{ + return _value; +} + +void Slider2::recomputeNobPosFromValue() +{ + int wide,tall; + + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float fvalue=(float)(_value-_range[0]); + float fper=fvalue/frange; + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + float fnobsize=frangewindow; + float freepixels = ftall - fnobsize; + + float firstpixel = freepixels * fper; + + _nobPos[0]=(int)( firstpixel ); + _nobPos[1]=(int)( firstpixel + fnobsize ); + + if(_nobPos[1]>tall) + { + _nobPos[0]=tall-((int)fnobsize); + _nobPos[1]=tall; + } + } + else + { + float fnobsize=frangewindow; + float freepixels = fwide - fnobsize; + + float firstpixel = freepixels * fper; + + _nobPos[0]=(int)( firstpixel ); + _nobPos[1]=(int)( firstpixel + fnobsize ); + + if(_nobPos[1]>wide) + { + _nobPos[0]=wide-((int)fnobsize); + _nobPos[1]=wide; + } + } + } + + repaint(); +} + +void Slider2::recomputeValueFromNobPos() +{ + int wide,tall; + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float fvalue=(float)(_value-_range[0]); + float fnob=(float)_nobPos[0]; + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + float fnobsize=frangewindow; + fvalue=frange*(fnob/(ftall-fnobsize)); + } + else + { + float fnobsize=frangewindow; + fvalue=frange*(fnob/(fwide-fnobsize)); + } + } + // Take care of rounding issues. + _value=(int)(fvalue+_range[0]+0.5); + + // Clamp final result + _value = ( _value < _range[1] ) ? _value : _range[1]; +} + +bool Slider2::hasFullRange() +{ + int wide,tall; + getPaintSize(wide,tall); + + float fwide=(float)wide; + float ftall=(float)tall; + float frange=(float)(_range[1]-_range[0]); + float frangewindow=(float)(_rangeWindow); + + if(frangewindow<0) + { + frangewindow=0; + } + + if(!_rangeWindowEnabled) + { + frangewindow=frange; + } + + if ( frangewindow > 0 ) + { + if(_vertical) + { + if( frangewindow <= ( ftall + _buttonOffset ) ) + { + return true; + } + } + else + { + if( frangewindow <= ( fwide + _buttonOffset ) ) + { + return true; + } + } + } + + return false; +} + +void Slider2::addIntChangeSignal(IntChangeSignal* s) +{ + _intChangeSignalDar.putElement(s); +} + +void Slider2::fireIntChangeSignal() +{ + for(int i=0;i<_intChangeSignalDar.getCount();i++) + { + _intChangeSignalDar[i]->intChanged(getValue(),this); + } +} + +void Slider2::paintBackground() +{ + int wide,tall; + getPaintSize(wide,tall); + + if (_vertical) + { + // background behind slider + drawSetColor(40, 40, 40, 0); + drawFilledRect(0, 0, wide, tall); + + // slider front + drawSetColor(0, 0, 0, 0); + drawFilledRect(0,_nobPos[0],wide,_nobPos[1]); + + // slider border + drawSetColor(60, 60, 60, 0); + drawFilledRect(0,_nobPos[0],wide,_nobPos[0]+1); // top + drawFilledRect(0,_nobPos[1],wide,_nobPos[1]+1); // bottom + drawFilledRect(0,_nobPos[0]+1,1,_nobPos[1]); // left + drawFilledRect(wide-1,_nobPos[0]+1,wide,_nobPos[1]); // right + } + else + { + //!! doesn't work + + drawSetColor(Scheme::sc_secondary3); + drawFilledRect(0,0,wide,tall); + + drawSetColor(Scheme::sc_black); + drawOutlinedRect(0,0,wide,tall); + + drawSetColor(Scheme::sc_primary2); + drawFilledRect(_nobPos[0],0,_nobPos[1],tall); + + drawSetColor(Scheme::sc_black); + drawOutlinedRect(_nobPos[0],0,_nobPos[1],tall); + } +} + +void Slider2::setRange(int min,int max) +{ + if(maxmax) + { + min=max; + } + + _range[0]=min; + _range[1]=max; +} + +void Slider2::getRange(int& min,int& max) +{ + min=_range[0]; + max=_range[1]; +} + +void Slider2::privateCursorMoved(int x,int y,Panel* panel) +{ + if(!_dragging) + { + return; + } + + getApp()->getCursorPos(x,y); + screenToLocal(x,y); + + int wide,tall; + getPaintSize(wide,tall); + + if(_vertical) + { + _nobPos[0]=_nobDragStartPos[0]+(y-_dragStartPos[1]); + _nobPos[1]=_nobDragStartPos[1]+(y-_dragStartPos[1]); + + if(_nobPos[1]>tall) + { + _nobPos[0]=tall-(_nobPos[1]-_nobPos[0]); + _nobPos[1]=tall; + } + + if(_nobPos[0]<0) + { + _nobPos[1]=_nobPos[1]-_nobPos[0]; + _nobPos[0]=0; + } + } + else + { + _nobPos[0]=_nobDragStartPos[0]+(x-_dragStartPos[0]); + _nobPos[1]=_nobDragStartPos[1]+(x-_dragStartPos[0]); + + if(_nobPos[1]>wide) + { + _nobPos[0]=wide-(_nobPos[1]-_nobPos[0]); + _nobPos[1]=wide; + } + + if(_nobPos[0]<0) + { + _nobPos[1]=_nobPos[1]-_nobPos[0]; + _nobPos[0]=0; + } + } + + recomputeValueFromNobPos(); + repaint(); + fireIntChangeSignal(); +} + +void Slider2::privateMousePressed(MouseCode code,Panel* panel) +{ + int x,y; + getApp()->getCursorPos(x,y); + screenToLocal(x,y); + + if(_vertical) + { + if((y>=_nobPos[0])&&(y<_nobPos[1])) + { + _dragging=true; + getApp()->setMouseCapture(this); + _nobDragStartPos[0]=_nobPos[0]; + _nobDragStartPos[1]=_nobPos[1]; + _dragStartPos[0]=x; + _dragStartPos[1]=y; + } + } + else + { + if((x>=_nobPos[0])&&(x<_nobPos[1])) + { + _dragging=true; + getApp()->setMouseCapture(this); + _nobDragStartPos[0]=_nobPos[0]; + _nobDragStartPos[1]=_nobPos[1]; + _dragStartPos[0]=x; + _dragStartPos[1]=y; + } + } + +} + +void Slider2::privateMouseReleased(MouseCode code,Panel* panel) +{ + _dragging=false; + getApp()->setMouseCapture(null); +} + +void Slider2::getNobPos(int& min, int& max) +{ + min=_nobPos[0]; + max=_nobPos[1]; +} + +void Slider2::setRangeWindow(int rangeWindow) +{ + _rangeWindow=rangeWindow; +} + +void Slider2::setRangeWindowEnabled(bool state) +{ + _rangeWindowEnabled=state; +} + +void Slider2::setButtonOffset(int buttonOffset) +{ + _buttonOffset=buttonOffset; +} \ No newline at end of file diff --git a/game_shared/vgui_slider2.h b/game_shared/vgui_slider2.h new file mode 100644 index 00000000..ec384210 --- /dev/null +++ b/game_shared/vgui_slider2.h @@ -0,0 +1,67 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VGUI_SLIDER2_H +#define VGUI_SLIDER2_H +#ifdef _WIN32 +#pragma once +#endif + +#include +#include +#include + +namespace vgui +{ + +enum MouseCode; +class IntChangeSignal; + +class VGUIAPI Slider2 : public Panel +{ +private: + bool _vertical; + bool _dragging; + int _nobPos[2]; + int _nobDragStartPos[2]; + int _dragStartPos[2]; + Dar _intChangeSignalDar; + int _range[2]; + int _value; + int _rangeWindow; + bool _rangeWindowEnabled; + int _buttonOffset; +public: + Slider2(int x,int y,int wide,int tall,bool vertical); +public: + virtual void setValue(int value); + virtual int getValue(); + virtual bool isVertical(); + virtual void addIntChangeSignal(IntChangeSignal* s); + virtual void setRange(int min,int max); + virtual void getRange(int& min,int& max); + virtual void setRangeWindow(int rangeWindow); + virtual void setRangeWindowEnabled(bool state); + virtual void setSize(int wide,int tall); + virtual void getNobPos(int& min, int& max); + virtual bool hasFullRange(); + virtual void setButtonOffset(int buttonOffset); +private: + virtual void recomputeNobPosFromValue(); + virtual void recomputeValueFromNobPos(); +public: //bullshit public + virtual void privateCursorMoved(int x,int y,Panel* panel); + virtual void privateMousePressed(MouseCode code,Panel* panel); + virtual void privateMouseReleased(MouseCode code,Panel* panel); +protected: + virtual void fireIntChangeSignal(); + virtual void paintBackground(); +}; + +} + +#endif // VGUI_SLIDER2_H diff --git a/game_shared/voice_banmgr.cpp b/game_shared/voice_banmgr.cpp new file mode 100644 index 00000000..470e80ec --- /dev/null +++ b/game_shared/voice_banmgr.cpp @@ -0,0 +1,197 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include +#include +#include "voice_banmgr.h" + + +#define BANMGR_FILEVERSION 1 +char const *g_pBanMgrFilename = "voice_ban.dt"; + + + +// Hash a player ID to a byte. +unsigned char HashPlayerID(char const playerID[16]) +{ + unsigned char curHash = 0; + + for(int i=0; i < 16; i++) + curHash += (unsigned char)playerID[i]; + + return curHash; +} + + + +CVoiceBanMgr::CVoiceBanMgr() +{ + Clear(); +} + + +CVoiceBanMgr::~CVoiceBanMgr() +{ + Term(); +} + + +bool CVoiceBanMgr::Init(char const *pGameDir) +{ + Term(); + + char filename[512]; + _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); + + // Load in the squelch file. + FILE *fp = fopen(filename, "rb"); + if(fp) + { + int version; + fread(&version, 1, sizeof(version), fp); + if(version == BANMGR_FILEVERSION) + { + fseek(fp, 0, SEEK_END); + int nIDs = (ftell(fp) - sizeof(version)) / 16; + fseek(fp, sizeof(version), SEEK_SET); + + for(int i=0; i < nIDs; i++) + { + char playerID[16]; + fread(playerID, 1, 16, fp); + AddBannedPlayer(playerID); + } + } + + fclose(fp); + } + + return true; +} + + +void CVoiceBanMgr::Term() +{ + // Free all the player structures. + for(int i=0; i < 256; i++) + { + BannedPlayer *pListHead = &m_PlayerHash[i]; + BannedPlayer *pNext; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pNext) + { + pNext = pCur->m_pNext; + delete pCur; + } + } + + Clear(); +} + + +void CVoiceBanMgr::SaveState(char const *pGameDir) +{ + // Save the file out. + char filename[512]; + _snprintf(filename, sizeof(filename), "%s/%s", pGameDir, g_pBanMgrFilename); + + FILE *fp = fopen(filename, "wb"); + if(fp) + { + int version = BANMGR_FILEVERSION; + fwrite(&version, 1, sizeof(version), fp); + + for(int i=0; i < 256; i++) + { + BannedPlayer *pListHead = &m_PlayerHash[i]; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) + { + fwrite(pCur->m_PlayerID, 1, 16, fp); + } + } + + fclose(fp); + } +} + + +bool CVoiceBanMgr::GetPlayerBan(char const playerID[16]) +{ + return !!InternalFindPlayerSquelch(playerID); +} + + +void CVoiceBanMgr::SetPlayerBan(char const playerID[16], bool bSquelch) +{ + if(bSquelch) + { + // Is this guy already squelched? + if(GetPlayerBan(playerID)) + return; + + AddBannedPlayer(playerID); + } + else + { + BannedPlayer *pPlayer = InternalFindPlayerSquelch(playerID); + if(pPlayer) + { + pPlayer->m_pPrev->m_pNext = pPlayer->m_pNext; + pPlayer->m_pNext->m_pPrev = pPlayer->m_pPrev; + delete pPlayer; + } + } +} + + +void CVoiceBanMgr::ForEachBannedPlayer(void (*callback)(char id[16])) +{ + for(int i=0; i < 256; i++) + { + for(BannedPlayer *pCur=m_PlayerHash[i].m_pNext; pCur != &m_PlayerHash[i]; pCur=pCur->m_pNext) + { + callback(pCur->m_PlayerID); + } + } +} + + +void CVoiceBanMgr::Clear() +{ + // Tie off the hash table entries. + for(int i=0; i < 256; i++) + m_PlayerHash[i].m_pNext = m_PlayerHash[i].m_pPrev = &m_PlayerHash[i]; +} + + +CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::InternalFindPlayerSquelch(char const playerID[16]) +{ + int index = HashPlayerID(playerID); + BannedPlayer *pListHead = &m_PlayerHash[index]; + for(BannedPlayer *pCur=pListHead->m_pNext; pCur != pListHead; pCur=pCur->m_pNext) + { + if(memcmp(playerID, pCur->m_PlayerID, 16) == 0) + return pCur; + } + + return NULL; +} + + +CVoiceBanMgr::BannedPlayer* CVoiceBanMgr::AddBannedPlayer(char const playerID[16]) +{ + BannedPlayer *pNew = new BannedPlayer; + if(!pNew) + return NULL; + + int index = HashPlayerID(playerID); + memcpy(pNew->m_PlayerID, playerID, 16); + pNew->m_pNext = &m_PlayerHash[index]; + pNew->m_pPrev = m_PlayerHash[index].m_pPrev; + pNew->m_pPrev->m_pNext = pNew->m_pNext->m_pPrev = pNew; + return pNew; +} + diff --git a/game_shared/voice_banmgr.h b/game_shared/voice_banmgr.h new file mode 100644 index 00000000..2f14d8b7 --- /dev/null +++ b/game_shared/voice_banmgr.h @@ -0,0 +1,57 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_BANMGR_H +#define VOICE_BANMGR_H +#ifdef _WIN32 +#pragma once +#endif + + +// This class manages the (persistent) list of squelched players. +class CVoiceBanMgr +{ +public: + + CVoiceBanMgr(); + ~CVoiceBanMgr(); + + // Init loads the list of squelched players from disk. + bool Init(char const *pGameDir); + void Term(); + + // Saves the state into voice_squelch.dt. + void SaveState(char const *pGameDir); + + bool GetPlayerBan(char const playerID[16]); + void SetPlayerBan(char const playerID[16], bool bSquelch); + + // Call your callback for each banned player. + void ForEachBannedPlayer(void (*callback)(char id[16])); + + +protected: + + class BannedPlayer + { + public: + char m_PlayerID[16]; + BannedPlayer *m_pPrev, *m_pNext; + }; + + void Clear(); + BannedPlayer* InternalFindPlayerSquelch(char const playerID[16]); + BannedPlayer* AddBannedPlayer(char const playerID[16]); + + +protected: + + BannedPlayer m_PlayerHash[256]; +}; + + +#endif // VOICE_BANMGR_H diff --git a/game_shared/voice_common.h b/game_shared/voice_common.h new file mode 100644 index 00000000..93e9353f --- /dev/null +++ b/game_shared/voice_common.h @@ -0,0 +1,24 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_COMMON_H +#define VOICE_COMMON_H +#ifdef _WIN32 +#pragma once +#endif + + +#include "bitvec.h" + + +#define VOICE_MAX_PLAYERS 32 // (todo: this should just be set to MAX_CLIENTS). +#define VOICE_MAX_PLAYERS_DW ((VOICE_MAX_PLAYERS / 32) + !!(VOICE_MAX_PLAYERS & 31)) + +typedef CBitVec CPlayerBitVec; + + +#endif // VOICE_COMMON_H diff --git a/game_shared/voice_gamemgr.cpp b/game_shared/voice_gamemgr.cpp new file mode 100644 index 00000000..5ba2edfe --- /dev/null +++ b/game_shared/voice_gamemgr.cpp @@ -0,0 +1,274 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "voice_gamemgr.h" +#include +#include +#include "extdll.h" +#include "util.h" +#include "cbase.h" +#include "player.h" + + + +#define UPDATE_INTERVAL 0.3 + + +// These are stored off as CVoiceGameMgr is created and deleted. +CPlayerBitVec g_PlayerModEnable; // Set to 1 for each player if the player wants to use voice in this mod. + // (If it's zero, then the server reports that the game rules are saying the + // player can't hear anyone). + +CPlayerBitVec g_BanMasks[VOICE_MAX_PLAYERS]; // Tells which players don't want to hear each other. + // These are indexed as clients and each bit represents a client + // (so player entity is bit+1). + +CPlayerBitVec g_SentGameRulesMasks[VOICE_MAX_PLAYERS]; // These store the masks we last sent to each client so we can determine if +CPlayerBitVec g_SentBanMasks[VOICE_MAX_PLAYERS]; // we need to resend them. +CPlayerBitVec g_bWantModEnable; + +cvar_t voice_serverdebug = {"voice_serverdebug", "0"}; + +// Set game rules to allow all clients to talk to each other. +// Muted players still can't talk to each other. +cvar_t sv_alltalk = {"sv_alltalk", "0"}; + +// ------------------------------------------------------------------------ // +// Static helpers. +// ------------------------------------------------------------------------ // + +// Find a player with a case-insensitive name search. +static CBasePlayer* FindPlayerByName(const char *pTestName) +{ + for(int i=1; i <= gpGlobals->maxClients; i++) + { + edict_t *pEdict = g_engfuncs.pfnPEntityOfEntIndex(i); + if(pEdict) + { + CBaseEntity *pEnt = CBaseEntity::Instance(pEdict); + if(pEnt && pEnt->IsPlayer()) + { + const char *pNetName = STRING(pEnt->pev->netname); + if(stricmp(pNetName, pTestName) == 0) + { + return (CBasePlayer*)pEnt; + } + } + } + } + + return NULL; +} + +static void VoiceServerDebug( char const *pFmt, ... ) +{ + char msg[4096]; + va_list marker; + + if( !voice_serverdebug.value ) + return; + + va_start( marker, pFmt ); + _vsnprintf( msg, sizeof(msg), pFmt, marker ); + va_end( marker ); + + ALERT( at_console, "%s", msg ); +} + + + +// ------------------------------------------------------------------------ // +// CVoiceGameMgr. +// ------------------------------------------------------------------------ // + +CVoiceGameMgr::CVoiceGameMgr() +{ + m_UpdateInterval = 0; + m_nMaxPlayers = 0; +} + + +CVoiceGameMgr::~CVoiceGameMgr() +{ +} + + +bool CVoiceGameMgr::Init( + IVoiceGameMgrHelper *pHelper, + int maxClients) +{ + m_pHelper = pHelper; + m_nMaxPlayers = VOICE_MAX_PLAYERS < maxClients ? VOICE_MAX_PLAYERS : maxClients; + g_engfuncs.pfnPrecacheModel("sprites/voiceicon.spr"); + + m_msgPlayerVoiceMask = REG_USER_MSG( "VoiceMask", VOICE_MAX_PLAYERS_DW*4 * 2 ); + m_msgRequestState = REG_USER_MSG( "ReqState", 0 ); + + // register voice_serverdebug if it hasn't been registered already + if ( !CVAR_GET_POINTER( "voice_serverdebug" ) ) + CVAR_REGISTER( &voice_serverdebug ); + + if( !CVAR_GET_POINTER( "sv_alltalk" ) ) + CVAR_REGISTER( &sv_alltalk ); + + return true; +} + + +void CVoiceGameMgr::SetHelper(IVoiceGameMgrHelper *pHelper) +{ + m_pHelper = pHelper; +} + + +void CVoiceGameMgr::Update(double frametime) +{ + // Only update periodically. + m_UpdateInterval += frametime; + if(m_UpdateInterval < UPDATE_INTERVAL) + return; + + UpdateMasks(); +} + + +void CVoiceGameMgr::ClientConnected(edict_t *pEdict) +{ + int index = ENTINDEX(pEdict) - 1; + + // Clear out everything we use for deltas on this guy. + g_bWantModEnable[index] = true; + g_SentGameRulesMasks[index].Init(0); + g_SentBanMasks[index].Init(0); +} + +// Called to determine if the Receiver has muted (blocked) the Sender +// Returns true if the receiver has blocked the sender +bool CVoiceGameMgr::PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender) +{ + int iReceiverIndex, iSenderIndex; + + if ( !pReceiver || !pSender ) + return false; + + iReceiverIndex = pReceiver->entindex() - 1; + iSenderIndex = pSender->entindex() - 1; + + if ( iReceiverIndex < 0 || iReceiverIndex >= m_nMaxPlayers || iSenderIndex < 0 || iSenderIndex >= m_nMaxPlayers ) + return false; + + return ( g_BanMasks[iReceiverIndex][iSenderIndex] ? true : false ); +} + +bool CVoiceGameMgr::ClientCommand(CBasePlayer *pPlayer, const char *cmd) +{ + int playerClientIndex = pPlayer->entindex() - 1; + if(playerClientIndex < 0 || playerClientIndex >= m_nMaxPlayers) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: cmd %s from invalid client (%d)\n", cmd, playerClientIndex ); + return true; + } + + bool bBan = stricmp(cmd, "vban") == 0; + if(bBan && CMD_ARGC() >= 2) + { + for(int i=1; i < CMD_ARGC(); i++) + { + unsigned long mask = 0; + sscanf(CMD_ARGV(i), "%x", &mask); + + if(i <= VOICE_MAX_PLAYERS_DW) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: vban (0x%x) from %d\n", mask, playerClientIndex ); + g_BanMasks[playerClientIndex].SetDWord(i-1, mask); + } + else + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: invalid index (%d)\n", i ); + } + } + + // Force it to update the masks now. + //UpdateMasks(); + return true; + } + else if(stricmp(cmd, "VModEnable") == 0 && CMD_ARGC() >= 2) + { + VoiceServerDebug( "CVoiceGameMgr::ClientCommand: VModEnable (%d)\n", !!atoi(CMD_ARGV(1)) ); + g_PlayerModEnable[playerClientIndex] = !!atoi(CMD_ARGV(1)); + g_bWantModEnable[playerClientIndex] = false; + //UpdateMasks(); + return true; + } + else + { + return false; + } +} + + +void CVoiceGameMgr::UpdateMasks() +{ + m_UpdateInterval = 0; + + bool bAllTalk = !!g_engfuncs.pfnCVarGetFloat( "sv_alltalk" ); + + for(int iClient=0; iClient < m_nMaxPlayers; iClient++) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex(iClient+1); + if(!pEnt || !pEnt->IsPlayer()) + continue; + + // Request the state of their "VModEnable" cvar. + if(g_bWantModEnable[iClient]) + { + MESSAGE_BEGIN(MSG_ONE, m_msgRequestState, NULL, pEnt->pev); + MESSAGE_END(); + } + + CBasePlayer *pPlayer = (CBasePlayer*)pEnt; + + CPlayerBitVec gameRulesMask; + if( g_PlayerModEnable[iClient] ) + { + // Build a mask of who they can hear based on the game rules. + for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + { + CBaseEntity *pEnt = UTIL_PlayerByIndex(iOtherClient+1); + if(pEnt && pEnt->IsPlayer() && + (bAllTalk || m_pHelper->CanPlayerHearPlayer(pPlayer, (CBasePlayer*)pEnt)) ) + { + gameRulesMask[iOtherClient] = true; + } + } + } + + // If this is different from what the client has, send an update. + if(gameRulesMask != g_SentGameRulesMasks[iClient] || + g_BanMasks[iClient] != g_SentBanMasks[iClient]) + { + g_SentGameRulesMasks[iClient] = gameRulesMask; + g_SentBanMasks[iClient] = g_BanMasks[iClient]; + + MESSAGE_BEGIN(MSG_ONE, m_msgPlayerVoiceMask, NULL, pPlayer->pev); + int dw; + for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + WRITE_LONG(gameRulesMask.GetDWord(dw)); + WRITE_LONG(g_BanMasks[iClient].GetDWord(dw)); + } + MESSAGE_END(); + } + + // Tell the engine. + for(int iOtherClient=0; iOtherClient < m_nMaxPlayers; iOtherClient++) + { + bool bCanHear = gameRulesMask[iOtherClient] && !g_BanMasks[iClient][iOtherClient]; + g_engfuncs.pfnVoice_SetClientListening(iClient+1, iOtherClient+1, bCanHear); + } + } +} diff --git a/game_shared/voice_gamemgr.h b/game_shared/voice_gamemgr.h new file mode 100644 index 00000000..9605c5c8 --- /dev/null +++ b/game_shared/voice_gamemgr.h @@ -0,0 +1,79 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_GAMEMGR_H +#define VOICE_GAMEMGR_H +#pragma once + + +#include "voice_common.h" + + +class CGameRules; +class CBasePlayer; + + +class IVoiceGameMgrHelper +{ +public: + virtual ~IVoiceGameMgrHelper() {} + + // Called each frame to determine which players are allowed to hear each other. This overrides + // whatever squelch settings players have. + virtual bool CanPlayerHearPlayer(CBasePlayer *pListener, CBasePlayer *pTalker) = 0; +}; + + +// CVoiceGameMgr manages which clients can hear which other clients. +class CVoiceGameMgr +{ +public: + CVoiceGameMgr(); + virtual ~CVoiceGameMgr(); + + bool Init( + IVoiceGameMgrHelper *m_pHelper, + int maxClients + ); + + void SetHelper(IVoiceGameMgrHelper *pHelper); + + // Updates which players can hear which other players. + // If gameplay mode is DM, then only players within the PVS can hear each other. + // If gameplay mode is teamplay, then only players on the same team can hear each other. + // Player masks are always applied. + void Update(double frametime); + + // Called when a new client connects (unsquelches its entity for everyone). + void ClientConnected(struct edict_s *pEdict); + + // Called on ClientCommand. Checks for the squelch and unsquelch commands. + // Returns true if it handled the command. + bool ClientCommand(CBasePlayer *pPlayer, const char *cmd); + + // Called to determine if the Receiver has muted (blocked) the Sender + // Returns true if the receiver has blocked the sender + bool PlayerHasBlockedPlayer(CBasePlayer *pReceiver, CBasePlayer *pSender); + + +private: + + // Force it to update the client masks. + void UpdateMasks(); + + +private: + int m_msgPlayerVoiceMask; + int m_msgRequestState; + + IVoiceGameMgrHelper *m_pHelper; + int m_nMaxPlayers; + double m_UpdateInterval; // How long since the last update. +}; + + +#endif // VOICE_GAMEMGR_H diff --git a/game_shared/voice_status.cpp b/game_shared/voice_status.cpp new file mode 100644 index 00000000..e5378d00 --- /dev/null +++ b/game_shared/voice_status.cpp @@ -0,0 +1,874 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +// There are hud.h's coming out of the woodwork so this ensures that we get the right one. +#if defined( DMC_BUILD ) + #include "../dmc/cl_dll/hud.h" + #include "../dmc/cl_dll/cl_util.h" +#elif defined( RICOCHET_BUILD ) + #include "../ricochet/cl_dll/hud.h" + #include "../ricochet/cl_dll/cl_util.h" +#else + #include "../cl_dll/hud.h" + #include "../cl_dll/cl_util.h" +#endif + +#include +#include +#include + +#if defined( DMC_BUILD ) + #include "../dmc/cl_dll/parsemsg.h" + #include "../dmc/cl_dll/hud_servers.h" + #include "../dmc/cl_dll/demo.h" +#elif defined( RICOCHET_BUILD ) + #include "../ricochet/cl_dll/parsemsg.h" + #include "../ricochet/cl_dll/hud_servers.h" + #include "../ricochet/cl_dll/demo.h" +#else + #include "../cl_dll/parsemsg.h" + #include "../cl_dll/hud_servers.h" + #include "../cl_dll/demo.h" +#endif + +#include "demo_api.h" +#include "voice_status.h" +#include "r_efx.h" +#include "entity_types.h" +#include "VGUI_ActionSignal.h" +#include "VGUI_Scheme.h" +#include "VGUI_TextImage.h" +#include "vgui_loadtga.h" +#include "vgui_helpers.h" +#include "vgui_mousecode.h" + + + +using namespace vgui; + + +extern int cam_thirdperson; + + +#define VOICE_MODEL_INTERVAL 0.3 +#define SCOREBOARD_BLINK_FREQUENCY 0.3 // How often to blink the scoreboard icons. +#define SQUELCHOSCILLATE_PER_SECOND 2.0f + + +extern BitmapTGA *LoadTGA( const char* pImageName ); + + + +// ---------------------------------------------------------------------- // +// The voice manager for the client. +// ---------------------------------------------------------------------- // +CVoiceStatus g_VoiceStatus; + +CVoiceStatus* GetClientVoiceMgr() +{ + return &g_VoiceStatus; +} + + + +// ---------------------------------------------------------------------- // +// CVoiceStatus. +// ---------------------------------------------------------------------- // + +static CVoiceStatus *g_pInternalVoiceStatus = NULL; + +int __MsgFunc_VoiceMask(const char *pszName, int iSize, void *pbuf) +{ + if(g_pInternalVoiceStatus) + g_pInternalVoiceStatus->HandleVoiceMaskMsg(iSize, pbuf); + + return 1; +} + +int __MsgFunc_ReqState(const char *pszName, int iSize, void *pbuf) +{ + if(g_pInternalVoiceStatus) + g_pInternalVoiceStatus->HandleReqStateMsg(iSize, pbuf); + + return 1; +} + + +int g_BannedPlayerPrintCount; +void ForEachBannedPlayer(char id[16]) +{ + char str[256]; + sprintf(str, "Ban %d: %2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x%2x\n", + g_BannedPlayerPrintCount++, + id[0], id[1], id[2], id[3], + id[4], id[5], id[6], id[7], + id[8], id[9], id[10], id[11], + id[12], id[13], id[14], id[15] + ); + strupr(str); + gEngfuncs.pfnConsolePrint(str); +} + + +void ShowBannedCallback() +{ + if(g_pInternalVoiceStatus) + { + g_BannedPlayerPrintCount = 0; + gEngfuncs.pfnConsolePrint("------- BANNED PLAYERS -------\n"); + g_pInternalVoiceStatus->m_BanMgr.ForEachBannedPlayer(ForEachBannedPlayer); + gEngfuncs.pfnConsolePrint("------------------------------\n"); + } +} + + +// ---------------------------------------------------------------------- // +// CVoiceStatus. +// ---------------------------------------------------------------------- // + +CVoiceStatus::CVoiceStatus() +{ + m_bBanMgrInitialized = false; + m_LastUpdateServerState = 0; + + m_pSpeakerLabelIcon = NULL; + m_pScoreboardNeverSpoken = NULL; + m_pScoreboardNotSpeaking = NULL; + m_pScoreboardSpeaking = NULL; + m_pScoreboardSpeaking2 = NULL; + m_pScoreboardSquelch = NULL; + m_pScoreboardBanned = NULL; + + m_pLocalBitmap = NULL; + m_pAckBitmap = NULL; + + m_bTalking = m_bServerAcked = false; + + memset(m_pBanButtons, 0, sizeof(m_pBanButtons)); + + m_bServerModEnable = -1; + + m_pchGameDir = NULL; +} + + +CVoiceStatus::~CVoiceStatus() +{ + g_pInternalVoiceStatus = NULL; + + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + delete m_Labels[i].m_pLabel; + m_Labels[i].m_pLabel = NULL; + + delete m_Labels[i].m_pIcon; + m_Labels[i].m_pIcon = NULL; + + delete m_Labels[i].m_pBackground; + m_Labels[i].m_pBackground = NULL; + } + + delete m_pLocalLabel; + m_pLocalLabel = NULL; + + FreeBitmaps(); + + if(m_pchGameDir) + { + if(m_bBanMgrInitialized) + { + m_BanMgr.SaveState(m_pchGameDir); + } + + free(m_pchGameDir); + } +} + + +int CVoiceStatus::Init( + IVoiceStatusHelper *pHelper, + Panel **pParentPanel) +{ + // Setup the voice_modenable cvar. + gEngfuncs.pfnRegisterVariable("voice_modenable", "1", FCVAR_ARCHIVE); + + gEngfuncs.pfnRegisterVariable("voice_clientdebug", "0", 0); + + gEngfuncs.pfnAddCommand("voice_showbanned", ShowBannedCallback); + + if(gEngfuncs.pfnGetGameDirectory()) + { + m_BanMgr.Init(gEngfuncs.pfnGetGameDirectory()); + m_bBanMgrInitialized = true; + } + + assert(!g_pInternalVoiceStatus); + g_pInternalVoiceStatus = this; + + m_BlinkTimer = 0; + m_VoiceHeadModel = NULL; + memset(m_Labels, 0, sizeof(m_Labels)); + + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + CVoiceLabel *pLabel = &m_Labels[i]; + + pLabel->m_pBackground = new Label(""); + + if(pLabel->m_pLabel = new Label("")) + { + pLabel->m_pLabel->setVisible( true ); + pLabel->m_pLabel->setFont( Scheme::sf_primary2 ); + pLabel->m_pLabel->setTextAlignment( Label::a_east ); + pLabel->m_pLabel->setContentAlignment( Label::a_east ); + pLabel->m_pLabel->setParent( pLabel->m_pBackground ); + } + + if( pLabel->m_pIcon = new ImagePanel( NULL ) ) + { + pLabel->m_pIcon->setVisible( true ); + pLabel->m_pIcon->setParent( pLabel->m_pBackground ); + } + + pLabel->m_clientindex = -1; + } + + m_pLocalLabel = new ImagePanel(NULL); + + m_bInSquelchMode = false; + + m_pHelper = pHelper; + m_pParentPanel = pParentPanel; + gHUD.AddHudElem(this); + m_iFlags = HUD_ACTIVE; + HOOK_MESSAGE(VoiceMask); + HOOK_MESSAGE(ReqState); + + // Cache the game directory for use when we shut down + const char *pchGameDirT = gEngfuncs.pfnGetGameDirectory(); + m_pchGameDir = (char *)malloc(strlen(pchGameDirT) + 1); + strcpy(m_pchGameDir, pchGameDirT); + + return 1; +} + + +int CVoiceStatus::VidInit() +{ + FreeBitmaps(); + + + if( m_pLocalBitmap = vgui_LoadTGA("gfx/vgui/icntlk_pl.tga") ) + { + m_pLocalBitmap->setColor(Color(255,255,255,135)); + } + + if( m_pAckBitmap = vgui_LoadTGA("gfx/vgui/icntlk_sv.tga") ) + { + m_pAckBitmap->setColor(Color(255,255,255,135)); // Give just a tiny bit of translucency so software draws correctly. + } + + m_pLocalLabel->setImage( m_pLocalBitmap ); + m_pLocalLabel->setVisible( false ); + + + if( m_pSpeakerLabelIcon = vgui_LoadTGANoInvertAlpha("gfx/vgui/speaker4.tga" ) ) + m_pSpeakerLabelIcon->setColor( Color(255,255,255,1) ); // Give just a tiny bit of translucency so software draws correctly. + + if (m_pScoreboardNeverSpoken = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker1.tga")) + m_pScoreboardNeverSpoken->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardNotSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker2.tga")) + m_pScoreboardNotSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSpeaking = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker3.tga")) + m_pScoreboardSpeaking->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSpeaking2 = vgui_LoadTGANoInvertAlpha("gfx/vgui/640_speaker4.tga")) + m_pScoreboardSpeaking2->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardSquelch = vgui_LoadTGA("gfx/vgui/icntlk_squelch.tga")) + m_pScoreboardSquelch->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + if(m_pScoreboardBanned = vgui_LoadTGA("gfx/vgui/640_voiceblocked.tga")) + m_pScoreboardBanned->setColor(Color(255,255,255,1)); // Give just a tiny bit of translucency so software draws correctly. + + // Figure out the voice head model height. + m_VoiceHeadModelHeight = 45; + char *pFile = (char *)gEngfuncs.COM_LoadFile("scripts/voicemodel.txt", 5, NULL); + if(pFile) + { + char token[4096]; + gEngfuncs.COM_ParseFile(pFile, token); + if(token[0] >= '0' && token[0] <= '9') + { + m_VoiceHeadModelHeight = (float)atof(token); + } + + gEngfuncs.COM_FreeFile(pFile); + } + + m_VoiceHeadModel = gEngfuncs.pfnSPR_Load("sprites/voiceicon.spr"); + return TRUE; +} + + +void CVoiceStatus::Frame(double frametime) +{ + // check server banned players once per second + if(gEngfuncs.GetClientTime() - m_LastUpdateServerState > 1) + { + UpdateServerState(false); + } + + m_BlinkTimer += frametime; + + // Update speaker labels. + if( m_pHelper->CanShowSpeakerLabels() ) + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pBackground->setVisible( m_Labels[i].m_clientindex != -1 ); + } + else + { + for( int i=0; i < MAX_VOICE_SPEAKERS; i++ ) + m_Labels[i].m_pBackground->setVisible( false ); + } + + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + UpdateBanButton(i); +} + + +void CVoiceStatus::CreateEntities() +{ + if(!m_VoiceHeadModel) + return; + + cl_entity_t *localPlayer = gEngfuncs.GetLocalPlayer(); + + int iOutModel = 0; + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + { + if(!m_VoicePlayers[i]) + continue; + + cl_entity_s *pClient = gEngfuncs.GetEntityByIndex(i+1); + + // Don't show an icon if the player is not in our PVS. + if(!pClient || pClient->curstate.messagenum < localPlayer->curstate.messagenum) + continue; + + // Don't show an icon for dead or spectating players (ie: invisible entities). + if(pClient->curstate.effects & EF_NODRAW) + continue; + + // Don't show an icon for the local player unless we're in thirdperson mode. + if(pClient == localPlayer && !cam_thirdperson) + continue; + + cl_entity_s *pEnt = &m_VoiceHeadModels[iOutModel]; + ++iOutModel; + + memset(pEnt, 0, sizeof(*pEnt)); + + pEnt->curstate.rendermode = kRenderTransAdd; + pEnt->curstate.renderamt = 255; + pEnt->baseline.renderamt = 255; + pEnt->curstate.renderfx = kRenderFxNoDissipation; + pEnt->curstate.framerate = 1; + pEnt->curstate.frame = 0; + pEnt->model = (struct model_s*)gEngfuncs.GetSpritePointer(m_VoiceHeadModel); + pEnt->angles[0] = pEnt->angles[1] = pEnt->angles[2] = 0; + pEnt->curstate.scale = 0.5f; + + pEnt->origin[0] = pEnt->origin[1] = 0; + pEnt->origin[2] = 45; + + VectorAdd(pEnt->origin, pClient->origin, pEnt->origin); + + // Tell the engine. + gEngfuncs.CL_CreateVisibleEntity(ET_NORMAL, pEnt); + } +} + + +void CVoiceStatus::UpdateSpeakerStatus(int entindex, qboolean bTalking) +{ + if(!*m_pParentPanel) + return; + + if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + { + char msg[256]; + _snprintf( msg, sizeof(msg), "CVoiceStatus::UpdateSpeakerStatus: ent %d talking = %d\n", entindex, bTalking ); + gEngfuncs.pfnConsolePrint( msg ); + } + + // Is it the local player talking? + if( entindex == -1 ) + { + m_bTalking = !!bTalking; + if( bTalking ) + { + // Enable voice for them automatically if they try to talk. + gEngfuncs.pfnClientCmd( "voice_modenable 1" ); + } + } + else if( entindex == -2 ) + { + m_bServerAcked = !!bTalking; + } + else if(entindex >= 0 && entindex <= VOICE_MAX_PLAYERS) + { + int iClient = entindex - 1; + if(iClient < 0) + return; + + CVoiceLabel *pLabel = FindVoiceLabel(iClient); + if(bTalking) + { + m_VoicePlayers[iClient] = true; + m_VoiceEnabledPlayers[iClient] = true; + + // If we don't have a label for this guy yet, then create one. + if(!pLabel) + { + if(pLabel = GetFreeVoiceLabel()) + { + // Get the name from the engine. + hud_player_info_t info; + memset(&info, 0, sizeof(info)); + GetPlayerInfo(entindex, &info); + + char paddedName[512]; + _snprintf(paddedName, sizeof(paddedName), "%s ", info.name); + + int color[3]; + m_pHelper->GetPlayerTextColor( entindex, color ); + + if( pLabel->m_pBackground ) + { + pLabel->m_pBackground->setBgColor( color[0], color[1], color[2], 135 ); + pLabel->m_pBackground->setParent( *m_pParentPanel ); + pLabel->m_pBackground->setVisible( m_pHelper->CanShowSpeakerLabels() ); + } + + if( pLabel->m_pLabel ) + { + pLabel->m_pLabel->setFgColor( 255, 255, 255, 0 ); + pLabel->m_pLabel->setBgColor( 0, 0, 0, 255 ); + pLabel->m_pLabel->setText( paddedName ); + } + + pLabel->m_clientindex = iClient; + } + } + } + else + { + m_VoicePlayers[iClient] = false; + + // If we have a label for this guy, kill it. + if(pLabel) + { + pLabel->m_pBackground->setVisible(false); + pLabel->m_clientindex = -1; + } + } + } + + RepositionLabels(); +} + + +void CVoiceStatus::UpdateServerState(bool bForce) +{ + // Can't do anything when we're not in a level. + char const *pLevelName = gEngfuncs.pfnGetLevelName(); + if( pLevelName[0] == 0 ) + { + if( gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: pLevelName[0]==0\n" ); + } + + return; + } + + int bCVarModEnable = !!gEngfuncs.pfnGetCvarFloat("voice_modenable"); + if(bForce || m_bServerModEnable != bCVarModEnable) + { + m_bServerModEnable = bCVarModEnable; + + char str[256]; + _snprintf(str, sizeof(str), "VModEnable %d", m_bServerModEnable); + ServerCmd(str); + + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char msg[256]; + sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); + gEngfuncs.pfnConsolePrint(msg); + } + } + + char str[2048]; + sprintf(str, "vban"); + bool bChange = false; + + for(unsigned long dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + unsigned long serverBanMask = 0; + unsigned long banMask = 0; + for(unsigned long i=0; i < 32; i++) + { + char playerID[16]; + if(!gEngfuncs.GetPlayerUniqueID(i+1, playerID)) + continue; + + if(m_BanMgr.GetPlayerBan(playerID)) + banMask |= 1 << i; + + if(m_ServerBannedPlayers[dw*32 + i]) + serverBanMask |= 1 << i; + } + + if(serverBanMask != banMask) + bChange = true; + + // Ok, the server needs to be updated. + char numStr[512]; + sprintf(numStr, " %x", banMask); + strcat(str, numStr); + } + + if(bChange || bForce) + { + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char msg[256]; + sprintf(msg, "CVoiceStatus::UpdateServerState: Sending '%s'\n", str); + gEngfuncs.pfnConsolePrint(msg); + } + + gEngfuncs.pfnServerCmdUnreliable(str); // Tell the server.. + } + else + { + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::UpdateServerState: no change\n" ); + } + } + + m_LastUpdateServerState = gEngfuncs.GetClientTime(); +} + +void CVoiceStatus::UpdateSpeakerImage(Label *pLabel, int iPlayer) +{ + m_pBanButtons[iPlayer-1] = pLabel; + UpdateBanButton(iPlayer-1); +} + +void CVoiceStatus::UpdateBanButton(int iClient) +{ + Label *pPanel = m_pBanButtons[iClient]; + + if (!pPanel) + return; + + char playerID[16]; + extern bool HACK_GetPlayerUniqueID( int iPlayer, char playerID[16] ); + if(!HACK_GetPlayerUniqueID(iClient+1, playerID)) + return; + + // Figure out if it's blinking or not. + bool bBlink = fmod(m_BlinkTimer, SCOREBOARD_BLINK_FREQUENCY*2) < SCOREBOARD_BLINK_FREQUENCY; + bool bTalking = !!m_VoicePlayers[iClient]; + bool bBanned = m_BanMgr.GetPlayerBan(playerID); + bool bNeverSpoken = !m_VoiceEnabledPlayers[iClient]; + + // Get the appropriate image to display on the panel. + if (bBanned) + { + pPanel->setImage(m_pScoreboardBanned); + } + else if (bTalking) + { + if (bBlink) + { + pPanel->setImage(m_pScoreboardSpeaking2); + } + else + { + pPanel->setImage(m_pScoreboardSpeaking); + } + pPanel->setFgColor(255, 170, 0, 1); + } + else if (bNeverSpoken) + { + pPanel->setImage(m_pScoreboardNeverSpoken); + pPanel->setFgColor(100, 100, 100, 1); + } + else + { + pPanel->setImage(m_pScoreboardNotSpeaking); + } +} + + +void CVoiceStatus::HandleVoiceMaskMsg(int iSize, void *pbuf) +{ + BEGIN_READ( pbuf, iSize ); + + unsigned long dw; + for(dw=0; dw < VOICE_MAX_PLAYERS_DW; dw++) + { + m_AudiblePlayers.SetDWord(dw, (unsigned long)READ_LONG()); + m_ServerBannedPlayers.SetDWord(dw, (unsigned long)READ_LONG()); + + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char str[256]; + gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleVoiceMaskMsg\n"); + + sprintf(str, " - m_AudiblePlayers[%d] = %lu\n", dw, m_AudiblePlayers.GetDWord(dw)); + gEngfuncs.pfnConsolePrint(str); + + sprintf(str, " - m_ServerBannedPlayers[%d] = %lu\n", dw, m_ServerBannedPlayers.GetDWord(dw)); + gEngfuncs.pfnConsolePrint(str); + } + } + + m_bServerModEnable = READ_BYTE(); +} + +void CVoiceStatus::HandleReqStateMsg(int iSize, void *pbuf) +{ + if(gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint("CVoiceStatus::HandleReqStateMsg\n"); + } + + UpdateServerState(true); +} + +void CVoiceStatus::StartSquelchMode() +{ + if(m_bInSquelchMode) + return; + + m_bInSquelchMode = true; + m_pHelper->UpdateCursorState(); +} + +void CVoiceStatus::StopSquelchMode() +{ + m_bInSquelchMode = false; + m_pHelper->UpdateCursorState(); +} + +bool CVoiceStatus::IsInSquelchMode() +{ + return m_bInSquelchMode; +} + +CVoiceLabel* CVoiceStatus::FindVoiceLabel(int clientindex) +{ + for(int i=0; i < MAX_VOICE_SPEAKERS; i++) + { + if(m_Labels[i].m_clientindex == clientindex) + return &m_Labels[i]; + } + + return NULL; +} + + +CVoiceLabel* CVoiceStatus::GetFreeVoiceLabel() +{ + return FindVoiceLabel(-1); +} + + +void CVoiceStatus::RepositionLabels() +{ + // find starting position to draw from, along right-hand side of screen + int y = ScreenHeight / 2; + + int iconWide = 8, iconTall = 8; + if( m_pSpeakerLabelIcon ) + { + m_pSpeakerLabelIcon->getSize( iconWide, iconTall ); + } + + // Reposition active labels. + for(int i = 0; i < MAX_VOICE_SPEAKERS; i++) + { + CVoiceLabel *pLabel = &m_Labels[i]; + + if( pLabel->m_clientindex == -1 || !pLabel->m_pLabel ) + { + if( pLabel->m_pBackground ) + pLabel->m_pBackground->setVisible( false ); + + continue; + } + + int textWide, textTall; + pLabel->m_pLabel->getContentSize( textWide, textTall ); + + // Don't let it stretch too far across their screen. + if( textWide > (ScreenWidth*2)/3 ) + textWide = (ScreenWidth*2)/3; + + // Setup the background label to fit everything in. + int border = 2; + int bgWide = textWide + iconWide + border*3; + int bgTall = max( textTall, iconTall ) + border*2; + pLabel->m_pBackground->setBounds( ScreenWidth - bgWide - 8, y, bgWide, bgTall ); + + // Put the text at the left. + pLabel->m_pLabel->setBounds( border, (bgTall - textTall) / 2, textWide, textTall ); + + // Put the icon at the right. + int iconLeft = border + textWide + border; + int iconTop = (bgTall - iconTall) / 2; + if( pLabel->m_pIcon ) + { + pLabel->m_pIcon->setImage( m_pSpeakerLabelIcon ); + pLabel->m_pIcon->setBounds( iconLeft, iconTop, iconWide, iconTall ); + } + + y += bgTall + 2; + } + + if( m_pLocalBitmap && m_pAckBitmap && m_pLocalLabel && (m_bTalking || m_bServerAcked) ) + { + m_pLocalLabel->setParent(*m_pParentPanel); + m_pLocalLabel->setVisible( true ); + + if( m_bServerAcked && !!gEngfuncs.pfnGetCvarFloat("voice_clientdebug") ) + m_pLocalLabel->setImage( m_pAckBitmap ); + else + m_pLocalLabel->setImage( m_pLocalBitmap ); + + int sizeX, sizeY; + m_pLocalBitmap->getSize(sizeX, sizeY); + + int local_xPos = ScreenWidth - sizeX - 10; + int local_yPos = m_pHelper->GetAckIconHeight() - sizeY; + + m_pLocalLabel->setPos( local_xPos, local_yPos ); + } + else + { + m_pLocalLabel->setVisible( false ); + } +} + + +void CVoiceStatus::FreeBitmaps() +{ + // Delete all the images we have loaded. + delete m_pLocalBitmap; + m_pLocalBitmap = NULL; + + delete m_pAckBitmap; + m_pAckBitmap = NULL; + + delete m_pSpeakerLabelIcon; + m_pSpeakerLabelIcon = NULL; + + delete m_pScoreboardNeverSpoken; + m_pScoreboardNeverSpoken = NULL; + + delete m_pScoreboardNotSpeaking; + m_pScoreboardNotSpeaking = NULL; + + delete m_pScoreboardSpeaking; + m_pScoreboardSpeaking = NULL; + + delete m_pScoreboardSpeaking2; + m_pScoreboardSpeaking2 = NULL; + + delete m_pScoreboardSquelch; + m_pScoreboardSquelch = NULL; + + delete m_pScoreboardBanned; + m_pScoreboardBanned = NULL; + + // Clear references to the images in panels. + for(int i=0; i < VOICE_MAX_PLAYERS; i++) + { + if (m_pBanButtons[i]) + { + m_pBanButtons[i]->setImage(NULL); + } + } + + if(m_pLocalLabel) + m_pLocalLabel->setImage(NULL); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the target client has been banned +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CVoiceStatus::IsPlayerBlocked(int iPlayer) +{ + char playerID[16]; + if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) + return false; + + return m_BanMgr.GetPlayerBan(playerID); +} + +//----------------------------------------------------------------------------- +// Purpose: returns true if the player can't hear the other client due to game rules (eg. the other team) +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool CVoiceStatus::IsPlayerAudible(int iPlayer) +{ + return !!m_AudiblePlayers[iPlayer-1]; +} + +//----------------------------------------------------------------------------- +// Purpose: blocks/unblocks the target client from being heard +// Input : playerID - +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +void CVoiceStatus::SetPlayerBlockedState(int iPlayer, bool blocked) +{ + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 1\n" ); + } + + char playerID[16]; + if (!gEngfuncs.GetPlayerUniqueID(iPlayer, playerID)) + return; + + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + gEngfuncs.pfnConsolePrint( "CVoiceStatus::SetPlayerBlockedState part 2\n" ); + } + + // Squelch or (try to) unsquelch this player. + if (gEngfuncs.pfnGetCvarFloat("voice_clientdebug")) + { + char str[256]; + sprintf(str, "CVoiceStatus::SetPlayerBlockedState: setting player %d ban to %d\n", iPlayer, !m_BanMgr.GetPlayerBan(playerID)); + gEngfuncs.pfnConsolePrint(str); + } + + m_BanMgr.SetPlayerBan( playerID, blocked ); + UpdateServerState(false); +} diff --git a/game_shared/voice_status.h b/game_shared/voice_status.h new file mode 100644 index 00000000..7825083a --- /dev/null +++ b/game_shared/voice_status.h @@ -0,0 +1,228 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_STATUS_H +#define VOICE_STATUS_H +#pragma once + + +#include "VGUI_Label.h" +#include "VGUI_LineBorder.h" +#include "VGUI_ImagePanel.h" +#include "VGUI_BitmapTGA.h" +#include "VGUI_InputSignal.h" +#include "VGUI_Button.h" +#include "voice_common.h" +#include "cl_entity.h" +#include "voice_banmgr.h" +#include "vgui_checkbutton2.h" +#include "vgui_defaultinputsignal.h" + + +class CVoiceStatus; + + +class CVoiceLabel +{ +public: + vgui::Label *m_pLabel; + vgui::Label *m_pBackground; + vgui::ImagePanel *m_pIcon; // Voice icon next to player name. + int m_clientindex; // Client index of the speaker. -1 if this label isn't being used. +}; + + +// This is provided by each mod to access data that may not be the same across mods. +class IVoiceStatusHelper +{ +public: + virtual ~IVoiceStatusHelper() {} + + // Get RGB color for voice status text about this player. + virtual void GetPlayerTextColor(int entindex, int color[3]) = 0; + + // Force it to update the cursor state. + virtual void UpdateCursorState() = 0; + + // Return the height above the bottom that the voice ack icons should be drawn at. + virtual int GetAckIconHeight() = 0; + + // Return true if the voice manager is allowed to show speaker labels + // (mods usually return false when the scoreboard is up). + virtual bool CanShowSpeakerLabels() = 0; +}; + +//----------------------------------------------------------------------------- +// Purpose: Holds a color for the shared image +//----------------------------------------------------------------------------- +class VoiceImagePanel : public vgui::ImagePanel +{ + virtual void paintBackground() + { + if (_image!=null) + { + vgui::Color col; + getFgColor(col); + _image->setColor(col); + _image->doPaint(this); + } + } +}; + + +class CVoiceStatus : public CHudBase, public vgui::CDefaultInputSignal +{ +public: + CVoiceStatus(); + virtual ~CVoiceStatus(); + +// CHudBase overrides. +public: + + // Initialize the cl_dll's voice manager. + virtual int Init( + IVoiceStatusHelper *m_pHelper, + vgui::Panel **pParentPanel); + + // ackPosition is the bottom position of where CVoiceStatus will draw the voice acknowledgement labels. + virtual int VidInit(); + + +public: + + // Call from HUD_Frame each frame. + void Frame(double frametime); + + // Called when a player starts or stops talking. + // entindex is -1 to represent the local client talking (before the data comes back from the server). + // When the server acknowledges that the local client is talking, then entindex will be gEngfuncs.GetLocalPlayer(). + // entindex is -2 to represent the local client's voice being acked by the server. + void UpdateSpeakerStatus(int entindex, qboolean bTalking); + + // sets the correct image in the label for the player + void UpdateSpeakerImage(vgui::Label *pLabel, int iPlayer); + + // Call from the HUD_CreateEntities function so it can add sprites above player heads. + void CreateEntities(); + + // Called when the server registers a change to who this client can hear. + void HandleVoiceMaskMsg(int iSize, void *pbuf); + + // The server sends this message initially to tell the client to send their state. + void HandleReqStateMsg(int iSize, void *pbuf); + + +// Squelch mode functions. +public: + + // When you enter squelch mode, pass in + void StartSquelchMode(); + void StopSquelchMode(); + bool IsInSquelchMode(); + + // returns true if the target client has been banned + // playerIndex is of range 1..maxplayers + bool IsPlayerBlocked(int iPlayerIndex); + + // returns false if the player can't hear the other client due to game rules (eg. the other team) + bool IsPlayerAudible(int iPlayerIndex); + + // blocks the target client from being heard + void SetPlayerBlockedState(int iPlayerIndex, bool blocked); + +public: + + CVoiceLabel* FindVoiceLabel(int clientindex); // Find a CVoiceLabel representing the specified speaker. + // Returns NULL if none. + // entindex can be -1 if you want a currently-unused voice label. + CVoiceLabel* GetFreeVoiceLabel(); // Get an unused voice label. Returns NULL if none. + + void RepositionLabels(); + + void FreeBitmaps(); + + void UpdateServerState(bool bForce); + + // Update the button artwork to reflect the client's current state. + void UpdateBanButton(int iClient); + + +public: + + enum {MAX_VOICE_SPEAKERS=7}; + + float m_LastUpdateServerState; // Last time we called this function. + int m_bServerModEnable; // What we've sent to the server about our "voice_modenable" cvar. + + vgui::Panel **m_pParentPanel; + CPlayerBitVec m_VoicePlayers; // Who is currently talking. Indexed by client index. + + // This is the gamerules-defined list of players that you can hear. It is based on what teams people are on + // and is totally separate from the ban list. Indexed by client index. + CPlayerBitVec m_AudiblePlayers; + + // Players who have spoken at least once in the game so far + CPlayerBitVec m_VoiceEnabledPlayers; + + // This is who the server THINKS we have banned (it can become incorrect when a new player arrives on the server). + // It is checked periodically, and the server is told to squelch or unsquelch the appropriate players. + CPlayerBitVec m_ServerBannedPlayers; + + cl_entity_s m_VoiceHeadModels[VOICE_MAX_PLAYERS]; // These aren't necessarily in the order of players. They are just + // a place for it to put data in during CreateEntities. + + IVoiceStatusHelper *m_pHelper; // Each mod provides an implementation of this. + + + // Scoreboard icons. + double m_BlinkTimer; // Blink scoreboard icons.. + vgui::BitmapTGA *m_pScoreboardNeverSpoken; + vgui::BitmapTGA *m_pScoreboardNotSpeaking; + vgui::BitmapTGA *m_pScoreboardSpeaking; + vgui::BitmapTGA *m_pScoreboardSpeaking2; + vgui::BitmapTGA *m_pScoreboardSquelch; + vgui::BitmapTGA *m_pScoreboardBanned; + + vgui::Label *m_pBanButtons[VOICE_MAX_PLAYERS]; // scoreboard buttons. + + // Squelch mode stuff. + bool m_bInSquelchMode; + + HSPRITE m_VoiceHeadModel; // Voice head model (goes above players who are speaking). + float m_VoiceHeadModelHeight; // Height above their head to place the model. + + vgui::Image *m_pSpeakerLabelIcon; // Icon next to speaker labels. + + // Lower-right icons telling when the local player is talking.. + vgui::BitmapTGA *m_pLocalBitmap; // Represents the local client talking. + vgui::BitmapTGA *m_pAckBitmap; // Represents the server ack'ing the client talking. + vgui::ImagePanel *m_pLocalLabel; // Represents the local client talking. + + bool m_bTalking; // Set to true when the client thinks it's talking. + bool m_bServerAcked; // Set to true when the server knows the client is talking. + +public: + + CVoiceBanMgr m_BanMgr; // Tracks which users we have squelched and don't want to hear. + +public: + + bool m_bBanMgrInitialized; + + // Labels telling who is speaking. + CVoiceLabel m_Labels[MAX_VOICE_SPEAKERS]; + + // Cache the game directory for use when we shut down + char * m_pchGameDir; +}; + + +// Get the (global) voice manager. +CVoiceStatus* GetClientVoiceMgr(); + + +#endif // VOICE_STATUS_H diff --git a/game_shared/voice_vgui_tweakdlg.cpp b/game_shared/voice_vgui_tweakdlg.cpp new file mode 100644 index 00000000..b5cde708 --- /dev/null +++ b/game_shared/voice_vgui_tweakdlg.cpp @@ -0,0 +1,289 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#include "../cl_dll/hud.h" +#include "../cl_dll/cl_util.h" +#include "../cl_dll/vgui_teamfortressviewport.h" + + +#include "vgui_actionsignal.h" +#include "voice_vgui_tweakdlg.h" +#include "voice_vgui_tweakdlg.h" +#include "vgui_panel.h" +#include "vgui_scrollbar.h" +#include "vgui_slider.h" +#include "ivoicetweak.h" +#include "vgui_button.h" +#include "vgui_checkbutton2.h" +#include "vgui_helpers.h" + + +#define ITEM_BORDER 40 // Border between text and scrollbars on left and right. +#define VOICETWEAK_TRANSPARENCY 150 + + +class TweakScroller +{ +public: + TweakScroller(); + void Init(Panel *pParent, char *pText, int yPos); + + // Get/set value. Values are 0-1. + float GetValue(); + void SetValue(float val); + +public: + Label m_Label; + ScrollBar m_Scroll; + Slider m_Slider; +}; + + +class CVoiceVGUITweakDlg : public CMenuPanel, public ICheckButton2Handler +{ +typedef CMenuPanel BaseClass; + +public: + CVoiceVGUITweakDlg(); + ~CVoiceVGUITweakDlg(); + +// CMenuPanel overrides. +public: + virtual void Open(); + virtual void Close(); + + +// ICheckButton2Handler overrides. +public: + + virtual void StateChanged(CCheckButton2 *pButton); + + + +// Panel overrides. +public: + virtual void paintBackground(); + + +private: + + int m_DlgWidth; + int m_DlgHeight; + + Label m_Label; + + IVoiceTweak *m_pVoiceTweak; // Engine voice tweak API. + + TweakScroller m_MicVolume; + TweakScroller m_SpeakerVolume; + + CCheckButton2 m_VoiceModEnable; + + Button m_Button_OK; +}; + + + +bool g_bTweakDlgOpen = false; + +bool IsTweakDlgOpen() +{ + return g_bTweakDlgOpen; +} + + + +// ------------------------------------------------------------------------ // +// Global functions. +// ------------------------------------------------------------------------ // + +static CVoiceVGUITweakDlg g_VoiceTweakDlg; +CMenuPanel* GetVoiceTweakDlg() +{ + return &g_VoiceTweakDlg; +} + + +class CVoiceTweakOKButton : public ActionSignal +{ +public: + virtual void actionPerformed(Panel *pPanel) + { + gViewPort->HideVGUIMenu(); + } +}; +CVoiceTweakOKButton g_OKButtonSignal; + + + +// ------------------------------------------------------------------------ // +// TweakScroller +// ------------------------------------------------------------------------ // + +TweakScroller::TweakScroller() : + m_Label(""), + m_Scroll(0,0,0,0,false), + m_Slider(0,0,10,10,false) +{ +} + + +void TweakScroller::Init(Panel *pParent, char *pText, int yPos) +{ + int parentWidth, parentHeight; + pParent->getSize(parentWidth, parentHeight); + + // Setup the volume scroll bar. + m_Label.setParent(pParent); + m_Label.setFont(Scheme::sf_primary1); + m_Label.setContentAlignment(vgui::Label::a_northwest); + m_Label.setBgColor(0, 0, 0, 255); + m_Label.setFgColor(255,255,255,0); + m_Label.setPos(ITEM_BORDER, yPos); + m_Label.setSize(parentWidth/2-ITEM_BORDER, 20); + m_Label.setText(pText); + m_Label.setVisible(true); + + m_Slider.setRangeWindow(10); + m_Slider.setRangeWindowEnabled(true); + + m_Scroll.setPos(parentWidth/2+ITEM_BORDER, yPos); + m_Scroll.setSize(parentWidth/2-ITEM_BORDER*2, 20); + m_Scroll.setSlider(&m_Slider); + m_Scroll.setParent(pParent); + m_Scroll.setRange(0, 100); + m_Scroll.setFgColor(255,255,255,0); + m_Scroll.setBgColor(255,255,255,0); +} + + +float TweakScroller::GetValue() +{ + return m_Scroll.getValue() / 100.0f; +} + + +void TweakScroller::SetValue(float val) +{ + m_Scroll.setValue((int)(val * 100.0f)); +} + + +// ------------------------------------------------------------------------ // +// CVoiceVGUITweakDlg implementation. +// ------------------------------------------------------------------------ // + +CVoiceVGUITweakDlg::CVoiceVGUITweakDlg() + : CMenuPanel(VOICETWEAK_TRANSPARENCY, false, 0, 0, 0, 0), + m_Button_OK("",0,0), + m_Label("") +{ + m_pVoiceTweak = NULL; + m_Button_OK.addActionSignal(&g_OKButtonSignal); + m_Label.setBgColor(255,255,255,200); +} + + +CVoiceVGUITweakDlg::~CVoiceVGUITweakDlg() +{ +} + + +void CVoiceVGUITweakDlg::Open() +{ + if(g_bTweakDlgOpen) + return; + + g_bTweakDlgOpen = true; + + m_DlgWidth = ScreenWidth; + m_DlgHeight = ScreenHeight; + + m_pVoiceTweak = gEngfuncs.pVoiceTweak; + + // Tell the engine to start voice tweak mode (pipe voice output right to speakers). + m_pVoiceTweak->StartVoiceTweakMode(); + + // Set our size. + setPos((ScreenWidth - m_DlgWidth) / 2, (ScreenHeight - m_DlgHeight) / 2); + setSize(m_DlgWidth, m_DlgHeight); + + int curY = ITEM_BORDER; + m_MicVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Mic_Volume"), curY); + m_MicVolume.SetValue(m_pVoiceTweak->GetControlFloat(MicrophoneVolume)); + curY = PanelBottom(&m_MicVolume.m_Label); + + m_SpeakerVolume.Init(this, gHUD.m_TextMessage.BufferedLocaliseTextString("#Speaker_Volume"), curY); + m_SpeakerVolume.SetValue(m_pVoiceTweak->GetControlFloat(OtherSpeakerScale)); + curY = PanelBottom(&m_SpeakerVolume.m_Label); + + m_VoiceModEnable.setParent(this); + m_VoiceModEnable.SetImages("gfx/vgui/checked.tga", "gfx/vgui/unchecked.tga"); + m_VoiceModEnable.SetText("Enable Voice In This Mod"); + m_VoiceModEnable.setPos(ITEM_BORDER, curY); + m_VoiceModEnable.SetCheckboxLeft(false); + m_VoiceModEnable.SetChecked(!!gEngfuncs.pfnGetCvarFloat("voice_modenable")); + m_VoiceModEnable.SetHandler(this); + + // Setup the OK button. + int buttonWidth, buttonHeight; + m_Button_OK.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Menu_OK")); + m_Button_OK.getSize(buttonWidth, buttonHeight); + m_Button_OK.setPos((m_DlgWidth - buttonWidth) / 2, m_DlgHeight - buttonHeight - 3); + m_Button_OK.setParent(this); + + // Put the label on the top. + m_Label.setBgColor(0, 0, 0, 255); + m_Label.setFgColor(255,255,255,0); + m_Label.setText(gHUD.m_TextMessage.BufferedLocaliseTextString("#Voice_Properties")); + int labelWidth, labelHeight; + m_Label.getSize(labelWidth, labelHeight); + m_Label.setPos((m_DlgWidth - labelWidth) / 2, 5); + m_Label.setParent(this); + + BaseClass::Open(); +} + + +void CVoiceVGUITweakDlg::Close() +{ + m_pVoiceTweak->EndVoiceTweakMode(); + g_bTweakDlgOpen = false; + + BaseClass::Close(); +} + + +void CVoiceVGUITweakDlg::paintBackground() +{ + BaseClass::paintBackground(); + + // Draw our border. + int w,h; + getSize(w,h); + + drawSetColor(128,128,128,1); + drawOutlinedRect(0, 0, w, h); + + float volume = m_MicVolume.GetValue(); + m_pVoiceTweak->SetControlFloat(MicrophoneVolume, volume); + + m_pVoiceTweak->SetControlFloat(OtherSpeakerScale, m_SpeakerVolume.GetValue()); +} + + +void CVoiceVGUITweakDlg::StateChanged(CCheckButton2 *pButton) +{ + if(pButton == &m_VoiceModEnable) + { + if(pButton->IsChecked()) + gEngfuncs.pfnClientCmd("voice_modenable 1"); + else + gEngfuncs.pfnClientCmd("voice_modenable 0"); + } +} + diff --git a/game_shared/voice_vgui_tweakdlg.h b/game_shared/voice_vgui_tweakdlg.h new file mode 100644 index 00000000..857ffd25 --- /dev/null +++ b/game_shared/voice_vgui_tweakdlg.h @@ -0,0 +1,25 @@ +//========= Copyright й 1996-2002, Valve LLC, All rights reserved. ============ +// +// Purpose: +// +// $NoKeywords: $ +//============================================================================= + +#ifndef VOICE_VGUI_TWEAKDLG_H +#define VOICE_VGUI_TWEAKDLG_H +#ifdef _WIN32 +#pragma once +#endif + + +class CMenuPanel; + + +// Returns true if the tweak dialog is currently up. +bool IsTweakDlgOpen(); + +// Returns a global instance of the tweak dialog. +CMenuPanel* GetVoiceTweakDlg(); + + +#endif // VOICE_VGUI_TWEAKDLG_H diff --git a/gameui/gameui.def b/gameui/gameui.def deleted file mode 100644 index c2375b41..00000000 --- a/gameui/gameui.def +++ /dev/null @@ -1,5 +0,0 @@ -LIBRARY gameui -EXPORTS - CreateAPI @1 -SECTIONS - .data READ WRITE diff --git a/launch/cpuinfo.c b/launch/cpuinfo.c index 6bfd20ef..1bb7c983 100644 --- a/launch/cpuinfo.c +++ b/launch/cpuinfo.c @@ -3,7 +3,6 @@ // cpuinfo.c - get cpu information //======================================================================= -#include "const.h" #include "launch.h" typedef signed __int64 int64; diff --git a/launch/filesystem.c b/launch/filesystem.c index d815a111..5463fb93 100644 --- a/launch/filesystem.c +++ b/launch/filesystem.c @@ -1187,7 +1187,7 @@ void FS_ClearSearchPath( void ) if( search->flags & FS_STATIC_PATH ) { - // skip read-only pathes e.g. "bin" + // skip read-only pathes if( search->next ) fs_searchpaths = search->next->next; else break; @@ -1440,8 +1440,8 @@ void FS_CreateDefaultGameInfo( const char *filename ) com.strncpy( defGI.basedir, fs_defaultdir->string, sizeof( defGI.basedir )); com.strncpy( defGI.sp_entity, "info_player_start", sizeof( defGI.sp_entity )); com.strncpy( defGI.mp_entity, "info_player_deathmatch", sizeof( defGI.mp_entity )); - com.strncpy( defGI.dll_path, "bin", sizeof( defGI.dll_path )); - com.strncpy( defGI.game_dll, "bin/server.dll", sizeof( defGI.game_dll )); + com.strncpy( defGI.dll_path, "cl_dlls", sizeof( defGI.dll_path )); + com.strncpy( defGI.game_dll, "dlls/hl.dll", sizeof( defGI.game_dll )); com.strncpy( defGI.startmap, "newmap", sizeof( defGI.startmap )); VectorSet( defGI.client_mins[0], 0, 0, 0 ); @@ -1481,9 +1481,7 @@ static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, g com.strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity )); com.strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll )); com.strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap )); - - // FIXME: replace with "cl_dlls" when support for client.dll will be it's finished - com.strncpy( GameInfo->dll_path, "bin", sizeof( GameInfo->dll_path )); + com.strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path )); VectorSet( GameInfo->client_mins[0], 0, 0, 0 ); VectorSet( GameInfo->client_maxs[0], 0, 0, 0 ); @@ -1627,8 +1625,8 @@ static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) com.strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title )); com.strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity )); com.strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity )); - com.strncpy( GameInfo->dll_path, "bin", sizeof( GameInfo->dll_path )); - com.strncpy( GameInfo->game_dll, "bin/server.dll", sizeof( GameInfo->game_dll )); + com.strncpy( GameInfo->dll_path, "cl_dlls", sizeof( GameInfo->dll_path )); + com.strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll )); com.strncpy( GameInfo->startmap, "", sizeof( GameInfo->startmap )); VectorSet( GameInfo->client_mins[0], 0, 0, 0 ); @@ -1816,7 +1814,7 @@ void FS_Init( void ) FS_InitMemory(); - FS_AddGameDirectory( "bin/", FS_STATIC_PATH ); // execute system config + FS_AddGameDirectory( "./", FS_STATIC_PATH ); // execute system config Cmd_AddCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" ); Cmd_AddCommand( "fs_path", FS_Path_f, "show filesystem search pathes" ); @@ -1839,8 +1837,7 @@ void FS_Init( void ) else com.strcpy( gs_basedir, fs_defaultdir->string ); // default dir } - // checked nasty path: "bin" it's a reserved word - if( FS_CheckNastyPath( gs_basedir, true ) || !com.stricmp( "bin", gs_basedir )) + if( FS_CheckNastyPath( gs_basedir, true )) { MsgDev( D_ERROR, "FS_Init: invalid game directory \"%s\"\n", gs_basedir ); com.strcpy( gs_basedir, fs_defaultdir->string ); // default dir @@ -3420,7 +3417,7 @@ static void FS_BuildPath( char *pPath, char *pOut ) { // set working directory SetCurrentDirectory ( pPath ); - com.sprintf( pOut, "%s\\bin\\launch.dll", pPath ); + com.sprintf( pOut, "%s\\launch.dll", pPath ); } void FS_UpdateEnvironmentVariables( void ) diff --git a/launch/filesystem.old b/launch/filesystem.old deleted file mode 100644 index 79facdc0..00000000 --- a/launch/filesystem.old +++ /dev/null @@ -1,4436 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 й -// filesystem.c - game filesystem based on DP fs -//======================================================================= - -#include "launch.h" -#include "wadfile.h" -#include "filesystem.h" -#include "byteorder.h" -#include "library.h" -#include "mathlib.h" - -#define ZIP_END_CDIR_SIZE 22 -#define ZIP_CDIR_CHUNK_BASE_SIZE 46 -#define ZIP_LOCAL_CHUNK_BASE_SIZE 30 - -#define FILE_FLAG_PACKED (1<<0) // inside a package (PAK or PK3) -#define FILE_FLAG_CRYPTED (1<<1) // file is crypted (PAK2) -#define FILE_FLAG_DEFLATED (1<<2) // (PK3 only) -#define PACKFILE_FLAG_TRUEOFFS (1<<0) // the offset in packfile_t is the true contents offset -#define PACKFILE_FLAG_DEFLATED (1<<1) // file compressed using the deflate algorithm -#define FILE_BUFF_SIZE 2048 - -typedef struct -{ - z_stream zstream; - size_t comp_length; // length of the compressed file - size_t in_ind, in_len; // input buffer current index and length - size_t in_position; // position in the compressed file - byte input [FILE_BUFF_SIZE]; -} ztoolkit_t; - -typedef struct stringlist_s -{ - // maxstrings changes as needed, causing reallocation of strings[] array - int maxstrings; - int numstrings; - char **strings; -} stringlist_t; - -typedef struct wadtype_s -{ - char *ext; - char type; -} wadtype_t; - -typedef struct file_s -{ - int flags; - int handle; // file descriptor - fs_offset_t real_length; // uncompressed file size (for files opened in "read" mode) - fs_offset_t position; // current position in the file - fs_offset_t offset; // offset into the package (0 if external file) - int ungetc; // single stored character from ungetc, cleared to EOF when read - time_t filetime; // pak, wad or real filetime - // Contents buffer - fs_offset_t buff_ind, buff_len; // buffer current index and length - byte buff [FILE_BUFF_SIZE]; - ztoolkit_t* ztk; // for zipped files -}; - -typedef struct vfile_s -{ - byte *buff; - file_t *handle; - int mode; - - fs_offset_t buffsize; - fs_offset_t length; - fs_offset_t offset; -}; - -typedef struct wfile_s -{ - char filename [MAX_SYSPATH]; - int infotableofs; - byte *mempool; // W_ReadLump temp buffers - int numlumps; - int mode; - file_t *file; - dlumpinfo_t *lumps; - time_t filetime; -}; - -typedef struct packfile_s -{ - char name[128]; - int flags; - fs_offset_t offset; - fs_offset_t packsize; // size in the package - fs_offset_t realsize; // real file size (uncompressed) -} packfile_t; - -typedef struct pack_s -{ - char filename [MAX_SYSPATH]; - int handle; - int numfiles; - packfile_t *files; - time_t filetime; // common for all packed files -} pack_t; - -typedef struct searchpath_s -{ - char filename[MAX_SYSPATH]; - pack_t *pack; - wfile_t *wad; - int flags; - struct searchpath_s *next; -} searchpath_t; - -byte *fs_mempool; -searchpath_t *fs_searchpaths = NULL; -searchpath_t fs_directpath; // static direct path - -static void FS_InitMemory( void ); -const char *FS_FileExtension( const char *in ); -static searchpath_t *FS_FindFile( const char *name, int *index, qboolean gamedironly ); -static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype ); -static packfile_t* FS_AddFileToPack (const char* name, pack_t* pack, fs_offset_t offset, fs_offset_t packsize, fs_offset_t realsize, int flags); -static byte *W_LoadFile( const char *path, fs_offset_t *filesizeptr ); -static qboolean FS_SysFileExists( const char *path ); -static long FS_SysFileTime( const char *filename ); -static char W_TypeFromExt( const char *lumpname ); -static const char *W_ExtFromType( char lumptype ); - -char sys_rootdir[MAX_SYSPATH]; // system root -char fs_rootdir[MAX_SYSPATH]; // engine root directory -char fs_basedir[MAX_SYSPATH]; // base directory of game -char fs_gamedir[MAX_SYSPATH]; // game current directory -char gs_basedir[MAX_SYSPATH]; // initial dir before loading gameinfo.txt (used for compilers too) - -// command ilne parms -int fs_argc; -char *fs_argv[MAX_NUM_ARGVS]; -qboolean fs_ext_path = false; // attempt to read\write from ./ or ../ pathes -qboolean fs_use_wads = false; // some utilities needs this -convar_t *fs_defaultdir; -sysinfo_t SI; - -/* -============================================================================= - -PRIVATE FUNCTIONS - PK3 HANDLING - -============================================================================= -*/ -/* -==================== -PK3_GetEndOfCentralDir - -Extract the end of the central directory from a PK3 package -==================== -*/ -qboolean PK3_GetEndOfCentralDir (const char *packfile, int packhandle, dpak3file_t *eocd) -{ - fs_offset_t filesize, maxsize; - byte *buffer, *ptr; - int ind; - - // Get the package size - filesize = lseek (packhandle, 0, SEEK_END); - if (filesize < ZIP_END_CDIR_SIZE) return false; - - // Load the end of the file in memory - if (filesize < (word)0xffff + ZIP_END_CDIR_SIZE) - maxsize = filesize; - else maxsize = (word)0xffff + ZIP_END_CDIR_SIZE; - buffer = (byte *)Mem_Alloc( fs_mempool, maxsize ); - lseek (packhandle, filesize - maxsize, SEEK_SET); - if(read(packhandle, buffer, maxsize) != (fs_offset_t)maxsize) - { - Mem_Free(buffer); - return false; - } - - // Look for the end of central dir signature around the end of the file - maxsize -= ZIP_END_CDIR_SIZE; - ptr = &buffer[maxsize]; - ind = 0; - while(BuffLittleLong(ptr) != IDPK3ENDHEADER) - { - if (ind == maxsize) - { - Mem_Free (buffer); - return false; - } - ind++; - ptr--; - } - - Mem_Copy (eocd, ptr, ZIP_END_CDIR_SIZE); - - eocd->ident = LittleLong (eocd->ident); - eocd->disknum = LittleShort (eocd->disknum); - eocd->cdir_disknum = LittleShort (eocd->cdir_disknum); - eocd->localentries = LittleShort (eocd->localentries); - eocd->nbentries = LittleShort (eocd->nbentries); - eocd->cdir_size = LittleLong (eocd->cdir_size); - eocd->cdir_offset = LittleLong (eocd->cdir_offset); - eocd->comment_size = LittleShort (eocd->comment_size); - Mem_Free (buffer); - - return true; -} - - -/* -==================== -PK3_BuildFileList - -Extract the file list from a PK3 file -==================== -*/ -int PK3_BuildFileList (pack_t *pack, const dpak3file_t *eocd) -{ - byte *central_dir, *ptr; - uint ind; - fs_offset_t remaining; - - // Load the central directory in memory - central_dir = (byte *)Mem_Alloc( fs_mempool, eocd->cdir_size ); - lseek( pack->handle, eocd->cdir_offset, SEEK_SET ); - read( pack->handle, central_dir, eocd->cdir_size ); - - // Extract the files properties - // The parsing is done "by hand" because some fields have variable sizes and - // the constant part isn't 4-bytes aligned, which makes the use of structs difficult - remaining = eocd->cdir_size; - pack->numfiles = 0; - ptr = central_dir; - for (ind = 0; ind < eocd->nbentries; ind++) - { - fs_offset_t namesize, count; - - // Checking the remaining size - if (remaining < ZIP_CDIR_CHUNK_BASE_SIZE) - { - Mem_Free (central_dir); - return -1; - } - remaining -= ZIP_CDIR_CHUNK_BASE_SIZE; - - // Check header - if (BuffLittleLong (ptr) != IDPK3CDRHEADER) - { - Mem_Free (central_dir); - return -1; - } - - namesize = BuffLittleShort(&ptr[28]); // filename length - - // Check encryption, compression, and attributes - // 1st uint8 : general purpose bit flag - // Check bits 0 (encryption), 3 (data descriptor after the file), and 5 (compressed patched data (?)) - // 2nd uint8 : external file attributes - // Check bits 3 (file is a directory) and 5 (file is a volume (?)) - if((ptr[8] & 0x29) == 0 && (ptr[38] & 0x18) == 0) - { - // Still enough bytes for the name? - if (remaining < namesize || namesize >= (int)sizeof (*pack->files)) - { - Mem_Free(central_dir); - return -1; - } - - // WinZip doesn't use the "directory" attribute, so we need to check the name directly - if (ptr[ZIP_CDIR_CHUNK_BASE_SIZE + namesize - 1] != '/') - { - char filename [sizeof (pack->files[0].name)]; - fs_offset_t offset, packsize, realsize; - int flags; - - // Extract the name (strip it if necessary) - namesize = min(namesize, (int)sizeof (filename) - 1); - Mem_Copy (filename, &ptr[ZIP_CDIR_CHUNK_BASE_SIZE], namesize); - filename[namesize] = '\0'; - - if (BuffLittleShort (&ptr[10])) - flags = PACKFILE_FLAG_DEFLATED; - else flags = 0; - offset = BuffLittleLong (&ptr[42]); - packsize = BuffLittleLong (&ptr[20]); - realsize = BuffLittleLong (&ptr[24]); - FS_AddFileToPack(filename, pack, offset, packsize, realsize, flags); - } - } - - // Skip the name, additionnal field, and comment - // 1er uint16 : extra field length - // 2eme uint16 : file comment length - count = namesize + BuffLittleShort (&ptr[30]) + BuffLittleShort (&ptr[32]); - ptr += ZIP_CDIR_CHUNK_BASE_SIZE + count; - remaining -= count; - } - // If the package is empty, central_dir is NULL here - if (central_dir != NULL) Mem_Free (central_dir); - return pack->numfiles; -} - - -/* -==================== -FS_LoadPackPK3 - -Create a package entry associated with a PK3 file -==================== -*/ -pack_t *FS_LoadPackPK3( const char *packfile ) -{ - int packhandle; - int real_nb_files; - dpak3file_t eocd; - pack_t *pack; - - packhandle = open( packfile, O_RDONLY|O_BINARY ); - if( packhandle < 0 ) return NULL; - - if( !PK3_GetEndOfCentralDir( packfile, packhandle, &eocd )) - { - MsgDev( D_NOTE, "%s is not a PK3 file\n", packfile ); - close( packhandle ); - return NULL; - } - - // multi-volume ZIP archives are NOT allowed - if( eocd.disknum != 0 || eocd.cdir_disknum != 0 ) - { - MsgDev( D_NOTE, "%s is a multi-volume ZIP archive. Ignored.\n", packfile ); - close( packhandle ); - return NULL; - } - - // Create a package structure in memory - pack = (pack_t *)Mem_Alloc( fs_mempool, sizeof( pack_t )); - com.strncpy( pack->filename, packfile, sizeof( pack->filename )); - pack->handle = packhandle; - pack->numfiles = eocd.nbentries; - pack->files = (packfile_t *)Mem_Alloc( fs_mempool, eocd.nbentries * sizeof( packfile_t )); - pack->filetime = FS_SysFileTime( packfile ); - - real_nb_files = PK3_BuildFileList( pack, &eocd ); - if( real_nb_files < 0 ) - { - MsgDev( D_ERROR, "%s is not a valid PK3 file\n", packfile ); - close( pack->handle ); - Mem_Free( pack ); - return NULL; - } - - MsgDev( D_NOTE, "Adding packfile %s (%i files)\n", packfile, real_nb_files ); - return pack; -} - -/* -==================== -PK3_GetTrueFileOffset - -Find where the true file data offset is -==================== -*/ -qboolean PK3_GetTrueFileOffset (packfile_t *pfile, pack_t *pack) -{ - byte buffer [ZIP_LOCAL_CHUNK_BASE_SIZE]; - fs_offset_t count; - - // already found? - if (pfile->flags & PACKFILE_FLAG_TRUEOFFS) return true; - - // Load the local file description - lseek (pack->handle, pfile->offset, SEEK_SET); - count = read (pack->handle, buffer, ZIP_LOCAL_CHUNK_BASE_SIZE); - if (count != ZIP_LOCAL_CHUNK_BASE_SIZE || BuffLittleLong (buffer) != IDPACKV3HEADER) - { - Msg("Can't retrieve file %s in package %s\n", pfile->name, pack->filename); - return false; - } - - // Skip name and extra field - pfile->offset += BuffLittleShort (&buffer[26]) + BuffLittleShort (&buffer[28]) + ZIP_LOCAL_CHUNK_BASE_SIZE; - pfile->flags |= PACKFILE_FLAG_TRUEOFFS; - return true; -} - -/* -============================================================================= - -FILEMATCH COMMON SYSTEM - -============================================================================= -*/ -int matchpattern(const char *in, const char *pattern, qboolean caseinsensitive) -{ - int c1, c2; - - while( *pattern ) - { - switch( *pattern ) - { - case 0: return 1; // end of pattern - case '?': // match any single character - if( *in == 0 || *in == '/' || *in == '\\' || *in == ':' ) - return 0; // no match - in++; - pattern++; - break; - case '*': // match anything until following string - if( !*in ) return 1; // match - pattern++; - while( *in ) - { - if( *in == '/' || *in == '\\' || *in == ':' ) - break; - // see if pattern matches at this offset - if( matchpattern( in, pattern, caseinsensitive )) - return 1; - // nope, advance to next offset - in++; - } - break; - default: - if( *in != *pattern ) - { - if( !caseinsensitive ) - return 0; // no match - c1 = *in; - if( c1 >= 'A' && c1 <= 'Z' ) - c1 += 'a' - 'A'; - c2 = *pattern; - if( c2 >= 'A' && c2 <= 'Z' ) - c2 += 'a' - 'A'; - if( c1 != c2) return 0; // no match - } - in++; - pattern++; - break; - } - } - - if( *in ) return 0; // reached end of pattern but not end of input - return 1; // success -} - -void stringlistinit( stringlist_t *list ) -{ - Mem_Set( list, 0, sizeof( *list )); -} - -void stringlistfreecontents(stringlist_t *list) -{ - int i; - for (i = 0;i < list->numstrings;i++) - { - if (list->strings[i]) Mem_Free(list->strings[i]); - list->strings[i] = NULL; - } - list->numstrings = 0; - list->maxstrings = 0; - if (list->strings) Mem_Free(list->strings); -} - -void stringlistappend( stringlist_t *list, char *text ) -{ - size_t textlen; - char **oldstrings; - - if (list->numstrings >= list->maxstrings) - { - oldstrings = list->strings; - list->maxstrings += 4096; - list->strings = Mem_Alloc(fs_mempool, list->maxstrings * sizeof(*list->strings)); - if (list->numstrings) Mem_Copy(list->strings, oldstrings, list->numstrings * sizeof(*list->strings)); - if (oldstrings) Mem_Free( oldstrings ); - } - textlen = com.strlen( text ) + 1; - list->strings[list->numstrings] = Mem_Alloc( fs_mempool, textlen ); - Mem_Copy( list->strings[list->numstrings], text, textlen ); - list->numstrings++; -} - -void stringlistsort( stringlist_t *list ) -{ - int i, j; - char *temp; - - // this is a selection sort (finds the best entry for each slot) - for( i = 0; i < list->numstrings - 1; i++ ) - { - for( j = i + 1; j < list->numstrings; j++ ) - { - if( com.strcmp( list->strings[i], list->strings[j] ) > 0 ) - { - temp = list->strings[i]; - list->strings[i] = list->strings[j]; - list->strings[j] = temp; - } - } - } -} - -void listdirectory( stringlist_t *list, const char *path ) -{ - int i; - char pattern[4096], *c; - struct _finddata_t n_file; - long hFile; - - com.strncpy( pattern, path, sizeof( pattern )); - com.strncat( pattern, "*", sizeof( pattern )); - - // ask for the directory listing handle - hFile = _findfirst( pattern, &n_file ); - if( hFile == -1 ) return; - - // start a new chain with the the first name - stringlistappend( list, n_file.name ); - // iterate through the directory - while( _findnext( hFile, &n_file ) == 0 ) - stringlistappend( list, n_file.name ); - _findclose( hFile ); - - // convert names to lowercase because windows doesn't care, but pattern matching code often does - for( i = 0; i < list->numstrings; i++ ) - { - for( c = list->strings[i]; *c; c++ ) - { - if( *c >= 'A' && *c <= 'Z' ) - *c += 'a' - 'A'; - } - } -} - -/* -============================================================================= - -OTHER PRIVATE FUNCTIONS - -============================================================================= -*/ - -/* -==================== -FS_AddFileToPack - -Add a file to the list of files contained into a package -==================== -*/ -static packfile_t* FS_AddFileToPack( const char* name, pack_t* pack, fs_offset_t offset, fs_offset_t packsize, fs_offset_t realsize, int flags) -{ - int left, right, middle; - packfile_t *pfile; - - // look for the slot we should put that file into (binary search) - left = 0; - right = pack->numfiles - 1; - while( left <= right ) - { - int diff; - - middle = (left + right) / 2; - diff = com.stricmp( pack->files[middle].name, name ); - - // If we found the file, there's a problem - if( !diff ) MsgDev( D_NOTE, "Package %s contains the file %s several times\n", pack->filename, name ); - - // If we're too far in the list - if( diff > 0 ) right = middle - 1; - else left = middle + 1; - } - - // We have to move the right of the list by one slot to free the one we need - pfile = &pack->files[left]; - memmove( pfile + 1, pfile, (pack->numfiles - left) * sizeof( *pfile )); - pack->numfiles++; - - com.strncpy( pfile->name, name, sizeof( pfile->name )); - pfile->offset = offset; - pfile->packsize = packsize; - pfile->realsize = realsize; - pfile->flags = flags; - - return pfile; -} - - -/* -============ -FS_CreatePath - -Only used for FS_Open. -============ -*/ -void FS_CreatePath( char *path ) -{ - char *ofs, save; - - for( ofs = path+1; *ofs; ofs++ ) - { - if( *ofs == '/' || *ofs == '\\' ) - { - // create the directory - save = *ofs; - *ofs = 0; - _mkdir( path ); - *ofs = save; - } - } -} - - -/* -============ -FS_Path_f - -debug info -============ -*/ -void FS_Path_f( void ) -{ - searchpath_t *s; - - Msg( "Current search path:\n" ); - for( s = fs_searchpaths; s; s = s->next ) - { - if( s->pack ) Msg( "%s (%i files)\n", s->pack->filename, s->pack->numfiles ); - else if( s->wad ) Msg( "%s (%i files)\n", s->wad->filename, s->wad->numlumps ); - else Msg( "%s\n", s->filename ); - } -} - -/* -============ -FS_ClearPath_f - -only for debug targets -============ -*/ -void FS_ClearPaths_f( void ) -{ - FS_ClearSearchPath(); -} - -/* -============ -FS_FileBase - -Extracts the base name of a file (no path, no extension, assumes '/' as path separator) -============ -*/ -void _FS_FileBase( const char *in, char *out, qboolean kill_backwardslash ) -{ - int len, start, end; - - len = com.strlen( in ); - if( !len ) return; - - // scan backward for '.' - end = len - 1; - - while( end && in[end] != '.' && in[end] != '/' && in[end] != '\\' ) - end--; - - if( in[end] != '.' ) - end = len-1; // no '.', copy to end - else end--; // found ',', copy to left of '.' - - - // scan backward for '/' - start = len - 1; - - if( kill_backwardslash ) - { - while( start >= 0 && in[start] != '/' && in[start] != '\\' ) - start--; - - if( start < 0 || ( in[start] != '/' && in[start] != '\\' )) - start = 0; - else start++; - } - else - { - // NOTE: some doomwads using backward slash as part of animation name - // e.g. vile\1, so ignore backward slash for wads - while ( start >= 0 && in[start] != '/' ) - start--; - - if ( start < 0 || in[start] != '/' ) - start = 0; - else start++; - } - - // length of new sting - len = end - start + 1; - - // Copy partial string - com.strncpy( out, &in[start], len + 1 ); - out[len] = 0; -} - -void FS_FileBase( const char *in, char *out ) -{ - _FS_FileBase( in, out, true ); -} - -void W_FileBase( const char *in, char *out ) -{ - _FS_FileBase( in, out, false ); -} - -/* -================= -FS_LoadPackPAK - -Takes an explicit (not game tree related) path to a pak file. - -Loads the header and directory, adding the files at the beginning -of the list so they override previous pack files. -================= -*/ -pack_t *FS_LoadPackPAK( const char *packfile ) -{ - dpackheader_t header; - int i, numpackfiles; - int packhandle; - pack_t *pack; - dpackfile_t *info; - - packhandle = open( packfile, O_RDONLY|O_BINARY ); - if( packhandle < 0 ) return NULL; - read( packhandle, (void *)&header, sizeof( header )); - - if( header.ident != IDPACKV1HEADER ) - { - MsgDev( D_NOTE, "%s is not a packfile. Ignored.\n", packfile ); - close( packhandle ); - return NULL; - } - header.dirofs = LittleLong( header.dirofs ); - header.dirlen = LittleLong( header.dirlen ); - - if( header.dirlen % sizeof( dpackfile_t )) - { - MsgDev( D_ERROR, "%s has an invalid directory size. Ignored.\n", packfile ); - close( packhandle ); - return NULL; - } - - numpackfiles = header.dirlen / sizeof( dpackfile_t ); - - if( numpackfiles > MAX_FILES_IN_PACK ) - { - MsgDev( D_ERROR, "%s has too many files ( %i ). Ignored.\n", packfile, numpackfiles ); - close( packhandle ); - return NULL; - } - - info = (dpackfile_t *)Mem_Alloc( fs_mempool, sizeof( *info ) * numpackfiles ); - lseek( packhandle, header.dirofs, SEEK_SET ); - - if( header.dirlen != read( packhandle, (void *)info, header.dirlen )) - { - MsgDev( D_NOTE, "%s is an incomplete PAK, not loading\n", packfile ); - Mem_Free( info ); - close( packhandle ); - return NULL; - } - - pack = (pack_t *)Mem_Alloc( fs_mempool, sizeof( pack_t )); - com.strncpy( pack->filename, packfile, sizeof( pack->filename )); - pack->handle = packhandle; - pack->numfiles = 0; - pack->files = (packfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( packfile_t )); - pack->filetime = FS_SysFileTime( packfile ); - - // parse the directory - for( i = 0; i < numpackfiles; i++ ) - { - fs_offset_t offset = LittleLong( info[i].filepos ); - fs_offset_t size = LittleLong( info[i].filelen ); - FS_AddFileToPack( info[i].name, pack, offset, size, size, PACKFILE_FLAG_TRUEOFFS ); - } - - Mem_Free( info ); - MsgDev( D_NOTE, "Adding packfile: %s (%i files)\n", packfile, numpackfiles ); - return pack; -} - -/* -================= -FS_LoadPackPK2 - -Takes an explicit (not game tree related) path to a pak file. - -Loads the header and directory, adding the files at the beginning -of the list so they override previous pack files. -================= -*/ -pack_t *FS_LoadPackPK2(const char *packfile) -{ - dpackheader_t header; - int i, numpackfiles; - int packhandle; - pack_t *pack; - dpak2file_t *info; - - packhandle = open (packfile, O_RDONLY | O_BINARY); - if (packhandle < 0) return NULL; - read (packhandle, (void *)&header, sizeof(header)); - if(header.ident != IDPACKV2HEADER) - { - Msg("%s is not a packfile\n", packfile); - close(packhandle); - return NULL; - } - header.dirofs = LittleLong (header.dirofs); - header.dirlen = LittleLong (header.dirlen); - - if (header.dirlen % sizeof(dpak2file_t)) - { - Msg("%s has an invalid directory size\n", packfile); - close(packhandle); - return NULL; - } - - numpackfiles = header.dirlen / sizeof(dpak2file_t); - - if (numpackfiles > MAX_FILES_IN_PACK) - { - Msg("%s has %i files\n", packfile, numpackfiles); - close(packhandle); - return NULL; - } - - info = (dpak2file_t *)Mem_Alloc( fs_mempool, sizeof(*info) * numpackfiles); - lseek (packhandle, header.dirofs, SEEK_SET); - if(header.dirlen != read(packhandle, (void *)info, header.dirlen)) - { - Msg("%s is an incomplete PAK, not loading\n", packfile); - Mem_Free(info); - close(packhandle); - return NULL; - } - - pack = (pack_t *)Mem_Alloc(fs_mempool, sizeof( pack_t )); - com.strncpy( pack->filename, packfile, sizeof( pack->filename )); - pack->handle = packhandle; - pack->numfiles = 0; - pack->files = (packfile_t *)Mem_Alloc( fs_mempool, numpackfiles * sizeof( packfile_t )); - - // parse the directory - for( i = 0; i < numpackfiles; i++ ) - { - fs_offset_t offset = LittleLong( info[i].filepos ); - fs_offset_t size = LittleLong( info[i].filelen ); - FS_AddFileToPack( info[i].name, pack, offset, size, size, PACKFILE_FLAG_TRUEOFFS ); - } - - Mem_Free( info ); - MsgDev( D_NOTE, "Adding packfile %s (%i files)\n", packfile, numpackfiles ); - return pack; -} - -/* -================ -FS_AddPack_Fullpath - -Adds the given pack to the search path. -The pack type is autodetected by the file extension. - -Returns true if the file was successfully added to the -search path or if it was already included. - -If keep_plain_dirs is set, the pack will be added AFTER the first sequence of -plain directories. -================ -*/ -static qboolean FS_AddPack_Fullpath( const char *pakfile, qboolean *already_loaded, qboolean keep_plain_dirs, int flags ) -{ - searchpath_t *search; - pack_t *pak = NULL; - const char *ext = FS_FileExtension( pakfile ); - - for( search = fs_searchpaths; search; search = search->next ) - { - if( search->pack && !com.stricmp( search->pack->filename, pakfile )) - { - if( already_loaded ) *already_loaded = true; - return true; // already loaded - } - } - - if( already_loaded ) *already_loaded = false; - - if( !com.stricmp( ext, "pak" )) pak = FS_LoadPackPAK( pakfile ); - else if( !com.stricmp( ext, "pk2" )) pak = FS_LoadPackPK3( pakfile ); - else if( !com.stricmp( ext, "pk3" )) pak = FS_LoadPackPK3( pakfile ); - else MsgDev( D_ERROR, "\"%s\" does not have a pack extension\n", pakfile ); - - if( pak ) - { - if( keep_plain_dirs ) - { - // find the first item whose next one is a pack or NULL - searchpath_t *insertion_point = 0; - if( fs_searchpaths && !fs_searchpaths->pack ) - { - insertion_point = fs_searchpaths; - while( 1 ) - { - if( !insertion_point->next ) break; - if( insertion_point->next->pack ) break; - insertion_point = insertion_point->next; - } - } - - // if insertion_point is NULL, this means that either there is no - // item in the list yet, or that the very first item is a pack. In - // that case, we want to insert at the beginning... - if( !insertion_point ) - { - search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); - search->pack = pak; - search->next = fs_searchpaths; - search->flags |= flags; - fs_searchpaths = search; - } - else // otherwise we want to append directly after insertion_point. - { - search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); - search->pack = pak; - search->next = insertion_point->next; - search->flags |= flags; - insertion_point->next = search; - } - } - else - { - search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); - search->pack = pak; - search->next = fs_searchpaths; - search->flags |= flags; - fs_searchpaths = search; - } - return true; - } - else - { - MsgDev( D_ERROR, "FS_AddPack_Fullpath: unable to load pak \"%s\"\n", pakfile ); - return false; - } -} - -/* -==================== -FS_AddWad_Fullpath -==================== -*/ -static qboolean FS_AddWad_Fullpath( const char *wadfile, qboolean *already_loaded, qboolean keep_plain_dirs ) -{ - searchpath_t *search; - wfile_t *wad = NULL; - const char *ext = FS_FileExtension( wadfile ); - - for( search = fs_searchpaths; search; search = search->next ) - { - if( search->wad && !com.stricmp( search->wad->filename, wadfile )) - { - if( already_loaded ) *already_loaded = true; - return true; // already loaded - } - } - - if( already_loaded ) *already_loaded = false; - if( !com.stricmp( ext, "wad" )) wad = W_Open( wadfile, "rb" ); - else MsgDev( D_ERROR, "\"%s\" doesn't have a wad extension\n", wadfile ); - - if( wad ) - { - if( keep_plain_dirs ) - { - // find the first item whose next one is a wad or NULL - searchpath_t *insertion_point = NULL; - if( fs_searchpaths && !fs_searchpaths->wad ) - { - insertion_point = fs_searchpaths; - while( 1 ) - { - if( !insertion_point->next ) break; - if( insertion_point->next->wad ) break; - insertion_point = insertion_point->next; - } - } - // if insertion_point is NULL, this means that either there is no - // item in the list yet, or that the very first item is a wad. In - // that case, we want to insert at the beginning... - if( !insertion_point ) - { - search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); - search->wad = wad; - search->next = fs_searchpaths; - fs_searchpaths = search; - } - else // otherwise we want to append directly after insertion_point. - { - search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); - search->wad = wad; - search->next = insertion_point->next; - insertion_point->next = search; - } - } - else - { - search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); - search->wad = wad; - search->next = fs_searchpaths; - fs_searchpaths = search; - } - - MsgDev( D_NOTE, "Adding wadfile %s (%i files)\n", wadfile, wad->numlumps ); - return true; - } - else - { - MsgDev( D_ERROR, "FS_AddWad_Fullpath: unable to load wad \"%s\"\n", wadfile ); - return false; - } -} - -/* -================ -FS_AddGameDirectory - -Sets fs_gamedir, adds the directory to the head of the path, -then loads and adds pak1.pak pak2.pak ... -================ -*/ -void FS_AddGameDirectory( const char *dir, int flags ) -{ - stringlist_t list; - searchpath_t *search; - string pakfile; - search_t *wads; - int i; - - if(!( flags & FS_NOWRITE_PATH )) - com.strncpy( fs_gamedir, dir, sizeof( fs_gamedir )); - - stringlistinit( &list ); - listdirectory( &list, dir ); - stringlistsort( &list ); - - // add any PAK package in the directory - for( i = 0; i < list.numstrings; i++ ) - { - if( !com.stricmp( FS_FileExtension( list.strings[i] ), "pak" )) - { - com.sprintf( pakfile, "%s%s", dir, list.strings[i] ); - FS_AddPack_Fullpath( pakfile, NULL, false, flags ); - } - } - - // add any PK2 package in the directory - for( i = 0; i < list.numstrings; i++ ) - { - if( !com.stricmp( FS_FileExtension( list.strings[i]), "pk2" )) - { - com.sprintf( pakfile, "%s%s", dir, list.strings[i] ); - FS_AddPack_Fullpath( pakfile, NULL, false, flags ); - } - } - - // add any PK3 package in the directory - for( i = 0; i < list.numstrings; i++ ) - { - if( !com.stricmp( FS_FileExtension( list.strings[i] ), "pk3" )) - { - com.sprintf( pakfile, "%s%s", dir, list.strings[i] ); - FS_AddPack_Fullpath( pakfile, NULL, false, flags ); - } - } - - // add the directory to the search path - // (unpacked files have the priority over packed files) - search = (searchpath_t *)Mem_Alloc( fs_mempool, sizeof( searchpath_t )); - com.strncpy( search->filename, dir, sizeof ( search->filename )); - search->next = fs_searchpaths; - search->flags = flags; - fs_searchpaths = search; - - stringlistfreecontents( &list ); - - if( Sys.app_name == HOST_NORMAL || Sys.app_name == HOST_DEDICATED || Sys.app_name == HOST_BSPLIB ) - { - // because we want first add gamedir wads - if(!( flags & FS_GAMEDIR_PATH )) return; - } - - // use normal method because we want take access to wad files through pak or pk3 archives - wads = FS_Search( "*.wad", true, false ); - for( i = 0; wads && i < wads->numfilenames; i++ ) - FS_AddWad_Fullpath( wads->filenames[i], NULL, false ); - if( wads ) Mem_Free( wads ); -} - -/* -================ -FS_AddGameHierarchy -================ -*/ -void FS_AddGameHierarchy( const char *dir, int flags ) -{ - // Add the common game directory - if( dir && *dir ) FS_AddGameDirectory( va( "%s%s/", fs_basedir, dir ), flags ); -} - - -/* -============ -FS_FileExtension -============ -*/ -const char *FS_FileExtension( const char *in ) -{ - const char *separator, *backslash, *colon, *dot; - - separator = com.strrchr( in, '/' ); - backslash = com.strrchr( in, '\\' ); - if( !separator || separator < backslash ) separator = backslash; - colon = com.strrchr( in, ':' ); - if( !separator || separator < colon ) separator = colon; - - dot = com.strrchr( in, '.' ); - if( dot == NULL || (separator && (dot < separator))) - return ""; - return dot + 1; -} - - -/* -============ -FS_FileWithoutPath -============ -*/ -const char *FS_FileWithoutPath( const char *in ) -{ - const char *separator, *backslash, *colon; - - separator = com.strrchr( in, '/' ); - backslash = com.strrchr( in, '\\' ); - if( !separator || separator < backslash ) separator = backslash; - colon = com.strrchr( in, ':' ); - if( !separator || separator < colon ) separator = colon; - return separator ? separator + 1 : in; -} - -/* -============ -FS_ExtractFilePath -============ -*/ -void FS_ExtractFilePath( const char* const path, char* dest ) -{ - const char *src; - src = path + com.strlen( path ) - 1; - - // back up until a \ or the start - while( src != path && !(*(src - 1) == '\\' || *(src - 1) == '/' )) - src--; - - if( src != path ) - { - Mem_Copy( dest, path, src - path ); - dest[src - path - 1] = 0; // cutoff backslash - } - else com.strcpy( dest, "" ); // file without path -} - -/* -================ -FS_ClearSearchPath -================ -*/ -void FS_ClearSearchPath( void ) -{ - while( fs_searchpaths ) - { - searchpath_t *search = fs_searchpaths; - - if( search->flags & FS_STATIC_PATH ) - { - // skip read-only pathes e.g. "bin" - if( search->next ) - fs_searchpaths = search->next->next; - else break; - } - else fs_searchpaths = search->next; - - if( search->pack ) - { - if( search->pack->files ) - Mem_Free( search->pack->files ); - Mem_Free( search->pack ); - } - if( search->wad ) - { - W_Close( search->wad ); - } - Mem_Free( search ); - } -} - -/* -==================== -FS_CheckNastyPath - -Return true if the path should be rejected due to one of the following: -1: path elements that are non-portable -2: path elements that would allow access to files outside the game directory, - or are just not a good idea for a mod to be using. -==================== -*/ -int FS_CheckNastyPath( const char *path, qboolean isgamedir ) -{ - // all: never allow an empty path, as for gamedir it would access the parent directory and a non-gamedir path it is just useless - if( !path[0] ) return 2; - - // Mac: don't allow Mac-only filenames - : is a directory separator - // instead of /, but we rely on / working already, so there's no reason to - // support a Mac-only path - // Amiga and Windows: : tries to go to root of drive - if( com.strstr( path, ":" ) && !fs_ext_path ) return 1; // non-portable attempt to go to root of drive - - // Amiga: // is parent directory - if( com.strstr( path, "//" ) && !fs_ext_path ) return 1; // non-portable attempt to go to parent directory - - // all: don't allow going to parent directory (../ or /../) - if( com.strstr( path, ".." ) && !fs_ext_path ) return 2; // attempt to go outside the game directory - - // Windows and UNIXes: don't allow absolute paths - if( path[0] == '/' && !fs_ext_path ) return 2; // attempt to go outside the game directory - - // all: don't allow . characters before the last slash (it should only be used in filenames, not path elements), - // this catches all imaginable cases of ./, ../, .../, etc - if( com.strchr( path, '.' ) && !fs_ext_path ) - { - if( isgamedir ) return 2; // gamedir is entirely path elements, so simply forbid . entirely - if( com.strchr( path, '.' ) < com.strrchr( path, '/' )) return 2; // possible attempt to go outside the game directory - } - - // all: forbid trailing slash on gamedir - if( isgamedir && !fs_ext_path && path[com.strlen( path )-1] == '/' ) return 2; - - // all: forbid leading dot on any filename for any reason - if( com.strstr( path, "/." ) && !fs_ext_path ) return 2; // attempt to go outside the game directory - - // after all these checks we're pretty sure it's a / separated filename - // and won't do much if any harm - return false; -} - -/* -================ -FS_Rescan -================ -*/ -void FS_Rescan( void ) -{ - MsgDev( D_NOTE, "FS_Rescan( %s )\n", SI.GameInfo->title ); - FS_ClearSearchPath(); - - FS_AddGameHierarchy( SI.GameInfo->basedir, 0 ); - FS_AddGameHierarchy( SI.GameInfo->gamedir, FS_GAMEDIR_PATH ); -} - -void FS_Rescan_f( void ) -{ - FS_Rescan(); -} - -void FS_UpdateSysInfo( void ) -{ - com.strcpy( SI.username, Sys_GetCurrentUser()); - SI.developer = Sys.developer; - SI.version = XASH_VERSION; -} - -static qboolean FS_ParseVector( script_t *script, float *v, size_t size ) -{ - uint i; - token_t token; - qboolean bracket = false; - - if( v == NULL || size == 0 ) - return false; - - Mem_Set( v, 0, sizeof( *v ) * size ); - - if( size == 1 ) - return PS_GetFloat( script, 0, v ); - - if( !PS_ReadToken( script, false, &token )) - return false; - if( token.type == TT_PUNCTUATION && !com.stricmp( token.string, "(" )) - bracket = true; - else PS_SaveToken( script, &token ); // save token to right get it again - - for( i = 0; i < size; i++ ) - { - if( !PS_GetFloat( script, false, &v[i] )) - v[i] = 0; // because Com_ReadFloat may return 0 if parsing expression it's not a number - } - - if( !bracket ) return true; // done - - if( !PS_ReadToken( script, false, &token )) - return false; - - if( token.type == TT_PUNCTUATION && !com.stricmp( token.string, ")" )) - return true; - return false; -} - -/* -================ -FS_WriteGameInfo - -assume GameInfo is valid -================ -*/ -static qboolean FS_WriteGameInfo( const char *filepath, gameinfo_t *GameInfo ) -{ - file_t *f; - int i; - - if( !GameInfo ) return false; - f = FS_Open( filepath, "w", false ); // we in binary-mode - if( !f ) return false; - - FS_Print( f, "// generated by Xash3D\r\r\n" ); - - if( com.strlen( GameInfo->basedir )) - FS_Printf( f, "basedir\t\t\"%s\"\n", GameInfo->basedir ); - - if( com.strlen( GameInfo->gamedir )) - FS_Printf( f, "gamedir\t\t\"%s\"\n", GameInfo->gamedir ); - - if( com.strlen( GameInfo->title )) - FS_Printf( f, "title\t\t\"%s\"\n", GameInfo->title ); - - if( com.strlen( GameInfo->startmap )) - FS_Printf( f, "startmap\t\t\"%s\"\n", GameInfo->startmap ); - - if( com.strlen( GameInfo->trainmap )) - FS_Printf( f, "trainmap\t\t\"%s\"\n", GameInfo->trainmap ); - - if( com.strlen( GameInfo->gameHint )) - FS_Printf( f, "gameHint\t\t\"%s\"\n", GameInfo->gameHint ); - - if( GameInfo->version != 0.0f ) - FS_Printf( f, "version\t\t%g\n", GameInfo->version ); - - if( GameInfo->size != 0 ) - FS_Printf( f, "size\t\t%i\n", GameInfo->size ); - - if( com.strlen( GameInfo->game_url )) - FS_Printf( f, "url_info\t\t\"%s\"\n", GameInfo->game_url ); - - if( com.strlen( GameInfo->update_url )) - FS_Printf( f, "url_update\t\t\"%s\"\n", GameInfo->update_url ); - - if( com.strlen( GameInfo->type )) - FS_Printf( f, "type\t\t\"%s\"\n", GameInfo->type ); - - if( com.strlen( GameInfo->date )) - FS_Printf( f, "date\t\t\"%s\"\n", GameInfo->date ); - - if( com.strlen( GameInfo->dll_path )) - FS_Printf( f, "dllpath\t\t\"%s\"\n", GameInfo->dll_path ); - if( com.strlen( GameInfo->game_dll )) - FS_Printf( f, "gamedll\t\t\"%s\"\n", GameInfo->game_dll ); - - switch( GameInfo->gamemode ) - { - case 1: FS_Print( f, "gamemode\t\t\"singleplayer_only\"\n" ); break; - case 2: FS_Print( f, "gamemode\t\t\"multiplayer_only\"\n" ); break; - } - - if( com.strlen( GameInfo->sp_entity )) - FS_Printf( f, "sp_entity\t\t\"%s\"\n", GameInfo->sp_entity ); - if( com.strlen( GameInfo->mp_entity )) - FS_Printf( f, "mp_entity\t\t\"%s\"\n", GameInfo->mp_entity ); - - for( i = 0; i < 4; i++ ) - { - float *min, *max; - - if( i && ( VectorIsNull( GameInfo->client_mins[i] ) || VectorIsNull( GameInfo->client_maxs[i] ))) - continue; - - min = GameInfo->client_mins[i]; - max = GameInfo->client_maxs[i]; - FS_Printf( f, "hull%i\t\t( %g %g %g ) ( %g %g %g )\n", i, min[0], min[1], min[2], max[0], max[1], max[2] ); - } - - if( GameInfo->max_edicts > 0 ) - FS_Printf( f, "max_edicts\t%i\n", GameInfo->max_edicts ); - if( GameInfo->max_tents > 0 ) - FS_Printf( f, "max_tempents\t%i\n", GameInfo->max_tents ); - if( GameInfo->max_beams > 0 ) - FS_Printf( f, "max_beams\t%i\n", GameInfo->max_beams ); - if( GameInfo->max_particles > 0 ) - FS_Printf( f, "max_particles\t%i\n", GameInfo->max_particles ); - - FS_Print( f, "\r\r\n" ); - FS_Close( f ); // all done - - return true; -} - -/* -================ -FS_CreateDefaultGameInfo -================ -*/ -void FS_CreateDefaultGameInfo( const char *filename ) -{ - gameinfo_t defGI; - - Mem_Set( &defGI, 0, sizeof( defGI )); - - // setup default values - defGI.max_edicts = 900; // default value if not specified - defGI.max_tents = 500; - defGI.max_tents = 64; - defGI.max_particles = 2048; - defGI.version = 1.0; - - com.strncpy( defGI.gameHint, "Half-Life", sizeof( defGI.gameHint )); - com.strncpy( defGI.title, "New Game", sizeof( defGI.title )); - com.strncpy( defGI.gamedir, gs_basedir, sizeof( defGI.gamedir )); - com.strncpy( defGI.basedir, fs_defaultdir->string, sizeof( defGI.basedir )); - com.strncpy( defGI.sp_entity, "info_player_start", sizeof( defGI.sp_entity )); - com.strncpy( defGI.mp_entity, "info_player_deathmatch", sizeof( defGI.mp_entity )); - com.strncpy( defGI.dll_path, "bin", sizeof( defGI.dll_path )); - com.strncpy( defGI.game_dll, "bin/server.dll", sizeof( defGI.game_dll )); - com.strncpy( defGI.startmap, "newmap", sizeof( defGI.startmap )); - - VectorSet( defGI.client_mins[0], 0, 0, 0 ); - VectorSet( defGI.client_maxs[0], 0, 0, 0 ); - VectorSet( defGI.client_mins[1], -16, -16, -36 ); - VectorSet( defGI.client_maxs[1], 16, 16, 36 ); - VectorSet( defGI.client_mins[2], -32, -32, -32 ); - VectorSet( defGI.client_maxs[2], 32, 32, 32 ); - VectorSet( defGI.client_mins[3], -16, -16, -18 ); - VectorSet( defGI.client_maxs[3], 16, 16, 18 ); - - // make simple gameinfo.txt - FS_WriteGameInfo( filename, &defGI ); -} - -static qboolean FS_ParseLiblistGam( const char *filename, const char *gamedir, gameinfo_t *GameInfo ) -{ - script_t *script = NULL; - token_t token; - - if( !GameInfo ) return false; - script = PS_LoadScript( filename, NULL, 0 ); - if( !script ) return false; - - // setup default values - GameInfo->max_edicts = 900; // default value if not specified - GameInfo->max_tents = 500; - GameInfo->max_tents = 64; - GameInfo->max_particles = 2048; - GameInfo->version = 1.0f; - - com.strncpy( GameInfo->gameHint, "Half-Life", sizeof( GameInfo->gameHint )); - com.strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title )); - com.strncpy( GameInfo->gamedir, gamedir, sizeof( GameInfo->gamedir )); - com.strncpy( GameInfo->basedir, "valve", sizeof( GameInfo->basedir )); // all liblist.gam have 'valve' as basedir - com.strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity )); - com.strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity )); - com.strncpy( GameInfo->game_dll, "dlls/hl.dll", sizeof( GameInfo->game_dll )); - com.strncpy( GameInfo->startmap, "newmap", sizeof( GameInfo->startmap )); - - // FIXME: replace with "cl_dlls" when support for client.dll will be it's finished - com.strncpy( GameInfo->dll_path, "bin", sizeof( GameInfo->dll_path )); - - VectorSet( GameInfo->client_mins[0], 0, 0, 0 ); - VectorSet( GameInfo->client_maxs[0], 0, 0, 0 ); - VectorSet( GameInfo->client_mins[1], -16, -16, -36 ); - VectorSet( GameInfo->client_maxs[1], 16, 16, 36 ); - VectorSet( GameInfo->client_mins[2], -32, -32, -32 ); - VectorSet( GameInfo->client_maxs[2], 32, 32, 32 ); - VectorSet( GameInfo->client_mins[3], -16, -16, -18 ); - VectorSet( GameInfo->client_maxs[3], 16, 16, 18 ); - - while( script ) - { - if( !PS_ReadToken( script, SC_ALLOW_NEWLINES, &token )) - break; - - if( !com.stricmp( token.string, "game" )) - { - PS_GetString( script, false, GameInfo->title, sizeof( GameInfo->title )); - } - if( !com.stricmp( token.string, "gamedir" )) - { - PS_GetString( script, false, GameInfo->gamedir, sizeof( GameInfo->gamedir )); - } - else if( !com.stricmp( token.string, "startmap" )) - { - PS_GetString( script, false, GameInfo->startmap, sizeof( GameInfo->startmap )); - FS_StripExtension( GameInfo->startmap ); // HQ2:Amen has extension .bsp - } - else if( !com.stricmp( token.string, "trainmap" )) - { - PS_GetString( script, false, GameInfo->trainmap, sizeof( GameInfo->trainmap )); - FS_StripExtension( GameInfo->trainmap ); // HQ2:Amen has extension .bsp - } - else if( !com.stricmp( token.string, "url_info" )) - { - PS_GetString( script, false, GameInfo->game_url, sizeof( GameInfo->game_url )); - } - else if( !com.stricmp( token.string, "url_dl" )) - { - PS_GetString( script, false, GameInfo->update_url, sizeof( GameInfo->update_url )); - } - else if( !com.stricmp( token.string, "gamedll" )) - { - PS_GetString( script, false, GameInfo->game_dll, sizeof( GameInfo->game_dll )); - } - else if( !com.stricmp( token.string, "type" )) - { - PS_ReadToken( script, 0, &token ); - - if( !com.stricmp( token.string, "singleplayer_only" )) - { - GameInfo->gamemode = 1; - com.strncpy( GameInfo->type, "Single", sizeof( GameInfo->type )); - } - else if( !com.stricmp( token.string, "multiplayer_only" )) - { - GameInfo->gamemode = 2; - com.strncpy( GameInfo->type, "Multiplayer", sizeof( GameInfo->type )); - } - else - { - // pass type without changes - GameInfo->gamemode = 0; - com.strncpy( GameInfo->type, token.string, sizeof( GameInfo->type )); - } - } - else if( !com.stricmp( token.string, "version" )) - { - PS_ReadToken( script, false, &token ); - GameInfo->version = com.atof( token.string ); - } - else if( !com.stricmp( token.string, "size" )) - { - PS_ReadToken( script, false, &token ); - GameInfo->size = com.atoi( token.string ); - } - else if( !com.stricmp( token.string, "mpentity" )) - { - PS_GetString( script, false, GameInfo->mp_entity, sizeof( GameInfo->mp_entity )); - } - } - - PS_FreeScript( script ); - return true; -} - -/* -================ -FS_ConvertGameInfo -================ -*/ -void FS_ConvertGameInfo( const char *gamedir, const char *gameinfo_path, const char *liblist_path ) -{ - gameinfo_t GameInfo; - - Mem_Set( &GameInfo, 0, sizeof( GameInfo )); - - if( FS_ParseLiblistGam( liblist_path, gamedir, &GameInfo )) - { - if( FS_WriteGameInfo( gameinfo_path, &GameInfo )) - MsgDev( D_INFO, "Convert %s to %s\n", liblist_path, gameinfo_path ); - } -} - -/* -================ -FS_ParseGameInfo -================ -*/ -static qboolean FS_ParseGameInfo( const char *gamedir, gameinfo_t *GameInfo ) -{ - script_t *script = NULL; - string fs_path, filepath; - string liblist; - token_t token; - - com.snprintf( filepath, sizeof( filepath ), "%s/gameinfo.txt", gamedir ); - com.snprintf( liblist, sizeof( liblist ), "%s/liblist.gam", gamedir ); - - if( !FS_FileExists( filepath, false ) && FS_FileExists( liblist, false )) - FS_ConvertGameInfo( gamedir, filepath, liblist ); - - // force to create gameinfo for specified game if missing - if( !com.stricmp( gs_basedir, gamedir ) && !FS_FileExists( filepath, false )) - FS_CreateDefaultGameInfo( filepath ); - - if( !GameInfo ) return false; // no dest - - script = PS_LoadScript( filepath, NULL, 0 ); - if( !script ) return false; - - // setup default values - com.strncpy( GameInfo->gamefolder, gamedir, sizeof( GameInfo->gamefolder )); - GameInfo->max_edicts = 900; // default value if not specified - GameInfo->max_tents = 500; - GameInfo->max_tents = 64; - GameInfo->max_particles = 2048; - GameInfo->version = 1.0f; - - com.strncpy( GameInfo->gameHint, "Half-Life", sizeof( GameInfo->gameHint )); - com.strncpy( GameInfo->title, "New Game", sizeof( GameInfo->title )); - com.strncpy( GameInfo->sp_entity, "info_player_start", sizeof( GameInfo->sp_entity )); - com.strncpy( GameInfo->mp_entity, "info_player_deathmatch", sizeof( GameInfo->mp_entity )); - com.strncpy( GameInfo->dll_path, "bin", sizeof( GameInfo->dll_path )); - com.strncpy( GameInfo->game_dll, "bin/server.dll", sizeof( GameInfo->game_dll )); - com.strncpy( GameInfo->startmap, "", sizeof( GameInfo->startmap )); - - VectorSet( GameInfo->client_mins[0], 0, 0, 0 ); - VectorSet( GameInfo->client_maxs[0], 0, 0, 0 ); - VectorSet( GameInfo->client_mins[1], -16, -16, -36 ); - VectorSet( GameInfo->client_maxs[1], 16, 16, 36 ); - VectorSet( GameInfo->client_mins[2], -32, -32, -32 ); - VectorSet( GameInfo->client_maxs[2], 32, 32, 32 ); - VectorSet( GameInfo->client_mins[3], -16, -16, -18 ); - VectorSet( GameInfo->client_maxs[3], 16, 16, 18 ); - - while( script ) - { - if( !PS_ReadToken( script, SC_ALLOW_NEWLINES, &token )) - break; - - if( !com.stricmp( token.string, "basedir" )) - { - PS_GetString( script, false, fs_path, sizeof( fs_path )); - if( com.stricmp( fs_path, GameInfo->basedir ) || com.stricmp( fs_path, GameInfo->gamedir )) - com.strncpy( GameInfo->basedir, fs_path, sizeof( GameInfo->basedir )); - } - else if( !com.stricmp( token.string, "gamedir" )) - { - PS_GetString( script, false, fs_path, sizeof( fs_path )); - if( com.stricmp( fs_path, GameInfo->basedir ) || com.stricmp( fs_path, GameInfo->gamedir )) - com.strncpy( GameInfo->gamedir, fs_path, sizeof( GameInfo->gamedir )); - } - else if( !com.stricmp( token.string, "title" )) - { - PS_GetString( script, false, GameInfo->title, sizeof( GameInfo->title )); - } - else if( !com.stricmp( token.string, "gameHint" )) - { - PS_GetString( script, false, GameInfo->gameHint, sizeof( GameInfo->gameHint )); - } - else if( !com.stricmp( token.string, "sp_entity" )) - { - PS_GetString( script, false, GameInfo->sp_entity, sizeof( GameInfo->sp_entity )); - } - else if( !com.stricmp( token.string, "mp_entity" )) - { - PS_GetString( script, false, GameInfo->mp_entity, sizeof( GameInfo->mp_entity )); - } - else if( !com.stricmp( token.string, "gamedll" )) - { - PS_GetString( script, false, GameInfo->game_dll, sizeof( GameInfo->game_dll )); - } - else if( !com.stricmp( token.string, "dllpath" )) - { - PS_GetString( script, false, GameInfo->dll_path, sizeof( GameInfo->dll_path )); - } - else if( !com.stricmp( token.string, "startmap" )) - { - PS_GetString( script, false, GameInfo->startmap, sizeof( GameInfo->startmap )); - FS_StripExtension( GameInfo->startmap ); // HQ2:Amen has extension .bsp - } - else if( !com.stricmp( token.string, "trainmap" )) - { - PS_GetString( script, false, GameInfo->trainmap, sizeof( GameInfo->trainmap )); - FS_StripExtension( GameInfo->trainmap ); // HQ2:Amen has extension .bsp - } - else if( !com.stricmp( token.string, "url_info" )) - { - PS_GetString( script, false, GameInfo->game_url, sizeof( GameInfo->game_url )); - } - else if( !com.stricmp( token.string, "url_update" )) - { - PS_GetString( script, false, GameInfo->update_url, sizeof( GameInfo->update_url )); - } - else if( !com.stricmp( token.string, "textures_path" )) - { - PS_GetString( script, false, GameInfo->texpath, sizeof( GameInfo->texpath )); - } - else if( !com.stricmp( token.string, "date" )) - { - PS_GetString( script, false, GameInfo->date, sizeof( GameInfo->date )); - } - else if( !com.stricmp( token.string, "type" )) - { - PS_GetString( script, false, GameInfo->type, sizeof( GameInfo->type )); - } - else if( !com.stricmp( token.string, "version" )) - { - PS_GetFloat( script, false, &GameInfo->version ); - } - else if( !com.stricmp( token.string, "size" )) - { - PS_ReadToken( script, 0, &token ); - GameInfo->size = com.atoi( token.string ); - } - else if( !com.stricmp( token.string, "max_edicts" )) - { - PS_GetInteger( script, false, &GameInfo->max_edicts ); - GameInfo->max_edicts = bound( 600, GameInfo->max_edicts, 4096 ); - } - else if( !com.stricmp( token.string, "max_tempents" )) - { - PS_GetInteger( script, false, &GameInfo->max_tents ); - GameInfo->max_tents = bound( 300, GameInfo->max_tents, 2048 ); - } - else if( !com.stricmp( token.string, "max_beams" )) - { - PS_GetInteger( script, false, &GameInfo->max_beams ); - GameInfo->max_beams = bound( 64, GameInfo->max_beams, 512 ); - } - else if( !com.stricmp( token.string, "max_particles" )) - { - PS_GetInteger( script, false, &GameInfo->max_particles ); - GameInfo->max_particles = bound( 1024, GameInfo->max_particles, 8192 ); - } - else if( !com.stricmp( token.string, "gamemode" )) - { - PS_ReadToken( script, 0, &token ); - if( !com.stricmp( token.string, "singleplayer_only" )) - GameInfo->gamemode = 1; - else if( !com.stricmp( token.string, "multiplayer_only" )) - GameInfo->gamemode = 2; - } - else if( !com.strnicmp( token.string, "hull", 4 )) - { - int hullNum = com.atoi( token.string + 4 ); - - if( hullNum < 0 || hullNum > 3 ) - { - MsgDev( D_ERROR, "FS_ParseGameInfo: Invalid hull number %i. Ignored.\n", hullNum ); - PS_SkipRestOfLine( script ); - } - else - { - FS_ParseVector( script, GameInfo->client_mins[hullNum], 3 ); - FS_ParseVector( script, GameInfo->client_maxs[hullNum], 3 ); - } - } - } - - PS_FreeScript( script ); - return true; -} - -/* -================ -FS_LoadGameInfo - -can be passed null arg -================ -*/ -void FS_LoadGameInfo( const char *rootfolder ) -{ - int i; - - // lock uplevel of gamedir for read\write - fs_ext_path = false; - - if( rootfolder ) com.strcpy( gs_basedir, rootfolder ); - MsgDev( D_NOTE, "FS_LoadGameInfo( %s )\n", gs_basedir ); - - // clear any old pathes - FS_ClearSearchPath(); - - // validate gamedir - for( i = 0; i < SI.numgames; i++ ) - { - if( !com.stricmp( SI.games[i]->gamefolder, gs_basedir )) - break; - } - - if( i == SI.numgames ) - Sys_Break( "Couldn't find game directory '%s'\n", gs_basedir ); - - SI.GameInfo = SI.games[i]; - FS_Rescan(); // create new filesystem -} - -/* -================ -FS_Init -================ -*/ -void FS_Init( void ) -{ - stringlist_t dirs; - qboolean hasDefaultDir = false; - int i; - - FS_InitMemory(); - - FS_AddGameDirectory( "bin/", FS_STATIC_PATH ); // execute system config - - Cmd_AddCommand( "fs_rescan", FS_Rescan_f, "rescan filesystem search pathes" ); - Cmd_AddCommand( "fs_path", FS_Path_f, "show filesystem search pathes" ); - Cmd_AddCommand( "fs_clearpaths", FS_ClearPaths_f, "clear filesystem search pathes" ); - fs_defaultdir = Cvar_Get( "fs_defaultdir", "valve", CVAR_INIT, "game default directory" ); - - // ignore commandlineoption "-game" for other stuff - if( Sys.app_name == HOST_NORMAL || Sys.app_name == HOST_DEDICATED || Sys.app_name == HOST_BSPLIB ) - { - stringlistinit( &dirs ); - listdirectory( &dirs, "./" ); - stringlistsort( &dirs ); - SI.numgames = 0; - - if( !FS_GetParmFromCmdLine( "-game", gs_basedir, sizeof( gs_basedir ))) - { - if( Sys.app_name == HOST_BSPLIB ) - com.strcpy( gs_basedir, fs_defaultdir->string ); - else if( Sys_GetModuleName( gs_basedir, MAX_SYSPATH )); - else com.strcpy( gs_basedir, fs_defaultdir->string ); // default dir - } - - // checked nasty path: "bin" it's a reserved word - if( FS_CheckNastyPath( gs_basedir, true ) || !com.stricmp( "bin", gs_basedir )) - { - MsgDev( D_ERROR, "FS_Init: invalid game directory \"%s\"\n", gs_basedir ); - com.strcpy( gs_basedir, fs_defaultdir->string ); // default dir - } - - // validate directories - for( i = 0; i < dirs.numstrings; i++ ) - { - if( !com.stricmp( fs_defaultdir->string, dirs.strings[i] )) - hasDefaultDir = true; - - if( !com.stricmp( gs_basedir, dirs.strings[i] )) - break; - } - - if( i == dirs.numstrings ) - { - MsgDev( D_INFO, "FS_Init: game directory \"%s\" not exist\n", gs_basedir ); - if( hasDefaultDir ) com.strcpy( gs_basedir, fs_defaultdir->string ); // default dir - } - - // build list of game directories here - FS_AddGameDirectory( "./", 0 ); - for( i = 0; i < dirs.numstrings; i++ ) - { - const char *ext = FS_FileExtension( dirs.strings[i] ); - - if( com.stricmp( ext, "" ) || (!com.stricmp( dirs.strings[i], ".." ) && !fs_ext_path )) - continue; - - if( !SI.games[SI.numgames] ) - SI.games[SI.numgames] = (gameinfo_t *)Mem_Alloc( fs_mempool, sizeof( gameinfo_t )); - if( FS_ParseGameInfo( dirs.strings[i], SI.games[SI.numgames] )) - SI.numgames++; // added - } - stringlistfreecontents( &dirs ); - } - - // enable explicit wad support for some tools - switch( Sys.app_name ) - { - case HOST_WADLIB: - case HOST_RIPPER: - case HOST_XIMAGE: - fs_use_wads = true; - break; - default: - fs_use_wads = false; - break; - } - - FS_UpdateSysInfo(); - - MsgDev( D_NOTE, "FS_Root: %s\n", sys_rootdir ); - MsgDev( D_NOTE, "FS_Init: done\n" ); -} - -void FS_InitRootDir( char *path ) -{ - char szTemp[4096]; - - FS_InitMemory(); - - // just set cwd - GetModuleFileName( NULL, szTemp, MAX_SYSPATH ); - FS_ExtractFilePath( szTemp, szTemp ); - SetCurrentDirectory ( szTemp ); - - // use extended pathname - fs_ext_path = true; - - FS_ClearSearchPath(); - FS_AddGameHierarchy( path, FS_STATIC_PATH ); -} - -qboolean FS_GetParmFromCmdLine( char *parm, char *out, size_t size ) -{ - int argc = FS_CheckParm( parm ); - - if(!argc) return false; - if(!out) return false; - if(!fs_argv[argc + 1]) return false; - - com.strncpy( out, fs_argv[argc+1], size ); - return true; -} - -void FS_AllowDirectPaths( qboolean enable ) -{ - fs_ext_path = enable; -} - -/* -================ -FS_Shutdown -================ -*/ -void FS_Shutdown( void ) -{ - int i; - - // release gamedirs - for( i = 0; i < SI.numgames; i++ ) - if( SI.games[i] ) Mem_Free( SI.games[i] ); - - Mem_Set( &SI, 0, sizeof( SI )); - - FS_ClearSearchPath(); // release all wad files too - FS_UpdateEnvironmentVariables(); // merge working directory - Mem_FreePool( &fs_mempool ); -} - -/* -==================== -FS_SysFileTime - -Internal function used to determine filetime -==================== -*/ -static long FS_SysFileTime( const char *filename ) -{ - struct stat buf; - - if( stat( filename, &buf ) == -1 ) - return -1; - - return buf.st_mtime; -} - -/* -==================== -FS_SysOpen - -Internal function used to create a file_t and open the relevant non-packed file on disk -==================== -*/ -static file_t* FS_SysOpen( const char* filepath, const char* mode ) -{ - file_t *file; - int mod, opt; - uint ind; - - // Parse the mode string - switch( mode[0] ) - { - case 'r': - mod = O_RDONLY; - opt = 0; - break; - case 'w': - mod = O_WRONLY; - opt = O_CREAT | O_TRUNC; - break; - case 'a': - mod = O_WRONLY; - opt = O_CREAT | O_APPEND; - break; - default: - MsgDev( D_ERROR, "FS_SysOpen(%s, %s): invalid mode\n", filepath, mode ); - return NULL; - } - for( ind = 1; mode[ind] != '\0'; ind++ ) - { - switch( mode[ind] ) - { - case '+': - mod = O_RDWR; - break; - case 'b': - opt |= O_BINARY; - break; - default: - MsgDev( D_ERROR, "FS_SysOpen: %s: unknown char in mode (%c)\n", filepath, mode, mode[ind] ); - break; - } - } - - file = (file_t *)Mem_Alloc( fs_mempool, sizeof( *file )); - file->filetime = FS_SysFileTime( filepath ); - file->ungetc = EOF; - - file->handle = open( filepath, mod|opt, 0666 ); - if( file->handle < 0 ) - { - Mem_Free( file ); - return NULL; - } - file->real_length = lseek( file->handle, 0, SEEK_END ); - - // For files opened in append mode, we start at the end of the file - if( mod & O_APPEND ) file->position = file->real_length; - else lseek( file->handle, 0, SEEK_SET ); - - return file; -} - - -/* -=========== -FS_OpenPackedFile - -Open a packed file using its package file descriptor -=========== -*/ -file_t *FS_OpenPackedFile( pack_t *pack, int pack_ind ) -{ - packfile_t *pfile; - int dup_handle; - file_t *file; - - pfile = &pack->files[pack_ind]; - - // if we don't have the true offset, get it now - if( !( pfile->flags & PACKFILE_FLAG_TRUEOFFS )) - if( !PK3_GetTrueFileOffset( pfile, pack )) - return NULL; - - if( lseek( pack->handle, pfile->offset, SEEK_SET ) == -1 ) - { - Msg( "FS_OpenPackedFile: can't lseek to %s in %s (offset: %d)\n", pfile->name, pack->filename, pfile->offset ); - return NULL; - } - - dup_handle = dup( pack->handle ); - - if( dup_handle < 0 ) - { - Msg( "FS_OpenPackedFile: can't dup package's handle (pack: %s)\n", pack->filename ); - return NULL; - } - - file = (file_t *)Mem_Alloc( fs_mempool, sizeof( *file )); - Mem_Set( file, 0, sizeof( *file )); - file->handle = dup_handle; - file->flags = FILE_FLAG_PACKED; - file->real_length = pfile->realsize; - file->offset = pfile->offset; - file->position = 0; - file->ungetc = EOF; - - if( pfile->flags & PACKFILE_FLAG_DEFLATED ) - { - ztoolkit_t *ztk; - - file->flags |= FILE_FLAG_DEFLATED; - - // We need some more variables - ztk = (ztoolkit_t *)Mem_Alloc( fs_mempool, sizeof( *ztk )); - ztk->comp_length = pfile->packsize; - - // Initialize zlib stream - ztk->zstream.next_in = ztk->input; - ztk->zstream.avail_in = 0; - - if( inflateInit2( &ztk->zstream, -MAX_WBITS ) != Z_OK ) - { - Msg( "FS_OpenPackedFile: inflate init error (file: %s)\n", pfile->name ); - close( dup_handle ); - Mem_Free( file ); - return NULL; - } - - ztk->zstream.next_out = file->buff; - ztk->zstream.avail_out = sizeof( file->buff ); - file->ztk = ztk; - } - return file; -} - -/* -================== -FS_SysFileExists - -Look for a file in the filesystem only -================== -*/ -qboolean FS_SysFileExists( const char *path ) -{ - int desc; - - desc = open( path, O_RDONLY|O_BINARY ); - - if( desc < 0 ) return false; - close( desc ); - return true; -} - -/* -==================== -FS_FindFile - -Look for a file in the packages and in the filesystem - -Return the searchpath where the file was found (or NULL) -and the file index in the package if relevant -==================== -*/ -static searchpath_t *FS_FindFile( const char *name, int* index, qboolean gamedironly ) -{ - searchpath_t *search; - char *pEnvPath; - pack_t *pak; - - // search through the path, one element at a time - for( search = fs_searchpaths; search; search = search->next ) - { - if( gamedironly & !( search->flags & FS_GAMEDIR_PATH )) - continue; - - // is the element a pak file? - if( search->pack ) - { - int left, right, middle; - - pak = search->pack; - - // look for the file (binary search) - left = 0; - right = pak->numfiles - 1; - while( left <= right ) - { - int diff; - - middle = (left + right) / 2; - diff = com.stricmp( pak->files[middle].name, name ); - - // Found it - if( !diff ) - { - if( index ) *index = middle; - return search; - } - - // if we're too far in the list - if( diff > 0 ) - right = middle - 1; - else left = middle + 1; - } - } - else if( search->wad ) - { - dlumpinfo_t *lump; - char type = W_TypeFromExt( name ); - qboolean anywadname = true; - string wadname, wadfolder; - string shortname; - - // quick reject by filetype - if( type == TYP_NONE ) continue; - FS_ExtractFilePath( name, wadname ); - wadfolder[0] = '\0'; - - if( com.strlen( wadname )) - { - FS_FileBase( wadname, wadname ); - com.strncpy( wadfolder, wadname, sizeof( wadfolder )); - FS_DefaultExtension( wadname, ".wad" ); - anywadname = false; - } - - // quick reject by wadname - if( !anywadname && com.stricmp( wadname, search->wad->filename )) - continue; - - // NOTE: we can't using long names for wad, - // because we using original wad names[16]; - W_FileBase( name, shortname ); - - // can't using binary search: wad lumps never sorting by alphabetical - lump = W_FindLump( search->wad, shortname, type ); - if( lump ) - { - if( index ) *index = lump - search->wad->lumps; - return search; - } - } - else - { - char netpath[MAX_SYSPATH]; - com.sprintf( netpath, "%s%s", search->filename, name ); - if( FS_SysFileExists( netpath )) - { - if( index != NULL ) *index = -1; - return search; - } - } - } - - if( fs_ext_path && ( pEnvPath = getenv( "Path" ))) - { - char netpath[MAX_SYSPATH]; - - // clear searchpath - search = &fs_directpath; - Mem_Set( search, 0, sizeof( searchpath_t )); - - // search for environment path - while( pEnvPath ) - { - char *end = com.strchr( pEnvPath, ';' ); - if( !end ) break; - com.strncpy( search->filename, pEnvPath, (end - pEnvPath) + 1 ); - com.strcat( search->filename, "\\" ); - com.snprintf( netpath, MAX_SYSPATH, "%s%s", search->filename, name ); - if( FS_SysFileExists( netpath )) - { - if( index != NULL ) *index = -1; - return search; - } - pEnvPath += (end - pEnvPath) + 1; // move pointer - } - } - - if( index != NULL ) *index = -1; - - return NULL; -} - - -/* -=========== -FS_OpenReadFile - -Look for a file in the search paths and open it in read-only mode -=========== -*/ -file_t *FS_OpenReadFile( const char *filename, const char *mode, qboolean gamedironly ) -{ - searchpath_t *search; - int pack_ind; - - search = FS_FindFile( filename, &pack_ind, gamedironly ); - - // not found? - if( search == NULL ) - return NULL; - - if( search->pack ) - return FS_OpenPackedFile( search->pack, pack_ind ); - else if( search->wad ) - return NULL; // let W_LoadFile get lump correctly - else if( pack_ind < 0 ) - { - // found in the filesystem? - char path [MAX_SYSPATH]; - com.sprintf( path, "%s%s", search->filename, filename ); - return FS_SysOpen( path, mode ); - } - return NULL; -} - -/* -============================================================================= - -MAIN PUBLIC FUNCTIONS - -============================================================================= -*/ -/* -==================== -FS_Open - -Open a file. The syntax is the same as fopen -==================== -*/ -file_t *FS_Open( const char *filepath, const char *mode, qboolean gamedironly ) -{ - if( Sys.app_name == HOST_NORMAL || Sys.app_name == HOST_DEDICATED || Sys.app_name == HOST_BSPLIB ) - { - // some stupid mappers used leading '/' in path to models or sounds - if( filepath[0] == '/' ) filepath++; - } - - if( FS_CheckNastyPath( filepath, false )) - { - MsgDev( D_NOTE, "FS_Open: (\"%s\", \"%s\"): nasty filename rejected\n", filepath, mode ); - return NULL; - } - - // if the file is opened in "write", "append", or "read/write" mode - if( mode[0] == 'w' || mode[0] == 'a' || com.strchr( mode, '+' )) - { - char real_path[MAX_SYSPATH]; - - // open the file on disk directly - com.sprintf( real_path, "%s/%s", fs_gamedir, filepath ); - FS_CreatePath( real_path );// Create directories up to the file - return FS_SysOpen( real_path, mode ); - } - - // else, we look at the various search paths and open the file in read-only mode - return FS_OpenReadFile( filepath, mode, gamedironly ); -} - -/* -==================== -FS_Close - -Close a file -==================== -*/ -int FS_Close( file_t* file ) -{ - if( close( file->handle )) - return EOF; - - if( file->ztk ) - { - inflateEnd( &file->ztk->zstream ); - Mem_Free( file->ztk ); - } - Mem_Free( file ); - return 0; -} - - -/* -==================== -FS_Write - -Write "datasize" bytes into a file -==================== -*/ -fs_offset_t FS_Write( file_t* file, const void* data, size_t datasize ) -{ - fs_offset_t result; - - if( !file ) return 0; - - // if necessary, seek to the exact file position we're supposed to be - if( file->buff_ind != file->buff_len ) - lseek (file->handle, file->buff_ind - file->buff_len, SEEK_CUR); - - // Purge cached data - FS_Purge (file); - - // Write the buffer and update the position - result = write (file->handle, data, (fs_offset_t)datasize); - file->position = lseek (file->handle, 0, SEEK_CUR); - if (file->real_length < file->position) - file->real_length = file->position; - - if( result < 0 ) return 0; - return result; -} - - -/* -==================== -FS_Read - -Read up to "buffersize" bytes from a file -==================== -*/ -fs_offset_t FS_Read (file_t* file, void* buffer, size_t buffersize) -{ - fs_offset_t count, done; - - // nothing to copy - if (buffersize == 0) return 1; - - // Get rid of the ungetc character - if (file->ungetc != EOF) - { - ((char*)buffer)[0] = file->ungetc; - buffersize--; - file->ungetc = EOF; - done = 1; - } - else done = 0; - - // First, we copy as many bytes as we can from "buff" - if (file->buff_ind < file->buff_len) - { - count = file->buff_len - file->buff_ind; - - done += ((fs_offset_t)buffersize > count) ? count : (fs_offset_t)buffersize; - Mem_Copy (buffer, &file->buff[file->buff_ind], done); - file->buff_ind += done; - - buffersize -= done; - if (buffersize == 0) return done; - } - - // NOTE: at this point, the read buffer is always empty - - // If the file isn't compressed - if (! (file->flags & FILE_FLAG_DEFLATED)) - { - fs_offset_t nb; - - // We must take care to not read after the end of the file - count = file->real_length - file->position; - - // If we have a lot of data to get, put them directly into "buffer" - if (buffersize > sizeof (file->buff) / 2) - { - if (count > (fs_offset_t)buffersize) - count = (fs_offset_t)buffersize; - lseek (file->handle, file->offset + file->position, SEEK_SET); - nb = read (file->handle, &((unsigned char*)buffer)[done], count); - if (nb > 0) - { - done += nb; - file->position += nb; - // Purge cached data - FS_Purge (file); - } - } - else - { - if (count > (fs_offset_t)sizeof (file->buff)) - count = (fs_offset_t)sizeof (file->buff); - lseek (file->handle, file->offset + file->position, SEEK_SET); - nb = read (file->handle, file->buff, count); - if (nb > 0) - { - file->buff_len = nb; - file->position += nb; - - // Copy the requested data in "buffer" (as much as we can) - count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize; - Mem_Copy (&((unsigned char*)buffer)[done], file->buff, count); - file->buff_ind = count; - done += count; - } - } - - return done; - } - - // If the file is compressed, it's more complicated... - // We cycle through a few operations until we have read enough data - while (buffersize > 0) - { - ztoolkit_t *ztk = file->ztk; - int error; - - // NOTE: at this point, the read buffer is always empty - - // If "input" is also empty, we need to refill it - if (ztk->in_ind == ztk->in_len) - { - // If we are at the end of the file - if (file->position == file->real_length) - return done; - - count = (fs_offset_t)(ztk->comp_length - ztk->in_position); - if (count > (fs_offset_t)sizeof (ztk->input)) - count = (fs_offset_t)sizeof (ztk->input); - lseek (file->handle, file->offset + (fs_offset_t)ztk->in_position, SEEK_SET); - if (read (file->handle, ztk->input, count) != count) - { - Msg("FS_Read: unexpected end of file\n"); - break; - } - ztk->in_ind = 0; - ztk->in_len = count; - ztk->in_position += count; - } - - ztk->zstream.next_in = &ztk->input[ztk->in_ind]; - ztk->zstream.avail_in = (uint)(ztk->in_len - ztk->in_ind); - - // Now that we are sure we have compressed data available, we need to determine - // if it's better to inflate it in "file->buff" or directly in "buffer" - - // Inflate the data in "file->buff" - if (buffersize < sizeof (file->buff) / 2) - { - ztk->zstream.next_out = file->buff; - ztk->zstream.avail_out = sizeof (file->buff); - error = inflate (&ztk->zstream, Z_SYNC_FLUSH); - if (error != Z_OK && error != Z_STREAM_END) - { - Msg("FS_Read: Can't inflate file: %s\n", ztk->zstream.msg ); - break; - } - ztk->in_ind = ztk->in_len - ztk->zstream.avail_in; - - file->buff_len = (fs_offset_t)sizeof (file->buff) - ztk->zstream.avail_out; - file->position += file->buff_len; - - // Copy the requested data in "buffer" (as much as we can) - count = (fs_offset_t)buffersize > file->buff_len ? file->buff_len : (fs_offset_t)buffersize; - Mem_Copy (&((unsigned char*)buffer)[done], file->buff, count); - file->buff_ind = count; - } - else // Else, we inflate directly in "buffer" - { - ztk->zstream.next_out = &((unsigned char*)buffer)[done]; - ztk->zstream.avail_out = (unsigned int)buffersize; - error = inflate (&ztk->zstream, Z_SYNC_FLUSH); - if (error != Z_OK && error != Z_STREAM_END) - { - Msg("FS_Read: Can't inflate file: %s\n", ztk->zstream.msg); - break; - } - ztk->in_ind = ztk->in_len - ztk->zstream.avail_in; - - // How much data did it inflate? - count = (fs_offset_t)(buffersize - ztk->zstream.avail_out); - file->position += count; - - // Purge cached data - FS_Purge (file); - } - done += count; - buffersize -= count; - } - - return done; -} - - -/* -==================== -FS_Print - -Print a string into a file -==================== -*/ -int FS_Print( file_t* file, const char *msg ) -{ - return FS_Write( file, msg, com.strlen( msg )); -} - -/* -==================== -FS_Printf - -Print a string into a file -==================== -*/ -int FS_Printf(file_t* file, const char* format, ...) -{ - int result; - va_list args; - - va_start (args, format); - result = FS_VPrintf (file, format, args); - va_end (args); - - return result; -} - - -/* -==================== -FS_VPrintf - -Print a string into a file -==================== -*/ -int FS_VPrintf( file_t* file, const char* format, va_list ap ) -{ - int len; - fs_offset_t buff_size = MAX_SYSPATH; - char *tempbuff; - - if( !file ) return 0; - - while( 1 ) - { - tempbuff = (char *)Mem_Alloc( fs_mempool, buff_size ); - len = com.vsprintf( tempbuff, format, ap ); - if( len >= 0 && len < buff_size ) break; - Mem_Free( tempbuff ); - buff_size *= 2; - } - - len = write( file->handle, tempbuff, len ); - Mem_Free( tempbuff ); - - return len; -} - -/* -==================== -FS_Getc - -Get the next character of a file -==================== -*/ -int FS_Getc( file_t* file ) -{ - char c; - - if (FS_Read (file, &c, 1) != 1) - return EOF; - - return c; -} - - -/* -==================== -FS_UnGetc - -Put a character back into the read buffer (only supports one character!) -==================== -*/ -int FS_UnGetc( file_t* file, byte c ) -{ - // If there's already a character waiting to be read - if (file->ungetc != EOF) - return EOF; - - file->ungetc = c; - return c; -} - -int FS_Gets( file_t* file, byte *string, size_t bufsize ) -{ - int c, end = 0; - - while( 1 ) - { - c = FS_Getc( file ); - if( c == '\r' || c == '\n' || c < 0 ) - break; - if( end < bufsize - 1 ) - string[end++] = c; - } - string[end] = 0; - - // remove \n following \r - if( c == '\r' ) - { - c = FS_Getc( file ); - if( c != '\n' ) FS_UnGetc( file, (byte)c ); - } - - return c; -} - -/* -==================== -FS_Seek - -Move the position index in a file -==================== -*/ -int FS_Seek (file_t* file, fs_offset_t offset, int whence) -{ - ztoolkit_t *ztk; - unsigned char* buffer; - fs_offset_t buffersize; - - // Compute the file offset - switch (whence) - { - case SEEK_CUR: - offset += file->position - file->buff_len + file->buff_ind; - break; - case SEEK_SET: - break; - case SEEK_END: - offset += file->real_length; - break; - - default: - return -1; - } - - if (offset < 0 || offset > (long)file->real_length) return -1; - - // If we have the data in our read buffer, we don't need to actually seek - if (file->position - file->buff_len <= offset && offset <= file->position) - { - file->buff_ind = offset + file->buff_len - file->position; - return 0; - } - - // Purge cached data - FS_Purge (file); - - // Unpacked or uncompressed files can seek directly - if (! (file->flags & FILE_FLAG_DEFLATED)) - { - if (lseek (file->handle, file->offset + offset, SEEK_SET) == -1) - return -1; - file->position = offset; - return 0; - } - - // Seeking in compressed files is more a hack than anything else, - // but we need to support it, so here we go. - ztk = file->ztk; - - // If we have to go back in the file, we need to restart from the beginning - if (offset <= file->position) - { - ztk->in_ind = 0; - ztk->in_len = 0; - ztk->in_position = 0; - file->position = 0; - lseek (file->handle, file->offset, SEEK_SET); - - // Reset the Zlib stream - ztk->zstream.next_in = ztk->input; - ztk->zstream.avail_in = 0; - inflateReset (&ztk->zstream); - } - - // We need a big buffer to force inflating into it directly - buffersize = 2 * sizeof (file->buff); - buffer = (byte *)Mem_Alloc( fs_mempool, buffersize ); - - // Skip all data until we reach the requested offset - while (offset > file->position) - { - fs_offset_t diff = offset - file->position; - fs_offset_t count, len; - - count = (diff > buffersize) ? buffersize : diff; - len = FS_Read (file, buffer, count); - if (len != count) - { - Mem_Free (buffer); - return -1; - } - } - Mem_Free (buffer); - return 0; -} - - -/* -==================== -FS_Tell - -Give the current position in a file -==================== -*/ -fs_offset_t FS_Tell( file_t* file ) -{ - if( !file ) return 0; - return file->position - file->buff_len + file->buff_ind; -} - -/* -==================== -FS_Eof - -indicates at reached end of file -==================== -*/ -qboolean FS_Eof( file_t* file ) -{ - if( !file ) return true; - return (file->position == file->real_length) ? true : false; -} - -/* -==================== -FS_Purge - -Erases any buffered input or output data -==================== -*/ -void FS_Purge( file_t* file ) -{ - file->buff_len = 0; - file->buff_ind = 0; - file->ungetc = EOF; -} - - -/* -============ -FS_LoadFile - -Filename are relative to the xash directory. -Always appends a 0 byte. -============ -*/ -byte *FS_LoadFile( const char *path, fs_offset_t *filesizeptr ) -{ - file_t *file; - byte *buf = NULL; - fs_offset_t filesize = 0; - const char *ext = FS_FileExtension( path ); - - file = FS_Open( path, "rb", false ); - - if( file ) - { - filesize = file->real_length; - buf = (byte *)Mem_Alloc( fs_mempool, filesize + 1 ); - buf[filesize] = '\0'; - FS_Read( file, buf, filesize ); - FS_Close( file ); - } - else buf = W_LoadFile( path, &filesize ); - - if( filesizeptr ) *filesizeptr = filesize; - return buf; -} - - -/* -============ -FS_WriteFile - -The filename will be prefixed by the current game directory -============ -*/ -qboolean FS_WriteFile( const char *filename, const void *data, fs_offset_t len ) -{ - file_t *file; - - file = FS_Open( filename, "wb", false ); - - if( !file ) - { - MsgDev( D_ERROR, "FS_WriteFile: failed on %s\n", filename); - return false; - } - - FS_Write (file, data, len); - FS_Close (file); - return true; -} - -/* -============================================================================= - -OTHERS PUBLIC FUNCTIONS - -============================================================================= -*/ - -/* -============ -FS_StripExtension -============ -*/ -void FS_StripExtension (char *path) -{ - size_t length; - - length = com.strlen( path ) - 1; - while( length > 0 && path[length] != '.' ) - { - length--; - if( path[length] == '/' || path[length] == '\\' || path[length] == ':' ) - return; // no extension - } - if( length ) path[length] = 0; -} - - -/* -================== -FS_DefaultExtension -================== -*/ -void FS_DefaultExtension( char *path, const char *extension ) -{ - const char *src; - - // if path doesn't have a .EXT, append extension - // (extension should include the .) - src = path + com.strlen( path ) - 1; - - while (*src != '/' && src != path) - { - // it has an extension - if (*src == '.') return; - src--; - } - com.strcat( path, extension ); -} - -/* -================== -FS_FileExists - -Look for a file in the packages and in the filesystem -================== -*/ -qboolean FS_FileExists( const char *filename, qboolean gamedironly ) -{ - if( FS_FindFile( filename, NULL, gamedironly )) - return true; - return false; -} - -const char *FS_GetDiskPath( const char *name, qboolean gamedironly ) -{ - int index; - searchpath_t *search; - - search = FS_FindFile( name, &index, gamedironly ); - - if( search ) - { - if( index != -1 ) - { - // file in pack or wad - return NULL; - } - return va( "%s%s", search->filename, name ); - } - return NULL; -} - -/* -================== -FS_FindLibrary - -search for library, assume index is valid -only for internal use -================== -*/ -dll_user_t *FS_FindLibrary( const char *dllname, qboolean directpath ) -{ - string dllpath; - searchpath_t *search; - dll_user_t *hInst; - int i, index; - - // check for bad exports - if( !dllname || !*dllname ) - return NULL; - - // some mods used direct path to dlls - if( com.strstr( dllname, ".." )) - directpath = true; - - fs_ext_path = directpath; - - // replace all backward slashes - for( i = 0; i < com.strlen( dllname ); i++ ) - { - if( dllname[i] == '\\' ) dllpath[i] = '/'; - else dllpath[i] = com.tolower( dllname[i] ); - } - dllpath[i] = '\0'; - - FS_DefaultExtension( dllpath, ".dll" ); // trying to apply if forget - - search = FS_FindFile( dllpath, &index, false ); - if( !search ) - { - fs_ext_path = false; - if( directpath ) return NULL; // direct paths fails here - - // trying check also 'bin' folder for indirect paths - com.strncpy( dllpath, dllname, sizeof( dllpath )); - search = FS_FindFile( dllpath, &index, false ); - if( !search ) return NULL; // unable to find - } - - // all done, create dll_user_t struct - hInst = Mem_Alloc( Sys.basepool, sizeof( dll_user_t )); - - // save dllname for debug purposes - com.strncpy( hInst->dllName, dllname, sizeof( hInst->dllName )); - - // shortPath is used for LibraryLoadSymbols only - com.strncpy( hInst->shortPath, dllpath, sizeof( hInst->shortPath )); - - if( index < 0 ) - { - com.snprintf( hInst->fullPath, sizeof( hInst->fullPath ), "%s%s", search->filename, dllpath ); - hInst->custom_loader = false; // we can loading from disk and use normal debugging - } - else - { - com.strncpy( hInst->fullPath, dllpath, sizeof( hInst->fullPath )); - hInst->custom_loader = true; // loading from pack or wad - for release, debug don't working - } - fs_ext_path = false; // always reset direct paths - - return hInst; -} - -/* -================== -FS_FileSize - -return size of file in bytes -================== -*/ -fs_offset_t FS_FileSize( const char *filename, qboolean gamedironly ) -{ - file_t *fp; - int length = 0; - - fp = FS_Open( filename, "rb", gamedironly ); - - if( fp ) - { - // it exists - FS_Seek( fp, 0, SEEK_END ); - length = FS_Tell( fp ); - FS_Close( fp ); - } - return length; -} - -/* -================== -FS_FileTime - -return time of creation file in seconds -================== -*/ -fs_offset_t FS_FileTime( const char *filename, qboolean gamedironly ) -{ - searchpath_t *search; - int pack_ind; - - search = FS_FindFile( filename, &pack_ind, gamedironly ); - if( !search ) return -1; // doesn't exist - - if( search->pack ) // grab pack filetime - return search->pack->filetime; - else if( search->wad ) // grab wad filetime - return search->wad->filetime; - else if( pack_ind < 0 ) - { - // found in the filesystem? - char path [MAX_SYSPATH]; - - com.sprintf( path, "%s%s", search->filename, filename ); - return FS_SysFileTime( path ); - } - return -1; // doesn't exist -} - -/* -================== -FS_Rename - -rename specified file from gamefolder -================== -*/ -qboolean FS_Rename( const char *oldname, const char *newname ) -{ - char oldpath[MAX_SYSPATH], newpath[MAX_SYSPATH]; - qboolean iRet; - - if( !oldname || !newname || !*oldname || !*newname ) - return false; - - com.snprintf( oldpath, sizeof( oldpath ), "%s/%s", fs_gamedir, oldname ); - com.snprintf( newpath, sizeof( newpath ), "%s/%s", fs_gamedir, newname ); - - iRet = rename( oldpath, newpath ); - - return iRet; -} - -/* -================== -FS_Delete - -delete specified file from gamefolder -================== -*/ -qboolean FS_Delete( const char *path ) -{ - char real_path[MAX_SYSPATH]; - qboolean iRet; - - if( !path || !*path ) - return false; - - com.snprintf( real_path, sizeof( real_path ), "%s/%s", fs_gamedir, path ); - iRet = remove( real_path ); - - return iRet; -} - -/* -=========== -FS_Search - -Allocate and fill a search structure with information on matching filenames. -=========== -*/ -search_t *FS_Search( const char *pattern, int caseinsensitive, int gamedironly ) -{ - search_t *search = NULL; - searchpath_t *searchpath; - pack_t *pak; - wfile_t *wad; - int i, basepathlength, numfiles, numchars; - int resultlistindex, dirlistindex; - const char *slash, *backslash, *colon, *separator; - string netpath, temp; - stringlist_t resultlist; - stringlist_t dirlist; - char *basepath; - - for( i = 0; pattern[i] == '.' || pattern[i] == ':' || pattern[i] == '/' || pattern[i] == '\\'; i++ ); - - if( i > 0 ) - { - MsgDev( D_INFO, "FS_Search: don't use punctuation at the beginning of a search pattern!\n"); - return NULL; - } - - stringlistinit( &resultlist ); - stringlistinit( &dirlist ); - slash = com.strrchr( pattern, '/' ); - backslash = com.strrchr( pattern, '\\' ); - colon = com.strrchr( pattern, ':' ); - separator = max( slash, backslash ); - separator = max( separator, colon ); - basepathlength = separator ? (separator + 1 - pattern) : 0; - basepath = Mem_Alloc( fs_mempool, basepathlength + 1 ); - if( basepathlength ) Mem_Copy( basepath, pattern, basepathlength ); - basepath[basepathlength] = 0; - - // search through the path, one element at a time - for( searchpath = fs_searchpaths; searchpath; searchpath = searchpath->next ) - { - if( gamedironly && !( searchpath->flags & FS_GAMEDIR_PATH )) - continue; - - // is the element a pak file? - if( searchpath->pack ) - { - // look through all the pak file elements - pak = searchpath->pack; - for( i = 0; i < pak->numfiles; i++ ) - { - com.strncpy( temp, pak->files[i].name, sizeof( temp )); - while( temp[0] ) - { - if( matchpattern( temp, (char *)pattern, true )) - { - for( resultlistindex = 0; resultlistindex < resultlist.numstrings; resultlistindex++ ) - { - if( !com.strcmp( resultlist.strings[resultlistindex], temp )) - break; - } - - if( resultlistindex == resultlist.numstrings ) - { - stringlistappend( &resultlist, temp ); - } - } - // strip off one path element at a time until empty - // this way directories are added to the listing if they match the pattern - slash = com.strrchr( temp, '/' ); - backslash = com.strrchr( temp, '\\' ); - colon = com.strrchr( temp, ':' ); - separator = temp; - if( separator < slash ) - separator = slash; - if( separator < backslash ) - separator = backslash; - if( separator < colon ) - separator = colon; - *((char *)separator) = 0; - } - } - } - else if( searchpath->wad ) - { - string wadpattern, wadname, temp2; - char type = W_TypeFromExt( pattern ); - qboolean anywadname = true; - string wadfolder; - - // quick reject by filetype - if( type == TYP_NONE ) continue; - FS_ExtractFilePath( pattern, wadname ); - FS_FileBase( pattern, wadpattern ); - wadfolder[0] = '\0'; - - if( com.strlen( wadname )) - { - FS_FileBase( wadname, wadname ); - com.strncpy( wadfolder, wadname, sizeof( wadfolder )); - FS_DefaultExtension( wadname, ".wad" ); - anywadname = false; - } - - // quick reject by wadname - if( !anywadname && com.stricmp( wadname, searchpath->wad->filename )) - continue; - - // look through all the wad file elements - wad = searchpath->wad; - for( i = 0; i < wad->numlumps; i++ ) - { - // if type not matching, we already no chance ... - if( type != TYP_ANY && wad->lumps[i].type != type ) - continue; - com.strncpy( temp, wad->lumps[i].name, sizeof( temp )); - while( temp[0] ) - { - if( matchpattern( temp, wadpattern, true )) - { - for( resultlistindex = 0; resultlistindex < resultlist.numstrings; resultlistindex++ ) - { - if( !com.strcmp( resultlist.strings[resultlistindex], temp )) - break; - } - if( resultlistindex == resultlist.numstrings ) - { - // build path: wadname/lumpname.ext - com.snprintf( temp2, sizeof(temp2), "%s/%s", wadfolder, temp ); - FS_DefaultExtension( temp2, va(".%s", W_ExtFromType( wad->lumps[i].type ))); // make ext - stringlistappend( &resultlist, temp2 ); - } - } - // strip off one path element at a time until empty - // this way directories are added to the listing if they match the pattern - slash = com.strrchr( temp, '/' ); - backslash = com.strrchr( temp, '\\' ); - colon = com.strrchr( temp, ':' ); - separator = temp; - if( separator < slash ) - separator = slash; - if( separator < backslash ) - separator = backslash; - if( separator < colon ) - separator = colon; - *((char *)separator) = 0; - } - } - } - else - { - // get a directory listing and look at each name - com.sprintf( netpath, "%s%s", searchpath->filename, basepath ); - stringlistinit( &dirlist ); - listdirectory( &dirlist, netpath ); - for( dirlistindex = 0; dirlistindex < dirlist.numstrings; dirlistindex++ ) - { - com.sprintf( temp, "%s%s", basepath, dirlist.strings[dirlistindex] ); - if( matchpattern( temp, (char *)pattern, true )) - { - for( resultlistindex = 0; resultlistindex < resultlist.numstrings; resultlistindex++ ) - { - if( !com.strcmp( resultlist.strings[resultlistindex], temp )) - break; - } - - if( resultlistindex == resultlist.numstrings ) - { - stringlistappend( &resultlist, temp ); - } - } - } - stringlistfreecontents( &dirlist ); - } - } - - if( resultlist.numstrings ) - { - stringlistsort( &resultlist ); - numfiles = resultlist.numstrings; - numchars = 0; - for( resultlistindex = 0; resultlistindex < resultlist.numstrings; resultlistindex++ ) - numchars += (int)com.strlen( resultlist.strings[resultlistindex]) + 1; - search = Mem_Alloc( fs_mempool, sizeof(search_t) + numchars + numfiles * sizeof( char * )); - search->filenames = (char **)((char *)search + sizeof(search_t)); - search->filenamesbuffer = (char *)((char *)search + sizeof(search_t) + numfiles * sizeof( char * )); - search->numfilenames = (int)numfiles; - numfiles = 0; - numchars = 0; - for( resultlistindex = 0; resultlistindex < resultlist.numstrings; resultlistindex++ ) - { - size_t textlen; - - search->filenames[numfiles] = search->filenamesbuffer + numchars; - textlen = com.strlen(resultlist.strings[resultlistindex]) + 1; - Mem_Copy( search->filenames[numfiles], resultlist.strings[resultlistindex], textlen ); - numfiles++; - numchars += (int)textlen; - } - } - stringlistfreecontents( &resultlist ); - - Mem_Free( basepath ); - return search; -} - -void FS_InitMemory( void ) -{ - fs_mempool = Mem_AllocPool( "Filesystem Pool" ); - - // add a path separator to the end of the basedir if it lacks one - if( fs_basedir[0] && fs_basedir[com.strlen(fs_basedir) - 1] != '/' && fs_basedir[com.strlen(fs_basedir) - 1] != '\\' ) - com.strncat( fs_basedir, "/", sizeof( fs_basedir )); - - fs_searchpaths = NULL; -} - -/* -================ -FS_CheckParm - -Returns the position (1 to argc-1) in the program's argument list -where the given parameter apears, or 0 if not present -================ -*/ -int FS_CheckParm( const char *parm ) -{ - int i; - - for( i = 1; i < fs_argc; i++ ) - { - // NEXTSTEP sometimes clears appkit vars. - if( !fs_argv[i] ) continue; - if( !com.stricmp( parm, fs_argv[i] )) return i; - } - return 0; -} - -void FS_GetBaseDir( char *pszBuffer, char *out ) -{ - char basedir[MAX_SYSPATH]; - char szBuffer[MAX_SYSPATH]; - char *pBuffer = NULL; - int j; - - com.strcpy( szBuffer, pszBuffer ); - - pBuffer = com.strrchr( szBuffer,'\\' ); - if ( pBuffer ) *(pBuffer + 1) = '\0'; - - com.strcpy( basedir, szBuffer ); - - j = com.strlen( basedir ); - if( j > 0 ) - { - if(( basedir[j-1] == '\\' ) || ( basedir[j-1] == '/' )) - basedir[j-1] = 0; - } - com.strcpy( out, basedir ); -} - -void FS_ReadEnvironmentVariables( char *pPath ) -{ - // get basepath from registry - REG_GetValue( HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\Session Manager\\Environment", "Xash3D", pPath ); -} - -void FS_SaveEnvironmentVariables( char *pPath ) -{ - // save new path - REG_SetValue( HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\Session Manager\\Environment", "Xash3D", pPath ); - SendMessageTimeout( HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0, SMTO_NORMAL, 10, NULL ); // system update message -} - -static void FS_BuildPath( char *pPath, char *pOut ) -{ - // set working directory - SetCurrentDirectory ( pPath ); - com.sprintf( pOut, "%s\\bin\\launch.dll", pPath ); -} - -void FS_UpdateEnvironmentVariables( void ) -{ - char szTemp[4096]; - char szPath[MAX_SYSPATH]; // test path - - if( Sys.app_name == HOST_NORMAL || Sys.app_name == HOST_DEDICATED ) - { - // just update environment path - FS_SaveEnvironmentVariables( sys_rootdir ); - return; - } - - // get variable from registry and current directory - FS_ReadEnvironmentVariables( szTemp ); - - // if both values is math - no run additional tests - if( com.stricmp( sys_rootdir, szTemp )) - { - // Step1: path from registry have higher priority than current working directory - // because user can execute launcher from random place or from a bat-file - // so, set current working directory as path from registry and test it - - FS_BuildPath( szTemp, szPath ); - if( !FS_SysFileExists( szPath )) // Step2: engine root dir has been moved to other place? - { - FS_BuildPath( sys_rootdir, szPath ); - if( !FS_SysFileExists( szPath )) // Step3: directly execute from bin directory? - { - // Step4: create last test for bin directory - FS_GetBaseDir( sys_rootdir, szTemp ); - FS_BuildPath( szTemp, szPath ); - if( !FS_SysFileExists( szPath )) - { - // big bada-boom: engine was moved and launcher was running from other place - // step5: so, path form registry is invalid, current path is no valid - Sys_Break( "Invalid root directory!\n\rPlease re-install Xash3D\n" ); - } - else FS_SaveEnvironmentVariables( szTemp ); // update registry - } - else FS_SaveEnvironmentVariables( sys_rootdir ); - } - } -} - -/* -============================================================================= - -VIRTUAL FILE SYSTEM - WRITE DATA INTO MEMORY - -============================================================================= -*/ -vfile_t *VFS_Create( const byte *buffer, size_t buffsize) -{ - vfile_t *file = (vfile_t *)Mem_Alloc( fs_mempool, sizeof (*file)); - - file->length = file->buffsize = buffsize; - file->buff = Mem_Alloc(fs_mempool, (file->buffsize)); - file->offset = 0; - file->mode = O_RDONLY; - Mem_Copy( file->buff, buffer, buffsize ); - - return file; -} - -vfile_t *VFS_Open( file_t *handle, const char *mode ) -{ - vfile_t *file = (vfile_t *)Mem_Alloc (fs_mempool, sizeof (vfile_t)); - - // If the file is opened in "write", "append", or "read/write" mode - if( mode[0] == 'w' ) - { - file->handle = handle; - file->buffsize = (64 * 1024); // will be resized if need - file->buff = Mem_Alloc( fs_mempool, file->buffsize ); - file->length = 0; - file->offset = 0; - file->mode = O_WRONLY; - } - else if( mode[0] == 'r' ) - { - int curpos, endpos; - - file->handle = handle; - curpos = FS_Tell( file->handle ); - FS_Seek( file->handle, 0, SEEK_END ); - endpos = FS_Tell( file->handle ); - FS_Seek( file->handle, curpos, SEEK_SET ); - - file->buffsize = endpos - curpos; - file->buff = Mem_Alloc( fs_mempool, file->buffsize ); - - FS_Read( file->handle, file->buff, file->buffsize ); - file->length = file->buffsize; - file->offset = 0; - file->mode = O_RDONLY; - } - else - { - Mem_Free( file ); - MsgDev( D_ERROR, "VFS_Open: unsupported mode %s\n", mode ); - return NULL; - } - return file; -} - -fs_offset_t VFS_Read( vfile_t* file, void* buffer, size_t buffersize) -{ - fs_offset_t read_size = 0; - - if( buffersize == 0 ) return 1; - if( !file ) return 0; - - // check for enough room - if( file->offset >= file->length ) - { - return 0; // hit EOF - } - - if( file->offset + buffersize <= file->length ) - { - Mem_Copy( buffer, file->buff + file->offset, buffersize ); - file->offset += buffersize; - read_size = buffersize; - } - else - { - int reduced_size = file->length - file->offset; - Mem_Copy( buffer, file->buff + file->offset, reduced_size ); - file->offset += reduced_size; - read_size = reduced_size; - MsgDev( D_NOTE, "VFS_Read: vfs buffer is out\n"); - } - - return read_size; -} - -fs_offset_t VFS_Write( vfile_t *file, const void *buf, size_t size ) -{ - if( !file ) return -1; - - if( file->offset + size >= file->buffsize ) - { - int newsize = file->offset + size + (64 * 1024); - - if( file->buffsize < newsize ) - { - // reallocate buffer now - file->buff = Mem_Realloc( fs_mempool, file->buff, newsize ); - file->buffsize = newsize; // merge buffsize - } - } - - // write into buffer - Mem_Copy( file->buff + file->offset, (byte *)buf, size ); - file->offset += size; - - if( file->offset > file->length ) - file->length = file->offset; - - return file->length; -} - -byte *VFS_GetBuffer( vfile_t *file ) -{ - if( !file ) return NULL; - return file->buff; -} - -/* -==================== -VFS_Print - -Print a string into a file -==================== -*/ -int VFS_Print( vfile_t* file, const char *msg ) -{ - return (int)VFS_Write( file, msg, com.strlen( msg )); -} - -/* -==================== -VFS_VPrintf - -Print a string into a buffer -==================== -*/ -int VFS_VPrintf( vfile_t* file, const char* format, va_list ap ) -{ - int len; - fs_offset_t buff_size = MAX_SYSPATH; - char *tempbuff; - - while( 1 ) - { - tempbuff = (char *)Mem_Alloc( fs_mempool, buff_size ); - len = com.vsprintf( tempbuff, format, ap ); - if( len >= 0 && len < buff_size ) break; - Mem_Free( tempbuff ); - buff_size *= 2; - } - - len = VFS_Write( file, tempbuff, len ); - Mem_Free( tempbuff ); - - return len; -} - -/* -==================== -VFS_Printf - -Print a string into a buffer -==================== -*/ -int VFS_Printf( vfile_t* file, const char* format, ... ) -{ - int result; - va_list args; - - va_start( args, format ); - result = VFS_VPrintf( file, format, args ); - va_end( args ); - - return result; -} - -fs_offset_t VFS_Tell( vfile_t *file ) -{ - if( !file ) return -1; - return file->offset; -} - -qboolean VFS_Eof( vfile_t *file ) -{ - if( !file ) return true; - return (file->offset == file->length) ? true : false; -} - -/* -==================== -VFS_Getc - -Get the next character of a file -==================== -*/ -int VFS_Getc( vfile_t *file ) -{ - char c; - - if(!VFS_Read( file, &c, 1 )) - return EOF; - return c; -} - -int VFS_Gets( vfile_t* file, byte *string, size_t bufsize ) -{ - int c, end = 0; - - while( 1 ) - { - c = VFS_Getc( file ); - if( c == '\r' || c == '\n' || c < 0 ) - break; - - if( end < bufsize - 1 ) - string[end++] = c; - } - string[end] = 0; - - // remove \n following \r - if( c == '\r' ) - { - c = VFS_Getc( file ); - if( c != '\n' ) VFS_Seek( file, -1, SEEK_CUR ); // rewind - } - - return c; -} - -int VFS_Seek( vfile_t *file, fs_offset_t offset, int whence ) -{ - if( !file ) return -1; - - // Compute the file offset - switch( whence ) - { - case SEEK_CUR: - offset += file->offset; - break; - case SEEK_SET: - break; - case SEEK_END: - offset += file->length; - break; - default: - return -1; - } - - if( offset < 0 || offset > (long)file->length ) - return -1; - - file->offset = offset; - return 0; -} - -file_t *VFS_Close( vfile_t *file ) -{ - file_t *handle; - - if( !file ) return NULL; - - if( file->mode == O_WRONLY ) - { - if( file->handle ) - FS_Write(file->handle, file->buff, (file->length + 3) & ~3); // align - } - - handle = file->handle; // keep real handle - - if( file->buff ) Mem_Free( file->buff ); - Mem_Free( file ); // himself - - return handle; -} - - -/* -============================================================================= - -WADSYSTEM PRIVATE COMMON FUNCTIONS - -============================================================================= -*/ -// associate extension with wad type -static const wadtype_t wad_types[] = -{ -{ "flp", TYP_FLMP }, // doom1 menu picture -{ "snd", TYP_SND }, // doom1 sound -{ "mus", TYP_MUS }, // doom1 .mus format -{ "skn", TYP_SKIN }, // doom1 sprite model -{ "flt", TYP_FLAT }, // doom1 wall texture -{ "pal", TYP_QPAL }, // palette -{ "lmp", TYP_QPIC }, // quake1, hl pic -{ "fnt", TYP_QFONT }, // hl qfonts -{ "mip", TYP_MIPTEX }, // hl/q1 mip -{ "raw", TYP_RAW }, // signed raw data -{ NULL, TYP_NONE } -}; - -static char W_TypeFromExt( const char *lumpname ) -{ - const char *ext = FS_FileExtension( lumpname ); - const wadtype_t *type; - - // we not known about filetype, so match only by filename - if( !com.strcmp( ext, "*" ) || !com.strcmp( ext, "" )) - return TYP_ANY; - - for( type = wad_types; type->ext; type++ ) - { - if(!com.stricmp( ext, type->ext )) - return type->type; - } - return TYP_NONE; -} - -static const char *W_ExtFromType( char lumptype ) -{ - const wadtype_t *type; - - // we not known aboyt filetype, so match only by filename - if( lumptype == TYP_NONE || lumptype == TYP_ANY ) - return ""; - - for( type = wad_types; type->ext; type++ ) - { - if( lumptype == type->type ) - return type->ext; - } - return ""; -} - -static dlumpinfo_t *W_FindLump( wfile_t *wad, const char *name, const char matchtype ) -{ - int left, right, middle; - - if( !wad || !wad->lumps || matchtype == TYP_NONE ) - return NULL; - - // look for the file (binary search) - left = 0; - right = wad->numlumps - 1; - - while( left <= right ) - { - int diff; - - middle = (left + right) / 2; - diff = com.stricmp( wad->lumps[middle].name, name ); - - // Found it - if( !diff ) - { - if( matchtype == TYP_ANY || matchtype == wad->lumps[middle].type ) - return &wad->lumps[middle]; // found - else break; - } - - // if we're too far in the list - if( diff > 0 ) - right = middle - 1; - else left = middle + 1; - } - return NULL; -} - -static void W_CleanupName( const char *dirtyname, char *cleanname ) -{ - string tempname; - - if( !dirtyname || !cleanname ) return; - - cleanname[0] = '\0'; // clear output - FS_FileBase( dirtyname, tempname ); - tempname[16] = '\0'; // cutoff all other ... - com.strncpy( cleanname, tempname, 16 ); - - // .. and turn big letters - com.strupr( cleanname, cleanname ); -} - -/* -==================== -FS_AddFileToWad - -Add a file to the list of files contained into a package -==================== -*/ -static dlumpinfo_t *W_AddFileToWad( const char *name, wfile_t *wad, int filepos, int packsize, int realsize, char type, char compression ) -{ - int left, right, middle; - dlumpinfo_t *plump; - - // look for the slot we should put that file into (binary search) - left = 0; - right = wad->numlumps - 1; - - while( left <= right ) - { - int diff; - - middle = ( left + right ) / 2; - diff = com.stricmp( wad->lumps[middle].name, name ); - - // If we found the file, there's a problem - if( !diff ) MsgDev( D_NOTE, "Wad %s contains the file %s several times\n", wad->filename, name ); - - // If we're too far in the list - if( diff > 0 ) right = middle - 1; - else left = middle + 1; - } - - // We have to move the right of the list by one slot to free the one we need - plump = &wad->lumps[left]; - memmove( plump + 1, plump, ( wad->numlumps - left ) * sizeof( *plump )); - wad->numlumps++; - - Mem_Copy( plump->name, name, sizeof( plump->name )); - plump->filepos = filepos; - plump->disksize = realsize; - plump->size = packsize; - plump->compression = compression; - - // convert all qmip types to miptex - if( type == TYP_QMIP ) - plump->type = TYP_MIPTEX; - else plump->type = type; - - // check for Quake 'conchars' issues (only lmp loader supposed to read this lame pic) - if( !com.stricmp( plump->name, "conchars" ) && plump->type == TYP_QMIP ) - plump->type = TYP_QPIC; - - return plump; -} - -static qboolean W_ConvertIWADLumps( wfile_t *wad ) -{ - dlumpfile_t *doomlumps; - qboolean flat_images = false; // doom1 wall texture marker - qboolean skin_images = false; // doom1 skin image ( sprite model ) marker - qboolean flmp_images = false; // doom1 menu image marker - size_t lat_size; // LAT - LumpAllocationTable - int i, k, numlumps; - - // nothing to convert ? - if( !wad ) return false; - - lat_size = wad->numlumps * sizeof( dlumpfile_t ); - doomlumps = (dlumpfile_t *)Mem_Alloc( wad->mempool, lat_size ); - numlumps = wad->numlumps; - wad->numlumps = 0; // reset it - - if( FS_Read( wad->file, doomlumps, lat_size ) != lat_size ) - { - MsgDev( D_ERROR, "W_ConvertIWADLumps: %s has corrupted lump allocation table\n", wad->filename ); - Mem_Free( doomlumps ); - W_Close( wad ); - return false; - } - - // convert doom1 format into WAD3 lump format - for( i = 0; i < numlumps; i++ ) - { - // W_Open will be swap lump later - int filepos = doomlumps[i].filepos; - int size = doomlumps[i].size; - char type = TYP_NONE; - char name[16]; - - com.strnlwr( doomlumps[i].name, name, 9 ); - - // check for backslash issues - k = com.strlen( com.strchr( name, '\\' )); - if( k ) name[com.strlen( name )-k] = '#'; // vile1.spr issues - - // textures begin - if( !com.stricmp( "S_START", name )) - { - skin_images = true; - continue; // skip identifier - } - else if( !com.stricmp( "P_START", name )) - { - flat_images = true; - continue; // skip identifier - } - else if( !com.stricmp( "P1_START", name )) - { - flat_images = true; - continue; // skip identifier - } - else if( !com.stricmp( "P2_START", name )) - { - flat_images = true; - continue; // skip identifier - } - else if( !com.stricmp( "P3_START", name )) - { - // only doom2 uses this name - flat_images = true; - continue; // skip identifier - } - else if( !com.strnicmp( "WI", name, 2 )) flmp_images = true; - else if( !com.strnicmp( "ST", name, 2 )) flmp_images = true; - else if( !com.strnicmp( "M_", name, 2 )) flmp_images = true; - else if( !com.strnicmp( "END", name, 3 )) flmp_images = true; - else if( !com.strnicmp( "HELP", name, 4 )) flmp_images = true; - else if( !com.strnicmp( "CREDIT", name, 6 )) flmp_images = true; - else if( !com.strnicmp( "TITLEPIC", name, 8 )) flmp_images = true; - else if( !com.strnicmp( "VICTORY", name, 7 )) flmp_images = true; - else if( !com.strnicmp( "PFUB", name, 4 )) flmp_images = true; - else if( !com.stricmp( "P_END", name )) flat_images = false; - else if( !com.stricmp( "P1_END", name )) flat_images = false; - else if( !com.stricmp( "P2_END", name )) flat_images = false; - else if( !com.stricmp("P3_END", name )) flat_images = false; - else if( !com.stricmp( "S_END", name )) skin_images = false; - else flmp_images = false; - - // setup lumptypes for doomwads - if( flmp_images ) type = TYP_FLMP; // mark as menu pic - if( flat_images ) type = TYP_FLAT; // mark as texture - if( skin_images ) type = TYP_SKIN; // mark as skin (sprite model) - if(!com.strnicmp( name, "D_", 2 )) wad->lumps[i].type = TYP_MUS; - if(!com.strnicmp( name, "DS", 2 )) wad->lumps[i].type = TYP_SND; - - // remove invalid resources - if( !com.strnicmp( name, "ENDOOM", 6 )) type = TYP_NONE; - if( !com.strnicmp( name, "STEP1", 5 )) type = TYP_NONE; - if( !com.strnicmp( name, "STEP2", 5 )) type = TYP_NONE; - - if( type == TYP_NONE ) continue; // invalid resource - - // add wad file - W_AddFileToWad( name, wad, filepos, size, size, type, CMP_NONE ); - } - - Mem_Free( doomlumps ); // no need anymore - return true; -} - -static qboolean W_ReadLumpTable( wfile_t *wad ) -{ - size_t lat_size; - dlumpinfo_t *srclumps; - int i, k, numlumps; - - // nothing to convert ? - if( !wad ) return false; - - lat_size = wad->numlumps * sizeof( dlumpinfo_t ); - srclumps = (dlumpinfo_t *)Mem_Alloc( wad->mempool, lat_size ); - numlumps = wad->numlumps; - wad->numlumps = 0; // reset it - - if( FS_Read( wad->file, srclumps, lat_size ) != lat_size ) - { - MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename ); - W_Close( wad ); - return false; - } - - // swap everything - for( i = 0; i < numlumps; i++ ) - { - int filepos = LittleLong( srclumps[i].filepos ); - int realsize = LittleLong( srclumps[i].disksize ); - int size = LittleLong( srclumps[i].size ); - char name[16]; - - // cleanup lumpname - com.strnlwr( srclumps[i].name, name, sizeof( srclumps[i].name )); - - // check for '*' symbol issues - k = com.strlen( com.strrchr( name, '*' )); - if( k ) name[com.strlen( name ) - k] = '!'; // quake1 issues (can't save images that contain '*' symbol) - - W_AddFileToWad( name, wad, filepos, size, realsize, srclumps[i].type, srclumps[i].compression ); - } - - // release source lumps - Mem_Free( srclumps ); - - return true; -} - -byte *W_ReadLump( wfile_t *wad, dlumpinfo_t *lump, size_t *lumpsizeptr ) -{ - byte *buf, *cbuf; - size_t size = 0; - - // assume error - if( lumpsizeptr ) *lumpsizeptr = 0; - - // no wads loaded - if( !wad || !lump ) return NULL; - - if( FS_Seek( wad->file, lump->filepos, SEEK_SET )) - { - MsgDev( D_ERROR, "W_ReadLump: %s is corrupted\n", lump->name ); - return NULL; - } - - switch( lump->compression ) - { - case CMP_LZSS: - cbuf = (byte *)Mem_Alloc( wad->mempool, lump->disksize ); - size = FS_Read( wad->file, cbuf, lump->disksize ); - buf = (byte *)Mem_Alloc( wad->mempool, lump->size ); - - if( size < lump->disksize ) - { - MsgDev( D_WARN, "W_ReadLump: %s is probably corrupted\n", lump->name ); - Mem_Free( cbuf ); - Mem_Free( buf ); - return NULL; - } - - if( lzss_decompress( cbuf, cbuf + lump->disksize, buf, buf + lump->size )) - { - MsgDev( D_WARN, "W_ReadLump: can't unpack %s\n", lump->name ); - Mem_Free( cbuf ); - Mem_Free( buf ); - return NULL; - } - - Mem_Free( cbuf ); // no reason to keep this data - break; - default: - buf = (byte *)Mem_Alloc( wad->mempool, lump->disksize ); - size = FS_Read( wad->file, buf, lump->disksize ); - if( size < lump->disksize ) - { - MsgDev( D_WARN, "W_ReadLump: %s is probably corrupted\n", lump->name ); - Mem_Free( buf ); - return NULL; - } - break; - } - - if( lumpsizeptr ) *lumpsizeptr = lump->size; - return buf; -} - -qboolean W_WriteLump( wfile_t *wad, dlumpinfo_t *lump, const void* data, size_t datasize, char cmp ) -{ - byte *inbuf, *outbuf; - - if( !wad || !lump ) return false; - - if( !data || !datasize ) - { - MsgDev( D_WARN, "W_WriteLump: ignore blank lump %s - nothing to save\n", lump->name ); - return false; - } - - switch( cmp ) - { - case CMP_LZSS: - inbuf = (byte *)data; - - // NOTE: abort compression if it matches or exceeds the original file's size - outbuf = Mem_Alloc( fs_mempool, datasize - 1 ); - lump->disksize = lzss_compress( inbuf, inbuf + datasize, outbuf, outbuf + datasize - 1 ); - lump->size = datasize; // realsize - lump->compression = CMP_LZSS; - - if( lump->disksize > 0 ) - { - FS_Write( wad->file, outbuf, lump->disksize ); // write compressed file - } - Mem_Free( outbuf ); - return ( lump->disksize != 0 ) ? true : false; - default: // CMP_NONE method - lump->size = lump->disksize = LittleLong( datasize ); - lump->compression = CMP_NONE; - FS_Write( wad->file, data, datasize ); // just write file - return true; - } -} - -/* -============================================================================= - -WADSYSTEM PUBLIC BASE FUNCTIONS - -============================================================================= -*/ -int W_Check( const char *filename ) -{ - file_t *testwad; - dwadinfo_t header; - int numlumps; - int infotableofs; - - testwad = FS_Open( filename, "rb", false ); - if( !testwad ) return 0; // just not exist - - if( FS_Read( testwad, &header, sizeof(dwadinfo_t)) != sizeof(dwadinfo_t)) - { - // corrupted or not wad - FS_Close( testwad ); - return -1; // too small file - } - - switch( header.ident ) - { - case IDIWADHEADER: - case IDPWADHEADER: - case IDWAD2HEADER: - case IDWAD3HEADER: break; - default: - FS_Close( testwad ); - return -2; // invalid id - } - - numlumps = LittleLong( header.numlumps ); - if( numlumps < 0 || numlumps > MAX_FILES_IN_WAD ) - { - // invalid lump number - FS_Close( testwad ); - return -3; // invalid lumpcount - } - infotableofs = LittleLong( header.infotableofs ); - if( FS_Seek( testwad, infotableofs, SEEK_SET )) - { - // corrupted or not wad - FS_Close( testwad ); - return -4; // invalid lumptable - } - - // all check is done - FS_Close( testwad ); - return 1; // valid -} - -wfile_t *W_Open( const char *filename, const char *mode ) -{ - dwadinfo_t header; - wfile_t *wad = (wfile_t *)Mem_Alloc( fs_mempool, sizeof( wfile_t )); - - if( mode[0] == 'a' ) wad->file = FS_Open( filename, "r+b", false ); - else if( mode[0] == 'w' ) wad->file = FS_Open( filename, "wb", false ); - else if( mode[0] == 'r' ) wad->file = FS_Open( filename, "rb", false ); - - if( !wad->file ) - { - W_Close( wad ); - MsgDev( D_ERROR, "W_Open: couldn't open %s\n", filename ); - return NULL; - } - - // copy wad name - com.strncpy( wad->filename, filename, sizeof( wad->filename )); - wad->mempool = Mem_AllocPool( filename ); - wad->filetime = wad->file->filetime; - - // if the file is opened in "write", "append", or "read/write" mode - if( mode[0] == 'w' ) - { - dwadinfo_t hdr; - - wad->numlumps = 0; // blank wad - wad->lumps = NULL; // - wad->mode = O_WRONLY; - - // save space for header - hdr.ident = IDWAD3HEADER; - hdr.numlumps = LittleLong( wad->numlumps ); - hdr.infotableofs = LittleLong(sizeof( dwadinfo_t )); - FS_Write( wad->file, &hdr, sizeof( hdr )); - FS_Print( wad->file, "Generated by Xash WadLib. " ); - wad->infotableofs = FS_Tell( wad->file ); - } - else if( mode[0] == 'r' || mode[0] == 'a' ) - { - if( mode[0] == 'a' ) - { - FS_Seek( wad->file, 0, SEEK_SET ); - wad->mode = O_APPEND; - } - - if( FS_Read( wad->file, &header, sizeof( dwadinfo_t )) != sizeof( dwadinfo_t )) - { - MsgDev( D_ERROR, "W_Open: %s can't read header\n", filename ); - W_Close( wad ); - return NULL; - } - - switch( header.ident ) - { - case IDIWADHEADER: - case IDPWADHEADER: - case IDWAD2HEADER: - if( wad->mode == O_APPEND ) - { - MsgDev( D_WARN, "W_Open: %s is readonly\n", filename, mode ); - wad->mode = O_RDONLY; // set read-only mode - } - break; - case IDWAD3HEADER: - break; // WAD3 allow r\w mode - default: - MsgDev( D_ERROR, "W_Open: %s unknown wadtype\n", filename ); - W_Close( wad ); - return NULL; - } - - wad->numlumps = LittleLong( header.numlumps ); - if( wad->numlumps >= MAX_FILES_IN_WAD && wad->mode == O_APPEND ) - { - MsgDev( D_WARN, "W_Open: %s is full (%i lumps)\n", wad->numlumps ); - wad->mode = O_RDONLY; // set read-only mode - } - wad->infotableofs = LittleLong( header.infotableofs ); // save infotableofs position - if( FS_Seek( wad->file, wad->infotableofs, SEEK_SET )) - { - MsgDev( D_ERROR, "W_Open: %s can't find lump allocation table\n", filename ); - W_Close( wad ); - return NULL; - } - - // NOTE: lumps table can be reallocated for O_APPEND mode - wad->lumps = Mem_Alloc( wad->mempool, wad->numlumps * sizeof( dlumpinfo_t )); - - if( wad->mode == O_APPEND ) - { - size_t lat_size = wad->numlumps * sizeof( dlumpinfo_t ); - - if( FS_Read( wad->file, wad->lumps, lat_size ) != lat_size ) - { - MsgDev( D_ERROR, "W_ReadLumpTable: %s has corrupted lump allocation table\n", wad->filename ); - W_Close( wad ); - return NULL; - } - - // if we are in append mode - we need started from infotableofs poisition - // overwrite lumptable as well, we have her copy in wad->lumps - FS_Seek( wad->file, wad->infotableofs, SEEK_SET ); - } - else - { - // setup lump allocation table - switch( header.ident ) - { - case IDIWADHEADER: - case IDPWADHEADER: - if(!W_ConvertIWADLumps( wad )) - return NULL; - break; - case IDWAD2HEADER: - case IDWAD3HEADER: - if(!W_ReadLumpTable( wad )) - return NULL; - break; - } - } - } - // and leaves the file open - return wad; -} - -void W_Close( wfile_t *wad ) -{ - fs_offset_t ofs; - - if( !wad ) return; - - if( wad->file && ( wad->mode == O_APPEND || wad->mode == O_WRONLY )) - { - dwadinfo_t hdr; - - // write the lumpingo - ofs = FS_Tell( wad->file ); - FS_Write( wad->file, wad->lumps, wad->numlumps * sizeof( dlumpinfo_t )); - - // write the header - hdr.ident = IDWAD3HEADER; - hdr.numlumps = LittleLong( wad->numlumps ); - hdr.infotableofs = LittleLong( ofs ); - - FS_Seek( wad->file, 0, SEEK_SET ); - FS_Write( wad->file, &hdr, sizeof( hdr )); - } - - Mem_FreePool( &wad->mempool ); - if( wad->file ) FS_Close( wad->file ); - Mem_Free( wad ); // free himself -} - -fs_offset_t W_SaveLump( wfile_t *wad, const char *lump, const void* data, size_t datasize, char type, char cmp ) -{ - size_t lat_size; - dlumpinfo_t *info; - int i; - - if( !wad || !lump ) return -1; - - if( !data || !datasize ) - { - MsgDev( D_WARN, "W_SaveLump: ignore blank lump %s - nothing to save\n", lump ); - return -1; - } - - if( wad->mode == O_RDONLY ) - { - MsgDev( D_ERROR, "W_SaveLump: %s opened in readonly mode\n", wad->filename ); - return -1; - } - - if( wad->numlumps >= MAX_FILES_IN_WAD ) - { - MsgDev( D_ERROR, "W_SaveLump: %s is full\n", wad->filename ); - return -1; - } - - if( W_FindLump( wad, lump, type )) - { - // don't make mirror lumps - MsgDev( D_ERROR, "W_SaveLump: %s already exist\n", lump ); - return -1; - } - - lat_size = sizeof( dlumpinfo_t ) * (wad->numlumps + 1); - - // reallocate lumptable - wad->lumps = Mem_Realloc( wad->mempool, wad->lumps, lat_size ); - info = wad->lumps + wad->numlumps; - - // write header - W_CleanupName( lump, info->name ); - info->filepos = LittleLong( FS_Tell( wad->file )); - info->compression = cmp; - info->type = type; - - i = FS_Tell( wad->file ); - if( !W_WriteLump( wad, info, data, datasize, cmp )) - { - if( cmp == CMP_LZSS ) - { - MsgDev( D_NOTE, "W_SaveLump: %s failed to compress\n", info->name ); - // in case we fail compress this lump, store it as non-compressed - if( !W_WriteLump( wad, info, data, datasize, CMP_NONE )) - return -1; - } - else return -1; - } - - MsgDev( D_NOTE, "W_SaveLump: %s, size %d\n", info->name, info->disksize ); - return wad->numlumps++; -} - -byte *W_LoadLump( wfile_t *wad, const char *lumpname, size_t *lumpsizeptr, const char type ) -{ - dlumpinfo_t *lump; - - // assume error - if( lumpsizeptr ) *lumpsizeptr = 0; - - if( !wad ) return NULL; - lump = W_FindLump( wad, lumpname, type ); - return W_ReadLump( wad, lump, lumpsizeptr ); -} - -/* -============================================================================= - -FILESYSTEM IMPLEMENTATION - -============================================================================= -*/ -static byte *W_LoadFile( const char *path, fs_offset_t *lumpsizeptr ) -{ - searchpath_t *search; - int index; - - search = FS_FindFile( path, &index, false ); - if( search && search->wad ) - return W_ReadLump( search->wad, &search->wad->lumps[index], lumpsizeptr ); - return NULL; -} \ No newline at end of file diff --git a/launch/launch.dsp b/launch/launch.dsp index 5506b89f..3c1e94a5 100644 --- a/launch/launch.dsp +++ b/launch/launch.dsp @@ -60,8 +60,8 @@ TargetDir=\Xash3D\src_main\temp\launch\!release InputPath=\Xash3D\src_main\temp\launch\!release\launch.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\launch.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\launch.dll "D:\Xash3D\bin\launch.dll" +"D:\Xash3D\launch.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\launch.dll "D:\Xash3D\launch.dll" # End Custom Build @@ -96,8 +96,8 @@ TargetDir=\Xash3D\src_main\temp\launch\!debug InputPath=\Xash3D\src_main\temp\launch\!debug\launch.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\launch.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\launch.dll "D:\Xash3D\bin\launch.dll" +"D:\Xash3D\launch.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\launch.dll "D:\Xash3D\launch.dll" # End Custom Build diff --git a/launch/system.c b/launch/system.c index b54a40ab..66d6393d 100644 --- a/launch/system.c +++ b/launch/system.c @@ -19,7 +19,7 @@ launch_exp_t *Host; // callback to mainframe sys_event_t event_que[MAX_QUED_EVENTS]; int event_head, event_tail; -dll_info_t xtools_dll = { "xtools.dll", NULL, "CreateAPI", NULL, NULL, 1, sizeof( launch_exp_t ), sizeof( stdlib_api_t ) }; +dll_info_t utils_dll = { "utils.dll", NULL, "CreateAPI", NULL, NULL, 1, sizeof( launch_exp_t ), sizeof( stdlib_api_t ) }; dll_info_t engine_dll = { "engine.dll", NULL, "CreateAPI", NULL, NULL, 1, sizeof( launch_exp_t ), sizeof( stdlib_api_t ) }; static const char *show_credits = "\n\n\n\n\tCopyright XashXT Group %s й\n\t\ @@ -392,28 +392,28 @@ void Sys_LookupInstance( void ) else if( !com.strcmp( Sys.progname, "bsplib" )) { Sys.app_name = HOST_BSPLIB; - Sys.linked_dll = &xtools_dll; // pointer to common.dll info + Sys.linked_dll = &utils_dll; // pointer to common.dll info com.strcpy( Sys.log_path, "bsplib.log" ); // xash3d root directory com.strcpy( Sys.caption, "Xash3D BSP Compiler"); } else if( !com.strcmp( Sys.progname, "sprite" )) { Sys.app_name = HOST_SPRITE; - Sys.linked_dll = &xtools_dll; // pointer to common.dll info + Sys.linked_dll = &utils_dll; // pointer to common.dll info com.sprintf( Sys.log_path, "%s/spritegen.log", sys_rootdir ); // same as .exe file com.strcpy( Sys.caption, "Xash3D Sprite Compiler"); } else if( !com.strcmp( Sys.progname, "studio" )) { Sys.app_name = HOST_STUDIO; - Sys.linked_dll = &xtools_dll; // pointer to common.dll info + Sys.linked_dll = &utils_dll; // pointer to common.dll info com.sprintf( Sys.log_path, "%s/studiomdl.log", sys_rootdir ); // same as .exe file com.strcpy( Sys.caption, "Xash3D Studio Models Compiler" ); } else if( !com.strcmp( Sys.progname, "wadlib" )) { Sys.app_name = HOST_WADLIB; - Sys.linked_dll = &xtools_dll; // pointer to common.dll info + Sys.linked_dll = &utils_dll; // pointer to common.dll info com.sprintf( Sys.log_path, "%s/wadlib.log", sys_rootdir ); // same as .exe file com.strcpy( Sys.caption, "Xash3D Wad2\\Wad3 maker" ); } @@ -422,7 +422,7 @@ void Sys_LookupInstance( void ) Sys.app_name = HOST_RIPPER; Sys.con_readonly = true; Sys.log_active = true; // always create log - Sys.linked_dll = &xtools_dll; // pointer to wdclib.dll info + Sys.linked_dll = &utils_dll; // pointer to wdclib.dll info com.sprintf( Sys.log_path, "%s/decompile.log", sys_rootdir ); // default com.strcpy( Sys.caption, va("Quake Recource Extractor ver.%g", XASH_VERSION )); } @@ -430,7 +430,7 @@ void Sys_LookupInstance( void ) { Sys.app_name = HOST_XIMAGE; Sys.con_readonly = true; - Sys.linked_dll = &xtools_dll; // pointer to dpvenc.dll info + Sys.linked_dll = &utils_dll; // pointer to dpvenc.dll info com.sprintf( Sys.log_path, "%s/image.log", sys_rootdir ); // logs folder com.strcpy( Sys.caption, "Image Processing Tool" ); } @@ -1063,7 +1063,6 @@ qboolean Sys_LoadLibrary( const char *dll_name, dll_info_t *dll ) } else if( dll->entry ) native_lib = true; - if( !dll->link ) dll->link = LoadLibrary ( va( "bin/%s", dll->name )); if( !dll->link ) dll->link = LoadLibrary ( dll->name ); // environment pathes // no DLL found diff --git a/launchers.bat b/launchers.bat index 0e1484ab..adffe9ca 100644 --- a/launchers.bat +++ b/launchers.bat @@ -1,6 +1,6 @@ @echo off -cd xtools +cd utils cd bsplib makefile.nmake diff --git a/gameui/basemenu.cpp b/mainui/basemenu.cpp similarity index 100% rename from gameui/basemenu.cpp rename to mainui/basemenu.cpp diff --git a/gameui/basemenu.h b/mainui/basemenu.h similarity index 95% rename from gameui/basemenu.h rename to mainui/basemenu.h index 20b7a817..a05b441c 100644 --- a/gameui/basemenu.h +++ b/mainui/basemenu.h @@ -1,6 +1,6 @@ //======================================================================= // Copyright XashXT Group 2010 й -// basemenu.h - gameui main header +// basemenu.h - menu basic header //======================================================================= #ifndef BASEMENU_H diff --git a/gameui/enginecallback.h b/mainui/enginecallback.h similarity index 100% rename from gameui/enginecallback.h rename to mainui/enginecallback.h diff --git a/gameui/extdll.h b/mainui/extdll.h similarity index 77% rename from gameui/extdll.h rename to mainui/extdll.h index daf3962c..53ad8807 100644 --- a/gameui/extdll.h +++ b/mainui/extdll.h @@ -1,6 +1,6 @@ //======================================================================= // Copyright XashXT Group 2010 й -// extdll.h - must be included into all gameui files +// extdll.h - must be included into all ui files //======================================================================= #ifndef EXTDLL_H @@ -22,12 +22,8 @@ #include #include -// shared engine/DLL constants -#include "const.h" +#define bound( min, num, max ) ((num) >= (min) ? ((num) < (max) ? (num) : (max)) : (min)) -// Vector class -#include "vector.h" - -#include "gameui_api.h" +#include "menu_int.h" #endif//EXTDLL_H \ No newline at end of file diff --git a/gameui/images.h b/mainui/images.h similarity index 100% rename from gameui/images.h rename to mainui/images.h diff --git a/mainui/mainui.def b/mainui/mainui.def new file mode 100644 index 00000000..d1511cc7 --- /dev/null +++ b/mainui/mainui.def @@ -0,0 +1,5 @@ +LIBRARY mainui +EXPORTS + GetMenuAPI @1 +SECTIONS + .data READ WRITE diff --git a/gameui/gameui.dsp b/mainui/mainui.dsp similarity index 73% rename from gameui/gameui.dsp rename to mainui/mainui.dsp index a25d15ed..d65618ce 100644 --- a/gameui/gameui.dsp +++ b/mainui/mainui.dsp @@ -1,24 +1,24 @@ -# Microsoft Developer Studio Project File - Name="gameui" - Package Owner=<4> +# Microsoft Developer Studio Project File - Name="mainui" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=gameui - Win32 Debug +CFG=mainui - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "gameui.mak". +!MESSAGE NMAKE /f "mainui.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "gameui.mak" CFG="gameui - Win32 Debug" +!MESSAGE NMAKE /f "mainui.mak" CFG="mainui - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "gameui - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "gameui - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mainui - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "mainui - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -29,7 +29,7 @@ CPP=cl.exe MTL=midl.exe RSC=rc.exe -!IF "$(CFG)" == "gameui - Win32 Release" +!IF "$(CFG)" == "mainui - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 @@ -38,12 +38,12 @@ RSC=rc.exe # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\gameui\!release" -# PROP Intermediate_Dir "..\temp\gameui\!release" +# PROP Output_Dir "..\temp\mainui\!release" +# PROP Intermediate_Dir "..\temp\mainui\!release" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /c -# ADD CPP /nologo /W3 /GX /O2 /I "./" /I "../common" /I "../game_shared" /I "../engine" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "./" /I "../common" /I "../pm_shared" /I "../engine" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -54,19 +54,19 @@ BSC32=bscmake.exe # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /opt:nowin98 -# ADD LINK32 msvcrt.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /def:".\gameui.def" /opt:nowin98 +# ADD LINK32 msvcrt.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /def:".\mainui.def" /opt:nowin98 # SUBTRACT LINK32 /profile /nodefaultlib # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\gameui\!release -InputPath=\Xash3D\src_main\temp\gameui\!release\gameui.dll +TargetDir=\Xash3D\src_main\temp\mainui\!release +InputPath=\Xash3D\src_main\temp\mainui\!release\mainui.dll SOURCE="$(InputPath)" -"D:\Xash3D\valve\bin\GameUI.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\gameui.dll "D:\Xash3D\valve\bin\GameUI.dll" +"D:\Xash3D\valve\cl_dlls\MainUI.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\mainui.dll "D:\Xash3D\valve\cl_dlls\MainUI.dll" # End Custom Build -!ELSEIF "$(CFG)" == "gameui - Win32 Debug" +!ELSEIF "$(CFG)" == "mainui - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 @@ -75,12 +75,12 @@ SOURCE="$(InputPath)" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\temp\gameui\!debug" -# PROP Intermediate_Dir "..\temp\gameui\!debug" +# PROP Output_Dir "..\temp\mainui\!debug" +# PROP Intermediate_Dir "..\temp\mainui\!debug" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../common" /I "../game_shared" /I "../engine" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "./" /I "../common" /I "../pm_shared" /I "../engine" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 @@ -90,16 +90,16 @@ BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe -# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /def:".\gameui.def" /pdbtype:sept -# ADD LINK32 msvcrtd.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /def:".\gameui.def" /pdbtype:sept +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /def:".\mainui.def" /pdbtype:sept +# ADD LINK32 msvcrtd.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"msvcrt.lib" /def:".\mainui.def" /pdbtype:sept # SUBTRACT LINK32 /incremental:no /nodefaultlib # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\gameui\!debug -InputPath=\Xash3D\src_main\temp\gameui\!debug\gameui.dll +TargetDir=\Xash3D\src_main\temp\mainui\!debug +InputPath=\Xash3D\src_main\temp\mainui\!debug\mainui.dll SOURCE="$(InputPath)" -"D:\Xash3D\valve\bin\GameUI.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\gameui.dll "D:\Xash3D\valve\bin\GameUI.dll" +"D:\Xash3D\valve\cl_dlls\MainUI.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\mainui.dll "D:\Xash3D\valve\cl_dlls\MainUI.dll" # End Custom Build @@ -107,8 +107,8 @@ SOURCE="$(InputPath)" # Begin Target -# Name "gameui - Win32 Release" -# Name "gameui - Win32 Debug" +# Name "mainui - Win32 Release" +# Name "mainui - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" diff --git a/gameui/menu_advcontrols.cpp b/mainui/menu_advcontrols.cpp similarity index 100% rename from gameui/menu_advcontrols.cpp rename to mainui/menu_advcontrols.cpp diff --git a/gameui/menu_audio.cpp b/mainui/menu_audio.cpp similarity index 100% rename from gameui/menu_audio.cpp rename to mainui/menu_audio.cpp diff --git a/gameui/menu_configuration.cpp b/mainui/menu_configuration.cpp similarity index 100% rename from gameui/menu_configuration.cpp rename to mainui/menu_configuration.cpp diff --git a/gameui/menu_controls.cpp b/mainui/menu_controls.cpp similarity index 100% rename from gameui/menu_controls.cpp rename to mainui/menu_controls.cpp diff --git a/gameui/menu_creategame.cpp b/mainui/menu_creategame.cpp similarity index 100% rename from gameui/menu_creategame.cpp rename to mainui/menu_creategame.cpp diff --git a/gameui/menu_credits.cpp b/mainui/menu_credits.cpp similarity index 100% rename from gameui/menu_credits.cpp rename to mainui/menu_credits.cpp diff --git a/gameui/menu_customgame.cpp b/mainui/menu_customgame.cpp similarity index 100% rename from gameui/menu_customgame.cpp rename to mainui/menu_customgame.cpp diff --git a/gameui/menu_gameoptions.cpp b/mainui/menu_gameoptions.cpp similarity index 100% rename from gameui/menu_gameoptions.cpp rename to mainui/menu_gameoptions.cpp diff --git a/gameui/menu_langame.cpp b/mainui/menu_langame.cpp similarity index 100% rename from gameui/menu_langame.cpp rename to mainui/menu_langame.cpp diff --git a/gameui/menu_loadgame.cpp b/mainui/menu_loadgame.cpp similarity index 100% rename from gameui/menu_loadgame.cpp rename to mainui/menu_loadgame.cpp diff --git a/gameui/menu_main.cpp b/mainui/menu_main.cpp similarity index 100% rename from gameui/menu_main.cpp rename to mainui/menu_main.cpp diff --git a/gameui/menu_multiplayer.cpp b/mainui/menu_multiplayer.cpp similarity index 100% rename from gameui/menu_multiplayer.cpp rename to mainui/menu_multiplayer.cpp diff --git a/gameui/menu_newgame.cpp b/mainui/menu_newgame.cpp similarity index 100% rename from gameui/menu_newgame.cpp rename to mainui/menu_newgame.cpp diff --git a/gameui/menu_playdemo.cpp b/mainui/menu_playdemo.cpp similarity index 100% rename from gameui/menu_playdemo.cpp rename to mainui/menu_playdemo.cpp diff --git a/gameui/menu_playersetup.cpp b/mainui/menu_playersetup.cpp similarity index 96% rename from gameui/menu_playersetup.cpp rename to mainui/menu_playersetup.cpp index fd2b6528..cec92000 100644 --- a/gameui/menu_playersetup.cpp +++ b/mainui/menu_playersetup.cpp @@ -18,7 +18,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +#include "mathlib.h" #include "extdll.h" +#include "const.h" #include "basemenu.h" #include "utils.h" #include "keydefs.h" @@ -389,8 +391,6 @@ static void UI_PlayerSetup_Init( void ) uiPlayerSetup.refdef.viewport[3] = uiPlayerSetup.view.generic.height-(uiPlayerSetup.view.generic.height / 6); UI_PlayerSetup_CalcFov( &uiPlayerSetup.refdef ); - uiPlayerSetup.refdef.flags = RDF_NOWORLDMODEL; - uiPlayerSetup.ent = GET_MENU_EDICT (); if( !uiPlayerSetup.ent ) diff --git a/gameui/menu_playrec.cpp b/mainui/menu_playrec.cpp similarity index 100% rename from gameui/menu_playrec.cpp rename to mainui/menu_playrec.cpp diff --git a/gameui/menu_recdemo.cpp b/mainui/menu_recdemo.cpp similarity index 100% rename from gameui/menu_recdemo.cpp rename to mainui/menu_recdemo.cpp diff --git a/gameui/menu_savegame.cpp b/mainui/menu_savegame.cpp similarity index 100% rename from gameui/menu_savegame.cpp rename to mainui/menu_savegame.cpp diff --git a/gameui/menu_saveload.cpp b/mainui/menu_saveload.cpp similarity index 100% rename from gameui/menu_saveload.cpp rename to mainui/menu_saveload.cpp diff --git a/gameui/menu_video.cpp b/mainui/menu_video.cpp similarity index 100% rename from gameui/menu_video.cpp rename to mainui/menu_video.cpp diff --git a/gameui/menu_vidmodes.cpp b/mainui/menu_vidmodes.cpp similarity index 100% rename from gameui/menu_vidmodes.cpp rename to mainui/menu_vidmodes.cpp diff --git a/gameui/menu_vidoptions.cpp b/mainui/menu_vidoptions.cpp similarity index 100% rename from gameui/menu_vidoptions.cpp rename to mainui/menu_vidoptions.cpp diff --git a/gameui/udll_int.cpp b/mainui/udll_int.cpp similarity index 88% rename from gameui/udll_int.cpp rename to mainui/udll_int.cpp index 8143523b..6da8ffec 100644 --- a/gameui/udll_int.cpp +++ b/mainui/udll_int.cpp @@ -40,7 +40,7 @@ static UI_FUNCTIONS gFunctionTable = //======================================================================= // GetApi //======================================================================= -int CreateAPI( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* pEngfuncsFromEngine, ui_globalvars_t *pGlobals ) +int GetMenuAPI( UI_FUNCTIONS *pFunctionTable, ui_enginefuncs_t* pEngfuncsFromEngine, ui_globalvars_t *pGlobals ) { if( !pFunctionTable || !pEngfuncsFromEngine ) { diff --git a/gameui/utils.cpp b/mainui/utils.cpp similarity index 100% rename from gameui/utils.cpp rename to mainui/utils.cpp diff --git a/gameui/utils.h b/mainui/utils.h similarity index 100% rename from gameui/utils.h rename to mainui/utils.h diff --git a/public/launch_api.h b/public/launch_api.h index d3b34373..1027fe6b 100644 --- a/public/launch_api.h +++ b/public/launch_api.h @@ -10,6 +10,7 @@ #pragma warning(disable : 4018) // signed/unsigned mismatch #pragma warning(disable : 4305) // truncation from const double to float +#define QCHAR_WIDTH 16 // font width #define MAX_STRING 256 // generic string #define MAX_INFO_STRING 256 // infostrings are transmitted across network #define MAX_SYSPATH 1024 // system filepath @@ -18,18 +19,16 @@ #define MAX_STRING_TABLES 8 // seperately stringsystems #define EXPORT __declspec( dllexport ) #define BIT( n ) (1<<( n )) -#define trace_t TraceResult #define NULL ((void *)0) // color strings #define IsColorString( p ) ( p && *( p ) == '^' && *(( p ) + 1) && *(( p ) + 1) >= '0' && *(( p ) + 1 ) <= '9' ) -#include "const.h" - typedef unsigned long dword; typedef unsigned int uint; typedef int sound_t; typedef int shader_t; +typedef float vec_t; typedef vec_t vec2_t[2]; typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4]; @@ -40,6 +39,8 @@ typedef vec_t matrix3x3[3][3]; typedef vec_t matrix4x4[4][4]; typedef char string[MAX_STRING]; +#include "const.h" + // platform instances typedef enum { diff --git a/public/render_api.h b/public/render_api.h index eaade310..28f86ecc 100644 --- a/public/render_api.h +++ b/public/render_api.h @@ -43,34 +43,6 @@ typedef struct vec3_t lightingOrigin; } poly_t; -#define MAX_SCOREBOARDNAME 32 - -// NOTE: share this with user SDK when StudioRenderer will be moved on the client.dll -typedef struct player_info_s -{ - int userid; // User id on server - char userinfo[MAX_INFO_STRING]; // User info string - char name[MAX_SCOREBOARDNAME]; // Name (extracted from userinfo) - int spectator; // Spectator or not, unused - - int ping; - int packet_loss; - - // skin information - char model[64]; - int topcolor; - int bottomcolor; - - // last frame rendered - int renderframe; - - // Gait frame estimation - int gaitsequence; - float gaitframe; - float gaityaw; - vec3_t prevgaitorigin; -} player_info_t; - typedef struct { vec3_t position; @@ -117,7 +89,7 @@ typedef struct render_exp_s void (*ClearScene)( void ); void (*BeginFrame)( qboolean clearScene ); - void (*RenderFrame)( const ref_params_t *fd ); + void (*RenderFrame)( const ref_params_t *fd, qboolean drawWorld ); void (*EndFrame)( void ); // triapi implementation @@ -130,8 +102,6 @@ typedef struct render_exp_s void (*TexCoord2f)( const float u, const float v ); void (*Bind)( shader_t shader, int frame ); void (*CullFace)( int mode ); - void (*Enable)( int cap ); - void (*Disable)( int cap ); void (*Begin)( int mode ); void (*End)( void ); @@ -141,6 +111,7 @@ typedef struct render_exp_s void (*GetParms)( int *w, int *h, int *frames, int frame, shader_t shader ); qboolean (*ScrShot)( const char *filename, int shot_type ); // write screenshot with same name qboolean (*EnvShot)( const char *filename, uint size, const float *vieworg, qboolean skyshot ); + void (*SetSkyPortal)( const vec3_t vieworg, const vec3_t viewangles, float scale, float fov ); void (*LightForPoint)( const vec3_t point, vec3_t ambientLight ); void (*DrawStretchRaw)( float x, float y, float w, float h, int cols, int rows, byte *data, qboolean redraw ); void (*DrawStretchPic)( float x, float y, float w, float h, float s1, float t1, float s2, float t2, shader_t shader ); @@ -162,15 +133,16 @@ typedef struct render_imp_s // client fundamental callbacks void (*UpdateScreen)( void ); // update screen while loading void (*StudioEvent)( struct mstudioevent_s *event, struct cl_entity_s *ent ); - void (*StudioFxTransform)( struct cl_entity_s *ent, float matrix[4][4] ); void (*ShowCollision)( cmdraw_t callback ); // debug long (*WndProc)( void *hWnd, uint uMsg, uint wParam, long lParam ); - struct cl_entity_s *(*GetClientEdict)( int index ); // get rid of this + struct cl_entity_s *(*GetClientEdict)( int index ); struct player_info_s *(*GetPlayerInfo)( int playerIndex ); // not an entityIndex!!! struct cl_entity_s *(*GetLocalPlayer)( void ); int (*GetMaxClients)( void ); void (*DrawTriangles)( int fTrans ); + qboolean (*IsThirdPerson)( void ); void (*ExtraUpdate)( void ); // call during RenderFrame + float (*GetLerpFrac)( void ); } render_imp_t; #endif//RENDER_API_H \ No newline at end of file diff --git a/release.bat b/release.bat index 0e15349f..06bb707a 100644 --- a/release.bat +++ b/release.bat @@ -11,13 +11,13 @@ call vcvars32 %MSDEV% dlls/hl.dsp %CONFIG%"hl - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% client/client.dsp %CONFIG%"client - Win32 Release" %build_target% +%MSDEV% cl_dll/cl_dll.dsp %CONFIG%"cl_dll - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 %MSDEV% engine/engine.dsp %CONFIG%"engine - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% gameui/gameui.dsp %CONFIG%"gameui - Win32 Release" %build_target% +%MSDEV% mainui/mainui.dsp %CONFIG%"mainui - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 %MSDEV% launch/launch.dsp %CONFIG%"launch - Win32 Release" %build_target% @@ -29,7 +29,7 @@ if errorlevel 1 set BUILD_ERROR=1 %MSDEV% snd_dx/snd_dx.dsp %CONFIG%"snd_dx - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 -%MSDEV% xtools/xtools.dsp %CONFIG%"xtools - Win32 Release" %build_target% +%MSDEV% utils/utils.dsp %CONFIG%"utils - Win32 Release" %build_target% if errorlevel 1 set BUILD_ERROR=1 if "%BUILD_ERROR%"=="" goto build_ok @@ -52,13 +52,13 @@ goto done rem //delete log files if exist dlls\hl.plg del /f /q dlls\hl.plg -if exist client\client.plg del /f /q client\client.plg +if exist cl_dll\cl_dll.plg del /f /q cl_dll\cl_dll.plg if exist engine\engine.plg del /f /q engine\engine.plg -if exist gameui\gameui.plg del /f /q gameui\gameui.plg +if exist mainui\mainui.plg del /f /q mainui\mainui.plg if exist launch\launch.plg del /f /q launch\launch.plg if exist vid_gl\vid_gl.plg del /f /q vid_gl\vid_gl.plg if exist snd_dx\snd_dx.plg del /f /q snd_dx\snd_dx.plg -if exist xtools\xtools.plg del /f /q xtools\xtools.plg +if exist utils\utils.plg del /f /q utils\utils.plg echo echo Build succeeded! diff --git a/snd_dx/snd_dx.dsp b/snd_dx/snd_dx.dsp index 1bce253d..7728ce33 100644 --- a/snd_dx/snd_dx.dsp +++ b/snd_dx/snd_dx.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /c -# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "../public" /I "../common" /I "../game_shared" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /I "./" /I "../public" /I "../common" /I "../pm_shared" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -61,8 +61,8 @@ TargetDir=\Xash3D\src_main\temp\snd_dx\!release InputPath=\Xash3D\src_main\temp\snd_dx\!release\snd_dx.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\snd_dx.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\snd_dx.dll "D:\Xash3D\bin\snd_dx.dll" +"D:\Xash3D\snd_dx.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\snd_dx.dll "D:\Xash3D\snd_dx.dll" # End Custom Build @@ -80,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /I "../common" /I "../game_shared" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "./" /I "../public" /I "../common" /I "../pm_shared" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /GZ /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 @@ -98,8 +98,8 @@ TargetDir=\Xash3D\src_main\temp\snd_dx\!debug InputPath=\Xash3D\src_main\temp\snd_dx\!debug\snd_dx.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\snd_dx.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\snd_dx.dll "D:\Xash3D\bin\snd_dx.dll" +"D:\Xash3D\snd_dx.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\snd_dx.dll "D:\Xash3D\snd_dx.dll" # End Custom Build diff --git a/xtools/badimage.h b/utils/badimage.h similarity index 100% rename from xtools/badimage.h rename to utils/badimage.h diff --git a/xtools/bsplib.c b/utils/bsplib.c similarity index 76% rename from xtools/bsplib.c rename to utils/bsplib.c index 17473a58..1ed26616 100644 --- a/xtools/bsplib.c +++ b/utils/bsplib.c @@ -1,4 +1,3 @@ -#include "xtools.h" #include "utils.h" // FIXME: implement bsplib @@ -12,7 +11,7 @@ void Bsp_PrintLog( const char *pMsg ) qboolean PrepareBSPModel( int argc, char **argv ) { - Sys_Break( "\r\rbsplib not implemented. Wait for Xash 0.72\r\r" ); + Sys_Break( "\r\rbsplib not implemented. Wait for Xash 0.75\r\r" ); return false; } diff --git a/xtools/bsplib/bsplib.c b/utils/bsplib/bsplib.c similarity index 100% rename from xtools/bsplib/bsplib.c rename to utils/bsplib/bsplib.c diff --git a/xtools/bsplib/bsplib.rc b/utils/bsplib/bsplib.rc similarity index 100% rename from xtools/bsplib/bsplib.rc rename to utils/bsplib/bsplib.rc diff --git a/xtools/bsplib/makefile.nmake b/utils/bsplib/makefile.nmake similarity index 85% rename from xtools/bsplib/makefile.nmake rename to utils/bsplib/makefile.nmake index e42ffe85..2585687e 100644 --- a/xtools/bsplib/makefile.nmake +++ b/utils/bsplib/makefile.nmake @@ -16,7 +16,7 @@ default: $(MAINTARGET).exe $(MAINTARGET).exe: $(MAINTARGET).obj bsplib.res $(link) $(OBJS) bsplib.res /out:"bsplib.exe" /subsystem:console /opt:nowin98 /nodefaultlib:"libc.lib" @del $(MAINTARGET).obj $(MAINTARGET).lib $(MAINTARGET).exp $(MAINTARGET).res > nul - @copy $(MAINTARGET).exe D:\Xash3D\bin\$(MAINTARGET).exe + @copy $(MAINTARGET).exe D:\Xash3D\$(MAINTARGET).exe @del $(MAINTARGET).exe @echo Скопировано файлов: 1. clean: diff --git a/xtools/bsplib/tool.ico b/utils/bsplib/tool.ico similarity index 100% rename from xtools/bsplib/tool.ico rename to utils/bsplib/tool.ico diff --git a/xtools/extragen/extragen.c b/utils/extragen/extragen.c similarity index 100% rename from xtools/extragen/extragen.c rename to utils/extragen/extragen.c diff --git a/xtools/extragen/extragen.rc b/utils/extragen/extragen.rc similarity index 100% rename from xtools/extragen/extragen.rc rename to utils/extragen/extragen.rc diff --git a/xtools/extragen/makefile.nmake b/utils/extragen/makefile.nmake similarity index 85% rename from xtools/extragen/makefile.nmake rename to utils/extragen/makefile.nmake index 8d193fb0..6e5a3a52 100644 --- a/xtools/extragen/makefile.nmake +++ b/utils/extragen/makefile.nmake @@ -16,7 +16,7 @@ default: $(MAINTARGET).exe $(MAINTARGET).exe: $(MAINTARGET).obj extragen.res $(link) $(OBJS) extragen.res /out:"extragen.exe" /subsystem:console /opt:nowin98 /nodefaultlib:"libc.lib" @del $(MAINTARGET).obj $(MAINTARGET).lib $(MAINTARGET).exp $(MAINTARGET).res > nul - @copy $(MAINTARGET).exe D:\Xash3D\bin\$(MAINTARGET).exe + @copy $(MAINTARGET).exe D:\Xash3D\$(MAINTARGET).exe @del $(MAINTARGET).exe @echo Скопировано файлов: 1. clean: diff --git a/xtools/extragen/tool.ico b/utils/extragen/tool.ico similarity index 100% rename from xtools/extragen/tool.ico rename to utils/extragen/tool.ico diff --git a/xtools/mdllib.h b/utils/mdllib.h similarity index 94% rename from xtools/mdllib.h rename to utils/mdllib.h index 459480f5..57a0a635 100644 --- a/xtools/mdllib.h +++ b/utils/mdllib.h @@ -5,7 +5,6 @@ #ifndef STUDIOMDL_H #define STUDIOMDL_H -#include "xtools.h" #include "utils.h" #include "studio.h" #include "mathlib.h" diff --git a/xtools/ripper/conv_bsplumps.c b/utils/ripper/conv_bsplumps.c similarity index 100% rename from xtools/ripper/conv_bsplumps.c rename to utils/ripper/conv_bsplumps.c diff --git a/xtools/ripper/conv_doom.c b/utils/ripper/conv_doom.c similarity index 100% rename from xtools/ripper/conv_doom.c rename to utils/ripper/conv_doom.c diff --git a/xtools/ripper/conv_image.c b/utils/ripper/conv_image.c similarity index 100% rename from xtools/ripper/conv_image.c rename to utils/ripper/conv_image.c diff --git a/xtools/ripper/conv_main.c b/utils/ripper/conv_main.c similarity index 100% rename from xtools/ripper/conv_main.c rename to utils/ripper/conv_main.c diff --git a/xtools/ripper/conv_shader.c b/utils/ripper/conv_shader.c similarity index 95% rename from xtools/ripper/conv_shader.c rename to utils/ripper/conv_shader.c index 506a41bf..58b82273 100644 --- a/xtools/ripper/conv_shader.c +++ b/utils/ripper/conv_shader.c @@ -60,6 +60,26 @@ int animcount; // process counter int num_anims; // shader total count file_t *f; +static float ColorNormalize( const vec3_t in, vec3_t out ) +{ + float max, scale; + + max = in[0]; + if( in[1] > max ) max = in[1]; + if( in[2] > max ) max = in[2]; + + if( max == 0 ) + { + out[0] = out[1] = out[2] = 1.0f; + return 0; + } + + scale = 1.0f / max; + VectorScale( in, scale, out ); + + return max; +} + qboolean Conv_WriteShader( const char *shaderpath, const char *imagepath, rgbdata_t *p, float *rad, float scale, int flags, int contents ) { file_t *f = NULL; diff --git a/xtools/ripper/conv_sprite.c b/utils/ripper/conv_sprite.c similarity index 100% rename from xtools/ripper/conv_sprite.c rename to utils/ripper/conv_sprite.c diff --git a/xtools/ripper/ripper.h b/utils/ripper/ripper.h similarity index 96% rename from xtools/ripper/ripper.h rename to utils/ripper/ripper.h index 11c3af2c..476e7c0f 100644 --- a/xtools/ripper/ripper.h +++ b/utils/ripper/ripper.h @@ -5,7 +5,7 @@ #ifndef BASECONVERTOR_H #define BASECONVERTOR_H -#include "xtools.h" +#include "utils.h" extern stdlib_api_t com; extern byte *basepool; diff --git a/xtools/rundll.h b/utils/rundll.h similarity index 91% rename from xtools/rundll.h rename to utils/rundll.h index 7d1a5f06..852177da 100644 --- a/xtools/rundll.h +++ b/utils/rundll.h @@ -101,21 +101,21 @@ void GetLibrary( void ) if( GetBin( )) { // assume run directory as XashDirectory - strcpy( szSearch[count], "bin\\launch.dll" ); + strcpy( szSearch[count], "launch.dll" ); count++; } if( GetEnv( )) { // get environment variable (e.g. compilers) - sprintf( szSearch[count], "%s\\bin\\launch.dll", szFsPath ); + sprintf( szSearch[count], "%s\\launch.dll", szFsPath ); count++; } if( GetReg( )) { // get environment variable direct from registry (paranoid) - sprintf( szSearch[count], "%s\\bin\\launch.dll", szFsPath ); + sprintf( szSearch[count], "%s\\launch.dll", szFsPath ); count++; } diff --git a/xtools/sprite/makefile.nmake b/utils/sprite/makefile.nmake similarity index 85% rename from xtools/sprite/makefile.nmake rename to utils/sprite/makefile.nmake index bae465cd..96f09968 100644 --- a/xtools/sprite/makefile.nmake +++ b/utils/sprite/makefile.nmake @@ -16,7 +16,7 @@ default: $(MAINTARGET).exe $(MAINTARGET).exe: $(MAINTARGET).obj spritegen.res $(link) $(OBJS) spritegen.res /out:"spritegen.exe" /subsystem:windows /opt:nowin98 /nodefaultlib:"libc.lib" @del $(MAINTARGET).obj $(MAINTARGET).lib $(MAINTARGET).exp $(MAINTARGET).res > nul - @copy $(MAINTARGET).exe D:\Xash3D\bin\$(MAINTARGET).exe + @copy $(MAINTARGET).exe D:\Xash3D\$(MAINTARGET).exe @del $(MAINTARGET).exe @echo Скопировано файлов: 1. clean: diff --git a/xtools/sprite/spritegen.c b/utils/sprite/spritegen.c similarity index 100% rename from xtools/sprite/spritegen.c rename to utils/sprite/spritegen.c diff --git a/xtools/sprite/spritegen.rc b/utils/sprite/spritegen.rc similarity index 100% rename from xtools/sprite/spritegen.rc rename to utils/sprite/spritegen.rc diff --git a/xtools/sprite/tool.ico b/utils/sprite/tool.ico similarity index 100% rename from xtools/sprite/tool.ico rename to utils/sprite/tool.ico diff --git a/xtools/spritegen.c b/utils/spritegen.c similarity index 96% rename from xtools/spritegen.c rename to utils/spritegen.c index 6115feeb..14e5f335 100644 --- a/xtools/spritegen.c +++ b/utils/spritegen.c @@ -3,10 +3,9 @@ // sprlib.c - sprite generator //======================================================================= -#include "xtools.h" +#include "utils.h" #include "sprite.h" #include "byteorder.h" -#include "utils.h" #include "mathlib.h" #define MAX_FRAMES 256 diff --git a/xtools/studio.c b/utils/studio.c similarity index 96% rename from xtools/studio.c rename to utils/studio.c index 10bcbe8f..c5e3aef0 100644 --- a/xtools/studio.c +++ b/utils/studio.c @@ -3,8 +3,8 @@ // studio.c - half-life model compiler //======================================================================= -#include "const.h" #include "mdllib.h" +#include "const.h" #include "matrix_lib.h" #include "stdio.h" // sscanf diff --git a/xtools/studio/makefile.nmake b/utils/studio/makefile.nmake similarity index 85% rename from xtools/studio/makefile.nmake rename to utils/studio/makefile.nmake index 6ae34e9a..87f0b051 100644 --- a/xtools/studio/makefile.nmake +++ b/utils/studio/makefile.nmake @@ -16,7 +16,7 @@ default: $(MAINTARGET).exe $(MAINTARGET).exe: $(MAINTARGET).obj studiomdl.res $(link) $(OBJS) studiomdl.res /out:"studiomdl.exe" /subsystem:windows /opt:nowin98 /nodefaultlib:"libc.lib" @del $(MAINTARGET).obj $(MAINTARGET).lib $(MAINTARGET).exp $(MAINTARGET).res > nul - @copy $(MAINTARGET).exe D:\Xash3D\bin\$(MAINTARGET).exe + @copy $(MAINTARGET).exe D:\Xash3D\$(MAINTARGET).exe @del $(MAINTARGET).exe @echo Скопировано файлов: 1. clean: diff --git a/xtools/studio/studiomdl.c b/utils/studio/studiomdl.c similarity index 100% rename from xtools/studio/studiomdl.c rename to utils/studio/studiomdl.c diff --git a/xtools/studio/studiomdl.rc b/utils/studio/studiomdl.rc similarity index 100% rename from xtools/studio/studiomdl.rc rename to utils/studio/studiomdl.rc diff --git a/xtools/studio/tool.ico b/utils/studio/tool.ico similarity index 100% rename from xtools/studio/tool.ico rename to utils/studio/tool.ico diff --git a/xtools/studio_utils.c b/utils/studio_utils.c similarity index 100% rename from xtools/studio_utils.c rename to utils/studio_utils.c diff --git a/xtools/xtools.c b/utils/utils.c similarity index 78% rename from xtools/xtools.c rename to utils/utils.c index 0b5c8939..1340f936 100644 --- a/xtools/xtools.c +++ b/utils/utils.c @@ -3,10 +3,8 @@ // platform.c - tools common dll //======================================================================= -#include "xtools.h" #include "utils.h" #include "mdllib.h" -#include "xtools.h" #include "engine_api.h" #include "mathlib.h" #include "badimage.h" @@ -20,6 +18,8 @@ string searchmask[MAX_SEARCHMASK]; int num_searchmask = 0; string gs_searchmask; string gs_gamedir; +string gs_basedir; +string gs_filename; byte *basepool; byte *zonepool; byte *error_bmp; @@ -46,6 +46,48 @@ void AddMask( const char *mask ) num_searchmask++; } +/* +================ +Com_ValidScript + +validate qc-script for unexcpected keywords +================ +*/ +qboolean Com_ValidScript( const char *token, qctype_t scripttype ) +{ + if( !com.stricmp( token, "$spritename") && scripttype != QC_SPRITEGEN ) + { + Msg( "%s probably spritegen qc.script, skipping...\n", gs_filename ); + return false; + } + else if( !com.stricmp( token, "$resample" ) && scripttype != QC_SPRITEGEN ) + { + Msg( "%s probably spritegen qc.script, skipping...\n", gs_filename ); + return false; + } + else if( !com.stricmp( token, "$modelname" ) && scripttype != QC_STUDIOMDL ) + { + Msg( "%s probably studio qc.script, skipping...\n", gs_filename ); + return false; + } + else if( !com.stricmp( token, "$body" ) && scripttype != QC_STUDIOMDL ) + { + Msg( "%s probably studio qc.script, skipping...\n", gs_filename ); + return false; + } + else if( !com.stricmp( token, "$wadname" ) && scripttype != QC_WADLIB ) + { + Msg( "%s probably wadlib qc.script, skipping...\n", gs_filename ); + return false; + } + else if( !com.stricmp( token, "$mipmap" ) && scripttype != QC_WADLIB ) + { + Msg("%s probably wadlib qc.script, skipping...\n", gs_filename ); + return false; + } + return true; +} + /* ================== CommonInit diff --git a/xtools/xtools.dsp b/utils/utils.dsp similarity index 75% rename from xtools/xtools.dsp rename to utils/utils.dsp index 7d421780..c44104d8 100644 --- a/xtools/xtools.dsp +++ b/utils/utils.dsp @@ -1,24 +1,24 @@ -# Microsoft Developer Studio Project File - Name="xtools" - Package Owner=<4> +# Microsoft Developer Studio Project File - Name="utils" - Package Owner=<4> # Microsoft Developer Studio Generated Build File, Format Version 6.00 # ** DO NOT EDIT ** # TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 -CFG=xtools - Win32 Debug +CFG=utils - Win32 Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE -!MESSAGE NMAKE /f "xtools.mak". +!MESSAGE NMAKE /f "utils.mak". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE -!MESSAGE NMAKE /f "xtools.mak" CFG="xtools - Win32 Debug" +!MESSAGE NMAKE /f "utils.mak" CFG="utils - Win32 Debug" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE -!MESSAGE "xtools - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") -!MESSAGE "xtools - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "utils - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "utils - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") !MESSAGE # Begin Project @@ -29,7 +29,7 @@ CPP=cl.exe MTL=midl.exe RSC=rc.exe -!IF "$(CFG)" == "xtools - Win32 Release" +!IF "$(CFG)" == "utils - Win32 Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 @@ -38,8 +38,8 @@ RSC=rc.exe # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 -# PROP Output_Dir "..\temp\xtools\!release" -# PROP Intermediate_Dir "..\temp\xtools\!release" +# PROP Output_Dir "..\temp\utils\!release" +# PROP Intermediate_Dir "..\temp\utils\!release" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /c @@ -57,16 +57,16 @@ LINK32=link.exe # ADD LINK32 msvcrt.lib /nologo /dll /pdb:none /machine:I386 /nodefaultlib:"libc.lib" /opt:nowin98 # SUBTRACT LINK32 /profile # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\xtools\!release -InputPath=\Xash3D\src_main\temp\xtools\!release\xtools.dll +TargetDir=\Xash3D\src_main\temp\utils\!release +InputPath=\Xash3D\src_main\temp\utils\!release\utils.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\xtools.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\xtools.dll "D:\Xash3D\bin\xtools.dll" +"D:\Xash3D\utils.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\utils.dll "D:\Xash3D\utils.dll" # End Custom Build -!ELSEIF "$(CFG)" == "xtools - Win32 Debug" +!ELSEIF "$(CFG)" == "utils - Win32 Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 @@ -75,8 +75,8 @@ SOURCE="$(InputPath)" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 -# PROP Output_Dir "..\temp\xtools\!debug" -# PROP Intermediate_Dir "..\temp\xtools\!debug" +# PROP Output_Dir "..\temp\utils\!debug" +# PROP Intermediate_Dir "..\temp\utils\!debug" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "" # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "PLATFORM_EXPORTS" /YX /FD /GZ /c @@ -94,12 +94,12 @@ LINK32=link.exe # ADD LINK32 msvcrtd.lib user32.lib /nologo /dll /debug /machine:I386 /nodefaultlib:"libc.lib" /pdbtype:sept # SUBTRACT LINK32 /incremental:no /nodefaultlib # Begin Custom Build -TargetDir=\Xash3D\src_main\temp\xtools\!debug -InputPath=\Xash3D\src_main\temp\xtools\!debug\xtools.dll +TargetDir=\Xash3D\src_main\temp\utils\!debug +InputPath=\Xash3D\src_main\temp\utils\!debug\utils.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\xtools.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\xtools.dll "D:\Xash3D\bin\xtools.dll" +"D:\Xash3D\utils.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\utils.dll "D:\Xash3D\utils.dll" # End Custom Build @@ -107,8 +107,8 @@ SOURCE="$(InputPath)" # Begin Target -# Name "xtools - Win32 Release" -# Name "xtools - Win32 Debug" +# Name "utils - Win32 Release" +# Name "utils - Win32 Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" @@ -154,10 +154,6 @@ SOURCE=.\studio_utils.c # End Source File # Begin Source File -SOURCE=.\utils.c -# End Source File -# Begin Source File - SOURCE=.\wadlib.c # End Source File # Begin Source File @@ -166,7 +162,7 @@ SOURCE=.\ximage.c # End Source File # Begin Source File -SOURCE=.\xtools.c +SOURCE=.\utils.c # End Source File # End Group # Begin Group "Header Files" @@ -184,10 +180,6 @@ SOURCE=.\ripper\ripper.h SOURCE=.\utils.h # End Source File -# Begin Source File - -SOURCE=.\xtools.h -# End Source File # End Group # End Target # End Project diff --git a/xtools/utils.h b/utils/utils.h similarity index 70% rename from xtools/utils.h rename to utils/utils.h index 9d6dee56..286c87a3 100644 --- a/xtools/utils.h +++ b/utils/utils.h @@ -6,8 +6,9 @@ #define UTILS_H #include +#include +#include "launch_api.h" -// bsplib compile flags #define ALIGN( a ) a = (byte *)((int)((byte *)a + 3) & ~ 3) extern byte *basepool; @@ -34,11 +35,8 @@ typedef enum QC_WADLIB } qctype_t; -qboolean Com_ValidScript( const char *token, qctype_t script_type ); -float ColorNormalize( const vec3_t in, vec3_t out ); -void NormalToLatLong( const vec3_t normal, byte bytes[2] ); - // misc +qboolean Com_ValidScript( const char *token, qctype_t script_type ); qboolean CompileStudioModel( byte *mempool, const char *name, byte parms ); qboolean CompileSpriteModel( byte *mempool, const char *name, byte parms ); qboolean CompileWad3Archive( byte *mempool, const char *name, byte parms ); @@ -46,4 +44,18 @@ qboolean ConvertImages( byte *mempool, const char *name, byte parms ); qboolean PrepareBSPModel( int argc, char **argv ); qboolean CompileBSPModel( void ); +//===================================== +// extragen export +//===================================== +qboolean ConvertResource( byte *mempool, const char *filename, byte parms ); +void Bsp_PrintLog( const char *pMsg ); +void Skin_FinalizeScript( void ); +void Conv_RunSearch( void ); + +// shared tools +void ClrMask( void ); +void AddMask( const char *mask ); +extern string searchmask[]; +extern int num_searchmask; + #endif//UTILS_H \ No newline at end of file diff --git a/xtools/wadlib.c b/utils/wadlib.c similarity index 95% rename from xtools/wadlib.c rename to utils/wadlib.c index 4a358bd3..ac569c79 100644 --- a/xtools/wadlib.c +++ b/utils/wadlib.c @@ -3,10 +3,9 @@ // wadlib.c.c - wad archive compiler //======================================================================= -#include "xtools.h" +#include "utils.h" #include "wadfile.h" #include "byteorder.h" -#include "utils.h" #include "mathlib.h" string wadoutname; diff --git a/xtools/ximage.c b/utils/ximage.c similarity index 96% rename from xtools/ximage.c rename to utils/ximage.c index 55b536b8..1a9cfdcc 100644 --- a/xtools/ximage.c +++ b/utils/ximage.c @@ -3,7 +3,6 @@ // ximage.c - Image FX & Processing //======================================================================= -#include "xtools.h" #include "utils.h" qboolean unknown_rotate = false; diff --git a/xtools/ximage/makefile.nmake b/utils/ximage/makefile.nmake similarity index 85% rename from xtools/ximage/makefile.nmake rename to utils/ximage/makefile.nmake index 9d176618..4733364d 100644 --- a/xtools/ximage/makefile.nmake +++ b/utils/ximage/makefile.nmake @@ -16,7 +16,7 @@ default: $(MAINTARGET).exe $(MAINTARGET).exe: $(MAINTARGET).obj ximage.res $(link) $(OBJS) ximage.res /out:"ximage.exe" /subsystem:windows /opt:nowin98 /nodefaultlib:"libc.lib" @del $(MAINTARGET).obj $(MAINTARGET).lib $(MAINTARGET).exp $(MAINTARGET).res > nul - @copy $(MAINTARGET).exe D:\Xash3D\bin\$(MAINTARGET).exe + @copy $(MAINTARGET).exe D:\Xash3D\$(MAINTARGET).exe @del $(MAINTARGET).exe @echo Скопировано файлов: 1. clean: diff --git a/xtools/ximage/tool.ico b/utils/ximage/tool.ico similarity index 100% rename from xtools/ximage/tool.ico rename to utils/ximage/tool.ico diff --git a/xtools/ximage/ximage.c b/utils/ximage/ximage.c similarity index 100% rename from xtools/ximage/ximage.c rename to utils/ximage/ximage.c diff --git a/xtools/ximage/ximage.rc b/utils/ximage/ximage.rc similarity index 100% rename from xtools/ximage/ximage.rc rename to utils/ximage/ximage.rc diff --git a/xtools/xwad/makefile.nmake b/utils/xwad/makefile.nmake similarity index 85% rename from xtools/xwad/makefile.nmake rename to utils/xwad/makefile.nmake index 5ac24a68..7b55d7b5 100644 --- a/xtools/xwad/makefile.nmake +++ b/utils/xwad/makefile.nmake @@ -16,7 +16,7 @@ default: $(MAINTARGET).exe $(MAINTARGET).exe: $(MAINTARGET).obj xwad.res $(link) $(OBJS) xwad.res /out:"xwad.exe" /subsystem:windows /opt:nowin98 /nodefaultlib:"libc.lib" @del $(MAINTARGET).obj $(MAINTARGET).lib $(MAINTARGET).exp $(MAINTARGET).res > nul - @copy $(MAINTARGET).exe D:\Xash3D\bin\$(MAINTARGET).exe + @copy $(MAINTARGET).exe D:\Xash3D\$(MAINTARGET).exe @del $(MAINTARGET).exe @echo Скопировано файлов: 1. clean: diff --git a/xtools/xwad/tool.ico b/utils/xwad/tool.ico similarity index 100% rename from xtools/xwad/tool.ico rename to utils/xwad/tool.ico diff --git a/xtools/xwad/xwad.c b/utils/xwad/xwad.c similarity index 100% rename from xtools/xwad/xwad.c rename to utils/xwad/xwad.c diff --git a/xtools/xwad/xwad.rc b/utils/xwad/xwad.rc similarity index 100% rename from xtools/xwad/xwad.rc rename to utils/xwad/xwad.rc diff --git a/vid_gl/r_backend.c b/vid_gl/r_backend.c index 1ac38ad0..fc29726c 100644 --- a/vid_gl/r_backend.c +++ b/vid_gl/r_backend.c @@ -414,7 +414,7 @@ void R_BackendEndFrame( void ) // clean up texture units R_CleanUpTextureUnits( 1 ); - if( r_speeds->integer && !( RI.refdef.flags & RDF_NOWORLDMODEL ) ) + if( r_speeds->integer && RI.drawWorld ) { switch( r_speeds->integer ) { @@ -565,7 +565,7 @@ void R_FlushArrays( void ) pglColorPointer( 4, GL_UNSIGNED_BYTE, 0, tr.colorsBuffer->pointer ); } - if( r_drawelements->integer || glState.in2DMode || RI.refdef.flags & RDF_NOWORLDMODEL ) + if( r_drawelements->integer || glState.in2DMode || RI.drawWorld == false ) { if( GL_Support( R_DRAW_RANGEELEMENTS_EXT )) pglDrawRangeElementsEXT( GL_TRIANGLES, 0, r_backacc.numVerts, r_backacc.numElems, GL_UNSIGNED_INT, elemsArray ); @@ -3111,7 +3111,7 @@ void R_DrawEntitiesDebug( void ) { int i; - if(( RI.refdef.flags & RDF_NOWORLDMODEL ) || ( r_drawentities->integer < 2 )) + if(( RI.drawWorld == false ) || ( r_drawentities->integer < 2 )) return; pglDisable( GL_TEXTURE_2D ); @@ -3129,11 +3129,11 @@ void R_DrawEntitiesDebug( void ) if( RP_LOCALCLIENT( RI.currententity )) { // ignore localcient in firstperson mode - if(!(RI.refdef.flags & RDF_THIRDPERSON) && !( RI.params & ( RP_MIRRORVIEW|RP_SHADOWMAPVIEW ))) + if( !RI.thirdPerson && !( RI.params & ( RP_MIRRORVIEW|RP_SHADOWMAPVIEW ))) continue; } - if( RP_FOLLOWENTITY( RI.currententity ) && RP_LOCALCLIENT( RI.currententity->parent ) && !(RI.refdef.flags & RDF_THIRDPERSON )) + if( RP_FOLLOWENTITY( RI.currententity ) && RP_LOCALCLIENT( RI.currententity->parent ) && !RI.thirdPerson ) { // ignore entities that linked to localcient if(!( RI.params & ( RP_MIRRORVIEW|RP_SHADOWMAPVIEW ))) diff --git a/vid_gl/r_cull.c b/vid_gl/r_cull.c index f6332645..4d8cc952 100644 --- a/vid_gl/r_cull.c +++ b/vid_gl/r_cull.c @@ -127,7 +127,7 @@ qboolean R_VisCullBox( const vec3_t mins, const vec3_t maxs ) vec3_t extmins, extmaxs; mnode_t *node, *localstack[2048]; - if( !r_worldmodel || ( RI.refdef.flags & RDF_NOWORLDMODEL ) ) + if( !r_worldmodel || ( RI.drawWorld == false )) return false; if( r_novis->integer ) return false; @@ -179,7 +179,7 @@ qboolean R_VisCullSphere( const vec3_t origin, float radius ) int stackdepth = 0; mnode_t *node, *localstack[2048]; - if( !r_worldmodel || ( RI.refdef.flags & RDF_NOWORLDMODEL ) ) + if( !r_worldmodel || ( RI.drawWorld == false )) return false; if( r_novis->integer ) return false; @@ -241,13 +241,13 @@ int R_CullModel( ref_entity_t *e, vec3_t mins, vec3_t maxs, float radius ) if( e->flags & EF_REFLECTONLY && !( RI.params & RP_MIRRORVIEW )) return 1; - if( RP_LOCALCLIENT( e ) && !( RI.refdef.flags & RDF_THIRDPERSON )) + if( RP_LOCALCLIENT( e ) && !RI.thirdPerson ) { if(!( RI.params & ( RP_MIRRORVIEW|RP_SHADOWMAPVIEW ))) return 1; } - if( RP_FOLLOWENTITY( e ) && RP_LOCALCLIENT( e->parent ) && !(RI.refdef.flags & RDF_THIRDPERSON )) + if( RP_FOLLOWENTITY( e ) && RP_LOCALCLIENT( e->parent ) && !RI.thirdPerson ) { if(!( RI.params & ( RP_MIRRORVIEW|RP_SHADOWMAPVIEW ))) return 1; @@ -256,7 +256,7 @@ int R_CullModel( ref_entity_t *e, vec3_t mins, vec3_t maxs, float radius ) if( R_CullSphere( e->origin, radius, RI.clipFlags )) return 1; - if( RI.refdef.flags & (RDF_PORTALINVIEW|RDF_SKYPORTALINVIEW) || (RI.params & RP_SKYPORTALVIEW)) + if( RI.rdflags & ( RDF_PORTALINVIEW|RDF_SKYPORTALINVIEW ) || ( RI.params & RP_SKYPORTALVIEW )) { if( R_VisCullSphere( e->origin, radius )) return 2; diff --git a/vid_gl/r_decals.c b/vid_gl/r_decals.c index e865480c..4341fd1e 100644 --- a/vid_gl/r_decals.c +++ b/vid_gl/r_decals.c @@ -1210,7 +1210,7 @@ int R_CreateDecalList( decallist_t *pList, qboolean changelevel ) int total = 0; int i, depth; - if( r_worldmodel && !( RI.refdef.flags & RDF_NOWORLDMODEL )) + if( r_worldmodel && RI.drawWorld ) { for( i = 0; i < MAX_RENDER_DECALS; i++ ) { diff --git a/vid_gl/r_draw.c b/vid_gl/r_draw.c index 93973e58..c2ff2d0a 100644 --- a/vid_gl/r_draw.c +++ b/vid_gl/r_draw.c @@ -289,7 +289,6 @@ static vec2_t tri_coords[MAX_TRIVERTS]; static rgba_t tri_colors[MAX_TRIVERTS]; static elem_t tri_elems[MAX_TRIELEMS]; static mesh_t tri_mesh; -static qboolean tri_caps[3]; meshbuffer_t tri_mbuffer; tristate_t triState; @@ -305,9 +304,7 @@ static void Tri_DrawPolygon( void ) ref_shader_t *shader; static int i, oldframe; - if( tri_caps[TRI_SHADER] ) - shader = &r_shaders[triState.currentShader]; - else shader = tr.fillShader; + shader = &r_shaders[triState.currentShader]; tri_mesh.numVerts = triState.numVertex; tri_mesh.numElems = triState.numIndex; @@ -581,18 +578,6 @@ void Tri_Bind( shader_t handle, int frame ) glState.draw_frame = bound( 0, frame, shader->stages[0].num_textures ); } -void Tri_Enable( int cap ) -{ - if( cap < 0 || cap > TRI_MAXCAPS ) return; - tri_caps[cap] = true; -} - -void Tri_Disable( int cap ) -{ - if( cap < 0 || cap > TRI_MAXCAPS ) return; - tri_caps[cap] = false; -} - void Tri_Begin( int mode ) { triState.drawMode = mode; @@ -609,8 +594,7 @@ void Tri_End( void ) void Tri_RenderCallback( int fTrans ) { - if( RI.refdef.flags & RDF_NOWORLDMODEL ) - return; + if( !RI.drawWorld ) return; triState.fActive = true; diff --git a/vid_gl/r_image.c b/vid_gl/r_image.c index 525dec66..1b3bab2f 100644 --- a/vid_gl/r_image.c +++ b/vid_gl/r_image.c @@ -3220,7 +3220,7 @@ qboolean VID_CubemapShot( const char *base, uint size, const float *vieworg, qbo string basename; int i = 1, flags, result; - if((RI.refdef.flags & RDF_NOWORLDMODEL) || !r_worldmodel ) + if( !RI.drawWorld || !r_worldmodel ) return false; // make sure the specified size is valid diff --git a/vid_gl/r_local.h b/vid_gl/r_local.h index b0c8ba2b..442813cb 100644 --- a/vid_gl/r_local.h +++ b/vid_gl/r_local.h @@ -164,6 +164,10 @@ typedef struct mplane_s #define SIDE_BACK 1 #define SIDE_ON 2 +// renderer flags +#define RDF_PORTALINVIEW BIT( 0 ) // draw portal pass +#define RDF_SKYPORTALINVIEW BIT( 1 ) // draw skyportal instead of regular sky + #define RP_NONE 0x0 #define RP_MIRRORVIEW 0x1 // lock pvs at vieworg #define RP_PORTALVIEW 0x2 @@ -181,7 +185,7 @@ typedef struct mplane_s #define RP_SHOWNORMALS 0x2000 #define RP_NONVIEWERREF ( RP_PORTALVIEW|RP_MIRRORVIEW|RP_ENVVIEW|RP_SKYPORTALVIEW|RP_SHADOWMAPVIEW ) -#define RP_LOCALCLIENT(e) (ri.GetLocalPlayer() && ((e)->index == ri.GetLocalPlayer()->index )) +#define RP_LOCALCLIENT(e) (ri.GetLocalPlayer() && ((e)->index == ri.GetLocalPlayer()->index && e->lerp->player )) #define RP_FOLLOWENTITY(e) (((e)->movetype == MOVETYPE_FOLLOW && (e)->parent)) #define MOD_ALLOWBUMP() (r_lighting_models_followdeluxe->integer ? mapConfig.deluxeMappingEnabled : GL_Support( R_SHADER_GLSL100_EXT )) @@ -251,14 +255,25 @@ typedef struct ref_entity_s float radius; // used as RT_SPRITE's radius } ref_entity_t; +typedef struct skyportal_s +{ + float fov; + float scale; + vec3_t vieworg; + vec3_t viewangles; +} skyportal_t; + typedef struct { int params; // rendering parameters + int rdflags; // actual rendering flags ref_params_t refdef; int scissor[4]; int viewport[4]; float lerpFrac; // lerpfraction + qboolean drawWorld; // ignore world for drawing PlayerModel + qboolean thirdPerson; // thirdperson camera is enabled meshlist_t *meshlist; // meshes to be rendered meshbuffer_t **surfmbuffers; // pointers to meshbuffers of world surfaces @@ -291,6 +306,8 @@ typedef struct float skyMins[2][6]; float skyMaxs[2][6]; + skyportal_t skyportal; // skyportal params + float fog_dist_to_eye[256]; // MAX_MAP_FOGS vec3_t pvsOrigin; @@ -365,6 +382,7 @@ extern convar_t *r_physbdebug; extern convar_t *r_check_errors; extern convar_t *r_allow_software; extern convar_t *r_frontbuffer; +extern convar_t *r_adjust_fov; extern convar_t *r_width; extern convar_t *r_height; @@ -437,7 +455,6 @@ extern convar_t *r_nobind; extern convar_t *r_picmip; extern convar_t *r_skymip; extern convar_t *gl_clear; -extern convar_t *r_polyblend; extern convar_t *r_lockpvs; extern convar_t *r_swapInterval; @@ -493,9 +510,9 @@ enum }; #define OCCLUSION_QUERIES_CVAR_HACK( RI ) ( !(r_occlusion_queries->integer == 2 && r_shadows->integer != SHADOW_MAPPING) \ - || ((RI).refdef.flags & RDF_PORTALINVIEW) ) + || ((RI).rdflags & RDF_PORTALINVIEW) ) #define OCCLUSION_QUERIES_ENABLED( RI ) ( GL_Support( R_OCCLUSION_QUERIES_EXT ) && r_occlusion_queries->integer && r_drawentities->integer \ - && !((RI).params & RP_NONVIEWERREF) && !((RI).refdef.flags & RDF_NOWORLDMODEL) \ + && !((RI).params & RP_NONVIEWERREF) && ((RI).drawWorld) \ && OCCLUSION_QUERIES_CVAR_HACK( RI ) ) #define OCCLUSION_OPAQUE_SHADER( s ) (((s)->sort == SORT_OPAQUE ) && ((s)->flags & SHADER_DEPTHWRITE ) && !(s)->numDeforms ) #define OCCLUSION_TEST_ENTITY( e ) (((e)->doOcclusionTest ) || ((e)->ent_type == ET_VIEWENTITY )) @@ -530,8 +547,6 @@ void Tri_TexCoord2f( const float u, const float v ); void Tri_Bind( shader_t shader, int frame ); void Tri_RenderCallback( int fTrans ); void Tri_CullFace( int mode ); -void Tri_Enable( int cap ); -void Tri_Disable( int cap ); void Tri_Begin( int mode ); void Tri_End( void ); @@ -593,7 +608,7 @@ void GL_SetState( int state ); void GL_FrontFace( int front ); void R_BeginFrame( qboolean clearScene ); void R_EndFrame( void ); -void R_RenderScene( const ref_params_t *fd ); +void R_RenderScene( const ref_params_t *fd, qboolean drawWorld ); void R_RenderView( const ref_params_t *fd ); void R_ClearScene( void ); diff --git a/vid_gl/r_main.c b/vid_gl/r_main.c index 93629de1..82dab2a2 100644 --- a/vid_gl/r_main.c +++ b/vid_gl/r_main.c @@ -374,7 +374,7 @@ mfog_t *R_FogForSphere( const vec3_t centre, const float radius ) mfog_t *fog; mplane_t *plane; - if( !r_worldmodel || ( RI.refdef.flags & RDF_NOWORLDMODEL ) || !r_worldbrushmodel->numfogs ) + if( !r_worldmodel || !RI.drawWorld || !r_worldbrushmodel->numfogs ) return NULL; if( RI.params & RP_SHADOWMAPVIEW ) return NULL; @@ -718,7 +718,7 @@ static void R_AddSpriteModelToList( ref_entity_t *e ) if( e->customShader ) shader = e->customShader; else shader = &r_shaders[frame->shader]; - if( RI.refdef.flags & (RDF_PORTALINVIEW|RDF_SKYPORTALINVIEW) || ( RI.params & RP_SKYPORTALVIEW )) + if( RI.rdflags & (RDF_PORTALINVIEW|RDF_SKYPORTALINVIEW) || ( RI.params & RP_SKYPORTALVIEW )) { if( R_VisCullSphere( e->origin, frame->radius )) return; @@ -739,43 +739,6 @@ qboolean R_SpriteOverflow( void ) } //================================================================================== -/* -============ -R_PolyBlend -============ -*/ -static void R_PolyBlend( void ) -{ - if( !r_polyblend->integer ) - return; - if( RI.refdef.blend[3] < 0.01f ) - return; - - pglMatrixMode( GL_PROJECTION ); - pglLoadIdentity(); - pglOrtho( 0, 1, 1, 0, -99999, 99999 ); - - pglMatrixMode( GL_MODELVIEW ); - pglLoadIdentity(); - - GL_Cull( 0 ); - GL_SetState( GLSTATE_NO_DEPTH_TEST|GLSTATE_SRCBLEND_SRC_ALPHA|GLSTATE_DSTBLEND_ONE_MINUS_SRC_ALPHA ); - - pglDisable( GL_TEXTURE_2D ); - - pglColor4fv( RI.refdef.blend ); - - pglBegin( GL_TRIANGLES ); - pglVertex2f( -5, -5 ); - pglVertex2f( 10, -5 ); - pglVertex2f( -5, 10 ); - pglEnd(); - - pglEnable( GL_TEXTURE_2D ); - - pglColor4f( 1, 1, 1, 1 ); -} - /* =============== R_ApplySoftwareGamma @@ -880,7 +843,7 @@ static float R_FarClip( void ) { float farclip_dist; - if( r_worldmodel && !( RI.refdef.flags & RDF_NOWORLDMODEL )) + if( r_worldmodel && RI.drawWorld ) { int i; float dist; @@ -926,10 +889,8 @@ static void R_SetupProjectionMatrix( const ref_params_t *rd, matrix4x4 m ) { GLdouble xMin, xMax, yMin, yMax, zNear, zFar; - if( rd->flags & RDF_NOWORLDMODEL ) - RI.farClip = 2048; - else - RI.farClip = R_FarClip(); + if( !RI.drawWorld ) RI.farClip = 2048; + else RI.farClip = R_FarClip(); zNear = Z_NEAR; zFar = RI.farClip; @@ -978,7 +939,7 @@ static void R_SetupFrame( void ) RI.vup = RI.viewAxis[2]; // ambient lighting - if( r_worldmodel && !( RI.refdef.flags & RDF_NOWORLDMODEL )) + if( r_worldmodel && RI.drawWorld ) { mapConfig.environmentColor[0] = RI.refdef.movevars->skycolor_r; mapConfig.environmentColor[1] = RI.refdef.movevars->skycolor_g; @@ -992,7 +953,7 @@ static void R_SetupFrame( void ) r_framecount++; // current viewleaf - if(!( RI.refdef.flags & RDF_NOWORLDMODEL )) + if( RI.drawWorld ) { mleaf_t *leaf; vec3_t tmp; @@ -1097,7 +1058,7 @@ static void R_Clear( int bitMask ) bits = GL_DEPTH_BUFFER_BIT; - if( !( RI.refdef.flags & RDF_NOWORLDMODEL ) && r_fastsky->integer ) + if( RI.drawWorld && r_fastsky->integer ) bits |= GL_COLOR_BUFFER_BIT; if( glState.stencilEnabled && ( r_shadows->integer >= SHADOW_PLANAR ) ) bits |= GL_STENCIL_BUFFER_BIT; @@ -1109,7 +1070,7 @@ static void R_Clear( int bitMask ) if( bits & GL_COLOR_BUFFER_BIT ) { - byte *color = r_worldmodel && !( RI.refdef.flags & RDF_NOWORLDMODEL ) && r_worldbrushmodel->globalfog ? + byte *color = ( r_worldmodel && RI.drawWorld && r_worldbrushmodel->globalfog ) ? r_worldbrushmodel->globalfog->shader->fog_color : mapConfig.environmentColor; pglClearColor( (float)color[0]*( 1.0/255.0 ), (float)color[1]*( 1.0/255.0 ), (float)color[2]*( 1.0/255.0 ), 1 ); } @@ -1495,7 +1456,7 @@ void R_RenderDebugSurface( void ) vec3_t forward; vec3_t start, end; - if( RI.params & RP_NONVIEWERREF || RI.refdef.flags & RDF_NOWORLDMODEL ) + if( RI.params & RP_NONVIEWERREF || !RI.drawWorld ) return; r_debug_surface = NULL; @@ -1551,7 +1512,7 @@ void R_RenderView( const ref_params_t *fd ) R_ClearMeshList( RI.meshlist ); - if( !r_worldmodel && !( RI.refdef.flags & RDF_NOWORLDMODEL )) + if( !r_worldmodel && RI.drawWorld ) Host_Error( "R_RenderView: NULL worldmodel\n" ); R_SetupFrame(); @@ -1826,7 +1787,7 @@ void R_AddLightStyleToScene( int style, float r, float g, float b ) R_RenderScene =============== */ -void R_RenderScene( const ref_params_t *fd ) +void R_RenderScene( const ref_params_t *fd, qboolean drawWorld ) { // flush any remaining 2D bits R_Set2DMode( false ); @@ -1836,7 +1797,7 @@ void R_RenderScene( const ref_params_t *fd ) R_BackendStartFrame(); - if(!( fd->flags & RDF_NOWORLDMODEL )) + if( drawWorld ) { r_lastRefdef = *fd; } @@ -1849,10 +1810,13 @@ void R_RenderScene( const ref_params_t *fd ) RI.params = RP_NONE; RI.refdef = *fd; RI.farClip = 0; + RI.rdflags = 0; RI.clipFlags = 15; - RI.lerpFrac = RI.refdef.lerpfrac; + RI.drawWorld = drawWorld; + RI.lerpFrac = ri.GetLerpFrac(); + RI.thirdPerson = ri.IsThirdPerson(); - if( r_worldmodel && !( RI.refdef.flags & RDF_NOWORLDMODEL ) && r_worldbrushmodel->globalfog ) + if( r_worldmodel && RI.drawWorld && r_worldbrushmodel->globalfog ) { RI.farClip = r_worldbrushmodel->globalfog->shader->fog_dist; RI.farClip = max( r_farclip_min, RI.farClip ) + r_farclip_bias; @@ -1864,14 +1828,14 @@ void R_RenderScene( const ref_params_t *fd ) RI.shadowGroup = NULL; // adjust field of view for widescreen - if( glState.wideScreen && !( fd->flags & RDF_NOFOVADJUSTMENT )) + if( glState.wideScreen && r_adjust_fov->integer ) AdjustFov( &RI.refdef.fov_x, &RI.refdef.fov_y, glState.width, glState.height, false ); Vector4Set( RI.scissor, fd->viewport[0], glState.height - fd->viewport[3] - fd->viewport[1], fd->viewport[2], fd->viewport[3] ); Vector4Set( RI.viewport, fd->viewport[0], glState.height - fd->viewport[3] - fd->viewport[1], fd->viewport[2], fd->viewport[3] ); VectorCopy( fd->vieworg, RI.pvsOrigin ); - if( gl_finish->integer && !gl_delayfinish->integer && !( fd->flags & RDF_NOWORLDMODEL )) + if( gl_finish->integer && !gl_delayfinish->integer && drawWorld ) pglFinish(); R_ClearShadowmaps(); @@ -1882,8 +1846,6 @@ void R_RenderScene( const ref_params_t *fd ) R_BloomBlend( fd ); - R_PolyBlend(); - R_BackendEndFrame(); R_Set2DMode( true ); @@ -2193,7 +2155,7 @@ msurface_t *R_TraceLine( pmtrace_t *tr, const vec3_t start, const vec3_t end, in e = &r_entities[i]; // don't trace localclient - if( RP_LOCALCLIENT( e ) && !( RI.refdef.flags & RDF_THIRDPERSON )) + if( RP_LOCALCLIENT( e ) && !RI.thirdPerson ) continue; if( !e->model || ( e->model->type != mod_brush && e->model->type != mod_studio )) @@ -2303,6 +2265,15 @@ shader_t R_GetSpriteTexture( int spriteIndex, int spriteFrame ) return pSpriteFrame->shader; } +void R_SetSkyPortal( const vec3_t vieworg, const vec3_t viewangles, float scale, float fov ) +{ + VectorCopy( vieworg, RI.skyportal.vieworg ); + VectorCopy( viewangles, RI.skyportal.viewangles ); + RI.skyportal.fov = max( 1.0f, fov ); // to avoid division by zero + RI.skyportal.scale = scale; + RI.rdflags |= RDF_SKYPORTALINVIEW; // enable sky portal +} + qboolean R_AddLightStyle( int stylenum, vec3_t color ) { if( stylenum < 0 || stylenum > MAX_LIGHTSTYLES ) @@ -2392,6 +2363,9 @@ qboolean R_AddPortalEntity( cl_entity_t *pRefEntity, ref_entity_t *refent ) VectorCopy( pRefEntity->origin, refent->origin ); VectorCopy( pRefEntity->curstate.vuser1, refent->origin2 ); // FIXME: oldorigin + if( !VectorCompare( pRefEntity->curstate.origin, pRefEntity->curstate.vuser1 )) + RI.rdflags |= RDF_PORTALINVIEW; + // calculate angles Matrix3x3_FromAngles( refent->angles, refent->axis ); return true; @@ -2568,8 +2542,6 @@ render_exp_t EXPORT *CreateAPI(stdlib_api_t *input, render_imp_t *engfuncs ) re.Vertex3f = Tri_Vertex3f; re.Color4ub = Tri_Color4ub; re.CullFace = Tri_CullFace; - re.Disable = Tri_Disable; - re.Enable = Tri_Enable; re.Begin = Tri_Begin; re.Bind = Tri_Bind; re.End = Tri_End; @@ -2580,6 +2552,7 @@ render_exp_t EXPORT *CreateAPI(stdlib_api_t *input, render_imp_t *engfuncs ) re.SetParms = R_DrawSetParms; re.ScrShot = VID_ScreenShot; re.EnvShot = VID_CubemapShot; + re.SetSkyPortal = R_SetSkyPortal; re.LightForPoint = R_LightForPoint; re.DrawStretchRaw = R_DrawStretchRaw; re.DrawStretchPic = R_DrawStretchPic; diff --git a/vid_gl/r_mesh.c b/vid_gl/r_mesh.c index 6115f747..849b270e 100644 --- a/vid_gl/r_mesh.c +++ b/vid_gl/r_mesh.c @@ -298,7 +298,7 @@ int R_ReAllocMeshList( meshbuffer_t **mb, int minMeshes, int maxMeshes ) *mb = newMB; // NULL all pointers to old membuffers so we don't crash - if( r_worldmodel && !( RI.refdef.flags & RDF_NOWORLDMODEL )) + if( r_worldmodel && RI.drawWorld ) Mem_Set( RI.surfmbuffers, 0, r_worldbrushmodel->numsurfaces * sizeof( meshbuffer_t* )); return newSize; @@ -651,7 +651,7 @@ void R_DrawPortals( void ) } } - if(( RI.refdef.flags & RDF_SKYPORTALINVIEW ) && !( RI.params & RP_NOSKY ) && !r_fastsky->integer ) + if(( RI.rdflags & RDF_SKYPORTALINVIEW ) && !( RI.params & RP_NOSKY ) && !r_fastsky->integer ) { for( i = 0, mb = RI.meshlist->meshbuffer_opaque; i < RI.meshlist->num_opaque_meshes; i++, mb++ ) { @@ -1310,14 +1310,14 @@ void R_DrawSkyPortal( skyportal_t *skyportal, vec3_t mins, vec3_t maxs ) VectorCopy( skyportal->vieworg, RI.refdef.vieworg ); } - VectorAdd( RI.refdef.viewangles, skyportal->viewanglesOffset, RI.refdef.viewangles ); + VectorCopy( skyportal->viewangles, RI.refdef.viewangles ); - RI.refdef.flags &= ~RDF_SKYPORTALINVIEW; + RI.rdflags &= ~RDF_SKYPORTALINVIEW; if( skyportal->fov ) { RI.refdef.fov_x = skyportal->fov; RI.refdef.fov_y = CalcFov( RI.refdef.fov_x, RI.refdef.viewport[2], RI.refdef.viewport[3] ); - if( glState.wideScreen && !( RI.refdef.flags & RDF_NOFOVADJUSTMENT ) ) + if( glState.wideScreen && r_adjust_fov->integer ) AdjustFov( &RI.refdef.fov_x, &RI.refdef.fov_y, glState.width, glState.height, false ); } @@ -1353,7 +1353,7 @@ void R_DrawCubemapView( const vec3_t origin, const vec3_t angles, int size ) r_numPolys = 0; r_numDlights = 0; - R_RenderScene( fd ); + R_RenderScene( fd, RI.drawWorld ); r_oldviewleaf = r_viewleaf = NULL; // force markleafs next frame } diff --git a/vid_gl/r_register.c b/vid_gl/r_register.c index 41778a44..13b4ab8d 100644 --- a/vid_gl/r_register.c +++ b/vid_gl/r_register.c @@ -52,6 +52,7 @@ convar_t *r_faceplanecull; convar_t *gl_wireframe; convar_t *r_shownormals; convar_t *r_showtextures; +convar_t *r_adjust_fov; convar_t *r_draworder; convar_t *r_width; convar_t *r_height; @@ -117,7 +118,6 @@ convar_t *r_picmip; convar_t *r_skymip; convar_t *r_nobind; convar_t *gl_clear; -convar_t *r_polyblend; convar_t *r_lockpvs; convar_t *r_swapInterval; convar_t *r_frontbuffer; @@ -502,7 +502,6 @@ void GL_InitCommands( void ) r_nobind = Cvar_Get( "r_nobind", "0", 0, "disable all textures (perfomance test)" ); r_picmip = Cvar_Get( "r_picmip", "0", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "reduces resolution of textures by powers of 2" ); r_skymip = Cvar_Get( "r_skymip", "0", CVAR_ARCHIVE|CVAR_LATCH_VIDEO, "reduces resolution of skybox textures by powers of 2" ); - r_polyblend = Cvar_Get( "r_polyblend", "1", 0, "tints view while underwater, hurt, etc" ); r_lefthand = Cvar_Get( "hand", "0", CVAR_ARCHIVE, "viewmodel handedness" ); r_physbdebug = Cvar_Get( "cm_debugdraw", "0", CVAR_ARCHIVE, "draw physics hulls" ); @@ -532,6 +531,7 @@ void GL_InitCommands( void ) r_shownormals = Cvar_Get( "r_shownormals", "0", CVAR_CHEAT, "show mesh normals" ); r_showtextures = Cvar_Get("r_showtextures", "0", CVAR_CHEAT, "show all uploaded textures" ); r_draworder = Cvar_Get( "r_draworder", "0", CVAR_CHEAT, "ignore mesh sorting" ); + r_adjust_fov = Cvar_Get( "r_adjust_fov", "1", CVAR_ARCHIVE, "making FOV adjustment for wide-screens" ); r_fastsky = Cvar_Get( "r_fastsky", "0", CVAR_ARCHIVE, "enable algorhytem fo fast sky rendering (for old machines)" ); r_portalonly = Cvar_Get( "r_portalonly", "0", 0, "render only portals" ); diff --git a/vid_gl/r_shadow.c b/vid_gl/r_shadow.c index 3115ac51..c3f2aea3 100644 --- a/vid_gl/r_shadow.c +++ b/vid_gl/r_shadow.c @@ -219,7 +219,7 @@ void R_ClearShadowmaps( void ) { r_numShadowGroups = 0; - if( r_shadows->integer != SHADOW_MAPPING || RI.refdef.flags & RDF_NOWORLDMODEL ) + if( r_shadows->integer != SHADOW_MAPPING || !RI.drawWorld ) return; // clear all possible values, should be called once per scene @@ -243,7 +243,7 @@ qboolean R_AddShadowCaster( ref_entity_t *ent ) mleaf_t *leaf; vec3_t mins, maxs, bbox[8]; - if( r_shadows->integer != SHADOW_MAPPING || RI.refdef.flags & RDF_NOWORLDMODEL ) + if( r_shadows->integer != SHADOW_MAPPING || !RI.drawWorld ) return false; if( !GL_Support( R_SHADER_GLSL100_EXT ) || !GL_Support( R_DEPTH_TEXTURE ) || !GL_Support( R_SHADOW_EXT )) return false; @@ -329,8 +329,7 @@ void R_CullShadowmapGroups( void ) vec3_t mins, maxs; shadowGroup_t *group; - if( RI.refdef.flags & RDF_NOWORLDMODEL ) - return; + if( !RI.drawWorld ) return; Mem_Set( r_shadowCullBits, 0, sizeof( r_shadowCullBits )); @@ -379,9 +378,9 @@ void R_DrawShadowmaps( void ) height = r_lastRefdef.viewport[3]; RI.previousentity = NULL; - Mem_Copy( &oldRI, &prevRI, sizeof( refinst_t ) ); - Mem_Copy( &prevRI, &RI, sizeof( refinst_t ) ); - RI.refdef.flags &= ~RDF_SKYPORTALINVIEW; + Mem_Copy( &oldRI, &prevRI, sizeof( refinst_t )); + Mem_Copy( &prevRI, &RI, sizeof( refinst_t )); + RI.rdflags &= ~RDF_SKYPORTALINVIEW; // find lighting group containing entities with same lightingOrigin as ours for( i = 0, group = r_shadowGroups; i < r_numShadowGroups; i++, group++ ) diff --git a/vid_gl/r_sky.c b/vid_gl/r_sky.c index 0054e462..24b46587 100644 --- a/vid_gl/r_sky.c +++ b/vid_gl/r_sky.c @@ -309,9 +309,9 @@ void R_DrawSky( ref_shader_t *shader ) VectorAdd( mins, RI.viewOrigin, mins ); VectorAdd( maxs, RI.viewOrigin, maxs ); - if( RI.refdef.flags & RDF_SKYPORTALINVIEW ) + if( RI.rdflags & RDF_SKYPORTALINVIEW ) { - R_DrawSkyPortal( &RI.refdef.skyportal, mins, maxs ); + R_DrawSkyPortal( &RI.skyportal, mins, maxs ); return; } diff --git a/vid_gl/r_sprite.c b/vid_gl/r_sprite.c index f4eae73c..b11ab950 100644 --- a/vid_gl/r_sprite.c +++ b/vid_gl/r_sprite.c @@ -774,7 +774,7 @@ void R_DrawSpriteModel( const meshbuffer_t *mb ) // pev->colormap is hardcoded to attachment number // NOTE: use interpolated origin to avoid flickering attachments - VectorAdd( e->parent->origin, e->parent->lerp->attachment[num-1], e->origin2 ); + VectorCopy( e->parent->lerp->attachment[num-1], e->origin2 ); } else VectorCopy( e->parent->origin, e->origin2 ); } diff --git a/vid_gl/r_studio.c b/vid_gl/r_studio.c index 1cfb9559..3e85a60b 100644 --- a/vid_gl/r_studio.c +++ b/vid_gl/r_studio.c @@ -216,6 +216,8 @@ static void R_StudioSetupRender( ref_entity_t *e, ref_model_t *mod ) // GetPlayerInfo returns NULL for non player entities m_pPlayerInfo = ri.GetPlayerInfo( e->index - 1 ); + m_fGaitEstimation = ( m_pPlayerInfo ) ? 1 : 0; + ASSERT( e->extradata ); // set cached bones @@ -709,23 +711,22 @@ void R_StudioProcessEvents( ref_entity_t *e, cl_entity_t *ent ) //Msg( "%i frame %f\n", r_framecount, e->lerp->latched.prevframe ); - if( e->lerp->m_iEventSequence != e->lerp->curstate.sequence ) + if( e->lerp->syncbase == -0.01f ) { flEventFrame = 0.0f; - e->lerp->m_flPrevEventFrame = -0.01f; // back up to get 0'th frame animations - e->lerp->m_iEventSequence = e->lerp->curstate.sequence; + // Msg( "Sequence changed\n" ); } // stalled? - if( flEventFrame == e->lerp->m_flPrevEventFrame ) + if( flEventFrame == e->lerp->syncbase ) return; - //Msg( "(seq %d cycle %.3f ) evframe %.3f prevevframe %.3f (time %.3f)\n", e->lerp->curstate.sequence, e->lerp->latched.prevframe, flEventFrame, e->lerp->m_flPrevEventFrame, RI.refdef.time ); + //Msg( "(seq %d cycle %.3f ) evframe %.3f prevevframe %.3f (time %.3f)\n", e->lerp->curstate.sequence, e->lerp->latched.prevframe, flEventFrame, e->lerp->syncbase, RI.refdef.time ); // check for looping - if( flEventFrame <= e->lerp->m_flPrevEventFrame ) + if( flEventFrame <= e->lerp->syncbase ) { - if( e->lerp->m_flPrevEventFrame - flEventFrame > 0.5f ) + if( e->lerp->syncbase - flEventFrame > 0.5f ) { bLooped = true; } @@ -746,23 +747,23 @@ void R_StudioProcessEvents( ref_entity_t *e, cl_entity_t *ent ) // looped if( bLooped ) { - if(( pevent[i].frame > e->lerp->m_flPrevEventFrame || pevent[i].frame <= flEventFrame )) + if(( pevent[i].frame > e->lerp->syncbase || pevent[i].frame <= flEventFrame )) { - //Msg( "FE %i Looped frame %i, prev %f ev %f (time %.3f)\n", pevent[i].event, pevent[i].frame, e->lerp->m_flPrevEventFrame, flEventFrame, RI.refdef.time ); + //Msg( "FE %i Looped frame %i, prev %f ev %f (time %.3f)\n", pevent[i].event, pevent[i].frame, e->lerp->syncbase, flEventFrame, RI.refdef.time ); ri.StudioEvent( &pevent[i], ent ); } } else { - if(( pevent[i].frame > e->lerp->m_flPrevEventFrame && pevent[i].frame <= flEventFrame )) + if(( pevent[i].frame > e->lerp->syncbase && pevent[i].frame <= flEventFrame )) { - //Msg( "FE %i Normal frame %i, prev %f ev %f (time %.3f)\n", pevent[i].event, pevent[i].frame, e->lerp->m_flPrevEventFrame, flEventFrame, RI.refdef.time ); + //Msg( "FE %i Normal frame %i, prev %f ev %f (time %.3f)\n", pevent[i].event, pevent[i].frame, e->lerp->syncbase, flEventFrame, RI.refdef.time ); ri.StudioEvent( &pevent[i], ent ); } } } - e->lerp->m_flPrevEventFrame = flEventFrame; + e->lerp->syncbase = flEventFrame; } /* @@ -1173,7 +1174,7 @@ void R_StudioSetUpTransform( ref_entity_t *e, qboolean trivial_accept ) f = f - 1.0f; } - m_pGroundEntity = e->lerp->onground; + m_pGroundEntity = ri.GetClientEdict( e->lerp->curstate.onground ); if( m_pGroundEntity && m_pGroundEntity->curstate.movetype == MOVETYPE_PUSH && !VectorIsNull( m_pGroundEntity->curstate.velocity )) { @@ -1226,9 +1227,6 @@ void R_StudioSetUpTransform( ref_entity_t *e, qboolean trivial_accept ) if( e->ent_type == ET_PLAYER ) angles[PITCH] = 0; - if( e->ent_type == ET_VIEWENTITY ) - angles[PITCH] = -angles[PITCH]; // stupid Half-Life bug - Matrix4x4_CreateFromEntity( m_protationmatrix, origin[0], origin[1], origin[2], -angles[PITCH], angles[YAW], angles[ROLL], e->scale ); if( e->ent_type == ET_VIEWENTITY && r_lefthand->integer == 1 ) @@ -1361,6 +1359,67 @@ float R_StudioEstimateFrame( mstudioseqdesc_t *pseqdesc ) return f; } +/* +==================== +StudioFxTransform + +==================== +*/ +void R_StudioFxTransform( cl_entity_t *ent, matrix4x4 transform ) +{ + switch( ent->curstate.renderfx ) + { + case kRenderFxDistort: + case kRenderFxHologram: + if(!Com_RandomLong( 0, 49 )) + { + int axis = Com_RandomLong( 0, 1 ); + float scale = Com_RandomFloat( 1, 1.484 ); + + if( axis == 1 ) axis = 2; // choose between x & z +#ifdef OPENGL_STYLE + transform[0][axis] *= scale; + transform[1][axis] *= scale; + transform[2][axis] *= scale; +#else + transform[axis][0] *= scale; + transform[axis][1] *= scale; + transform[axis][2] *= scale; +#endif + } + else if(!Com_RandomLong( 0, 49 )) + { + float offset; + int axis = Com_RandomLong( 0, 1 ); + if( axis == 1 ) axis = 2; // choose between x & z + offset = Com_RandomFloat( -10, 10 ); +#ifdef OPENGL_STYLE + transform[3][Com_RandomLong( 0, 2 )] += offset; +#else + transform[Com_RandomLong( 0, 2 )][3] += offset; +#endif + } + break; + case kRenderFxExplode: + { + float scale; + + scale = 1.0f + ( RI.refdef.time - ent->curstate.animtime ) * 10.0f; + if( scale > 2 ) scale = 2; // don't blow up more than 200% +#ifdef OPENGL_STYLE + transform[1][0] *= scale; + transform[1][1] *= scale; + transform[1][2] *= scale; +#else + transform[0][1] *= scale; + transform[1][1] *= scale; + transform[2][1] *= scale; +#endif + } + break; + } +} + /* ==================== StudioSetupBones @@ -1515,7 +1574,7 @@ void R_StudioSetupBones( ref_entity_t *e ) Matrix4x4_ConcatTransforms( m_pbonestransform[i], m_protationmatrix, bonematrix ); // apply client-side effects to the transformation matrix - ri.StudioFxTransform( e->lerp, m_pbonestransform[i] ); + R_StudioFxTransform( e->lerp, m_pbonestransform[i] ); } else Matrix4x4_ConcatTransforms( m_pbonestransform[i], m_pbonestransform[pbones[i].parent], bonematrix ); } @@ -1596,7 +1655,7 @@ void R_StudioMergeBones( ref_entity_t *e, ref_model_t *m_pSubModel ) Matrix4x4_ConcatTransforms( localbones[i], m_protationmatrix, bonematrix ); // apply client-side effects to the transformation matrix - if( cl_entity ) ri.StudioFxTransform( cl_entity, m_pbonestransform[i] ); + R_StudioFxTransform( cl_entity, m_pbonestransform[i] ); } else Matrix4x4_ConcatTransforms( localbones[i], m_pbonestransform[pbones[i].parent], bonematrix ); } @@ -1628,10 +1687,7 @@ static void R_StudioCalcAttachments( ref_entity_t *e ) { // clear attachments for( i = 0; i < MAXSTUDIOATTACHMENTS; i++ ) - { VectorClear( e->lerp->attachment[i] ); - VectorClear( e->lerp->attachment_angles[i] ); - } return; } else if( m_pStudioHeader->numattachments > MAXSTUDIOATTACHMENTS ) @@ -1656,8 +1712,7 @@ static void R_StudioCalcAttachments( ref_entity_t *e ) Matrix3x3_ToAngles( axis, localAng, false ); // FIXME: dll's uses FLU ? - VectorCopy( localOrg, e->lerp->attachment[i] ); - VectorCopy( localAng, e->lerp->attachment_angles[i] ); + VectorAdd( e->lerp->origin, localOrg, e->lerp->attachment[i] ); } } @@ -2164,7 +2219,7 @@ void R_StudioProcessGait( ref_entity_t *e, entity_state_t *pplayer, studiovars_t pseqdesc = (mstudioseqdesc_t *)((byte *)m_pStudioHeader + m_pStudioHeader->seqindex) + e->lerp->curstate.sequence; R_StudioPlayerBlend( pseqdesc, &iBlend, &e->lerp->angles[PITCH] ); - pstudio->lerp->latched.prevangles[PITCH] = e->lerp->angles[PITCH]; + pstudio->lerp->latched.prevangles[PITCH] = e->angles[PITCH]; pstudio->lerp->curstate.blending[0] = iBlend; pstudio->lerp->latched.prevblending[0] = pstudio->lerp->curstate.blending[0]; pstudio->lerp->latched.prevseqblending[0] = pstudio->lerp->curstate.blending[0]; @@ -2206,9 +2261,9 @@ void R_StudioProcessGait( ref_entity_t *e, entity_state_t *pplayer, studiovars_t pstudio->lerp->latched.prevcontroller[2] = pstudio->lerp->curstate.controller[2]; pstudio->lerp->latched.prevcontroller[3] = pstudio->lerp->curstate.controller[3]; - e->lerp->angles[YAW] = m_pPlayerInfo->gaityaw; - if( e->lerp->angles[YAW] < -0 ) e->angles[YAW] += 360; - e->lerp->latched.prevangles[YAW] = e->lerp->angles[YAW]; + e->angles[YAW] = m_pPlayerInfo->gaityaw; + if( e->angles[YAW] < -0 ) e->angles[YAW] += 360; + e->lerp->latched.prevangles[YAW] = e->angles[YAW]; if( pplayer->gaitsequence >= m_pStudioHeader->numseq ) pplayer->gaitsequence = 0; @@ -2496,7 +2551,7 @@ qboolean R_CullStudioModel( ref_entity_t *e ) query = OCCLUSION_QUERIES_ENABLED( RI ) && OCCLUSION_TEST_ENTITY( e ) ? true : false; if( !frustum && query ) R_IssueOcclusionQuery( R_GetOcclusionQueryNum( OQ_ENTITY, e - r_entities ), e, studio_mins, studio_maxs ); - if(( RI.refdef.flags & RDF_NOWORLDMODEL ) || ( r_shadows->integer != 1 ) || R_CullPlanarShadow( e, studio_mins, studio_maxs, query )) + if( !RI.drawWorld || ( r_shadows->integer != 1 ) || R_CullPlanarShadow( e, studio_mins, studio_maxs, query )) return frustum; // entity is not in PVS or shadow is culled away by frustum culling R_StudioSetupRender( e, e->model ); diff --git a/vid_gl/r_surf.c b/vid_gl/r_surf.c index f71f2a71..5a78a7e9 100644 --- a/vid_gl/r_surf.c +++ b/vid_gl/r_surf.c @@ -201,7 +201,7 @@ qboolean R_CullBrushModel( ref_entity_t *e ) return true; } - if( RI.refdef.flags & ( RDF_PORTALINVIEW|RDF_SKYPORTALINVIEW ) || ( RI.params & RP_SKYPORTALVIEW )) + if( RI.rdflags & ( RDF_PORTALINVIEW|RDF_SKYPORTALINVIEW ) || ( RI.params & RP_SKYPORTALVIEW )) { if( rotated ) { @@ -603,8 +603,7 @@ void R_DrawWorld( void ) if( !r_drawworld->integer ) return; - if( RI.refdef.flags & RDF_NOWORLDMODEL ) - return; + if( !RI.drawWorld ) return; if( !r_worldmodel || !r_worldbrushmodel ) return; @@ -658,8 +657,7 @@ void R_MarkLeaves( void ) mnode_t *node; int i; - if( RI.refdef.flags & RDF_NOWORLDMODEL ) - return; + if( !RI.drawWorld ) return; if( RI.params & RP_SHADOWMAPVIEW ) return; diff --git a/vid_gl/vid_gl.dsp b/vid_gl/vid_gl.dsp index d1f5e334..893d053e 100644 --- a/vid_gl/vid_gl.dsp +++ b/vid_gl/vid_gl.dsp @@ -43,7 +43,7 @@ RSC=rc.exe # PROP Ignore_Export_Lib 1 # PROP Target_Dir "." # ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "../public" /I "../common" /I "../game_shared" /I "../engine" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c +# ADD CPP /nologo /MD /W3 /GX /O2 /Ob2 /I "../public" /I "../common" /I "../pm_shared" /I "../engine" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "NDEBUG" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 @@ -61,8 +61,8 @@ TargetDir=\Xash3D\src_main\temp\vid_gl\!release InputPath=\Xash3D\src_main\temp\vid_gl\!release\vid_gl.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\vid_gl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\vid_gl.dll "D:\Xash3D\bin\vid_gl.dll" +"D:\Xash3D\vid_gl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\vid_gl.dll "D:\Xash3D\vid_gl.dll" # End Custom Build @@ -80,7 +80,7 @@ SOURCE="$(InputPath)" # PROP Ignore_Export_Lib 1 # PROP Target_Dir "." # ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c -# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../public" /I "../common" /I "../game_shared" /I "../engine" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c +# ADD CPP /nologo /MDd /W3 /Gm /Gi /GX /ZI /Od /I "../public" /I "../common" /I "../pm_shared" /I "../engine" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /FD /c # SUBTRACT CPP /YX # ADD BASE MTL /nologo /D "_DEBUG" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 @@ -98,8 +98,8 @@ TargetDir=\Xash3D\src_main\temp\vid_gl\!debug InputPath=\Xash3D\src_main\temp\vid_gl\!debug\vid_gl.dll SOURCE="$(InputPath)" -"D:\Xash3D\bin\vid_gl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" - copy $(TargetDir)\vid_gl.dll "D:\Xash3D\bin\vid_gl.dll" +"D:\Xash3D\vid_gl.dll" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" + copy $(TargetDir)\vid_gl.dll "D:\Xash3D\vid_gl.dll" # End Custom Build diff --git a/xash.dsw b/xash.dsw index 944dce28..8f2e2e60 100644 --- a/xash.dsw +++ b/xash.dsw @@ -15,7 +15,7 @@ Package=<4> ############################################################################### -Project: "bshift"=".\dlls\bshift.dsp" - Package Owner=<4> +Project: "client"=".\cl_dll\cl_dll.dsp" - Package Owner=<4> Package=<5> {{{ @@ -27,7 +27,7 @@ Package=<4> ############################################################################### -Project: "client"=".\client\client.dsp" - Package Owner=<4> +Project: "mainui"=".\mainui\mainui.dsp" - Package Owner=<4> Package=<5> {{{ @@ -39,19 +39,7 @@ Package=<4> ############################################################################### -Project: "gameui"=".\gameui\gameui.dsp" - Package Owner=<4> - -Package=<5> -{{{ -}}} - -Package=<4> -{{{ -}}} - -############################################################################### - -Project: "xtools"=".\xtools\xtools.dsp" - Package Owner=<4> +Project: "utils"=".\utils\utils.dsp" - Package Owner=<4> Package=<5> {{{ diff --git a/xtools/utils.c b/xtools/utils.c deleted file mode 100644 index c8caea95..00000000 --- a/xtools/utils.c +++ /dev/null @@ -1,114 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 й -// utils.c - platform utils -//======================================================================= - -#include "xtools.h" -#include "const.h" -#include "utils.h" -#include "mdllib.h" - -string gs_basedir; // initial dir before loading gameinfo.txt (used for compilers too) -string gs_filename; // used for compilers only - -float ColorNormalize( const vec3_t in, vec3_t out ) -{ - float max, scale; - - max = in[0]; - if( in[1] > max ) max = in[1]; - if( in[2] > max ) max = in[2]; - - if( max == 0 ) - { - out[0] = out[1] = out[2] = 1.0f; - return 0; - } - - scale = 1.0f / max; - VectorScale( in, scale, out ); - - return max; -} - -/* -================ -NormalToLatLong - -We use two byte encoded normals in some space critical applications. -Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format -Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format -================ -*/ -void NormalToLatLong( const vec3_t normal, byte bytes[2] ) -{ - // check for singularities - if( normal[0] == 0 && normal[1] == 0 ) - { - if( normal[2] > 0 ) - { - bytes[0] = 0; - bytes[1] = 0; // lat = 0, long = 0 - } - else - { - bytes[0] = 128; - bytes[1] = 0; // lat = 0, long = 128 - } - } - else - { - int a, b; - - a = (int)( RAD2DEG( atan2( normal[1], normal[0] )) * (255.0f / 360.0f )); - a &= 0xff; - - b = (int)( RAD2DEG( acos( normal[2] )) * ( 255.0f / 360.0f )); - b &= 0xff; - - bytes[0] = b; // longitude - bytes[1] = a; // lattitude - } -} - -/* -================ -Com_ValidScript - -validate qc-script for unexcpected keywords -================ -*/ -qboolean Com_ValidScript( const char *token, qctype_t scripttype ) -{ - if( !com.stricmp( token, "$spritename") && scripttype != QC_SPRITEGEN ) - { - Msg( "%s probably spritegen qc.script, skipping...\n", gs_filename ); - return false; - } - else if( !com.stricmp( token, "$resample" ) && scripttype != QC_SPRITEGEN ) - { - Msg( "%s probably spritegen qc.script, skipping...\n", gs_filename ); - return false; - } - else if( !com.stricmp( token, "$modelname" ) && scripttype != QC_STUDIOMDL ) - { - Msg( "%s probably studio qc.script, skipping...\n", gs_filename ); - return false; - } - else if( !com.stricmp( token, "$body" ) && scripttype != QC_STUDIOMDL ) - { - Msg( "%s probably studio qc.script, skipping...\n", gs_filename ); - return false; - } - else if( !com.stricmp( token, "$wadname" ) && scripttype != QC_WADLIB ) - { - Msg( "%s probably wadlib qc.script, skipping...\n", gs_filename ); - return false; - } - else if( !com.stricmp( token, "$mipmap" ) && scripttype != QC_WADLIB ) - { - Msg("%s probably wadlib qc.script, skipping...\n", gs_filename ); - return false; - } - return true; -}; diff --git a/xtools/xtools.h b/xtools/xtools.h deleted file mode 100644 index 4e99403d..00000000 --- a/xtools/xtools.h +++ /dev/null @@ -1,33 +0,0 @@ -//======================================================================= -// Copyright XashXT Group 2007 й -// xtools.h - Xash Game Tools -//======================================================================= -#ifndef XTOOLS_H -#define XTOOLS_H - -#include -#include "launch_api.h" - -//===================================== -// platform export -//===================================== - -void InitPlatform ( int argc, char **argv ); // init host -void RunPlatform ( void ); // host frame -void ClosePlatform ( void ); // close host - -//===================================== -// extragen export -//===================================== -qboolean ConvertResource( byte *mempool, const char *filename, byte parms ); -void Bsp_PrintLog( const char *pMsg ); -void Skin_FinalizeScript( void ); -void Conv_RunSearch( void ); - -// shared tools -void ClrMask( void ); -void AddMask( const char *mask ); -extern string searchmask[]; -extern int num_searchmask; - -#endif//XTOOLS_H \ No newline at end of file