sof2-sdk/code/cgame/cg_main.c

1983 lines
51 KiB
C

// Copyright (C) 2001-2002 Raven Software.
//
// cg_main.c -- initialization and primary entry point for cgame
#include "cg_local.h"
#include "../ui/ui_shared.h"
// display context for new ui stuff
displayContextDef_t cgDC;
#if !defined(CL_LIGHT_H_INC)
#include "cg_lights.h"
#endif
int forceModelModificationCount = -1;
void CG_Init ( int serverMessageNum, int serverCommandSequence, int clientNum );
void CG_InitItems ( void );
void CG_Shutdown ( void );
void CG_CalcEntityLerpPositions( centity_t *cent );
static int C_PointContents (void);
static void C_GetLerpOrigin (void);
static void C_GetLerpAngles (void);
static void C_GetModelScale (void);
static void C_Trace (void);
static void C_CameraShake (void);
/*
================
vmMain
This is the only way control passes into the module.
This must be the very first function compiled into the .q3vm file
================
*/
int vmMain( int command, int arg0, int arg1, int arg2, int arg3, int arg4, int arg5, int arg6, int arg7, int arg8, int arg9, int arg10, int arg11 )
{
switch ( command )
{
case CG_INIT:
CG_Init( arg0, arg1, arg2 );
return 0;
case CG_SHUTDOWN:
CG_Shutdown();
return 0;
case CG_CONSOLE_COMMAND:
return CG_ConsoleCommand();
case CG_DRAW_ACTIVE_FRAME:
CG_DrawActiveFrame( arg0, arg1, arg2 );
return 0;
case CG_CROSSHAIR_PLAYER:
return CG_CrosshairPlayer();
case CG_LAST_ATTACKER:
return CG_LastAttacker();
case CG_KEY_EVENT:
CG_KeyEvent(arg0, arg1);
return 0;
case CG_MOUSE_EVENT:
cgDC.cursorx = cgs.cursorX;
cgDC.cursory = cgs.cursorY;
CG_MouseEvent(arg0, arg1);
return 0;
case CG_EVENT_HANDLING:
CG_EventHandling(arg0);
return 0;
case CG_POINT_CONTENTS:
return C_PointContents();
case CG_GET_LERP_ORIGIN:
C_GetLerpOrigin();
return 0;
case CG_GET_LERP_ANGLES:
C_GetLerpAngles();
return 0;
case CG_GET_MODEL_SCALE:
C_GetModelScale();
return 0;
case CG_GET_GHOUL2:
return (int)CG_GetEntity (arg0)->ghoul2;
case CG_GET_MODEL_LIST:
return (int)cgs.gameModels;
case CG_CALC_LERP_POSITIONS:
CG_CalcEntityLerpPositions( CG_GetEntity ( arg0 ) );
return 0;
case CG_TRACE:
C_Trace();
return 0;
case CG_GET_ORIGIN:
VectorCopy( CG_GetEntity (arg0)->currentState.pos.trBase, (float *)arg1);
return 0;
case CG_GET_ANGLES:
VectorCopy( CG_GetEntity (arg0)->currentState.apos.trBase, (float *)arg1);
return 0;
case CG_GET_ORIGIN_TRAJECTORY:
return (int)&CG_GetEntity (arg0)->nextState.pos;
case CG_GET_ANGLE_TRAJECTORY:
return (int)&CG_GetEntity (arg0)->nextState.apos;
case CG_FX_CAMERASHAKE:
C_CameraShake();
return 0;
case CG_MISC_ENT:
CG_MiscEnt();
return 0;
case CG_MAP_CHANGE:
// this trap map be called more than once for a given map change, as the
// server is going to attempt to send out multiple broadcasts in hopes that
// the client will receive one of them
cg.mMapChange = qtrue;
trap_S_ClearLoopingSounds ( qtrue );
trap_S_StopAllSounds ( );
trap_UI_CloseAll ( );
return 0;
case CG_VOICE_EVENT:
Com_Printf ( "voice: event %d\n", arg0 );
switch ( arg0 )
{
case VEV_TALKSTART:
if ( arg1 != cg.predictedPlayerState.clientNum )
{
trap_S_StartLocalSound ( trap_S_RegisterSound ( "sound/radiostart.wav" ), CHAN_AUTO );
}
cgs.clientinfo[arg1].voice = qtrue;
break;
case VEV_TALKSTOP:
if ( arg1 != cg.predictedPlayerState.clientNum )
{
trap_S_StartLocalSound ( trap_S_RegisterSound ( "sound/radiostart.wav" ), CHAN_AUTO );
}
cgs.clientinfo[arg1].voice = qfalse;
break;
}
return 0;
default:
Com_Error( ERR_FATAL, "vmMain: unknown command %i", command );
break;
}
return -1;
}
static int C_PointContents(void)
{
TCGPointContents *data = (TCGPointContents *)cg.sharedBuffer;
return CG_PointContents( data->mPoint, data->mPassEntityNum );
}
static void C_GetLerpOrigin(void)
{
TCGVectorData *data = (TCGVectorData *)cg.sharedBuffer;
VectorCopy( CG_GetEntity (data->mEntityNum)->lerpOrigin, data->mPoint);
}
static void C_GetLerpAngles(void)
{
TCGVectorData *data = (TCGVectorData *)cg.sharedBuffer;
VectorCopy(CG_GetEntity(data->mEntityNum)->lerpAngles, data->mPoint);
}
static void C_GetModelScale(void)
{
TCGVectorData *data = (TCGVectorData *)cg.sharedBuffer;
VectorCopy(CG_GetEntity(data->mEntityNum)->modelScale, data->mPoint);
}
static void C_Trace(void)
{
TCGTrace *td = (TCGTrace *)cg.sharedBuffer;
CG_Trace(&td->mResult, td->mStart, td->mMins, td->mMaxs, td->mEnd, td->mSkipNumber, td->mMask);
}
static void C_CameraShake(void)
{
TCGCameraShake *data = (TCGCameraShake *)cg.sharedBuffer;
CG_CameraShake ( data->mOrigin, data->mIntensity, data->mRadius, data->mTime );
}
cg_t cg;
cgs_t cgs;
centity_t cg_entities[MAX_GENTITIES];
centity_t *cg_permanents[MAX_GENTITIES];
int cg_numpermanents = 0;
weaponInfo_t cg_weapons[MAX_WEAPONS];
itemInfo_t cg_items[MAX_ITEMS];
vmCvar_t cg_centertime;
vmCvar_t cg_centerY;
vmCvar_t cg_runpitch;
vmCvar_t cg_runroll;
vmCvar_t cg_bobup;
vmCvar_t cg_bobpitch;
vmCvar_t cg_bobroll;
vmCvar_t cg_shadows;
vmCvar_t cg_drawTimer;
vmCvar_t cg_drawFPS;
vmCvar_t cg_drawSnapshot;
vmCvar_t cg_drawCrosshair;
vmCvar_t cg_drawCrosshairNames;
vmCvar_t cg_drawRadar;
vmCvar_t cg_drawTeamScores;
vmCvar_t cg_drawHUDIcons;
vmCvar_t cg_crosshairSize;
vmCvar_t cg_crosshairGrow;
vmCvar_t cg_crosshairX;
vmCvar_t cg_crosshairY;
vmCvar_t cg_crosshairRGBA;
vmCvar_t cg_crosshairFriendRGBA;
vmCvar_t cg_draw2D;
vmCvar_t cg_debugEvents;
vmCvar_t cg_errorDecay;
vmCvar_t cg_nopredict;
vmCvar_t cg_showmiss;
vmCvar_t cg_footsteps;
vmCvar_t cg_drawGun;
vmCvar_t cg_gun_x;
vmCvar_t cg_gun_y;
vmCvar_t cg_gun_z;
vmCvar_t cg_autoswitch;
vmCvar_t cg_ignore;
vmCvar_t cg_simpleItems;
vmCvar_t cg_fov;
vmCvar_t cg_goreDetail;
vmCvar_t cg_thirdPerson;
vmCvar_t cg_thirdPersonRange;
vmCvar_t cg_thirdPersonYaw;
vmCvar_t cg_thirdPersonPitch;
vmCvar_t cg_thirdPersonHorzOffset;
vmCvar_t cg_stereoSeparation;
vmCvar_t cg_lagometer;
vmCvar_t cg_synchronousClients;
vmCvar_t cg_chatTime;
vmCvar_t cg_chatHeight;
vmCvar_t cg_stats;
vmCvar_t cg_buildScript;
vmCvar_t cg_forceModel;
vmCvar_t cg_paused;
vmCvar_t cg_predictItems;
vmCvar_t cg_antiLag;
vmCvar_t cg_impactPrediction;
vmCvar_t cg_autoReload;
vmCvar_t cg_deferPlayers;
vmCvar_t cg_drawFriend;
vmCvar_t cg_teamChatsOnly;
vmCvar_t cg_noVoiceText;
vmCvar_t cg_hudFiles;
vmCvar_t cg_smoothClients;
vmCvar_t pmove_fixed;
vmCvar_t pmove_msec;
vmCvar_t cg_pmove_msec;
vmCvar_t cg_cameraMode;
vmCvar_t cg_cameraOrbit;
vmCvar_t cg_cameraOrbitDelay;
vmCvar_t cg_timescale;
vmCvar_t cg_noProjectileTrail;
vmCvar_t cg_currentSelectedPlayer;
vmCvar_t cg_currentSelectedPlayerName;
vmCvar_t cg_DebugGore;
vmCvar_t cg_lockBlood;
vmCvar_t cg_lockSever;
vmCvar_t cg_lockDeaths;
vmCvar_t cg_marks;
vmCvar_t cg_shellEjection;
vmCvar_t RMG_distancecull;
vmCvar_t cg_blueteamname;
vmCvar_t cg_redteamname;
vmCvar_t cg_damageindicator;
vmCvar_t cg_tracerChance;
vmCvar_t cg_animBlend;
vmCvar_t cg_automap_x;
vmCvar_t cg_automap_y;
vmCvar_t cg_automap_w;
vmCvar_t cg_automap_h;
vmCvar_t cg_automap_a;
vmCvar_t ui_info_redcount;
vmCvar_t ui_info_bluecount;
vmCvar_t ui_info_speccount;
vmCvar_t ui_info_freecount;
vmCvar_t ui_info_pickupsdisabled;
vmCvar_t ui_info_seenobjectives;
vmCvar_t cg_voiceRadio;
vmCvar_t cg_voiceGlobal;
vmCvar_t cg_soundGlobal;
vmCvar_t cg_soundFrag;
vmCvar_t cg_weaponMenuFast;
vmCvar_t cg_bodyTime;
vmCvar_t cg_zoomWeaponChange;
vmCvar_t rw_enabled;
typedef struct
{
vmCvar_t *vmCvar;
char *cvarName;
char *defaultString;
int cvarFlags;
float mMinValue, mMaxValue;
} cvarTable_t;
static cvarTable_t cvarTable[] =
{
{ &cg_lockBlood, "lock_blood", "1", 0 },
{ &cg_lockSever, "lock_sever", "1", 0 },
{ &cg_lockDeaths, "lock_deaths", "1", 0 },
{ &rw_enabled, "rw_enabled", "0", 0 },
{ &cg_shellEjection, "cg_shellEjection", "1", CVAR_ARCHIVE },
{ &cg_ignore, "cg_ignore", "0", 0 },
{ &cg_autoswitch, "cg_autoswitch", "2", CVAR_ARCHIVE },
{ &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
{ &cg_fov, "cg_fov", "80", CVAR_ARCHIVE | CVAR_LOCK_RANGE, 80.0, 100.0 },
{ &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE },
{ &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE },
{ &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE|CVAR_CHEAT },
{ &cg_drawTimer, "cg_drawTimer", "1", CVAR_ARCHIVE },
{ &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE },
{ &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
{ &cg_drawCrosshair, "cg_drawCrosshair", "4", CVAR_ARCHIVE },
{ &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
{ &cg_drawHUDIcons, "cg_drawHUDIcons", "1", CVAR_ARCHIVE },
{ &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE },
{ &cg_crosshairGrow, "cg_crosshairGrow", "1", CVAR_ARCHIVE },
{ &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
{ &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
{ &cg_crosshairRGBA, "cg_crosshairRGBA", "1,1,1,1", CVAR_ARCHIVE },
{ &cg_crosshairFriendRGBA, "cg_crosshairFriendRGBA", "1,0,0,1", CVAR_ARCHIVE },
{ &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
{ &cg_lagometer, "cg_lagometer", "0", CVAR_ARCHIVE },
{ &cg_gun_x, "cg_gunX", "0", CVAR_CHEAT },
{ &cg_gun_y, "cg_gunY", "0", CVAR_CHEAT },
{ &cg_gun_z, "cg_gunZ", "0", CVAR_CHEAT },
{ &cg_centertime, "cg_centertime", "4", CVAR_ARCHIVE },
{ &cg_centerY, "cg_centerY", "70", CVAR_ARCHIVE },
{ &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE|CVAR_LOCK_RANGE, 0.0f, 0.002f },
{ &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE|CVAR_LOCK_RANGE, 0.0f, 0.005f },
{ &cg_bobup , "cg_bobup", "0.005", CVAR_ARCHIVE|CVAR_LOCK_RANGE, 0.0f, 0.005f },
{ &cg_bobpitch, "cg_bobpitch", "0.001", CVAR_ARCHIVE|CVAR_LOCK_RANGE, 0.0f, 0.001f },
{ &cg_bobroll, "cg_bobroll", "0.001", CVAR_ARCHIVE|CVAR_LOCK_RANGE, 0.0f, 0.001f },
{ &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT },
{ &cg_errorDecay, "cg_errordecay", "100", 0 },
{ &cg_nopredict, "cg_nopredict", "0", 0 },
{ &cg_showmiss, "cg_showmiss", "0", 0 },
{ &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT },
{ &cg_goreDetail, "cg_goreDetail", "1", CVAR_ARCHIVE },
{ &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_CHEAT },
{ &cg_thirdPersonRange, "cg_thirdPersonRange", "80", CVAR_CHEAT },
{ &cg_thirdPersonYaw, "cg_thirdPersonYaw", "0", CVAR_CHEAT },
{ &cg_thirdPersonPitch, "cg_thirdPersonPitch", "15", CVAR_CHEAT },
{ &cg_thirdPersonHorzOffset, "cg_thirdPersonHorzOffset", "0", CVAR_CHEAT },
{ &cg_chatTime, "cg_chatTime", "8000", CVAR_ARCHIVE },
{ &cg_chatHeight, "cg_chatHeight", "4", CVAR_ARCHIVE },
{ &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE },
{ &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE },
{ &cg_antiLag, "cg_antiLag", "1", CVAR_ARCHIVE | CVAR_USERINFO },
#ifdef _SOF2_FLESHIMPACTPREDICTION
{ &cg_impactPrediction, "cg_impactPrediction", "2", CVAR_ARCHIVE },
#else
{ &cg_impactPrediction, "cg_impactPrediction", "1", CVAR_ARCHIVE },
#endif
{ &cg_autoReload, "cg_autoReload", "1", CVAR_ARCHIVE | CVAR_USERINFO },
{ &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE },
{ &cg_stats, "cg_stats", "0", 0 },
{ &cg_drawFriend, "cg_drawFriend", "1", CVAR_ARCHIVE },
{ &cg_teamChatsOnly, "cg_teamChatsOnly", "0", CVAR_ARCHIVE },
{ &cg_noVoiceText, "cg_noVoiceText", "0", CVAR_ARCHIVE },
// the following variables are created in other parts of the system,
// but we also reference them here
{ &cg_buildScript, "com_buildScript", "0", 0 }, // force loading of all possible data amd error on failures
{ &cg_paused, "cl_paused", "0", CVAR_ROM },
{ &cg_synchronousClients, "g_synchronousClients", "0", 0 }, // communicated by systeminfo
{ &cg_currentSelectedPlayer, "cg_currentSelectedPlayer", "0", CVAR_ARCHIVE},
{ &cg_currentSelectedPlayerName, "cg_currentSelectedPlayerName", "", CVAR_ARCHIVE},
{ &cg_hudFiles, "cg_hudFiles", "ui/hud.txt", CVAR_ARCHIVE},
{ &cg_cameraOrbit, "cg_cameraOrbit", "0", CVAR_CHEAT},
{ &cg_cameraOrbitDelay, "cg_cameraOrbitDelay", "50", CVAR_ARCHIVE},
{ &cg_timescale, "timescale", "1", 0},
{ &cg_smoothClients, "cg_smoothClients", "0", CVAR_USERINFO | CVAR_ARCHIVE},
{ &cg_cameraMode, "com_cameraMode", "0", CVAR_CHEAT},
{ &pmove_fixed, "pmove_fixed", "0", 0},
{ &pmove_msec, "pmove_msec", "8", 0},
{ &cg_noProjectileTrail, "cg_noProjectileTrail", "0", CVAR_ARCHIVE},
{ &cg_DebugGore, "cg_debuggore", "", CVAR_CHEAT },
{ &RMG_distancecull, "RMG_distancecull", "5000", CVAR_CHEAT },
{ &cg_blueteamname, "ui_blueteamname", "0", CVAR_ROM|CVAR_INTERNAL },
{ &cg_redteamname, "ui_redteamname", "0", CVAR_ROM|CVAR_INTERNAL },
{ &cg_damageindicator, "cg_damageindicator", "1.5", CVAR_ARCHIVE },
{ &cg_tracerChance, "cg_tracerChance", "1", CVAR_ARCHIVE | CVAR_LOCK_RANGE, 0.0f, 0.50f },
{ &cg_animBlend, "cg_animBlend", "1", CVAR_ARCHIVE },
{ &cg_automap_x, "cg_automap_x", "485", CVAR_ARCHIVE | CVAR_LOCK_RANGE, 0.0, 629.0 },
{ &cg_automap_y, "cg_automap_y", "5", CVAR_ARCHIVE | CVAR_LOCK_RANGE, 0.0, 469.0},
{ &cg_automap_w, "cg_automap_w", "150", CVAR_ARCHIVE | CVAR_LOCK_RANGE, 10.0, 640.0 },
{ &cg_automap_h, "cg_automap_h", "150", CVAR_ARCHIVE | CVAR_LOCK_RANGE, 10.0, 480.0},
{ &cg_automap_a, "cg_automap_a", "0.75", CVAR_ARCHIVE | CVAR_LOCK_RANGE, 0.0, 1.0},
{ &cg_drawRadar, "cg_drawRadar", "2", CVAR_ARCHIVE },
{ &cg_drawTeamScores, "cg_drawTeamScores", "1", CVAR_ARCHIVE },
{ &ui_info_redcount, "ui_info_redcount", "0", CVAR_INTERNAL|CVAR_ROM },
{ &ui_info_bluecount, "ui_info_bluecount", "0", CVAR_INTERNAL|CVAR_ROM },
{ &ui_info_speccount, "ui_info_speccount", "0", CVAR_INTERNAL|CVAR_ROM },
{ &ui_info_freecount, "ui_info_freecount", "0", CVAR_INTERNAL|CVAR_ROM },
{ &ui_info_pickupsdisabled, "ui_info_pickupsdisabled", "0", CVAR_INTERNAL|CVAR_ROM },
{ &ui_info_seenobjectives, "ui_info_seenobjectives", "0", CVAR_INTERNAL|CVAR_ROM },
{ &cg_voiceRadio, "cg_voiceRadio", "1", CVAR_ARCHIVE, 0.0f, 0.0f },
{ &cg_voiceGlobal, "cg_voiceGlobal", "1", CVAR_ARCHIVE, 0.0f, 0.0f },
{ &cg_soundGlobal, "cg_soundGlobal", "1", CVAR_ARCHIVE, 0.0f, 0.0f },
{ &cg_soundFrag, "cg_soundFrag", "1", CVAR_ARCHIVE, 0.0f, 0.0f },
{ &cg_weaponMenuFast, "cg_weaponMenuFast", "0", CVAR_ARCHIVE },
{ &cg_bodyTime, "cg_bodyTime", "0", CVAR_ARCHIVE, 0.0f, 0.0f },
{ &cg_zoomWeaponChange, "cg_zoomWeaponChange", "1", CVAR_ARCHIVE, 0.0f, 0.0f },
};
static int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
/*
=================
CG_RegisterCvars
=================
*/
void CG_RegisterCvars( void )
{
int i;
cvarTable_t *cv;
char var[MAX_TOKEN_CHARS];
for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ )
{
trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags, cv->mMinValue, cv->mMaxValue );
}
// see if we are also running the server on this machine
trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) );
cgs.localServer = atoi( var );
forceModelModificationCount = cg_forceModel.modificationCount;
trap_Cvar_Register(NULL, "identity", DEFAULT_IDENTITY, CVAR_USERINFO | CVAR_ARCHIVE, 0.0, 0.0 );
trap_Cvar_Register(NULL, "team_identity", DEFAULT_IDENTITY, CVAR_USERINFO | CVAR_ARCHIVE, 0.0, 0.0 );
trap_Cvar_Register(NULL, "outfitting", "AAAA", CVAR_USERINFO | CVAR_ARCHIVE, 0.0, 0.0 );
// Cvars uses for transferring data between client and server
trap_Cvar_Register(NULL, "ui_about_gametype", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_gametypename", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_scorelimit", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_timelimit", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_maxclients", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_dmflags", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_mapname", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_hostname", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_needpass", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_botminplayers", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_info_availableweapons","0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_info_redscore", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_info_bluescore", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "cg_lastobjectives", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Register(NULL, "ui_about_seed", "0", CVAR_ROM|CVAR_INTERNAL, 0.0, 0.0 );
trap_Cvar_Set ( "ui_info_seenobjectives", "0" );
trap_Cvar_Set ( "ui_info_redscore", "0" );
trap_Cvar_Set ( "ui_info_bluescore", "0" );
}
/*
===================
CG_ForceModelChange
===================
*/
static void CG_ForceModelChange( void )
{
int i;
for (i=0 ; i<MAX_CLIENTS ; i++)
{
const char *clientInfo;
clientInfo = CG_ConfigString( CS_PLAYERS+i );
if ( !clientInfo[0] )
{
continue;
}
CG_NewClientInfo( i );
}
}
/*
==================
CG_UpdateTeamCountCvars
==================
*/
void CG_UpdateTeamCountCvars ( void )
{
int i;
int counts[TEAM_NUM_TEAMS];
memset ( counts, 0, sizeof(counts) );
for ( i = 0 ; i < cgs.maxclients ; i++ )
{
clientInfo_t* cl;
cl = &cgs.clientinfo[ i ];
if ( !cl->infoValid )
{
continue;
}
counts[cl->team]++;
}
trap_Cvar_Set ( "ui_info_redcount", va("%i", counts[TEAM_RED] ) );
trap_Cvar_Set ( "ui_info_bluecount", va("%i", counts[TEAM_BLUE]) );
trap_Cvar_Set ( "ui_info_freecount", va("%i", counts[TEAM_FREE]) );
trap_Cvar_Set ( "ui_info_speccount", va("%i", counts[TEAM_SPECTATOR] ) );
}
/*
=================
CG_UpdateCvars
=================
*/
void CG_UpdateCvars( void )
{
int i;
cvarTable_t *cv;
static int crosshairRGBAModificationCount = -1;
static int crosshairFriendRGBAModificationCount = -1;
for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ )
{
trap_Cvar_Update( cv->vmCvar );
}
// if force model changed
if ( forceModelModificationCount != cg_forceModel.modificationCount )
{
forceModelModificationCount = cg_forceModel.modificationCount;
CG_ForceModelChange();
}
// If the crosshair RGBA was modified then update the globals
if ( crosshairRGBAModificationCount != cg_crosshairRGBA.modificationCount )
{
sscanf ( cg_crosshairRGBA.string, "%f,%f,%f,%f",
&cg.crosshairRGBA[0],
&cg.crosshairRGBA[1],
&cg.crosshairRGBA[2],
&cg.crosshairRGBA[3] );
crosshairRGBAModificationCount = cg_crosshairRGBA.modificationCount;
}
// If the crosshair RGBA was modified then update the globals
if ( crosshairFriendRGBAModificationCount != cg_crosshairFriendRGBA.modificationCount )
{
sscanf ( cg_crosshairFriendRGBA.string, "%f,%f,%f,%f",
&cg.crosshairFriendRGBA[0],
&cg.crosshairFriendRGBA[1],
&cg.crosshairFriendRGBA[2],
&cg.crosshairFriendRGBA[3] );
crosshairFriendRGBAModificationCount = cg_crosshairFriendRGBA.modificationCount;
}
}
int CG_CrosshairPlayer( void )
{
if ( cg.time > ( cg.crosshairClientTime + 1000 ) )
{
return -1;
}
return cg.crosshairClientNum;
}
int CG_LastAttacker( void ) {
if ( !cg.attackerTime ) {
return -1;
}
return cg.snap->ps.persistant[PERS_ATTACKER];
}
#ifndef CGAME_HARD_LINKED
// this is only here so the functions in q_shared.c and bg_*.c can link (FIXME)
void QDECL Com_Error( int level, const char *msg, ... )
{
va_list argptr;
char text[1024];
va_start (argptr, msg);
vsprintf (text, msg, argptr);
va_end (argptr);
trap_Error( text );
}
void QDECL Com_Printf( const char *msg, ... )
{
va_list argptr;
char text[1024];
va_start (argptr, msg);
vsprintf (text, msg, argptr);
va_end (argptr);
trap_Print( text );
}
#endif
/*
=================
CG_GetEntity
This function handles the predicted player entitiy specially. The player
should always be using the predicted entity rather than whats in the main
entity array.
=================
*/
centity_t* CG_GetEntity ( int index )
{
/*
if ( index == cg.clientNum )
{
return &cg.predictedPlayerEntity;
}
*/
return &cg_entities[index];
}
/*
================
CG_Argv
================
*/
const char *CG_Argv( int arg ) {
static char buffer[MAX_STRING_CHARS];
trap_Argv( arg, buffer, sizeof( buffer ) );
return buffer;
}
//========================================================================
/*
=================
CG_RegisterItemSounds
The server says this item is used on this level
=================
*/
static void CG_RegisterItemSounds( int itemNum ) {
gitem_t *item;
char data[MAX_QPATH];
char *s, *start;
int len;
item = &bg_itemlist[ itemNum ];
if( item->pickup_sound ) {
trap_S_RegisterSound( item->pickup_sound );
}
// parse the space seperated precache string for other media
s = item->sounds;
if (!s || !s[0])
{
return;
}
while (*s) {
start = s;
while (*s && *s != ' ')
{
s++;
}
len = s-start;
if (len >= MAX_QPATH || len < 5)
{
Com_Error( ERR_FATAL, "PrecacheItem: %s has bad precache string", item->classname);
return;
}
memcpy (data, start, len);
data[len] = 0;
if ( *s )
{
s++;
}
if ( !strcmp(data+len-3, "wav" ))
{
trap_S_RegisterSound( data );
}
}
}
/*
=================
CG_RegisterLadders
Registers all the ladders in the current map
=================
*/
static void CG_RegisterLadders ( void )
{
int i;
const char *ladder;
for ( i = 0 ; i < MAX_LADDERS ; i++ )
{
vec3_t absmin;
vec3_t absmax;
vec3_t fwd;
vec3_t angles;
ladder = CG_ConfigString( CS_LADDERS + i );
// No ladder?
if ( !ladder || !ladder[0] )
{
continue;
}
VectorClear ( angles );
sscanf ( ladder, "%f,%f,%f,%f,%f,%f,%f",
&absmin[0], &absmin[1], &absmin[2],
&absmax[0], &absmax[1], &absmax[2],
&angles[YAW] );
AngleVectors( angles, fwd, 0, 0);
BG_AddLadder ( absmin, absmax, fwd );
}
}
/*
=================
CG_RegisterSounds
called during a precache command
=================
*/
static void CG_RegisterSounds( void )
{
int i;
char items[MAX_ITEMS+1];
const char *soundName;
// voice commands
CG_LoadVoiceChats();
CG_LoadingStage ( 3 );
cgs.media.talkSound = trap_S_RegisterSound( "sound/player/talk.wav" );
cgs.media.waterFootstep[0] = trap_S_RegisterSound( "sound/player/steps/water/water_step0");
cgs.media.waterFootstep[1] = trap_S_RegisterSound( "sound/player/steps/water/water_step1");
cgs.media.waterWade[0] = trap_S_RegisterSound( "sound/player/steps/water/water_wade0");
cgs.media.waterWade[1] = trap_S_RegisterSound( "sound/player/steps/water/water_wade1");
cgs.media.waterJumpIn = trap_S_RegisterSound( "sound/player/jumps/water_jump");
cgs.media.waterLeave = trap_S_RegisterSound( "sound/pain_death/mullins/water_surface");
cgs.media.armorHitSound[0] = trap_S_RegisterSound( "sound/pain_death/mullins/armor01");
cgs.media.armorHitSound[1] = trap_S_RegisterSound( "sound/pain_death/mullins/armor02");
cgs.media.fleshHitSound[0] = trap_S_RegisterSound( "sound/pain_death/mullins/hit01");
cgs.media.fleshHitSound[1] = trap_S_RegisterSound( "sound/pain_death/mullins/hit02");
// only register the items that the server says we need
strcpy( items, CG_ConfigString( CS_ITEMS ) );
CG_LoadingStage ( 4 );
for (i = 0; i < MAX_AMBIENT_SOUNDSETS; i++) // 0 is reserved for current
{
const char *psString = CG_ConfigString( CS_AMBIENT_SOUNDSETS + i);
if (psString && strlen(psString))
{
trap_AS_AddPrecacheEntry( psString );
}
else
{
// break; // EOL
}
}
trap_AS_ParseSets();
for ( i = 1 ; i < bg_numItems ; i++ )
{
CG_RegisterItemSounds( i );
}
for ( i = 1 ; i < MAX_SOUNDS ; i++ )
{
soundName = CG_ConfigString( CS_SOUNDS+i );
if ( !soundName[0] )
{
break;
}
// custom sound
if ( soundName[0] == '*' )
{
continue;
}
cgs.gameSounds[i] = trap_S_RegisterSound( soundName );
}
cgs.media.glassBreakSound = trap_S_RegisterSound("sound/effects/glassbreak1.wav");
// Respawn sound is only used in gametypes where you respawn
if ( cgs.gametypeData->respawnType != RT_NONE )
{
cgs.media.respawnSound = trap_S_RegisterSound("sound/player_respawn.wav");
}
cgs.media.itemRespawnSound = trap_S_RegisterSound ( "sound/item_respawn.mp3" );
cgs.media.fragSound = trap_S_RegisterSound ( "sound/frag.mp3" );
cgs.media.fragSelfSound = trap_S_RegisterSound ( "sound/self_frag.mp3" );
cgs.media.zoomSound = trap_S_RegisterSound ( "sound/weapons/sniper/scope_zoom.wav" );
cgs.media.gogglesOnSound = trap_S_RegisterSound ( "sound/weapons/goggles/turn_on.mp3" );
cgs.media.gogglesOffSound = trap_S_RegisterSound ( "sound/weapons/goggles/turn_off.mp3" );
// Move out sound
if ( cgs.gametypeData->respawnType == RT_NONE )
{
cgs.media.goSound = trap_S_RegisterSound ( "sound/radio/male/move.mp3" );
}
// bullet flyby sounds
for (i = 0; i < NUMFLYBYS; i++)
{
cgs.media.flybySounds[i] = trap_S_RegisterSound ( va("sound/player/bullet_impacts/whine/b_whine%d", i));
}
// Water sounds
cgs.media.drownPainSound[0] = trap_S_RegisterSound ( "sound/pain_death/mullins/drown01.mp3" );
cgs.media.drownPainSound[1] = trap_S_RegisterSound ( "sound/pain_death/mullins/drown02.mp3" );
cgs.media.drownDeathSound = trap_S_RegisterSound ( "sound/pain_death/mullins/drown_dead.mp3" );
CG_LoadingStage ( 5 );
}
//-------------------------------------
// CG_RegisterEffects
//
// Handles precaching all effect files
// and any shader, model, or sound
// files an effect may use.
//-------------------------------------
static void CG_RegisterEffects( void )
{
const char *effectName;
int i;
for ( i = 1 ; i < MAX_FX ; i++ )
{
effectName = CG_ConfigString( CS_EFFECTS + i );
if ( !effectName[0] )
{
break;
}
trap_FX_RegisterEffect( effectName );
}
}
//===================================================================================
/*
=================
CG_RegisterGraphics
This function may execute for a couple of minutes with a slow disk.
=================
*/
static void CG_RegisterGraphics( void )
{
int i;
char items[MAX_ITEMS+1];
int sub;
char temp[MAX_QPATH];
int breakPoint;
const char *terrainInfo;
int terrainID;
vec3_t distance;
// clear any references to old media
memset( &cg.refdef, 0, sizeof( cg.refdef ) );
trap_R_ClearScene();
// Load the map
CG_LoadingString( cgs.mapname );
trap_R_LoadWorldMap( cgs.mapname );
// precache status bar pics
CG_LoadingString( "game media" );
CG_LoadingStage ( 6 );
cgs.media.cursor = trap_R_RegisterShaderNoMip( "gfx/menus/cursor/cursor" );
// Register the graphics for the scoreboard
cgs.media.scoreboard = trap_R_RegisterShaderNoMip ( "gfx/menus/scoreboard/scoreboard.tga" );
cgs.media.scoreboardHeader = trap_R_RegisterShaderNoMip ( "gfx/menus/scoreboard/scorelineheader.tga" );
cgs.media.scoreboardLine = trap_R_RegisterShaderNoMip ( "gfx/menus/scoreboard/scoreline.tga" );
cgs.media.scoreboardFooter = trap_R_RegisterShaderNoMip ( "gfx/menus/scoreboard/scorelinefooter.tga" );
cgs.media.scoreboardTotals = trap_R_RegisterShaderNoMip ( "gfx/menus/scoreboard/scorelinetotals.tga" );
cgs.media.smokePuffShader = trap_R_RegisterShader( "smokePuff" );
cgs.media.lagometerShader = trap_R_RegisterShader("gfx/menus/hud/lagometer.tga" );
cgs.media.disconnectShader = trap_R_RegisterShader("gfx/menus/hud/disconnect.tga" );
cgs.media.waterBubbleShader = trap_R_RegisterShader( "gfx/misc/bubble" );
cgs.media.backTileShader = trap_R_RegisterShader( "gfx/2d/backtile" );
cgs.media.mAutomapPlayerIcon = trap_R_RegisterShader( "gfx/menus/rmg/arrow_w" );
CG_LoadingStage ( 7 );
Com_Printf( S_COLOR_CYAN "---------- Fx System Initialization ---------\n" );
trap_FX_InitSystem( &cg.refdef);
Com_Printf( S_COLOR_CYAN "----- Fx System Initialization Complete -----\n" );
CG_RegisterEffects();
// Initialize the materials
trap_MAT_Init();
CG_LoadingStage ( 8 );
// Initialize the crosshairs
for ( i = 0 ; i < NUM_CROSSHAIRS ; i++ )
{
cgs.media.crosshairShader[i] = trap_R_RegisterShader( va("gfx/menus/crosshairs/ch%i", i) );
}
CG_LoadingStage ( 9 );
if ( cgs.gametypeData->teams )
{
cgs.media.blueFriendShader = trap_R_RegisterShader ( "gfx/menus/hud/team_blue" );
cgs.media.redFriendShader = trap_R_RegisterShader ( "gfx/menus/hud/team_red" );
cgs.media.radarShader = trap_R_RegisterShaderNoMip ( "gfx/menus/hud/radar.png" );
}
cgs.media.botSmallShader = trap_R_RegisterShaderNoMip ( "gfx/menus/hud/bot_small" );
cgs.media.armorShader = trap_R_RegisterShaderNoMip ( "gfx/menus/hud/hud_armor" );
cgs.media.deadShader = trap_R_RegisterShaderNoMip ( "gfx/menus/hud/dead" );
CG_LoadingStage ( 10 );
// Initialize weapons, load them all
memset( cg_weapons, 0, sizeof( cg_weapons ) );
for (i = WP_NONE + 1; i < WP_NUM_WEAPONS; i ++ )
{
if ( cgs.pickupsDisabled && !BG_IsWeaponAvailableForOutfitting ( i, 2 ) )
{
continue;
}
CG_RegisterWeapon ( i );
}
CG_LoadingStage ( 11 );
// only register the items that the server says we need
strcpy( items, CG_ConfigString( CS_ITEMS) );
for ( i = 1 ; i < bg_numItems ; i++ )
{
// Dont bother with weapons, theyare already loaded
if ( items[ i ] == '1' || cg_buildScript.integer )
{
CG_RegisterItemVisuals( i );
}
}
CG_LoadingStage ( 12 );
// wall marks
cgs.media.burnMarkShader = trap_R_RegisterShader( "gfx/damage/burnmark5" );
cgs.media.shadowMarkShader = trap_R_RegisterShader( "markShadow" );
cgs.media.wakeMarkShader = trap_R_RegisterShader( "wake" );
cgs.media.bloodMarkShader = trap_R_RegisterShader( "bloodMark" );
cgs.media.mAutomap = 0;
// register the inline models
breakPoint = cgs.numInlineModels = trap_CM_NumInlineModels();
for ( i = 0 ; i < cgs.numInlineModels ; i++ )
{
char name[10];
vec3_t mins;
vec3_t maxs;
int j;
Com_sprintf( name, sizeof(name), "*%i", i );
cgs.inlineDrawModel[i] = trap_R_RegisterModel( name );
if (!cgs.inlineDrawModel[i])
{
breakPoint = i;
break;
}
trap_R_ModelBounds( cgs.inlineDrawModel[i], mins, maxs );
for ( j = 0 ; j < 3 ; j++ )
{
cgs.inlineModelMidpoints[i][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
}
}
// register all the server specified models
for (i=1 ; i<MAX_MODELS ; i++)
{
const char *modelName;
modelName = CG_ConfigString( CS_MODELS+i );
if ( !modelName[0] )
{
break;
}
cgs.gameModels[i] = trap_R_RegisterModel( modelName );
}
// register all the server specified icons
for ( i = 1; i < MAX_ICONS; i ++ )
{
const char* iconName;
iconName = CG_ConfigString ( CS_ICONS + i );
if ( !iconName[0] )
{
break;
}
cgs.gameIcons[i] = trap_R_RegisterShaderNoMip ( iconName );
}
CG_LoadingString( "BSP instances" );
for(i = 1; i < MAX_SUB_BSP; i++)
{
const char *bspName = 0;
vec3_t mins, maxs;
int j;
bspName = CG_ConfigString( CS_BSP_MODELS+i );
if ( !bspName[0] )
{
break;
}
trap_CM_LoadMap( bspName, qtrue );
cgs.inlineDrawModel[breakPoint] = trap_R_RegisterModel( bspName );
trap_R_ModelBounds( cgs.inlineDrawModel[breakPoint], mins, maxs );
for ( j = 0 ; j < 3 ; j++ )
{
cgs.inlineModelMidpoints[breakPoint][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
}
breakPoint++;
for(sub=1;sub<MAX_MODELS;sub++)
{
Com_sprintf(temp, MAX_QPATH, "*%d-%d", i, sub);
cgs.inlineDrawModel[breakPoint] = trap_R_RegisterModel( temp );
if (!cgs.inlineDrawModel[breakPoint])
{
break;
}
trap_R_ModelBounds( cgs.inlineDrawModel[breakPoint], mins, maxs );
for ( j = 0 ; j < 3 ; j++ )
{
cgs.inlineModelMidpoints[breakPoint][j] = mins[j] + 0.5 * ( maxs[j] - mins[j] );
}
breakPoint++;
}
}
// cg.mInRMG = qfalse;
// Register all the terrain ents
CG_LoadingString( "Creating terrain" );
for(i = 1; i < MAX_TERRAINS; i++)
{
terrainInfo = CG_ConfigString( CS_TERRAINS + i );
if ( !terrainInfo[0] )
{
break;
}
terrainID = trap_CM_RegisterTerrain(terrainInfo);
/*
if (i == 1)
{
cg.mInRMG = qtrue;
}
*/
trap_RMG_Init(terrainID, terrainInfo);
// Send off the terrainInfo to the renderer
trap_RE_InitRendererTerrain( terrainInfo );
}
if (cg.mInRMG)
{
const char* info;
trap_CM_TM_Upload(0, 0); // do not draw the origin / angles on the map itself
cgs.media.mAutomap = trap_R_RegisterShader( "gfx/menus/rmg/automap" );
cgs.mIRDist = RMG_distancecull.integer;
info = CG_ConfigString ( CS_SYSTEMINFO );
trap_Cvar_Set ( "ui_about_seed", Info_ValueForKey ( info,"RMG_textseed" ) );
}
else
{
trap_R_ModelBounds( cgs.inlineDrawModel[0], cgs.mWorldMins, cgs.mWorldMaxs );
VectorSubtract(cgs.mWorldMaxs, cgs.mWorldMins, distance);
cgs.mIRDist = VectorLength(distance);
// cgs.mIRSeeThrough = cgs.mIRDist / 2.0;
}
cgs.mIRDist = 2500.0;
cgs.mIRSeeThrough = 150.0;
CG_LoadingString("skins");
cgs.media.damageDirShader = trap_R_RegisterShader("gfx/misc/hit_direction_final");
cgs.media.glassChunkEffect = trap_FX_RegisterEffect ( "chunks/debris_glass.efx" );
cgs.media.playerFleshImpactEffect = trap_FX_RegisterEffect ( "blood_squirt_mp.efx" );
cgs.media.mBloodSmall = trap_FX_RegisterEffect ( "impact_player_mp.efx" );
cgs.media.test = trap_FX_RegisterEffect ( "arterial_squirt_small.efx" );
trap_G2API_InitGhoul2Model ( &cgs.media.nightVisionModel, "models/characters/bolt_ons/nightvision_bolt_on.glm", 0, 0, 0, 0, 0 );
CG_LoadingStage ( 13 );
}
/*
===================
CG_RegisterClients
===================
*/
static void CG_RegisterClients( void )
{
int i;
CG_LoadingClient(cg.clientNum);
CG_NewClientInfo(cg.clientNum);
for (i=0 ; i<MAX_CLIENTS ; i++)
{
const char *clientInfo;
if (cg.clientNum == i)
{
continue;
}
clientInfo = CG_ConfigString( CS_PLAYERS+i );
if ( !clientInfo[0])
{
continue;
}
CG_LoadingClient( i );
CG_NewClientInfo( i );
}
}
//===========================================================================
/*
=================
CG_ConfigString
=================
*/
const char *CG_ConfigString( int index )
{
if ( index < 0 || index >= MAX_CONFIGSTRINGS )
{
Com_Error( ERR_FATAL, "CG_ConfigString: bad index: %i", index );
}
return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];
}
//==================================================================
/*
======================
CG_StartMusic
======================
*/
void CG_StartMusic( qboolean bForceStart )
{
const char *s;
char parm1[MAX_QPATH], parm2[MAX_QPATH];
// start the background music
s = (char *)CG_ConfigString( CS_MUSIC );
Q_strncpyz( parm1, COM_Parse( &s ), sizeof( parm1 ) );
Q_strncpyz( parm2, COM_Parse( &s ), sizeof( parm2 ) );
if (!parm2[0])
{
strcpy(parm2, parm1);
}
if ( *parm1 && *parm2 )
{
trap_S_StartBackgroundTrack( parm1, parm2, !bForceStart );
}
}
char *CG_GetMenuBuffer(const char *filename)
{
int len;
fileHandle_t f;
static char buf[MAX_MENUFILE];
len = trap_FS_FOpenFile( filename, &f, FS_READ );
if ( !f ) {
trap_Print( va( S_COLOR_RED "menu file not found: %s, using default\n", filename ) );
return NULL;
}
if ( len >= MAX_MENUFILE ) {
trap_Print( va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", filename, len, MAX_MENUFILE ) );
trap_FS_FCloseFile( f );
return NULL;
}
trap_FS_Read( buf, len, f );
buf[len] = 0;
trap_FS_FCloseFile( f );
return buf;
}
//
// ==============================
// new hud stuff ( mission pack )
// ==============================
//
qboolean CG_Asset_Parse(int handle) {
pc_token_t token;
const char *tempStr;
if (!trap_PC_ReadToken(handle, &token))
return qfalse;
if (Q_stricmp(token.string, "{") != 0) {
return qfalse;
}
while ( 1 )
{
if (!trap_PC_ReadToken(handle, &token))
return qfalse;
if (Q_stricmp(token.string, "}") == 0)
{
return qtrue;
}
// font
if (Q_stricmp(token.string, "defaultFont") == 0)
{
if (!PC_String_Parse(handle, &tempStr) )
{
return qfalse;
}
cgDC.Assets.defaultFont = cgDC.registerFont(tempStr);
continue;
}
// itemFocusSound
if (Q_stricmp(token.string, "itemFocusSound") == 0)
{
if (!PC_String_Parse(handle, &tempStr))
{
return qfalse;
}
cgDC.Assets.itemFocusSound = trap_S_RegisterSound( tempStr );
continue;
}
if (Q_stricmp(token.string, "cursor") == 0) {
if (!PC_String_Parse(handle, &cgDC.Assets.cursorStr)) {
return qfalse;
}
cgDC.Assets.cursor = trap_R_RegisterShaderNoMip( cgDC.Assets.cursorStr);
continue;
}
if (Q_stricmp(token.string, "fadeClamp") == 0) {
if (!PC_Float_Parse(handle, &cgDC.Assets.fadeClamp)) {
return qfalse;
}
continue;
}
if (Q_stricmp(token.string, "fadeCycle") == 0) {
if (!PC_Int_Parse(handle, &cgDC.Assets.fadeCycle)) {
return qfalse;
}
continue;
}
if (Q_stricmp(token.string, "fadeAmount") == 0) {
if (!PC_Float_Parse(handle, &cgDC.Assets.fadeAmount)) {
return qfalse;
}
continue;
}
if (Q_stricmp(token.string, "shadowX") == 0) {
if (!PC_Float_Parse(handle, &cgDC.Assets.shadowX)) {
return qfalse;
}
continue;
}
if (Q_stricmp(token.string, "shadowY") == 0) {
if (!PC_Float_Parse(handle, &cgDC.Assets.shadowY)) {
return qfalse;
}
continue;
}
if (Q_stricmp(token.string, "shader") == 0)
{
if (!PC_String_Parse(handle, &tempStr))
{
return qfalse;
}
trap_R_RegisterShaderNoMip ( tempStr );
continue;
}
if (Q_stricmp(token.string, "shadowColor") == 0) {
if (!PC_Color_Parse(handle, &cgDC.Assets.shadowColor)) {
return qfalse;
}
cgDC.Assets.shadowFadeClamp = cgDC.Assets.shadowColor[3];
continue;
}
}
return qfalse; // bk001204 - why not?
}
/*
======================
CG_ParseMenu
======================
*/
void CG_ParseMenu ( const char *menuFile )
{
pc_token_t token;
int handle;
// Load the menu file
handle = trap_PC_LoadSource(menuFile);
if (!handle)
{
return;
}
while ( 1 )
{
if (!trap_PC_ReadToken( handle, &token ))
{
break;
}
if ( token.string[0] == '}' )
{
break;
}
if (Q_stricmp(token.string, "assetGlobalDef") == 0)
{
if (CG_Asset_Parse(handle))
{
continue;
}
else
{
break;
}
}
if (Q_stricmp(token.string, "menudef") == 0)
{
// start a new menu
Menu_New ( handle );
}
}
trap_PC_FreeSource(handle);
}
/*
======================
CG_LoadMenu
======================
*/
qboolean CG_LoadMenu ( const char **p )
{
char *token;
token = COM_ParseExt(p, qtrue);
if (token[0] != '{')
{
return qfalse;
}
while ( 1 )
{
token = COM_ParseExt(p, qtrue);
if (Q_stricmp(token, "}") == 0)
{
return qtrue;
}
if ( !token || token[0] == 0 )
{
return qfalse;
}
CG_ParseMenu(token);
}
return qfalse;
}
/*
======================
CG_LoadMenus
======================
*/
void CG_LoadMenus ( const char *menuFile )
{
char *token;
const char *p;
int len, start;
fileHandle_t f;
static char buf[MAX_MENUDEFFILE];
start = trap_Milliseconds();
trap_PC_LoadGlobalDefines ( "ui/menudef.h" );
// Open the hud menu file
len = trap_FS_FOpenFile( menuFile, &f, FS_READ );
if ( !f )
{
Com_Error( ERR_FATAL, va( S_COLOR_RED "hud menu file not found: ui/hud.txt, unable to continue!\n", menuFile ) );
return;
}
// Too big?
if ( len >= MAX_MENUDEFFILE )
{
Com_Error( ERR_FATAL, va( S_COLOR_RED "menu file too large: %s is %i, max allowed is %i", menuFile, len, MAX_MENUDEFFILE ) );
trap_FS_FCloseFile( f );
return;
}
trap_FS_Read( buf, len, f );
buf[len] = 0;
trap_FS_FCloseFile( f );
COM_Compress(buf);
Menu_Reset();
p = buf;
while ( 1 )
{
token = COM_ParseExt( &p, qtrue );
if( !token || token[0] == 0 || token[0] == '}')
{
break;
}
if ( Q_stricmp( token, "}" ) == 0 )
{
break;
}
if (Q_stricmp(token, "loadmenu") == 0)
{
if ( CG_LoadMenu ( &p ) )
{
continue;
}
else
{
break;
}
}
}
trap_PC_RemoveAllGlobalDefines ( );
Com_Printf("HUD menu load time = %d milli seconds\n", trap_Milliseconds() - start);
}
/*
======================
CG_LoadMenus
======================
*/
static qboolean CG_OwnerDrawHandleKey(int ownerDraw, int flags, float *special, int key, const char* param )
{
return qfalse;
}
static int CG_FeederCount(float feederID)
{
return 0;
}
static const char *CG_FeederItemText ( float feederID, int index, int column, qhandle_t *handle)
{
return "";
}
static qhandle_t CG_FeederItemImage(float feederID, int index)
{
return 0;
}
static void CG_FeederSelection(float feederID, int index)
{
}
static float CG_Cvar_Get(const char *cvar)
{
char buff[128];
memset(buff, 0, sizeof(buff));
trap_Cvar_VariableStringBuffer(cvar, buff, sizeof(buff));
return atof(buff);
}
static int CG_OwnerDrawWidth(int ownerDraw, qhandle_t font, float scale )
{
switch (ownerDraw)
{
case CG_GAME_TYPE:
return trap_R_GetTextWidth (CG_GameTypeString(), font, scale, 0 );
case CG_GAME_STATUS:
return trap_R_GetTextWidth (CG_GetGameStatusText(), font, scale, 0 );
}
return 0;
}
static int CG_PlayCinematic(const char *name, float x, float y, float w, float h) {
return trap_CIN_PlayCinematic(name, x, y, w, h, CIN_loop);
}
static void CG_StopCinematic(int handle) {
trap_CIN_StopCinematic(handle);
}
static void CG_DrawCinematic(int handle, float x, float y, float w, float h) {
trap_CIN_SetExtents(handle, x, y, w, h);
trap_CIN_DrawCinematic(handle);
}
static void CG_RunCinematicFrame(int handle) {
trap_CIN_RunCinematic(handle);
}
/*
=================
CG_LoadHudMenu
=================
*/
void CG_LoadHudMenu()
{
cgDC.registerShaderNoMip = &trap_R_RegisterShaderNoMip;
cgDC.setColor = &trap_R_SetColor;
cgDC.drawHandlePic = &CG_DrawPic;
cgDC.drawStretchPic = &trap_R_DrawStretchPic;
cgDC.drawText = &CG_DrawText;
cgDC.drawTextWithCursor = &CG_DrawTextWithCursor;
cgDC.getTextWidth = &trap_R_GetTextWidth;
cgDC.getTextHeight = &trap_R_GetTextHeight;
cgDC.registerModel = &trap_R_RegisterModel;
cgDC.modelBounds = &trap_R_ModelBounds;
cgDC.fillRect = &CG_FillRect;
cgDC.drawRect = &CG_DrawRect;
cgDC.drawSides = &CG_DrawSides;
cgDC.drawTopBottom = &CG_DrawTopBottom;
cgDC.clearScene = &trap_R_ClearScene;
cgDC.addRefEntityToScene = &trap_R_AddRefEntityToScene;
cgDC.renderScene = &trap_R_RenderScene;
cgDC.registerFont = &trap_R_RegisterFont;
cgDC.ownerDrawItem = &CG_OwnerDraw;
cgDC.getValue = &CG_GetValue;
cgDC.ownerDrawVisible = &CG_OwnerDrawVisible;
cgDC.ownerDrawDisabled = &CG_OwnerDrawDisabled;
cgDC.runScript = &CG_RunMenuScript;
cgDC.getTeamColor = &CG_GetTeamColor;
cgDC.setCVar = trap_Cvar_Set;
cgDC.getCVarString = trap_Cvar_VariableStringBuffer;
cgDC.getCVarValue = CG_Cvar_Get;
cgDC.startLocalSound = &trap_S_StartLocalSound;
cgDC.ownerDrawHandleKey = &CG_OwnerDrawHandleKey;
cgDC.feederCount = &CG_FeederCount;
cgDC.feederItemImage = &CG_FeederItemImage;
cgDC.feederItemText = &CG_FeederItemText;
cgDC.feederSelection = &CG_FeederSelection;
cgDC.Error = &Com_Error;
cgDC.Print = &Com_Printf;
cgDC.ownerDrawWidth = &CG_OwnerDrawWidth;
cgDC.registerSound = &trap_S_RegisterSound;
cgDC.startBackgroundTrack = &trap_S_StartBackgroundTrack;
cgDC.stopBackgroundTrack = &trap_S_StopBackgroundTrack;
cgDC.playCinematic = &CG_PlayCinematic;
cgDC.stopCinematic = &CG_StopCinematic;
cgDC.drawCinematic = &CG_DrawCinematic;
cgDC.runCinematicFrame = &CG_RunCinematicFrame;
cgDC.yscale = cgDC.glconfig.vidHeight * (1.0/480.0);
cgDC.xscale = cgDC.glconfig.vidWidth * (1.0/640.0);
Init_Display(&cgDC);
Menu_Reset();
CG_LoadMenus( "ui/hud.txt" );
}
/*
=================
CG_AssetCache
=================
*/
void CG_AssetCache()
{
cgDC.Assets.scrollBar = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR );
cgDC.Assets.scrollBarArrowDown = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWDOWN );
cgDC.Assets.scrollBarArrowUp = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWUP );
cgDC.Assets.scrollBarArrowLeft = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWLEFT );
cgDC.Assets.scrollBarArrowRight = trap_R_RegisterShaderNoMip( ASSET_SCROLLBAR_ARROWRIGHT );
cgDC.Assets.scrollBarThumb = trap_R_RegisterShaderNoMip( ASSET_SCROLL_THUMB );
cgDC.Assets.sliderBar = trap_R_RegisterShaderNoMip( ASSET_SLIDER_BAR );
cgDC.Assets.sliderThumb = trap_R_RegisterShaderNoMip( ASSET_SLIDER_THUMB );
}
// initialise the cg_entities structure - take into account the ghoul2 stl stuff in the active snap shots
void CG_Init_CG(void)
{
memset( &cg, 0, sizeof(cg));
}
// initialise the cg_entities structure - take into account the ghoul2 stl stuff
void CG_Init_CGents(void)
{
memset(&cg_entities, 0, sizeof(cg_entities));
}
void CG_InitItems(void)
{
memset( cg_items, 0, sizeof( cg_items ) );
}
void CG_TransitionPermanent(void)
{
centity_t *cent = cg_entities;
int i;
cg_numpermanents = 0;
for(i=0;i<MAX_GENTITIES;i++,cent++)
{
if (trap_GetDefaultState(i, &cent->currentState))
{
cent->nextState = cent->currentState;
VectorCopy (cent->currentState.origin, cent->lerpOrigin);
VectorCopy (cent->currentState.angles, cent->lerpAngles);
cent->currentValid = qtrue;
cg_permanents[cg_numpermanents++] = cent;
}
}
}
/*
=================
CG_Init
Called after every level change or subsystem restart
Will perform callbacks to make the loading info screen update.
=================
*/
void CG_Init( int serverMessageNum, int serverCommandSequence, int clientNum )
{
const char *s;
// Some of the new SOF2 features required more traffic through
// the trap calls than than the original vm code would allow for. Therefore
// a block of shared memory is registered with the engine to allow for
// larger pieced of data to be transferred back and forth.
trap_CG_RegisterSharedMemory(cg.sharedBuffer);
// clear everything
CG_Init_CGents();
CG_Init_CG();
CG_InitItems();
BG_ParseNPCFiles ( );
memset( &cgs, 0, sizeof( cgs ) );
memset( cg_weapons, 0, sizeof(cg_weapons) );
// Load these first since they are used to display the status
cgs.media.loadBulletShader = trap_R_RegisterShaderNoMip ( "gfx/menus/misc/load_bullet.tga" );
cgs.media.loadClipShader = trap_R_RegisterShaderNoMip ( "gfx/menus/misc/load_clip.tga" );
cgs.media.whiteShader = trap_R_RegisterShaderNoMip ( "white" );
cg.clientNum = clientNum;
cgs.processedSnapshotNum = serverMessageNum;
cgs.serverCommandSequence = serverCommandSequence;
CG_LoadingStage ( 0 );
CG_RegisterCvars();
CG_InitConsoleCommands();
// Populate the gametypeData array with the gametypes available
// in the scripts directory
BG_BuildGametypeList();
cg.weaponSelect = WP_USSOCOM_PISTOL;
// get the rendering configuration from the client system
trap_GetGlconfig( &cgs.glconfig );
cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
cgs.screenYScale = cgs.glconfig.vidHeight / 480.0;
// Register the fonts
cgs.media.hudFont = trap_R_RegisterFont ( "hud" );
cgs.media.lcdFont = trap_R_RegisterFont ( "lcdsmall" );
// Load the user interface
String_Init();
CG_AssetCache();
CG_LoadHudMenu();
// get the gamestate from the client system
trap_GetGameState( &cgs.gameState );
CG_TransitionPermanent();
// check version
s = CG_ConfigString( CS_GAME_VERSION );
if ( strcmp( s, GAME_VERSION ) )
{
Com_Error( ERR_FATAL, "Client/Server game mismatch: %s/%s", GAME_VERSION, s );
}
s = CG_ConfigString( CS_LEVEL_START_TIME );
cgs.levelStartTime = atoi( s );
CG_ParseServerinfo();
CG_ParseGametypeFile ( );
// load the new map
CG_LoadingString( "collision map" );
CG_LoadingStage ( 1 );
trap_CM_LoadMap( cgs.mapname, qfalse );
// Make sure we have update values (scores)
CG_SetConfigValues();
CG_LoadingStage ( 2 );
// force players to load instead of defer
cg.loading = qtrue;
CG_LoadingString( "sounds" );
CG_RegisterLadders ( );
CG_RegisterSounds();
CG_InitHitModel( );
CG_LoadingString( "graphics" );
BG_ParseInviewFile ( cgs.pickupsDisabled );
CG_RegisterGraphics ( );
// CG_RegisterMission ( );
CG_ParseGore();
CG_LoadingString( "clients" );
CG_RegisterClients(); // if low on memory, some clients will be deferred
CG_LoadingStage ( 14 );
CG_InitLocalEntities();
CG_LoadingStage ( 15 );
CG_StartMusic(qfalse);
CG_LoadingString( "Clearing light styles" );
CG_ClearLightStyles();
CG_LoadingString( "" );
CG_ShaderStateChanged();
trap_S_ClearLoopingSounds( qtrue );
// In a mission game we want to bring up the objective screen on initial connection
if ( cgs.gametypeData->description || cgs.pickupsDisabled || cgs.gametypeData->teams )
{
cg.popupObjectives = qtrue;
}
trap_Cvar_Set ( "ui_info_gametype", va("%i",cgs.gametype ) );
trap_Cvar_Set ( "ui_info_objectives", cgs.gametypeData->description );
trap_Cvar_Set ( "con_draw", cg.scoreBoardShowing?"0":"1" );
// remove the last loading update
cg.infoScreenText[0] = 0;
cg.loading = qfalse; // future players will be deferred
}
void CG_ShutdownG2Models(void)
{
int i, j;
clientInfo_t *ci;
for(i=0;i<MAX_ITEMS;i++)
{
for(j=0;j<MAX_ITEM_MODELS;j++)
{
if (cg_items[i].g2Models[j])
{
trap_G2API_CleanGhoul2Models(&cg_items[i].g2Models[j]);
}
}
}
for(i=0;i<MAX_GENTITIES;i++)
{
if (cg_entities[i].ghoul2)
{
trap_G2API_CleanGhoul2Models(&cg_entities[i].ghoul2);
}
}
for(i=0;i<MAX_CLIENTS;i++)
{
ci = &cgs.clientinfo[i];
if (ci->ghoul2Model)
{
trap_G2API_CleanGhoul2Models(&ci->ghoul2Model);
}
}
}
void CG_ShutdownGore(void);
/*
=================
CG_Shutdown
Called before every level change or subsystem restart
=================
*/
void CG_Shutdown( void )
{
trap_FX_FreeSystem();
CG_ShutDownWeapons();
CG_ShutdownG2Models();
CG_ShutdownGore();
// some mods may need to do cleanup work here,
// like closing files or archiving session data
}