stvoy-sp-sdk/cgame/cg_main.cpp

1675 lines
50 KiB
C++
Raw Permalink Normal View History

2002-11-22 00:00:00 +00:00
#include "cg_local.h"
#include "fx_public.h"
#include "..\client\vmachine.h"
#include "cg_text.h"
#include "..\game\characters.h"
#include "..\game\speakers.h"
//NOTENOTE: Be sure to change the mirrored code in g_shared.h
typedef map< string, unsigned char, less<string>, allocator< unsigned char > > namePrecache_m;
extern namePrecache_m as_preCacheMap;
extern void CG_RegisterNPCCustomSounds( clientInfo_t *ci );
extern qboolean G_AddSexToMunroString ( char *string, qboolean qDoBoth );
extern void CG_RegisterNPCEffects( team_t team );
extern qboolean G_ParseAnimFileSet( const char *filename, int *animFileIndex, qboolean cacheSounds );
void CG_Init( int serverCommandSequence );
qboolean CG_ConsoleCommand( void );
void CG_Shutdown( void );
int CG_GetCameraPos( vec3_t camerapos );
void CG_LoadIngameText(void);
#define NUM_CHUNKS 6
#define BORG_CHUNKS 3
#define STASIS_CHUNKS 4
/*
================
vmMain
This is the only way control passes into the cgame 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 ) {
switch ( command ) {
case CG_INIT:
CG_Init( arg0 );
return 0;
case CG_SHUTDOWN:
CG_Shutdown();
return 0;
case CG_CONSOLE_COMMAND:
return CG_ConsoleCommand();
case CG_DRAW_ACTIVE_FRAME:
CG_DrawActiveFrame( arg0, (stereoFrame_t) arg1 );
return 0;
case CG_CROSSHAIR_PLAYER:
return CG_CrosshairPlayer();
case CG_CAMERA_POS:
return CG_GetCameraPos( (float*)arg0);
}
return -1;
}
cg_t cg;
cgs_t cgs;
centity_t cg_entities[MAX_GENTITIES];
weaponInfo_t cg_weapons[MAX_WEAPONS];
itemInfo_t cg_items[MAX_ITEMS];
vmCvar_t cg_centertime;
vmCvar_t cg_runpitch;
vmCvar_t cg_runroll;
vmCvar_t cg_bobup;
vmCvar_t cg_bobpitch;
vmCvar_t cg_bobroll;
vmCvar_t cg_swingSpeed;
vmCvar_t cg_shadows;
vmCvar_t cg_paused;
vmCvar_t cg_drawTimer;
vmCvar_t cg_drawFPS;
vmCvar_t cg_drawSnapshot;
vmCvar_t cg_drawAmmoWarning;
vmCvar_t cg_drawCrosshair;
vmCvar_t cg_drawCrosshairNames;
vmCvar_t cg_crosshairX;
vmCvar_t cg_crosshairY;
vmCvar_t cg_crosshairSize;
vmCvar_t cg_crosshairHealth;
vmCvar_t cg_draw2D;
vmCvar_t cg_drawStatus;
vmCvar_t cg_animSpeed;
vmCvar_t cg_debugAnim;
vmCvar_t cg_debugPosition;
vmCvar_t cg_debugEvents;
vmCvar_t cg_errorDecay;
vmCvar_t cg_noPlayerAnims;
vmCvar_t cg_footsteps;
vmCvar_t cg_addMarks;
vmCvar_t cg_viewsize;
vmCvar_t cg_drawGun;
vmCvar_t cg_gun_frame;
vmCvar_t cg_gun_x;
vmCvar_t cg_gun_y;
vmCvar_t cg_gun_z;
vmCvar_t cg_autoswitch;
vmCvar_t cg_simpleItems;
vmCvar_t cg_fov;
vmCvar_t cg_thirdPerson;
vmCvar_t cg_thirdPersonRange;
vmCvar_t cg_thirdPersonAngle;
vmCvar_t cg_stereoSeparation;
vmCvar_t cg_developer;
vmCvar_t cg_timescale;
vmCvar_t cg_skippingcin;
vmCvar_t cg_language;
vmCvar_t cg_pano;
vmCvar_t cg_panoNumShots;
vmCvar_t cg_freezeFX;
vmCvar_t cg_debugFX;
vmCvar_t fx_memoryInfo;
vmCvar_t cg_virtualVoyager;
vmCvar_t cg_missionInfoFlashTime;
typedef struct {
vmCvar_t *vmCvar;
char *cvarName;
char *defaultString;
int cvarFlags;
} cvarTable_t;
cvarTable_t cvarTable[] = {
{ &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE },
{ &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE },
{ &cg_fov, "cg_fov", "80", CVAR_ARCHIVE },
{ &cg_viewsize, "cg_viewsize", "100", CVAR_ARCHIVE },
{ &cg_stereoSeparation, "cg_stereoSeparation", "0.4", CVAR_ARCHIVE },
{ &cg_shadows, "cg_shadows", "1", CVAR_ARCHIVE },
{ &cg_draw2D, "cg_draw2D", "1", CVAR_ARCHIVE },
{ &cg_drawStatus, "cg_drawStatus", "1", CVAR_ARCHIVE },
{ &cg_drawTimer, "cg_drawTimer", "0", CVAR_ARCHIVE },
{ &cg_drawFPS, "cg_drawFPS", "0", CVAR_ARCHIVE },
{ &cg_drawSnapshot, "cg_drawSnapshot", "0", CVAR_ARCHIVE },
{ &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE },
{ &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE },
{ &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE },
{ &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE },
{ &cg_crosshairHealth, "cg_crosshairHealth", "0", CVAR_ARCHIVE },
{ &cg_crosshairX, "cg_crosshairX", "0", CVAR_ARCHIVE },
{ &cg_crosshairY, "cg_crosshairY", "0", CVAR_ARCHIVE },
{ &cg_simpleItems, "cg_simpleItems", "0", CVAR_ARCHIVE },
{ &cg_addMarks, "cg_marks", "1", CVAR_ARCHIVE },
{ &cg_gun_frame, "gun_frame", "0", CVAR_CHEAT },
{ &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", "3", CVAR_CHEAT },
{ &cg_runpitch, "cg_runpitch", "0.002", CVAR_ARCHIVE},
{ &cg_runroll, "cg_runroll", "0.005", CVAR_ARCHIVE },
{ &cg_bobup , "cg_bobup", "0.005", CVAR_ARCHIVE },
{ &cg_bobpitch, "cg_bobpitch", "0.002", CVAR_ARCHIVE },
{ &cg_bobroll, "cg_bobroll", "0.002", CVAR_ARCHIVE },
{ &cg_swingSpeed, "cg_swingSpeed", "0.3", CVAR_CHEAT },
{ &cg_animSpeed, "cg_animspeed", "1", CVAR_CHEAT },
{ &cg_debugAnim, "cg_debuganim", "0", CVAR_CHEAT },
{ &cg_debugPosition, "cg_debugposition", "0", CVAR_CHEAT },
{ &cg_debugEvents, "cg_debugevents", "0", CVAR_CHEAT },
{ &cg_errorDecay, "cg_errordecay", "100", 0 },
{ &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT },
{ &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT },
{ &cg_thirdPersonRange, "cg_thirdPersonRange", "40", 0 },
{ &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", 0 },
{ &cg_thirdPerson, "cg_thirdPerson", "0", 0 },
{ &cg_pano, "pano", "0", 0 },
{ &cg_panoNumShots, "panoNumShots", "10", 0 },
{ &cg_freezeFX, "fx_freeze", "0", 0 },
{ &cg_debugFX, "fx_debug", "0", 0 },
{ &fx_memoryInfo, "fx_memoryInfo", "0", 0 },
// the following variables are created in other parts of the system,
// but we also reference them here
{ &cg_paused, "cl_paused", "0", CVAR_ROM },
{ &cg_developer, "developer", "", 0 },
{ &cg_timescale, "timescale", "1", 0 },
{ &cg_skippingcin, "skippingCinematic", "0", CVAR_ROM},
{ &cg_language, "g_language", "", CVAR_ARCHIVE | CVAR_NORESTART},
{ &cg_virtualVoyager, "cg_virtualvoyager", "0", CVAR_NORESTART },
{ &cg_missionInfoFlashTime, "cg_missionInfoFlashTime", "15000", CVAR_ARCHIVE },
};
int cvarTableSize = sizeof( cvarTable ) / sizeof( cvarTable[0] );
characterName_t CharacterNames[CHARACTER_NUM_CHARS] =
{
//NPC_type sound soundIndex
//HazTeam Alpha
"foster", "sound/voice/munro/misc/sir.wav", 0, //CHARACTER_FOSTER,
"telsia", "sound/voice/munro/misc/telsia.wav", 0, //CHARACTER_TELSIA,
"biessman", "sound/voice/munro/misc/rick.wav", 0, //CHARACTER_BIESSMAN,
"chang", "sound/voice/munro/misc/austin.wav", 0, //CHARACTER_CHANG,
"chell", "sound/voice/munro/misc/chell.wav", 0, //CHARACTER_CHELL,
"jurot", "sound/voice/munro/misc/jurot.wav", 0, //CHARACTER_JUROT,
//HazTeam Beta
"laird", "sound/voice/munro/misc/liz.wav", 0, //CHARACTER_LAIRD,
"kenn", "sound/voice/munro/misc/kenn.wav", 0, //CHARACTER_KENN,
"oviedo", "sound/voice/munro/misc/oviedo.wav", 0, //CHARACTER_OVIEDO,
"odell", "sound/voice/munro/misc/tom.wav", 0, //CHARACTER_ODELL,
"nelson", "sound/voice/munro/misc/jeff.wav", 0, //CHARACTER_NELSON,
"jaworski", "sound/voice/munro/misc/michael.wav", 0, //CHARACTER_JAWORSKI,
"csatlos", "sound/voice/munro/misc/mitch.wav", 0, //CHARACTER_CSATLOS,
//Senior Crew
"janeway", "sound/voice/munro/misc/captain.wav", 0, //CHARACTER_JANEWAY,
"chakotay", "sound/voice/munro/misc/commander.wav", 0, //CHARACTER_CHAKOTAY,
"tuvok", "sound/voice/munro/misc/tuvok.wav", 0, //CHARACTER_TUVOK,
"tuvokhaz", "sound/voice/munro/misc/tuvok.wav", 0, //CHARACTER_TUVOKHAZ,
"torres", "sound/voice/munro/misc/torres.wav", 0, //CHARACTER_TORRES,
"paris", "sound/voice/munro/misc/tom.wav", 0, //CHARACTER_PARIS,
"kim", "sound/voice/munro/misc/harry.wav", 0, //CHARACTER_KIM,
"doctor", "sound/voice/munro/misc/doctor.wav", 0, //CHARACTER_DOCTOR,
"seven", "sound/voice/munro/misc/seven.wav", 0, //CHARACTER_SEVEN,
"sevenhazard", "sound/voice/munro/misc/seven.wav", 0, //CHARACTER_SEVENHAZ,
"neelix", "sound/voice/munro/misc/neelix.wav", 0, //CHARACTER_NEELIX,
//Other Crew
"pelletier", "sound/voice/munro/misc/brian.wav", 0, //CHARACTER_PELLETIER,
//Generic Crew
"crewman", "sound/voice/munro/misc/crewman.wav", 0, //CHARACTER_CREWMAN,
//"ensign", "sound/voice/munro/misc/ensign.wav", 0, //CHARACTER_ENSIGN,
"lt", "sound/voice/munro/misc/lt.wav", 0, //CHARACTER_LT
"commander", "sound/voice/munro/misc/commander.wav", 0, //CHARACTER_COMM
"captain", "sound/voice/munro/misc/captain.wav", 0, //CHARACTER_CAPT
"generic1", "sound/voice/munro/misc/hey1.wav", 0, //CHARACTER_GENERIC1
"generic2", "sound/voice/munro/misc/hey2.wav", 0, //CHARACTER_GENERIC2
"generic3", "sound/voice/munro/misc/excuseme1.wav", 0, //CHARACTER_GENERIC3
"generic4", "sound/voice/munro/misc/excuseme2.wav", 0 //CHARACTER_GENERIC4
};
/*
=================
CG_RegisterCvars
=================
*/
void CG_RegisterCvars( void ) {
int i;
cvarTable_t *cv;
for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
cgi_Cvar_Register( cv->vmCvar, cv->cvarName,
cv->defaultString, cv->cvarFlags );
}
if ( cg_thirdPerson.integer == 2 )//to appease the testers who deliberately avoid the reset at the end of borgslayer
{//if in borgslayer mode, restore to normal
cgi_Cvar_Set("cg_thirdPerson","0");
}
}
/*
=================
CG_UpdateCvars
=================
*/
void CG_UpdateCvars( void ) {
int i;
cvarTable_t *cv;
for ( i = 0, cv = cvarTable ; i < cvarTableSize ; i++, cv++ ) {
cgi_Cvar_Update( cv->vmCvar );
}
}
int CG_CrosshairPlayer( void )
{
if ( cg.time > ( cg.crosshairClientTime + 1000 ) )
{
return -1;
}
return cg.crosshairClientNum;
}
int CG_GetCameraPos( vec3_t camerapos ) {
if ( in_camera) {
VectorCopy(client_camera.origin, camerapos);
return 1;
}
return 0;
}
void CG_TargetCommand_f( void ) {
int targetNum;
char test[4];
targetNum = CG_CrosshairPlayer();
if (targetNum <= 0) {
return;
}
cgi_Argv( 1, test, 4 ); //FIXME: this is now an exec_now command - in case we start using it... JFM
cgi_SendConsoleCommand( va( "gc %i %i", targetNum, atoi( test ) ) );
}
void CG_Printf( const char *msg, ... ) {
va_list argptr;
char text[1024];
va_start (argptr, msg);
vsprintf (text, msg, argptr);
va_end (argptr);
cgi_Printf( text );
}
void CG_Error( const char *msg, ... ) {
va_list argptr;
char text[1024];
va_start (argptr, msg);
vsprintf (text, msg, argptr);
va_end (argptr);
cgi_Error( text );
}
/*
================
CG_Argv
================
*/
const char *CG_Argv( int arg ) {
static char buffer[MAX_STRING_CHARS];
cgi_Argv( arg, buffer, sizeof( buffer ) );
return buffer;
}
//========================================================================
/*
=================
CG_RegisterItemSounds
The server says this item is used on this level
=================
*/
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)
{
cgi_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) {
CG_Error( "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" )) {
cgi_S_RegisterSound( data );
}
}
}
/*
======================
CG_LoadingString
======================
*/
void CG_LoadingString( const char *s ) {
Q_strncpyz( cg.infoScreenText, s, sizeof( cg.infoScreenText ) );
cgi_UpdateScreen();
}
/*
=================
CG_RegisterSounds
called during a precache command
=================
*/
static void CG_RegisterSounds( void ) {
int i;
char items[MAX_ITEMS+1];
char name[MAX_QPATH];
const char *soundName;
CG_LoadingString( "ambient sound sets" );
//Load the ambient sets
//FIXME: Don't ask... I had to get around a really nasty MS error in the templates with this...
namePrecache_m::iterator pi;
STL_ITERATE( pi, as_preCacheMap )
{
cgi_AS_AddPrecacheEntry( ((*pi).first).c_str() );
}
cgi_AS_ParseSets();
CG_LoadingString( "general sounds" );
cgs.media.selectSound = cgi_S_RegisterSound( "sound/weapons/change.wav" );
cgs.media.useNothingSound = cgi_S_RegisterSound( "sound/items/use_nothing.wav" );
cgs.media.noAmmoSound = cgi_S_RegisterSound( "sound/weapons/noammo.wav" );
cgs.media.talkSound = cgi_S_RegisterSound( "sound/interface/communicator.wav" );
cgs.media.landSound = cgi_S_RegisterSound( "sound/player/land1.wav");
cgs.media.tedTextSound = cgi_S_RegisterSound( "sound/interface/tedtext.wav" );
cgs.media.interfaceSnd1 = cgi_S_RegisterSound( "sound/interface/button4.wav" );
cgs.media.interfaceSnd2 = cgi_S_RegisterSound( "sound/interface/button2.wav" );
cgs.media.interfaceSnd3 = cgi_S_RegisterSound( "sound/interface/button1.wav" );
cgs.media.watrInSound = cgi_S_RegisterSound ("sound/player/watr_in.wav");
cgs.media.watrOutSound = cgi_S_RegisterSound ("sound/player/watr_out.wav");
cgs.media.watrUnSound = cgi_S_RegisterSound ("sound/player/watr_un.wav");
cgs.media.respawnSound = cgi_S_RegisterSound( "sound/items/respawn1.wav" );
//cgs.media.teleInSound = cgi_S_RegisterSound("sound/world/telein.wav");
//cgs.media.teleOutSound = cgi_S_RegisterSound("sound/world/teleout.wav");
cgs.media.transporterSound = cgi_S_RegisterSound( "sound/world/transporter.wav");
// Zoom
cgs.media.zoomStart = cgi_S_RegisterSound( "sound/interface/zoomstart.wav" );
cgs.media.zoomLoop = cgi_S_RegisterSound( "sound/interface/zoomloop.wav" );
cgs.media.zoomEnd = cgi_S_RegisterSound( "sound/interface/zoomend.wav" );
for (i=0 ; i<4 ; i++) {
Com_sprintf (name, sizeof(name), "sound/player/footsteps/step%i.wav", i+1);
cgs.media.footsteps[FOOTSTEP_NORMAL][i] = cgi_S_RegisterSound (name);
Com_sprintf (name, sizeof(name), "sound/player/footsteps/splash%i.wav", i+1);
cgs.media.footsteps[FOOTSTEP_SPLASH][i] = cgi_S_RegisterSound (name);
Com_sprintf (name, sizeof(name), "sound/player/footsteps/clank%i.wav", i+1);
cgs.media.footsteps[FOOTSTEP_METAL][i] = cgi_S_RegisterSound (name);
Com_sprintf (name, sizeof(name), "sound/enemies/borg/borgstep%ia.wav", i+1);
cgs.media.footsteps[FOOTSTEP_BORG][i] = cgi_S_RegisterSound (name);
}
cg.loadLCARSStage = 1;
CG_LoadingString( "item sounds" );
// only register the items that the server says we need
strcpy( items, CG_ConfigString( CS_ITEMS ) );
for ( i = 1 ; i < bg_numItems ; i++ ) {
if ( items[ i ] == '1' ) {
CG_RegisterItemSounds( i );
}
}
cg.loadLCARSStage = 2;
CG_LoadingString( "preregistered sounds" );
for ( i = 1 ; i < MAX_SOUNDS ; i++ ) {
soundName = CG_ConfigString( CS_SOUNDS+i );
if ( !soundName[0] ) {
break;
}
if ( soundName[0] == '*' ) {
continue; // custom sound
}
if (i&31) {
CG_LoadingString( soundName );
}
cgs.sound_precache[i] = cgi_S_RegisterSound( soundName );
}
}
/*
=============================================================================
CLIENT INFO
=============================================================================
*/
qhandle_t CG_RegisterHeadSkin( const char *headModelName, const char *headSkinName, qboolean *extensions )
{
char hfilename[MAX_QPATH];
qhandle_t headSkin;
Com_sprintf( hfilename, sizeof( hfilename ), "models/players/%s/head_%s.skin", headModelName, headSkinName );
headSkin = cgi_R_RegisterSkin( hfilename );
if ( headSkin < 0 )
{ //have extensions
*extensions = qtrue;
headSkin = -headSkin;
}
else
{
*extensions = qfalse; //just to be sure.
}
if ( !headSkin )
{
Com_Printf( "Failed to load skin file: %s : %s\n", headModelName, headSkinName );
}
return headSkin;
}
/*
==========================
CG_RegisterClientSkin
==========================
*/
qboolean CG_RegisterClientSkin( clientInfo_t *ci,
const char *headModelName, const char *headSkinName,
const char *torsoModelName, const char *torsoSkinName,
const char *legsModelName, const char *legsSkinName)
{
char hfilename[MAX_QPATH];
char tfilename[MAX_QPATH];
char lfilename[MAX_QPATH];
Com_sprintf( lfilename, sizeof( lfilename ), "models/players/%s/lower_%s.skin", legsModelName, legsSkinName );
ci->legsSkin = cgi_R_RegisterSkin( lfilename );
if ( !ci->legsSkin )
{
Com_Printf( "Failed to load skin file: %s : %s\n", legsModelName, legsSkinName );
//return qfalse;
}
if(torsoModelName && torsoSkinName && torsoModelName[0] && torsoSkinName[0])
{
Com_sprintf( tfilename, sizeof( tfilename ), "models/players/%s/upper_%s.skin", torsoModelName, torsoSkinName );
ci->torsoSkin = cgi_R_RegisterSkin( tfilename );
if ( !ci->torsoSkin )
{
Com_Printf( "Failed to load skin file: %s : %s\n", torsoModelName, torsoSkinName );
return qfalse;
}
}
if(headModelName && headSkinName && headModelName[0] && headSkinName[0])
{
Com_sprintf( hfilename, sizeof( hfilename ), "models/players/%s/head_%s.skin", headModelName, headSkinName );
ci->headSkin = cgi_R_RegisterSkin( hfilename );
if (ci->headSkin <0) { //have extensions
ci->extensions = qtrue;
ci->headSkin = -ci->headSkin;
} else {
ci->extensions = qfalse; //just to be sure.
}
if ( !ci->headSkin )
{
Com_Printf( "Failed to load skin file: %s : %s\n", headModelName, headSkinName );
return qfalse;
}
}
return qtrue;
}
/*
==========================
CG_RegisterClientModelname
==========================
*/
qboolean CG_RegisterClientModelname( clientInfo_t *ci,
const char *headModelName, const char *headSkinName,
const char *torsoModelName, const char *torsoSkinName,
const char *legsModelName, const char *legsSkinName )
{
char filename[MAX_QPATH];
Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.mdr", legsModelName );
ci->legsModel = cgi_R_RegisterModel( filename );
if ( !ci->legsModel )
{//he's not skeletal, try the old way
Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", legsModelName );
ci->legsModel = cgi_R_RegisterModel( filename );
if ( !ci->legsModel )
{
Com_Printf( S_COLOR_RED"Failed to load model file %s\n", filename );
return qfalse;
}
}
if(torsoModelName && torsoModelName[0])
{//You are trying to set one
Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.mdr", torsoModelName );
ci->torsoModel = cgi_R_RegisterModel( filename );
if ( !ci->torsoModel )
{//he's not skeletal, try the old way
Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", torsoModelName );
ci->torsoModel = cgi_R_RegisterModel( filename );
if ( !ci->torsoModel )
{
Com_Printf( S_COLOR_RED"Failed to load model file %s\n", filename );
return qfalse;
}
}
}
else
{
ci->torsoModel = 0;
}
if(headModelName && headModelName[0])
{//You are trying to set one
Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headModelName );
ci->headModel = cgi_R_RegisterModel( filename );
if ( !ci->headModel )
{
Com_Printf( S_COLOR_RED"Failed to load model file %s\n", filename );
return qfalse;
}
}
else
{
ci->headModel = 0;
}
// if any skins failed to load, return failure
if ( !CG_RegisterClientSkin( ci, headModelName, headSkinName, torsoModelName, torsoSkinName, legsModelName, legsSkinName ) )
{
//Com_Printf( "Failed to load skin file: %s : %s/%s : %s/%s : %s\n", headModelName, headSkinName, torsoModelName, torsoSkinName, legsModelName, legsSkinName );
return qfalse;
}
//FIXME: for now, uses the legs model dir for anim cfg, but should we set this in some sort of NPCs.cfg?
// load the animation file set
if ( !G_ParseAnimFileSet( legsModelName, &ci->animFileIndex, qtrue ) )
{
Com_Printf( S_COLOR_RED"Failed to load animation file set models/players/%s\n", legsModelName );
return qfalse;
}
return qtrue;
}
void CG_RegisterClientRenderInfo(clientInfo_t *ci, renderInfo_t *ri)
{
char *slash;
char headModelName[MAX_QPATH];
char torsoModelName[MAX_QPATH];
char legsModelName[MAX_QPATH];
char headSkinName[MAX_QPATH];
char torsoSkinName[MAX_QPATH];
char legsSkinName[MAX_QPATH];
if(!ri->legsModelName || !ri->legsModelName[0])
{//Must have at LEAST a legs model
return;
}
Q_strncpyz( legsModelName, ri->legsModelName, sizeof( legsModelName ) );
//Legs skin
slash = strchr( legsModelName, '/' );
if ( !slash )
{
// modelName didn not include a skin name
Q_strncpyz( legsSkinName, "default", sizeof( legsSkinName ) );
}
else
{
Q_strncpyz( legsSkinName, slash + 1, sizeof( legsSkinName ) );
// truncate modelName
*slash = 0;
}
if(ri->torsoModelName && ri->torsoModelName[0])
{
Q_strncpyz( torsoModelName, ri->torsoModelName, sizeof( torsoModelName ) );
//Torso skin
slash = strchr( torsoModelName, '/' );
if ( !slash )
{
// modelName didn't include a skin name
Q_strncpyz( torsoSkinName, "default", sizeof( torsoSkinName ) );
}
else
{
Q_strncpyz( torsoSkinName, slash + 1, sizeof( torsoSkinName ) );
// truncate modelName
*slash = 0;
}
}
else
{
torsoModelName[0] = 0;
}
//Head
if(ri->headModelName && ri->headModelName[0])
{
Q_strncpyz( headModelName, ri->headModelName, sizeof( headModelName ) );
//Head skin
slash = strchr( headModelName, '/' );
if ( !slash )
{
// modelName didn not include a skin name
Q_strncpyz( headSkinName, "default", sizeof( headSkinName ) );
}
else
{
Q_strncpyz( headSkinName, slash + 1, sizeof( headSkinName ) );
// truncate modelName
*slash = 0;
}
}
else
{
headModelName[0] = 0;
}
if ( !CG_RegisterClientModelname( ci, headModelName, headSkinName, torsoModelName, torsoSkinName, legsModelName, legsSkinName) )
{
if ( !CG_RegisterClientModelname( ci, DEFAULT_HEADMODEL, "default", DEFAULT_TORSOMODEL, "default", DEFAULT_LEGSMODEL, "default" ) )
{
CG_Error( "DEFAULT_MODELS failed to register");
}
}
}
/*
void CG_RegisterClientModels (int entityNum)
Only call if clientInfo->infoValid is not true
For players and NPCs to register their models
*/
void CG_RegisterClientModels (int entityNum)
{
gentity_t *ent;
if(entityNum < 0 || entityNum > ENTITYNUM_WORLD)
{
return;
}
ent = &g_entities[entityNum];
if(!ent->client)
{
return;
}
CG_RegisterClientRenderInfo(&ent->client->clientInfo, &ent->client->renderInfo);
ent->client->clientInfo.infoValid = qtrue;
if(entityNum < MAX_CLIENTS)
{
memcpy(&cgs.clientinfo[entityNum], &ent->client->clientInfo, sizeof(clientInfo_t));
}
}
//===================================================================================
extern cvar_t *com_buildScript;
sfxHandle_t CG_RegisterSexedSound(char* string)
{
if (com_buildScript->integer) {
cgi_S_RegisterSound(string); //grab the original file before changing for sex
}
G_AddSexToMunroString( string, qfalse );
return cgi_S_RegisterSound( string );
}
//===================================================================================
void CG_PrecachePlayerGreetingSound( char *NPC_type )
{
for ( int character = 0; character < CHARACTER_NUM_CHARS; character++ )
{
if ( Q_stricmp( NPC_type, CharacterNames[character].name ) == 0 )
{
//if ( !CharacterNames[character].soundIndex )
//remmed out because soundIndexes weren't being updated on vid_restarts
//FIXME? Should we zero this array on vid_restarts? Called also from NPC spawns
char temp[MAX_QPATH];
Q_strncpyz(temp, CharacterNames[character].sound, sizeof(temp), qtrue );
CharacterNames[character].soundIndex = CG_RegisterSexedSound( temp );
}
}
}
extern void NPC_Precache ( gentity_t *spawner );
qboolean NPCsPrecached = qfalse;
/*
=================
CG_PrepRefresh
Call before entering a new level, or after changing renderers
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];
static char *sb_nums[11] = {
"gfx/2d/numbers/zero",
"gfx/2d/numbers/one",
"gfx/2d/numbers/two",
"gfx/2d/numbers/three",
"gfx/2d/numbers/four",
"gfx/2d/numbers/five",
"gfx/2d/numbers/six",
"gfx/2d/numbers/seven",
"gfx/2d/numbers/eight",
"gfx/2d/numbers/nine",
"gfx/2d/numbers/minus",
};
static char *sb_t_nums[11] = {
"gfx/2d/numbers/t_zero",
"gfx/2d/numbers/t_one",
"gfx/2d/numbers/t_two",
"gfx/2d/numbers/t_three",
"gfx/2d/numbers/t_four",
"gfx/2d/numbers/t_five",
"gfx/2d/numbers/t_six",
"gfx/2d/numbers/t_seven",
"gfx/2d/numbers/t_eight",
"gfx/2d/numbers/t_nine",
"gfx/2d/numbers/t_minus",
};
FX_Free();
// clear any references to old media
memset( &cg.refdef, 0, sizeof( cg.refdef ) );
cgi_R_ClearScene();
cg.loadLCARSStage = 3;
CG_LoadingString( cgs.mapname );
cgi_R_LoadWorldMap( cgs.mapname );
cg.loadLCARSStage = 4;
CG_LoadingString( "game media shaders" );
for ( i=0; i < 11; i++ )
{
cgs.media.numberShaders[i] = cgi_R_RegisterShaderNoMip( sb_nums[i] );
cgs.media.smallnumberShaders[i] = cgi_R_RegisterShaderNoMip( sb_t_nums[i] );
}
cgs.media.sparkShader = cgi_R_RegisterShader( "gfx/misc/spark" );
cgs.media.spark2Shader = cgi_R_RegisterShader( "gfx/misc/spark2" );
cgs.media.spark3Shader = cgi_R_RegisterShader( "gfx/misc/spark_or" ); //used in PsychoJismThinkGo from cg_env
cgs.media.steamShader = cgi_R_RegisterShader( "gfx/misc/steam" );
cgs.media.smokeShader = cgi_R_RegisterShader( "gfx/misc/smoke" );
cgs.media.spooShader = cgi_R_RegisterShader( "gfx/misc/spoo" );
cgs.media.explosionModel = cgi_R_RegisterModel ( "models/weaphits/explosion.md3" );
cgs.media.electricalExplosionSlowShader = cgi_R_RegisterShader( "electricalExplosionSlow" );//elec, imod, and prifle
cgs.media.surfaceExplosionShader = cgi_R_RegisterShader( "surfaceExplosion" );
cgs.media.boltShader = cgi_R_RegisterShader( "gfx/effects/electric" ); //FX_StasisAttackThink
cgs.media.pjBoltShader = cgi_R_RegisterShader( "gfx/effects/electric_or" );
//Used by fx_bolts and borg taser, so leave it here for now until can figure out
//way to have fx_bolts precache their shaders
for ( i = 0; i < 4; i++ ) {
cgs.media.borgLightningShaders[i] = cgi_R_RegisterShader( va( "gfx/misc/blightning%i", i+1 ) );
}
cgs.media.solidWhiteShader = cgi_R_RegisterShader( "white2" );
cgs.media.whiteRingShader = cgi_R_RegisterShader( "gfx/misc/whitering" );
cgs.media.plasmaShader = cgi_R_RegisterShader( "gfx/misc/plasma" );
cgs.media.bolt2Shader = cgi_R_RegisterShader( "gfx/effects/electrica" );
cgs.media.yellowBoltShader = cgi_R_RegisterShader( "gfx/effects/yellow_electric" );
cgs.media.waterDropShader = cgi_R_RegisterShader( "gfx/misc/drop" );
cgs.media.ltblueParticleShader = cgi_R_RegisterShader( "gfx/misc/ltblueparticle" );
cgs.media.blueParticleShader = cgi_R_RegisterShader( "gfx/misc/blueparticle" );
cgs.media.purpleParticleShader = cgi_R_RegisterShader( "gfx/misc/purpleparticle" );
cgs.media.yellowParticleShader = cgi_R_RegisterShader( "gfx/misc/yellowparticle" );
cgs.media.orangeParticleShader = cgi_R_RegisterShader( "gfx/misc/orangeparticle" );
cgs.media.dkorangeParticleShader = cgi_R_RegisterShader( "gfx/misc/dkorangeparticle" );
cgs.media.whiteLaserShader = cgi_R_RegisterShader( "gfx/effects/whitelaser" );
cgs.media.oilDropShader = cgi_R_RegisterShader( "gfx/misc/oildrop" );
cgs.media.sunnyFlareShader = cgi_R_RegisterShader( "gfx/misc/sunny_flare" );
cgs.media.bigBoomShader = cgi_R_RegisterShader( "gfx/misc/bigboom" );
cgs.media.blueHitShader = cgi_R_RegisterShader( "gfx/misc/blue_hit" );
cgs.media.ghostRingShader = cgi_R_RegisterShader( "gfx/misc/ghost_ring" );
cgs.media.splosionShader = cgi_R_RegisterShader( "gfx/misc/splosion" );
cgs.media.yellowTrailShader = cgi_R_RegisterShader( "gfx/misc/yellowtrail" );
cgs.media.stasisBoltShader = cgi_R_RegisterShader( "gfx/effects/electric_stasis" );
cgs.media.fountainShader = cgi_R_RegisterShader( "garden/fountain" );
cgs.media.rippleShader = cgi_R_RegisterShader( "garden/ripple" );
//on players
cgs.media.psychicShader = cgi_R_RegisterShader( "gfx/misc/psychic" );
cgs.media.transportShader = cgi_R_RegisterShader( "powerups/beamEffect" );//always precache this since the player uses it
cgs.media.disruptorShader = cgi_R_RegisterShader( "powerups/disruptor");
cgs.media.quantumDisruptorShader = cgi_R_RegisterShader( "powerups/quantum_disruptor");
cgs.media.phaserDisruptorShader = cgi_R_RegisterShader( "powerups/phaser_disruptor");
cgs.media.shieldShader = cgi_R_RegisterShader( "gfx/effects/hirogenshield" );
cgs.media.playerTeleportShader = cgi_R_RegisterShader( "playerTeleport" );
cgs.media.borgFullBodyShieldShader = cgi_R_RegisterShader( "gfx/effects/borgfullbodyshield" );
cgs.media.fixitEffectShader = cgi_R_RegisterShader( "fixitEffect" );
cgs.media.trans1Shader = cgi_R_RegisterShader( "gfx/misc/trans1" );
cgs.media.trans2Shader = cgi_R_RegisterShader( "gfx/misc/trans2" );
//interface
for ( i = 0 ; i < NUM_CROSSHAIRS ; i++ ) {
cgs.media.crosshairShader[i] = cgi_R_RegisterShaderNoMip( va("gfx/2d/crosshair%c", 'a'+i) );
}
cgs.media.backTileShader = cgi_R_RegisterShader( "gfx/2d/backtile" );
cgs.media.noammoShader = cgi_R_RegisterShader( "gfx/interface/noammo");
// Zoom interface
cgs.media.zoomMaskShader = cgi_R_RegisterShader( "gfx/misc/zoom_mask2" );
cgs.media.zoomBarShader = cgi_R_RegisterShader( "gfx/2d/zoom_ctrl" );
cgs.media.zoomBar2Shader = cgi_R_RegisterShader( "gfx/2d/zoom_ctrl2" );
cgs.media.zoomArrowShader = cgi_R_RegisterShaderNoMip( "gfx/2d/arrow" );
cgs.media.zoomInsertShader = cgi_R_RegisterShaderNoMip( "gfx/misc/zoom_insert" );
cgs.media.zoomInsert2Shader = cgi_R_RegisterShaderNoMip( "gfx/misc/zoom_insert2" );
cg.loadLCARSStage = 5;
CG_LoadingString( "game media models" );
// Chunk models
//FIXME: jfm:? bother to conditionally load these if an ent has this material type?
for (i = 0; i < NUM_CHUNKS; i++)
cgs.media.chunkModels[0][i] = cgi_R_RegisterModel( va( "models/chunks/generic/chunks_%i.md3", i+1 ) );
cgs.media.chunkSound = cgi_S_RegisterSound("sound/weapons/explosions/glasslcar.wav");
cgs.media.surfaceExpSound[0] = cgi_S_RegisterSound("sound/weapons/explosions/explode8.wav");
cgs.media.surfaceExpSound[1] = cgi_S_RegisterSound("sound/weapons/explosions/explode9.wav");
cgs.media.surfaceExpSound[2] = cgi_S_RegisterSound("sound/weapons/explosions/explode14.wav");
cgs.media.electricExpSound[0] = cgi_S_RegisterSound("sound/weapons/explosions/explode10.wav");
cgs.media.electricExpSound[1] = cgi_S_RegisterSound("sound/weapons/explosions/explode11.wav");
cgs.media.electricExpSound[2] = cgi_S_RegisterSound("sound/weapons/explosions/explode15.wav");
cgs.media.bigSurfExpSound = cgi_S_RegisterSound("sound/weapons/explosions/explode12.wav");
for (i = 0; i < NUM_CHUNKS; i++)
cgs.media.glassChunkModels[0][i] = cgi_R_RegisterModel( va( "models/chunks/glass/glchunks_%i.md3", i+1 ) );
cgs.media.glassChunkSound = cgi_S_RegisterSound("sound/weapons/explosions/glassbreak1.wav");
for (i = 0; i < BORG_CHUNKS; i++)
cgs.media.borgChunkModels[0][i] = cgi_R_RegisterModel( va( "models/chunks/borg/borg_%i.md3", i+1 ) );
cgs.media.borgChunkSound = cgi_S_RegisterSound("sound/weapons/explosions/metalexplode.wav");
for (i = 0; i < STASIS_CHUNKS; i++)
cgs.media.stasisChunkModels[0][i] = cgi_R_RegisterModel( va( "models/chunks/stasis/stasis_%i.md3", i+1 ) );
cgs.media.stasisChunkSound = cgi_S_RegisterSound("sound/weapons/explosions/mine1.wav");
//Models & Shaders
cgs.media.laserShader = cgi_R_RegisterShader ( "textures/borg/rbeam" );
cgs.media.borgEyeFlareShader = cgi_R_RegisterShader( "gfx/misc/borgeyeflare" );
cgs.media.assimTubesShader = cgi_R_RegisterShader("models/players/borgbolts/b_asstubes");
//Vohrsoth shaders
cgs.media.vohrConeShader = cgi_R_RegisterShader( /*"gfx/effects/vor_cone"*/"textures/borg/rbeam" );
cg.loadLCARSStage = 6;
memset( cg_items, 0, sizeof( cg_items ) );
memset( cg_weapons, 0, sizeof( cg_weapons ) );
// only register the items that the server says we need
strcpy( items, CG_ConfigString( CS_ITEMS) );
for ( i = 1 ; i < bg_numItems ; i++ ) {
if ( items[ i ] == '1' )
{
if (bg_itemlist[i].pickup_name)
{
CG_LoadingString( bg_itemlist[i].pickup_name );
CG_RegisterItemVisuals( i );
}
}
}
// wall marks
cgs.media.compressionMarkShader = cgi_R_RegisterShader( "gfx/damage/burnmark1" );
cgs.media.IMODMarkShader = cgi_R_RegisterShader( "gfx/damage/burnmark2" );
cgs.media.phaserMarkShader = cgi_R_RegisterShader( "gfx/damage/burnmark3" );
cgs.media.scavMarkShader = cgi_R_RegisterShader( "gfx/damage/burnmark4" );
cgs.media.bulletmarksShader = cgi_R_RegisterShader( "textures/decals/bulletmark4" );
cgs.media.rivetMarkShader = cgi_R_RegisterShader( "gfx/damage/rivetmark" );
cgs.media.shadowMarkShader = cgi_R_RegisterShader( "markShadow" );
cgs.media.wakeMarkShader = cgi_R_RegisterShader( "wake" );
CG_LoadingString("map brushes");
// register the inline models
cgs.numInlineModels = cgi_CM_NumInlineModels();
for ( i = 1 ; i < cgs.numInlineModels ; i++ ) {
char name[10];
vec3_t mins, maxs;
int j;
Com_sprintf( name, sizeof(name), "*%i", i );
cgs.inlineDrawModel[i] = cgi_R_RegisterModel( name );
cgi_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] );
}
}
cg.loadLCARSStage = 7;
CG_LoadingString("map models");
// 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.model_draw[i] = cgi_R_RegisterModel( modelName );
}
for (i=0 ; i<MAX_CLIENTS ; i++)
{
const char *clientInfo;
clientInfo = CG_ConfigString( CS_PLAYERS+i );
if ( !clientInfo[0] )
{
continue;
}
//feedback( va("client %i", i ) );
CG_NewClientinfo( i );
}
for (i=0 ; i < ENTITYNUM_WORLD ; i++)
{
if(&g_entities[i])
{
if(g_entities[i].client)
{
//if(!g_entities[i].client->clientInfo.infoValid)
//We presume this
{
CG_LoadingString( va("client %s", g_entities[i].client->clientInfo.name ) );
CG_RegisterClientModels(i);
if ( i != 0 )
{//Client weapons already precached
CG_RegisterWeapon( g_entities[i].client->ps.weapon );
CG_RegisterNPCCustomSounds( &g_entities[i].client->clientInfo );
CG_RegisterNPCEffects( g_entities[i].client->playerTeam );
CG_PrecachePlayerGreetingSound( g_entities[i].NPC_type );
if ( g_entities[i].NPC_type && Q_stricmp( "satan", g_entities[i].NPC_type ) == 0 )
{//very special case
for ( int x = 0; x < 4; x++ ) {
cgs.media.BWLightningShaders[x] = cgi_R_RegisterShader( va( "gfx/misc/bwlightning%i", x+1 ) );
}
}
}
}
}
else if ( g_entities[i].svFlags & SVF_NPC_PRECACHE && g_entities[i].NPC_type && g_entities[i].NPC_type[0] )
{//Precache the NPC_type
//FIXME: make sure we didn't precache this NPC_type already
CG_LoadingString( va("NPC %s", g_entities[i].NPC_type ) );
NPC_Precache( &g_entities[i] );
CG_PrecachePlayerGreetingSound( g_entities[i].NPC_type );
}
}
}
//always precache these, I guess...
CG_PrecachePlayerGreetingSound( "crewman" );
CG_PrecachePlayerGreetingSound( "ensign" );
CG_PrecachePlayerGreetingSound( "lt" );
CG_PrecachePlayerGreetingSound( "generic1" );
CG_PrecachePlayerGreetingSound( "generic2" );
CG_PrecachePlayerGreetingSound( "generic3" );
CG_PrecachePlayerGreetingSound( "generic4" );
cg.loadLCARSStage = 8;
// Registering interface graphics
for (i=0;i<IG_MAX;++i)
{
if (interface_graphics[i].file)
{
interface_graphics[i].graphic = cgi_R_RegisterShaderNoMip(interface_graphics[i].file);
}
// Turn everything off at first
if ((interface_graphics[i].type == SG_GRAPHIC) || (interface_graphics[i].type == SG_NUMBER))
{
interface_graphics[i].type = SG_OFF;
}
}
interface_graphics[IG_GROW].type = SG_OFF;
//register speaker table skins
for ( i = 0; i < SP_MAX ; i++ )
{
if ( speakerTable[i].headModel != 0 )
{//had a model registered for it, so register the skins
speakerTable[i].headSkin = CG_RegisterHeadSkin( speakerTable[i].headModelFile, speakerTable[i].skinName, &speakerTable[i].extensions );
}
}
cg.loadLCARSStage = 9;
// For mission objectives
cgs.media.objcorner1= cgi_R_RegisterShaderNoMip("menu/objectives/swoop1.tga");
cgs.media.objcorner2= cgi_R_RegisterShaderNoMip("menu/objectives/swoop2.tga");
cgs.media.objcorner3= cgi_R_RegisterShaderNoMip("menu/common/corner_ll_22_47.tga");
cgs.media.pending= cgi_R_RegisterShaderNoMip("menu/objectives/circle_out.tga");
cgs.media.notpending= cgi_R_RegisterShaderNoMip("menu/objectives/circle.tga");
//lcars interface
cgs.media.weaponcap1 = cgi_R_RegisterShaderNoMip("gfx/interface/cap4");
cgs.media.weaponcap2 = cgi_R_RegisterShaderNoMip("gfx/interface/cap5");
cgs.media.ammoslider = cgi_R_RegisterShaderNoMip("gfx/interface/ammobar");
cgs.media.weaponbox = cgi_R_RegisterShaderNoMip( "gfx/interface/weapon_box");
cgs.media.talkingtop = cgi_R_RegisterShaderNoMip("gfx/interface/captop");
cgs.media.talkingbot = cgi_R_RegisterShaderNoMip("gfx/interface/capbot");
cgs.media.talkingcap = cgi_R_RegisterShaderNoMip("gfx/interface/captopside");
cgs.media.bracketlu = cgi_R_RegisterShader("gfx/interface/bracketlefttop");
cgs.media.bracketld = cgi_R_RegisterShader("gfx/interface/bracketleftbot");
cgs.media.bracketru = cgi_R_RegisterShader("gfx/interface/bracketrighttop");
cgs.media.bracketrd = cgi_R_RegisterShader("gfx/interface/bracketrightbot");
NPCsPrecached = qtrue;
if (com_buildScript->integer) {
cgi_R_RegisterShader( "gfx/misc/nav_cpoint" );
cgi_R_RegisterShader( "gfx/misc/nav_line" );
cgi_R_RegisterShader( "gfx/misc/nav_arrow" );
cgi_R_RegisterShader( "gfx/misc/nav_node" );
}
}
//===========================================================================
/*
=================
CG_ConfigString
=================
*/
const char *CG_ConfigString( int index ) {
if ( index < 0 || index >= MAX_CONFIGSTRINGS ) {
CG_Error( "CG_ConfigString: bad index: %i", index );
}
return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ];
}
//==================================================================
void CG_LinkCentsToGents(void)
{
int i;
for(i = 0; i < MAX_GENTITIES; i++)
{
cg_entities[i].gent = &g_entities[i];
}
}
/*
======================
CG_StartMusic
======================
*/
void CG_StartMusic( void ) {
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 ) );
cgi_S_StartBackgroundTrack( parm1, parm2 );
}
/*
======================
CG_GameStateReceived
Displays the info screen while loading media
======================
*/
int iCGResetCount=0;
qboolean qbVidRestartOccured = qfalse;
void CG_GameStateReceived( void ) {
// clear everything
extern void CG_ClearAnimSndCache( void );
CG_ClearAnimSndCache(); // else sound handles wrong after vid_restart
qbVidRestartOccured = qtrue;
iCGResetCount++;
if (iCGResetCount == 1) // this will only equal 1 first time, after each vid_restart it just gets higher.
{ // This non-clear is so the user can vid_restart during scrolling text without losing it.
qbVidRestartOccured = qfalse;
}
if (!qbVidRestartOccured)
{
memset( &cg, 0, sizeof( cg ) );
}
memset( cg_entities, 0, sizeof(cg_entities) );
memset( cg_weapons, 0, sizeof(cg_weapons) );
memset( cg_items, 0, sizeof(cg_items) );
CG_LinkCentsToGents();
cg.weaponSelect = WP_PHASER;
// get the rendering configuration from the client system
cgi_GetGlconfig( &cgs.glconfig );
cgs.screenXScale = cgs.glconfig.vidWidth / 640.0;
cgs.screenYScale = cgs.glconfig.vidHeight / 480.0;
/* cgs.charScale = cgs.glconfig.vidHeight * (1.0/480.0);
if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) {
// wide screen
cgs.bias = 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * (640.0/480.0) ) );
}
else {
// no wide screen
cgs.bias = 0;
}
*/
// get the gamestate from the client system
cgi_GetGameState( &cgs.gameState );
CG_ParseServerinfo();
// load the new map
CG_LoadingString( "collision map" );
cgi_CM_LoadMap( cgs.mapname );
CG_RegisterSounds();
CG_RegisterGraphics();
//jfm: moved down to preinit
// CG_InitLocalEntities();
// CG_InitMarkPolys();
CG_StartMusic();
// remove the last loading update
cg.infoScreenText[0] = 0;
// To get the interface timing started
cg.interfaceStartupTime = 0;
cg.interfaceStartupDone = 0;
CGCam_Init();
FX_Init();
}
/*
=================
CG_PreInit
Called when DLL loads (after subsystem restart, but before gamestate is received)
=================
*/
void CG_PreInit() {
memset( &cg, 0, sizeof( cg ) );
memset( &cgs, 0, sizeof( cgs ) );
iCGResetCount = 0;
CG_RegisterCvars();
//moved from CG_GameStateReceived because it's loaded sooner now
CG_InitLocalEntities();
CG_InitMarkPolys();
}
/*
=================
CG_Init
Called after every level change or subsystem restart
=================
*/
void CG_Init( int serverCommandSequence ) {
cgs.serverCommandSequence = serverCommandSequence;
// cgs.media.charsetShader = cgi_R_RegisterShaderNoMip( "gfx/2d/bigchars" );
cgs.media.charsetShader = cgi_R_RegisterShaderNoMip("gfx/2d/charsgrid_med");
cgs.media.charsetProp = cgi_R_RegisterShaderNoMip("gfx/2d/chars_medium");
cgs.media.charsetPropTiny = cgi_R_RegisterShaderNoMip("gfx/2d/chars_tiny");
cgs.media.charsetPropBig = cgi_R_RegisterShaderNoMip("gfx/2d/chars_big");
cgs.media.whiteShader = cgi_R_RegisterShader( "white" );
cgs.media.status_corner_18_22 = cgi_R_RegisterShaderNoMip( "menu/common/corner_ul_18_22");
cgs.media.status_corner_16_18 = cgi_R_RegisterShaderNoMip( "menu/common/corner_ll_16_18");
cgs.media.status_corner_8_16_b = cgi_R_RegisterShaderNoMip( "menu/common/corner_lr_8_16_b");
cgs.media.status_corner_8_22 = cgi_R_RegisterShaderNoMip( "menu/common/corner_ur_8_22");
CG_LoadIngameText();
CG_LoadFonts();
// Loading graphics
cgs.media.loading1 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece1.tga" );
cgs.media.loading2 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece2.tga" );
cgs.media.loading3 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece3.tga" );
cgs.media.loading4 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece4.tga" );
cgs.media.loading5 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece5.tga" );
cgs.media.loading6 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece6.tga" );
cgs.media.loading7 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece7.tga" );
cgs.media.loading8 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece8.tga" );
cgs.media.loading9 = cgi_R_RegisterShaderNoMip( "menu/loading/smpiece9.tga" );
cgs.media.loadingcircle = cgi_R_RegisterShaderNoMip( "menu/loading/arrowpiece.tga" );
cgs.media.loadingquarter= cgi_R_RegisterShaderNoMip( "menu/loading/quarter.tga" );
cgs.media.loadingcorner = cgi_R_RegisterShaderNoMip( "menu/common/corner_lr_8_16.tga" );
cgs.media.loadingtrim = cgi_R_RegisterShaderNoMip( "menu/loading/trimupper.tga" );
cg.loadLCARSStage = 0;
cg.loadLCARScnt = 0;
CG_GameStateReceived();
CG_InitConsoleCommands();
//
// the game server will interpret these commands, which will be automatically
// forwarded to the server after they are not recognized locally
//
cgi_AddCommand ("kill");
cgi_AddCommand ("give");
cgi_AddCommand ("god");
cgi_AddCommand ("notarget");
cgi_AddCommand ("noclip");
cgi_AddCommand ("undying");
cgi_AddCommand ("setviewpos");
cgi_AddCommand ("setobjective");
cgi_AddCommand ("viewobjective");
// Not until it's done will it be seen
interface_graphics[IG_HEALTH_START].timer = cg.time + 3000;
interface_graphics[IG_ARMOR_START].timer = cg.time + 3100;
interface_graphics[IG_AMMO_START].timer = cg.time + 3200;
cg.missionInfoFlashTime = 0;
cg.missionStatusShow = qfalse;
}
/*
=================
CG_Shutdown
Called before every level change or subsystem restart
=================
*/
void CG_Shutdown( void )
{
FX_Free();
}
//// DEBUG STUFF
/*
-------------------------
CG_DrawNode
-------------------------
*/
void CG_DrawNode( vec3_t origin, int type )
{
vec3_t color;
float scale = 16.0f;
switch ( type )
{
case NODE_NORMAL:
VectorSet( color, 255, 0, 0 );
break;
case NODE_START:
VectorSet( color, 0, 0, 255 );
scale += 16.0f;
break;
case NODE_GOAL:
VectorSet( color, 0, 255, 0 );
scale += 16.0f;
break;
case NODE_NAVGOAL:
VectorSet( color, 255, 255, 0 );
break;
}
FX_AddSprite( origin, NULL, NULL, scale, 0.0f, 1.0f, 1.0f, color, color, 0.0f, 0.0f, 100, cgi_R_RegisterShader( "gfx/misc/nav_node" ) );
}
/*
-------------------------
CG_DrawRadius
-------------------------
*/
void CG_DrawRadius( vec3_t origin, unsigned int radius, int type )
{
vec3_t color;
switch ( type )
{
case NODE_NORMAL:
VectorSet( color, 255, 0, 0 );
break;
case NODE_START:
VectorSet( color, 0, 0, 255 );
break;
case NODE_GOAL:
VectorSet( color, 0, 255, 0 );
break;
case NODE_NAVGOAL:
VectorSet( color, 255, 255, 0 );
break;
}
vec3_t normal = { 0, 0, 1 }; //Up
FX_AddQuad( origin, normal, NULL, NULL, radius, 0.0f, 1.0f, 1.0f, color, color, 0, 0, 0, 100, cgi_R_RegisterShader( "gfx/misc/nav_node" ) );
}
/*
-------------------------
CG_DrawEdge
-------------------------
*/
void CG_DrawEdge( vec3_t start, vec3_t end, int type )
{
switch ( type )
{
case EDGE_PATH:
FX_AddLine( start, end, 4.0f, 4.0f, 0.0f, 1.0f, 1.0f, 100, cgi_R_RegisterShader( "gfx/misc/nav_arrow" ), 0 );
break;
case EDGE_NORMAL:
FX_AddLine( start, end, 8.0f, 4.0f, 0.0f, 0.5f, 0.5f, 100, cgi_R_RegisterShader( "gfx/misc/nav_line" ), 0 );
break;
case EDGE_BROKEN:
{
vec3_t color = { 255, 0, 0 };
FX_AddLine( start, end, 8.0f, 4.0f, 0.0f, 0.5f, 0.5f, color, color, 100, cgi_R_RegisterShader( "gfx/misc/nav_line" ), 0 );
}
break;
default:
break;
}
}
/*
-------------------------
CG_DrawCombatPoint
-------------------------
*/
void CG_DrawCombatPoint( vec3_t origin, int type )
{
vec3_t color = { 0, 255, 255 };
switch( type )
{
case 0: //FIXME: To shut up the compiler warning (more will be added here later of course)
default:
FX_AddSprite( origin, NULL, NULL, 8.0f, 0.0f, 1.0f, 1.0f, color, color, 0.0f, 0.0f, 100, cgi_R_RegisterShader( "gfx/misc/nav_cpoint" ) );
break;
}
}
/*
-------------------------
CG_DrawAlert
-------------------------
*/
void CG_DrawAlert( vec3_t origin, float rating )
{
vec3_t drawPos;
VectorCopy( origin, drawPos );
drawPos[2] += 48;
vec3_t startRGB;
//Fades from green at 0, to red at 1
startRGB[0] = rating;
startRGB[1] = 1 - rating;
startRGB[2] = 0;
FX_AddSprite( drawPos, NULL, NULL, 16, 0.0f, 1.0f, 1.0f, startRGB, startRGB, 0, 0, 100, cgs.media.whiteShader );
}
#define MAXINGAMETEXT 4000
char ingameText[MAXINGAMETEXT];
/*
=================
CG_ParseIngameText
=================
*/
void CG_ParseIngameText(void)
{
char *token;
char *buffer;
int i;
int len;
COM_BeginParseSession();
buffer = ingameText;
i = 1; // Zero is null string
while ( buffer )
{
token = COM_ParseExt( &buffer, qtrue );
len = strlen(token);
if (len)
{
ingame_text[i] = (buffer - (len + 1)); // The +1 is to get rid of the " at the beginning of the sting.
*(buffer - 1) = '\0'; // Place an string end where is belongs.
++i;
}
if (i> IGT_MAX)
{
Com_Printf( S_COLOR_RED "CG_ParseIngameText : too many values! Needed %d but got %d.\n",IGT_MAX,i);
return;
}
}
if (i != IGT_MAX)
{
Com_Printf( S_COLOR_RED "CG_ParseIngameText : not enough values! Needed %d but only got %d.\n",IGT_MAX,i);
for(;i<IGT_MAX;i++) {
ingame_text[i] = "?";
}
}
}
/*
CG_LanguageFilename - create a filename with an extension based on the value in g_language
*/
void CG_LanguageFilename(char *baseName,char *baseExtension,char *finalName)
{
char language[32];
fileHandle_t file;
Q_strncpyz(language,cg_language.string,sizeof(language));
// If it's English then no extension
if (language[0]=='\0' || Q_stricmp("ENGLISH",language)==0)
{
Com_sprintf(finalName,MAX_QPATH,"%s.%s",baseName,baseExtension);
}
else
{
Com_sprintf(finalName,MAX_QPATH,"%s_%s.%s",baseName,language,baseExtension);
//Attempt to load the file
cgi_FS_FOpenFile( finalName, &file, FS_READ );
if ( file == 0 ) // This extension doesn't exist, go English.
{
Com_sprintf(finalName,MAX_QPATH,"%s.%s",baseName,baseExtension);
}
else
{
cgi_FS_FCloseFile( file );
}
}
}
/*
=================
CG_LoadIngameText
=================
*/
void CG_LoadIngameText(void)
{
int len;
fileHandle_t f;
char filename[MAX_QPATH];
CG_LanguageFilename("ext_data/sp_ingametext","dat",filename);
len = cgi_FS_FOpenFile( filename, &f, FS_READ );
if ( !f )
{
Com_Printf( S_COLOR_RED "CG_LoadIngameText : sp_ingametext.dat file not found!\n");
return;
}
if (len > MAXINGAMETEXT)
{
Com_Printf( S_COLOR_RED "CG_LoadIngameText : sp_ingametext.dat file bigger than %d!\n",MAXINGAMETEXT);
return;
}
// initialise the data area
memset(ingameText, 0, sizeof(ingameText));
cgi_FS_Read( ingameText, len, f );
cgi_FS_FCloseFile( f );
CG_ParseIngameText();
}