// Copyright (C) 1999-2000 Id Software, Inc. // // cg_main.c -- initialization and primary entry point for cgame //TiM : 22/12/2005 - Commented out any assets that we no longer use. //TiM : 24/12/2005 - Added a ranks parsing function. #include "cg_local.h" #include "cg_text.h" #include "cg_logger.h" void CG_Init( int32_t serverMessageNum, int32_t serverCommandSequence ); void CG_Shutdown( void ); void CG_LoadIngameText(void); void CG_LoadObjectivesForMap(void); void BG_LoadItemNames(void); qboolean CG_LoadUsablesStrings( void ); //TiM - Placed the func @ the bottom of the page for easier access //extern static qboolean CG_LoadRanks( void ); extern void FX_InitSinTable(void); int32_t cg_liftEnts[MAX_CLIENTS]; int32_t cg_numAnims; int32_t cg_numSndAnims; animsSndList_t cg_animsSndList[MAX_CLIENTS]; animsList_t cg_animsList[MAX_CLIENTS]; /* ================ vmMain This is the only way control passes into the module. This must be the very first function compiled into the .q3vm file ================ */ Q_EXPORT intptr_t vmMain( int32_t command, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6 ) { CG_LogFuncBegin(); switch ( command ) { case CG_INIT: CG_Init( arg0, arg1 ); CG_LogFuncEnd(); return 0; case CG_SHUTDOWN: CG_Shutdown(); CG_LogFuncEnd(); return 0; case CG_CONSOLE_COMMAND: CG_LogFuncEnd(); return CG_ConsoleCommand(); case CG_DRAW_ACTIVE_FRAME: CG_DrawActiveFrame( arg0, (stereoFrame_t)arg1, (qboolean)arg2 ); CG_LogFuncEnd(); return 0; case CG_CROSSHAIR_PLAYER: CG_LogFuncEnd(); return CG_CrosshairPlayer(); case CG_LAST_ATTACKER: CG_LogFuncEnd(); return CG_LastAttacker(); default: CG_Error( "vmMain: unknown command %i", command ); break; } CG_LogFuncEnd(); 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_gibs; vmCvar_t cg_drawTimer; vmCvar_t cg_drawFPS; vmCvar_t cg_drawSnapshot; vmCvar_t cg_draw3dIcons; vmCvar_t cg_drawIcons; vmCvar_t cg_drawAmmoWarning; vmCvar_t cg_drawCrosshair; vmCvar_t cg_drawCrosshairNames; vmCvar_t cg_dynamicCrosshairNames; vmCvar_t cg_drawRewards; vmCvar_t cg_crosshairSize; vmCvar_t cg_crosshairX; vmCvar_t cg_crosshairY; 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_nopredict; vmCvar_t cg_noPlayerAnims; vmCvar_t cg_showmiss; 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_ignore; vmCvar_t cg_simpleItems; vmCvar_t cg_fov; vmCvar_t cg_zoomFov; vmCvar_t cg_thirdPerson; vmCvar_t cg_thirdPersonRange; vmCvar_t cg_thirdPersonAngle; vmCvar_t cg_thirdPersonVertOffset; vmCvar_t cg_thirdPersonHorzOffset; vmCvar_t cg_thirdPersonAlpha; vmCvar_t cg_thirdPersonCameraDamp; vmCvar_t cg_thirdPersonTargetDamp; vmCvar_t cg_thirdPersonPitchOffset; vmCvar_t cg_stereoSeparation; vmCvar_t cg_lagometer; vmCvar_t cg_synchronousClients; vmCvar_t cg_teamChatTime; vmCvar_t cg_teamChatHeight; vmCvar_t cg_stats; vmCvar_t cg_reportDamage; vmCvar_t cg_buildScript; vmCvar_t cg_forceModel; vmCvar_t cg_paused; vmCvar_t cg_predictItems; vmCvar_t cg_deferPlayers; vmCvar_t cg_drawTeamOverlay; vmCvar_t cg_teamOverlayUserinfo; vmCvar_t ui_playerClass; vmCvar_t ui_playerRank; vmCvar_t cg_disablekillmsgs; vmCvar_t cg_drawradar; vmCvar_t rpg_ctribgrenade; //RPG-X: - RedTechie i think J2J added this to control invisible tripmines on clients end - TOFIX:THIS ALSO COULD BE HACKED! vmCvar_t cg_dynamicCrosshair; //RPG-X | Phenix | 09/06/2005 vmCvar_t doomHead; //RPG-X | Phenix | 09/06/2005 vmCvar_t cg_dynamiclensflares; vmCvar_t cg_noTalkingHeads; vmCvar_t cg_noDynamicRanks; vmCvar_t noAdminChat; //TiM //RPG-X: TiM - Player Model Parameters vmCvar_t pms_age; vmCvar_t pms_height; vmCvar_t pms_weight; vmCvar_t pms_race; vmCvar_t cg_defaultChar; //RPG-X: TiM - Emote system model offset vmCvar_t emote_Offset; vmCvar_t cg_thirdPersonZoomRate; vmCvar_t cg_noFrowningHeads; vmCvar_t cg_noBlinkingHeads; //RPG-X: TiM - First Person Body vmCvar_t cg_firstPersonBody; vmCvar_t cg_defaultModel; vmCvar_t cg_showEntityNums; //TiM - SecurityCode vmCvar_t sv_securityHash; vmCvar_t sv_securityCode; //TiM - widescreen vmCvar_t cg_handleWidescreen; vmCvar_t ui_handleWidescreen; //vmCvar_t cg_chatBGColor; vmCvar_t cg_chatColor; //RPG-X | GSIO01 | 11/05/2009 vmCvar_t rpg_forceFieldSet; // grp cvars vmCvar_t grp_berp; // debugging cvars vmCvar_t cg_logLevel; // lua #ifdef CG_LUA vmCvar_t cg_debugLua; vmCvar_t cg_logLua; #endif typedef struct { vmCvar_t *vmCvar; char *cvarName; char *defaultString; int32_t cvarFlags; } cvarTable_t; static cvarTable_t cvarTable[] = { { &cg_ignore, "cg_ignore", "0", 0 }, // used for debugging { &cg_autoswitch, "cg_autoswitch", "1", CVAR_ARCHIVE }, { &cg_drawGun, "cg_drawGun", "1", CVAR_ARCHIVE }, { &cg_zoomFov, "cg_zoomfov", "22.5", 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_gibs, "cg_gibs", "0", CVAR_ARCHIVE }, //no gibs in trek { &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_draw3dIcons, "cg_draw3dIcons", "1", CVAR_ARCHIVE }, { &cg_drawIcons, "cg_drawIcons", "1", CVAR_ARCHIVE }, { &cg_drawAmmoWarning, "cg_drawAmmoWarning", "1", CVAR_ARCHIVE }, { &cg_drawCrosshair, "cg_drawCrosshair", "1", CVAR_ARCHIVE }, { &cg_drawCrosshairNames, "cg_drawCrosshairNames", "1", CVAR_ARCHIVE }, { &cg_drawRewards, "cg_drawRewards", "1", CVAR_ARCHIVE }, { &cg_crosshairSize, "cg_crosshairSize", "24", CVAR_ARCHIVE }, { &cg_crosshairHealth, "cg_crosshairHealth", "1", 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_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", "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.2", CVAR_CHEAT }, //0.3 //TiM - slowed for better realism { &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_nopredict, "cg_nopredict", "0", 0 }, { &cg_noPlayerAnims, "cg_noplayeranims", "0", CVAR_CHEAT }, { &cg_showmiss, "cg_showmiss", "0", 0 }, { &cg_footsteps, "cg_footsteps", "1", CVAR_CHEAT }, { &cg_thirdPersonRange, "cg_thirdPersonRange", "80", CVAR_ARCHIVE }, { &cg_thirdPersonAngle, "cg_thirdPersonAngle", "0", CVAR_ARCHIVE }, { &cg_thirdPerson, "cg_thirdPerson", "0", CVAR_ARCHIVE }, { &cg_thirdPersonVertOffset, "cg_thirdPersonVertOffset", "16", CVAR_ARCHIVE }, //RPG-X: TiM { &cg_thirdPersonHorzOffset, "cg_thirdPersonHorzOffset", "0", CVAR_ARCHIVE }, //RPG-X: TiM { &cg_thirdPersonAlpha, "cg_thirdPersonAlpha", "1.0", CVAR_ARCHIVE },//RPG-X: TiM { &cg_thirdPersonCameraDamp, "cg_thirdPersonCameraDamp", "0.3", CVAR_ARCHIVE },//RPG-X: TiM { &cg_thirdPersonTargetDamp, "cg_thirdPersonTargetDamp", "0.5", CVAR_ARCHIVE },//RPG-X: TiM { &cg_thirdPersonPitchOffset, "cg_thirdPersonPitchOffset", "0.0", CVAR_ARCHIVE},//RPG-X: TiM { &cg_firstPersonBody, "cg_firstPersonBody", "0", CVAR_ARCHIVE}, { &cg_teamChatTime, "cg_teamChatTime", "3000", CVAR_ARCHIVE }, { &cg_teamChatHeight, "cg_teamChatHeight", "0", CVAR_ARCHIVE }, { &cg_forceModel, "cg_forceModel", "0", CVAR_ARCHIVE }, { &cg_predictItems, "cg_predictItems", "1", CVAR_ARCHIVE }, { &cg_deferPlayers, "cg_deferPlayers", "1", CVAR_ARCHIVE }, { &cg_drawTeamOverlay, "cg_drawTeamOverlay", "0", CVAR_ARCHIVE }, { &cg_teamOverlayUserinfo, "teamoverlay", "0", CVAR_ROM | CVAR_USERINFO }, { &cg_stats, "cg_stats", "0", 0 }, { &cg_reportDamage, "cg_reportDamage", "0", 0}, { &rpg_ctribgrenade, "rpg_ctribgrenade", "0", CVAR_ARCHIVE}, //RPG-X: - RedTechie i think J2J added this to control invisible tripmines on clients end - TOFIX:THIS ALSO COULD BE HACKED! { &pms_age, "age", "Unknown", CVAR_ARCHIVE | CVAR_USERINFO }, { &pms_height, "height", "1.0", CVAR_ARCHIVE | CVAR_USERINFO }, { &pms_weight, "weight", "1.0", CVAR_ARCHIVE | CVAR_USERINFO }, { &pms_race, "race", "Unknown", CVAR_ARCHIVE | CVAR_USERINFO }, { &emote_Offset, "modelOffset", "0", CVAR_ARCHIVE | CVAR_USERINFO }, { &cg_defaultChar, "cg_defaultChar", (char*)DEFAULT_CHAR, 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 { &ui_playerClass, "ui_playerClass", "noclass", CVAR_ARCHIVE /*| CVAR_ROM | CVAR_USERINFO*/ }, { &ui_playerRank, "ui_playerRank", "crewman", CVAR_ARCHIVE /*| CVAR_ROM | CVAR_USERINFO*/ }, { &cg_disablekillmsgs, "cg_disablekillmsgs", "0", CVAR_ARCHIVE }, { &cg_drawradar, "cg_drawradar", "1", CVAR_ARCHIVE }, { &cg_dynamicCrosshair, "cg_dynamicCrosshair", "1", CVAR_ARCHIVE }, //RPG-X | Phenix | 09/06/2005 { &doomHead, "doomHead", "0", CVAR_ARCHIVE }, //RPG-X | Phenix | 09/06/2005 { &cg_dynamiclensflares, "cg_dynamicLensFlares", "1", CVAR_ARCHIVE }, //RPG-X | TiM | 29/6/2005 { &cg_dynamicCrosshairNames, "cg_dynamicCrosshairNames", "1", CVAR_ARCHIVE }, { &noAdminChat, "noAdminChat", "0", CVAR_ARCHIVE | CVAR_USERINFO }, //RPG-X Memory optimization CVARs { &cg_noTalkingHeads, "cg_noTalkingHeads", "0", CVAR_ARCHIVE }, { &cg_noDynamicRanks, "cg_noDynamicRanks", "0", CVAR_ARCHIVE }, { &cg_noFrowningHeads, "cg_noFrowningHeads", "1", CVAR_ARCHIVE }, //On by default since this isn't REALLY needed... :P { &cg_noBlinkingHeads, "cg_noBlinkingHeads", "0", CVAR_ARCHIVE }, { &cg_thirdPersonZoomRate, "cg_thirdPersonZoomRate", "25", CVAR_ARCHIVE }, { &cg_showEntityNums, "cg_showEntityNums", "1", CVAR_ARCHIVE }, //TiM - security cvars { &sv_securityHash, "sv_securityHash", "4294967295", CVAR_ARCHIVE | CVAR_ROM | CVAR_NORESTART }, { &sv_securityCode, "sv_securityCode", "4294967295", CVAR_ARCHIVE | CVAR_USERINFO | CVAR_ROM | CVAR_NORESTART }, { &cg_handleWidescreen, "cg_handleWidescreen", "1", CVAR_ARCHIVE }, { &ui_handleWidescreen, "ui_handleWidescreen", "1", CVAR_ARCHIVE }, { &cg_chatColor, "cg_chatColor", "", CVAR_ARCHIVE }, //RPG-X | GSIO01 | 11/05/2009 { &rpg_forceFieldSet, "rpg_forceFieldSet", "1", CVAR_ARCHIVE | CVAR_LATCH }, // grp cvars { &grp_berp, "grp_berp", "0", CVAR_ARCHIVE | CVAR_LATCH }, // debugging cvars { &cg_logLevel, "cg_loglevel", "2", CVAR_ARCHIVE }, // lua #ifdef CG_LUA { &cg_debugLua, "cg_debuglua", "0", CVAR_ARCHIVE | CVAR_LATCH }, { &cg_logLua, "cg_loglua", "0", CVAR_ARCHIVE } #endif }; #define CVAR_TABLE_SIZE sizeof( cvarTable ) / sizeof( cvarTable[0] ) /* ======================= CG_PrecacheRemapShaders ======================= */ void CG_PrecacheRemapShaders(void) { char filepath[MAX_QPATH]; fileHandle_t f; int32_t len; char* data; char* ptr; char* token; qhandle_t shader; CG_LogFuncBegin(); COM_StripExtension(cgs.mapname, filepath); Com_sprintf(filepath, MAX_QPATH, "%s.precache", filepath); len = trap_FS_FOpenFile(filepath, &f, FS_READ); if(!f) { CG_Logger(LL_INFO, "No precache file ...\n"); CG_LogFuncEnd(); return; } data = (char *)malloc(sizeof(char)*(len+1)); if(!data) { trap_FS_FCloseFile(f); CG_Printf(S_COLOR_RED "Error - could not allocate %d byte of memory.\n", sizeof(char)*(len+1)); CG_LogFuncEnd(); return; } trap_FS_Read(data, len, f); trap_FS_FCloseFile(f); //CG_Printf("Precaching texture files ..."); CG_Logger(LL_INFO, "Precaching texture files ..."); COM_BeginParseSession(); ptr = data; token = COM_Parse(&ptr); while(token != NULL) { if(token == NULL || token[0] == 0) { CG_Logger(LL_DEBUG, "token == NULL\n"); break; } if(strcmp(token, "END") == 0) { CG_Logger(LL_DEBUG, "token == END\n"); break; } CG_Logger(LL_INFO, "\t%s ... ", token); shader = trap_R_RegisterShader(token); if(shader == 0) { CG_Logger(LL_WARN, "FAIL\n"); } else { CG_Logger(LL_INFO, "OK\n"); } token = COM_Parse(&ptr); } CG_LogFuncEnd(); free(data); } /* ================= CG_RegisterCvars ================= */ void CG_RegisterCvars( void ) { int32_t i; cvarTable_t *cv; char var[MAX_TOKEN_CHARS]; CG_LogFuncBegin(); for ( i = 0, cv = cvarTable ; i < CVAR_TABLE_SIZE ; i++, cv++ ) { trap_Cvar_Register( cv->vmCvar, cv->cvarName, cv->defaultString, cv->cvarFlags ); } // see if we are also running the server on this machine trap_Cvar_VariableStringBuffer( "sv_running", var, sizeof( var ) ); cgs.localServer = (qboolean)atoi( var ); CG_LogFuncEnd(); } /* ================= CG_UpdateCvars ================= */ void CG_UpdateCvars( void ) { int32_t i; cvarTable_t *cv; CG_LogFuncBegin(); for ( i = 0, cv = cvarTable ; i < CVAR_TABLE_SIZE ; i++, cv++ ) { trap_Cvar_Update( cv->vmCvar ); } // check for modications here // If team overlay is on, ask for updates from the server. If its off, // let the server know so we don't receive it if ( drawTeamOverlayModificationCount != cg_drawTeamOverlay.modificationCount ) { drawTeamOverlayModificationCount = cg_drawTeamOverlay.modificationCount; if ( cg_drawTeamOverlay.integer > 0 ) { trap_Cvar_Set( "teamoverlay", "1" ); } else { trap_Cvar_Set( "teamoverlay", "0" ); } } CG_LogFuncEnd(); } int32_t CG_CrosshairPlayer( void ) { CG_LogFuncBegin(); if ( cg.time > ( cg.crosshairClientTime + 1000 ) ) { CG_LogFuncEnd(); return -1; } CG_LogFuncEnd(); return cg.crosshairClientNum; } int32_t CG_LastAttacker( void ) { CG_LogFuncBegin(); if ( !cg.attackerTime ) { CG_LogFuncEnd(); return -1; } CG_LogFuncEnd(); return cg.snap->ps.persistant[PERS_ATTACKER]; } void QDECL CG_Printf( const char *msg, ... ) { va_list argptr; char text[1024]; char *msgPtr; va_start (argptr, msg); vsprintf (text, msg, argptr); va_end (argptr); if ( cg_chatColor.integer > 0 && cg_chatColor.integer < 8 ) { msgPtr = text; while ( msgPtr && *msgPtr != '\0' ) { if ( *msgPtr == '^' ) { msgPtr++; *msgPtr = 48 + cg_chatColor.integer; } msgPtr++; } } trap_Print( text ); } void QDECL CG_Error( const char *msg, ... ) { va_list argptr; char text[1024]; CG_LogFuncBegin(); va_start (argptr, msg); vsprintf (text, msg, argptr); va_end (argptr); CG_LogFuncEnd(); trap_Error( text ); } #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( int32_t level, const char *error, ... ) { va_list argptr; char text[1024]; CG_LogFuncBegin(); va_start (argptr, error); vsprintf (text, error, argptr); va_end (argptr); CG_LogFuncEnd(); CG_Error( "%s", 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); CG_Printf ("%s", text); } #endif /* ================ CG_Argv ================ */ const char *CG_Argv( int32_t arg ) { static char buffer[MAX_STRING_CHARS]; CG_LogFuncBegin(); trap_Argv( arg, buffer, sizeof( buffer ) ); CG_LogFuncEnd(); return buffer; } //======================================================================== /* ================= CG_RegisterItemSounds The server says this item is used on this level ================= */ static void CG_RegisterItemSounds( int32_t itemNum ) { gitem_t *item; char data[MAX_QPATH]; char *s, *start; int32_t len; CG_LogFuncBegin(); 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 == NULL || s[0] == 0) { CG_LogFuncEnd(); return; } while (*s) { start = s; while (*s && *s != ' ') { s++; } len = s-start; if (len >= MAX_QPATH || len < 5) { CG_LogFuncEnd(); 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" )) { trap_S_RegisterSound( data ); } } CG_LogFuncEnd(); } /* ================= CG_RegisterSounds called during a precache command ================= */ static void CG_RegisterSounds( void ) { int32_t i; char items[MAX_ITEMS+1]; char name[MAX_QPATH]; const char *soundName; CG_LogFuncBegin(); cg.loadLCARSStage = 1; // Loading bar stage 1 CG_LoadingString( "sounds" ); cgs.media.count2Sound = trap_S_RegisterSound( "sound/voice/computer/misc/two.wav" ); cgs.media.count1Sound = trap_S_RegisterSound( "sound/voice/computer/misc/one.wav" ); cgs.media.countFightSound = trap_S_RegisterSound( "sound/voice/computer/misc/fight.wav" ); cgs.media.countPrepareSound = trap_S_RegisterSound( "sound/voice/computer/misc/prepare.wav" ); cgs.media.interfaceSnd1 = trap_S_RegisterSound( "sound/interface/button4.wav" ); cgs.media.useNothingSound = trap_S_RegisterSound( "sound/items/use_nothing.wav" ); cgs.media.teleInSound = trap_S_RegisterSound( "sound/world/transin.wav" ); cgs.media.transportSound = trap_S_RegisterSound( "sound/world/transporter.wav" ); cgs.media.respawnSound = trap_S_RegisterSound( "sound/items/respawn1.wav" ); cgs.media.talkSound = trap_S_RegisterSound( "sound/interface/communicator.wav" ); cgs.media.landSound[LANDSOUND_NORMAL] = trap_S_RegisterSound("sound/player/land1.wav"); cgs.media.landSound[LANDSOUND_GRASS] = trap_S_RegisterSound("sound/player/footsteps/grass_jump.wav"); cgs.media.landSound[LANDSOUND_GRAVEL] = trap_S_RegisterSound("sound/player/footsteps/gravel_jump.wav"); cgs.media.landSound[LANDSOUND_SNOW] = trap_S_RegisterSound("sound/player/footsteps/snow_jump.wav"); cgs.media.landSound[LANDSOUND_WOOD] = trap_S_RegisterSound("sound/player/footsteps/wood_jump.wav"); cgs.media.splatSound = trap_S_RegisterSound( "sound/weapons/bodyfall.wav"); cgs.media.watrInSound = trap_S_RegisterSound( "sound/player/watr_in.wav"); cgs.media.watrOutSound = trap_S_RegisterSound( "sound/player/watr_out.wav"); cgs.media.watrUnSound = trap_S_RegisterSound( "sound/player/watr_un.wav"); cgs.media.jumpPadSound = trap_S_RegisterSound ("sound/items/damage3.wav" ); cgs.media.disintegrateSound = trap_S_RegisterSound( "sound/weapons/prifle/disint.wav" ); cgs.media.disintegrate2Sound = trap_S_RegisterSound( "sound/weapons/prifle/disint2.wav" ); cgs.media.playerExplodeSound = trap_S_RegisterSound( "sound/weapons/explosions/fireball.wav" ); cgs.media.phaserEmptySound = trap_S_RegisterSound("sound/weapons/phaser/phaserempty.wav"); cgs.media.ShakeSound = trap_S_RegisterSound("sound/shake.wav"); cgs.media.tedTextSound = trap_S_RegisterSound( "sound/interface/tedtext.wav" ); for (i=0 ; i 0 ) { cgs.locations = qtrue; break; } } cg.loadLCARSStage = 7; // Loading bar stage 7 CG_LoadingString( "Interface" ); // Registering interface graphics for (i=0;i= MAX_CONFIGSTRINGS ) { CG_LogFuncEnd(); CG_Error( "CG_ConfigString: bad index: %i", index ); } CG_LogFuncEnd(); return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ]; } //================================================================== /* ====================== CG_StartMusic ====================== */ void CG_StartMusic( void ) { char* s = NULL; static char parm1[MAX_QPATH]; static char parm2[MAX_QPATH]; CG_LogFuncBegin(); // 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 ) ); trap_S_StartBackgroundTrack(parm1, parm2); CG_LogFuncEnd(); } extern int32_t altAmmoUsage[]; void CG_InitModRules( void ) { CG_LogFuncBegin(); if ( cgs.pModDisintegration ) {//don't use up ammo in disintegration mode altAmmoUsage[WP_6] = 0; } if ( cgs.pModSpecialties ) {//tripwires use more ammo altAmmoUsage[WP_8] = 3; } CG_LogFuncEnd(); } /* ================= CG_Init Called after every level change or subsystem restart Will perform callbacks to make the loading info screen update. ================= */ void CG_Init( int32_t serverMessageNum, int32_t serverCommandSequence ) { const char *s; int32_t i; CG_LogFuncBegin(); CG_Logger(LL_ALWAYS, "This is RPG-X version %s compiled by %s on %s.\n", RPGX_VERSION, RPGX_COMPILEDBY, RPGX_COMPILEDATE); // clear everything memset( &cgs, 0, sizeof( cgs ) ); 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) ); //Flush Sound Effects memset( &cg_animsSndList, 0, sizeof( cg_animsSndList ) ); init_tonextint(qfalse); cgs.processedSnapshotNum = serverMessageNum; cgs.serverCommandSequence = serverCommandSequence; CG_LoadIngameText(); CG_LoadFonts(); // Loading graphics cgs.media.loading1 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece1.tga" ); cgs.media.loading2 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece2.tga" ); cgs.media.loading3 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece3.tga" ); cgs.media.loading4 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece4.tga" ); cgs.media.loading5 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece5.tga" ); cgs.media.loading6 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece6.tga" ); cgs.media.loading7 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece7.tga" ); cgs.media.loading8 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece8.tga" ); cgs.media.loading9 = trap_R_RegisterShaderNoMip( "menu/loading/smpiece9.tga" ); cgs.media.loadingcircle = trap_R_RegisterShaderNoMip( "menu/loading/arrowpiece.tga" ); cgs.media.loadingquarter= trap_R_RegisterShaderNoMip( "menu/loading/quarter.tga" ); cgs.media.loadingcorner = trap_R_RegisterShaderNoMip( "menu/common/corner_lr_8_16.tga" ); cgs.media.loadingtrim = trap_R_RegisterShaderNoMip( "menu/loading/trimupper.tga" ); cgs.media.circle = trap_R_RegisterShaderNoMip( "menu/common/circle.tga" ); cgs.media.circle2 = trap_R_RegisterShaderNoMip( "menu/objectives/circle_out.tga" ); cgs.media.corner_12_18 = trap_R_RegisterShaderNoMip( "menu/common/corner_ll_12_18.tga" ); cgs.media.halfroundr_22 = trap_R_RegisterShaderNoMip( "menu/common/halfroundr_22.tga" ); cgs.media.corner_ul_20_30= trap_R_RegisterShaderNoMip( "menu/common/corner_ul_20_30.tga" ); cgs.media.corner_ll_8_30= trap_R_RegisterShaderNoMip( "menu/common/corner_ll_8_30.tga" ); cg.loadLCARSStage = 0; cg.loadLCARScnt = 0; // load a few needed things before we do any screen updates cgs.media.charsetShader = trap_R_RegisterShaderNoMip( "gfx/2d/charsgrid_med" ); cgs.media.whiteShader = trap_R_RegisterShader( "white" ); cgs.media.white2Shader = trap_R_RegisterShader( "white2" ); cgs.media.charsetPropTiny = trap_R_RegisterShaderNoMip("gfx/2d/chars_tiny"); cgs.media.charsetProp = trap_R_RegisterShaderNoMip("gfx/2d/chars_medium"); cgs.media.charsetPropBig = trap_R_RegisterShaderNoMip("gfx/2d/chars_big"); cgs.media.charsetPropB = trap_R_RegisterShaderNoMip( "gfx/2d/chars_medium.tga" ); CG_RegisterCvars(); CG_InitConsoleCommands(); BG_LoadItemNames(); cg.weaponSelect = WP_1; cgs.redflag = cgs.blueflag = -1; // For compatibily, default to unset for // old servers // 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; //TiM - handle wide screens if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) { cgs.widescreen.ratio = 640.0f*cgs.screenYScale * (1.0f/cgs.glconfig.vidWidth); cgs.widescreen.bias = 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * (640.0/480.0) ) ); } else { cgs.widescreen.ratio = 0; cgs.widescreen.bias = 0; } // get the gamestate from the client system trap_GetGameState( &cgs.gameState ); // check version s = CG_ConfigString( CS_GAME_VERSION ); if ( strcmp( s, GAME_VERSION ) ) { CG_LogFuncEnd(); CG_Error( "Client/Server game mismatch: %s/%s", GAME_VERSION, s ); } s = CG_ConfigString( CS_LEVEL_START_TIME ); cgs.levelStartTime = atoi( s ); CG_ParseServerinfo(); // load the new map CG_LoadingString( "collision map" ); trap_CM_LoadMap( cgs.mapname ); cg.loading = qtrue; // force players to load instead of defer CG_LoadObjectivesForMap(); CG_RegisterSounds(); CG_RegisterGraphics(); CG_RegisterClients(); // if low on memory, some clients will be deferred cg.loading = qfalse; // future players will be deferred CG_InitLocalEntities(); CG_InitMarkPolys(); // remove the last loading update cg.infoScreenText[0] = 0; // Make sure we have update values (scores) CG_SetConfigValues(); CG_StartMusic(); CG_LoadingString( "" ); //RPG-X | GSIO01 | 08/05/09: //Make sure all weapons are registered to prevent //missing models when someone get killed and weapons are dropped for(i = 0; i < WP_NUM_WEAPONS; i++) { CG_RegisterWeapon(i); } // To get the interface timing started cg.interfaceStartupTime = 0; cg.interfaceStartupDone = 0; CG_InitModRules(); if ( !CG_LoadCrosshairs() ) { CG_LogFuncEnd(); CG_Error( "Couldn't load crosshairs script" ); } if ( !CG_LoadRanks() ) { CG_LogFuncEnd(); CG_Error( "Couldn't load rankset script: %s", cgs.rankSet ); } if ( !CG_LoadClasses() ) { CG_LogFuncEnd(); CG_Error( "Couldn't load classset script: %s", cgs.classSet ); } //where possible, load in the usable strings locally if ( cgs.scannablePanels ) CG_LoadUsablesStrings(); /* shader remapping */ CG_ShaderStateChanged(); CG_PrecacheRemapShaders(); CG_LogFuncEnd(); } /* ================= CG_Shutdown Called before every level change or subsystem restart ================= */ void CG_Shutdown( void ) { CG_LocLogger(LL_TRACE, "%s\n", __FUNCTION__); } #define MAXINGAMETEXT 5000 char ingameText[MAXINGAMETEXT]; /* ================= CG_ParseIngameText ================= */ void CG_ParseIngameText(void) { char *token; char *buffer; int32_t i; int32_t len; CG_LogFuncBegin(); 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) { CG_LocLogger(LL_ERROR, "CG_ParseIngameText : too many values!\n"); CG_LogFuncEnd(); return; } } if (i != IGT_MAX) { CG_LocLogger(LL_ERROR, "CG_ParseIngameText : not enough lines! Read %d of %d!\n", i, IGT_MAX); for(;i MAXINGAMETEXT) { CG_LocLogger(LL_ERROR, "CG_LoadIngameText : mp_ingametext.dat file bigger than %d!\n", MAXINGAMETEXT); CG_LogFuncEnd(); return; } // initialise the data area memset(ingameText, 0, sizeof(ingameText)); trap_FS_Read( ingameText, len, f ); trap_FS_FCloseFile( f ); CG_ParseIngameText(); CG_LogFuncEnd(); } /* ================= CG_LoadObjectivesForMap ================= */ void CG_LoadObjectivesForMap(void) { int32_t len, objnum = 0; char *token; char *buf; fileHandle_t f; char fileName[MAX_QPATH]; char fullFileName[MAX_QPATH]; char objtext[MAX_OBJ_TEXT_LENGTH]; CG_LogFuncBegin(); COM_StripExtension( cgs.mapname, fileName ); CG_LanguageFilename( fileName, "efo", fullFileName); len = trap_FS_FOpenFile( fullFileName, &f, FS_READ ); if (f == 0 || len > MAX_OBJ_TEXT_LENGTH ) // TODO split these checks { CG_LocLogger(LL_ERROR, "CG_LoadObjectivesForMap : %s file bigger than %d!\n", fileName, MAX_OBJ_TEXT_LENGTH ); CG_LogFuncEnd(); return; } trap_FS_Read( objtext, len, f ); trap_FS_FCloseFile( f ); buf = objtext; //Now parse out each objective while ( 1 ) { token = COM_ParseExt( &buf, qtrue ); if ( !token[0] ) { break; } // Normal objective text if ( !Q_strncmp( token, "obj", 3 ) ) { objnum = atoi( &token[3] ); if ( objnum < 1 || objnum == MAX_OBJECTIVES ) { Com_Printf( "Invalid objective number (%d), valid range is 1 to %d\n", objnum, MAX_OBJECTIVES ); break; } //Now read the objective text into the current objective token = COM_ParseExt( &buf, qfalse ); Q_strncpyz( cgs.objectives[objnum-1].text, token, sizeof(cgs.objectives[objnum-1].text) ); } else if ( !Q_strncmp( token, "abridged_obj", 12 ) ) { objnum = atoi( &token[12] ); if ( objnum < 1 || objnum == MAX_OBJECTIVES ) { Com_Printf( "Invalid objective number (%d), valid range is 1 to %d\n", objnum, MAX_OBJECTIVES ); break; } //Now read the objective text into the current objective token = COM_ParseExt( &buf, qfalse ); Q_strncpyz( cgs.objectives[objnum-1].abridgedText, token, sizeof(cgs.objectives[objnum-1].abridgedText) ); } } CG_LogFuncEnd(); } qboolean CG_LoadClasses( void ) { fileHandle_t f; int32_t file_len; char buffer[32000]; char *token, *textPtr; char filePath[MAX_QPATH]; int32_t numClasses=0; int32_t i; CG_LogFuncBegin(); Com_sprintf( filePath, sizeof( filePath ), "ext_data/classes/%s.classes", cgs.classSet ); memset( &cgs.classData, 0, sizeof( cg_classData_t ) ); file_len = trap_FS_FOpenFile( filePath, &f, FS_READ ); if (f == 0) { return qfalse; // TODO logging } if ( !file_len ) { CG_LocLogger(LL_ERROR, "Couldn't find class file: %s\n", filePath ); CG_LogFuncEnd(); return qfalse; } if ( file_len > sizeof( buffer ) ) { CG_LocLogger(LL_ERROR, "File %s was way too big to be loaded.\n", filePath ); CG_LogFuncEnd(); return qfalse; } trap_FS_Read( buffer, file_len, f ); trap_FS_FCloseFile( f ); buffer[file_len] = '\0'; COM_BeginParseSession(); textPtr = buffer; token = COM_Parse( &textPtr ); if ( !token[0] ) { CG_LocLogger(LL_ERROR, "ERROR: No data was found when going to parse the file!\n" ); CG_LogFuncEnd(); return qfalse; } if ( Q_stricmpn( token, "{", 1 ) ) { CG_LocLogger(LL_ERROR, "ERROR: File did not start with a '{' symbol!\n" ); CG_LogFuncEnd(); return qfalse; } while( 1 ) { if ( numClasses >= MAX_CLASSES ) break; if ( !Q_strncmp( token, "{", 1 ) ) { while ( 1 ) { token = COM_Parse( &textPtr ); if (!token[0]) { break; } if ( !Q_stricmpn( token, "formalName", 10 ) ) { if ( COM_ParseString( &textPtr, &token ) ) { CG_LocLogger(LL_ERROR, "ERROR: Invalid class formal name in class index: %i.\n", numClasses ); continue; } Q_strncpyz( cgs.classData[numClasses].formalName, token, sizeof( cgs.classData[numClasses].formalName ) ); continue; } if ( !Q_stricmpn( token, "radarColor", 5 ) ) { vec3_t temp; if ( COM_ParseVec3( &textPtr, temp ) ) { CG_LocLogger(LL_ERROR, "ERROR: Invalid color values in class index: %i.\n", numClasses ); continue; } for ( i = 0; i < 3; i++ ) { cgs.classData[numClasses].radarColor[i] = (int32_t)Com_Clamp( 0, 255, (int32_t)temp[i] ); } continue; } if ( !Q_stricmpn( token, "iconColor", 9 ) ) { if ( COM_ParseString( &textPtr, &token ) ) { CG_LocLogger(LL_ERROR, "ERROR: Invalid class icon color in class index: %i.\n", numClasses ); continue; } //Eh... there are enum values for these, //but they're currently out of scope ;P if ( !Q_stricmp( token, "red" ) ) { cgs.classData[numClasses].iconColor = 1; //CLR_RED } else if ( !Q_stricmp( token, "gold" ) ) { cgs.classData[numClasses].iconColor = 2; //CLR_GOLD } else if ( !Q_stricmp( token, "teal" ) ) { cgs.classData[numClasses].iconColor = 3; //CLR_TEAL } else if ( !Q_stricmp( token, "green" ) ) { cgs.classData[numClasses].iconColor = 4; //CLR_GREEN } else { cgs.classData[numClasses].iconColor = 0; //0 } continue; } if ( !Q_stricmpn( token, "medical", 7 ) ) { if ( COM_ParseInt( &textPtr, (int32_t *)&cgs.classData[numClasses].isMedic ) ) { CG_LocLogger(LL_ERROR, "ERROR: Class medic check for class %i was invalid.\n", numClasses ); continue; } continue; } if( !Q_stricmpn( token, "isBorg", 6 ) ) { if( COM_ParseInt( &textPtr, (int32_t *)&cgs.classData[numClasses].isBorg ) ) { CG_LocLogger(LL_ERROR, "ERROR: Class borg check for class %i was invalid.\n", numClasses ); continue; } continue; } if ( !Q_stricmpn( token, "hasRanks", 8 ) ) { if ( COM_ParseInt( &textPtr, (int32_t *)&cgs.classData[numClasses].showRanks ) ) { CG_LocLogger(LL_ERROR, "ERROR: Class Ranks check for class %i was invalid.\n", numClasses ); continue; } continue; } //I'm a n00b lol. I made a class called 'medical' and a parameter called 'medical'. //I have to double check both parms or else it confuses the parser //better check all of them. I'm still getting errors if ( !Q_stricmpn( token, "consoleName", 10 ) || !Q_stricmpn( token, "modelSkin", 9 ) || !Q_stricmpn( token, "message", 7 ) || !Q_stricmpn( token, "admin", 5 ) || !Q_stricmpn( token, "marine", 6 ) || !Q_stricmpn( token, "noShow", 6 ) ) { SkipRestOfLine(&textPtr); continue; } //this one is a pain since it can potentially have multiple lines if ( !Q_stricmpn( token, "weapons", 7 ) ) { SkipBracedSection( &textPtr ); continue; } if ( !Q_stricmpn( token, "}", 1 ) ) { numClasses++; break; } } } token = COM_Parse( &textPtr ); if (!token[0]) { break; } } if ( numClasses > 0 ) { CG_LogFuncEnd(); return qtrue; } else { CG_LocLogger(LL_ERROR, "ERROR: No classes were found in the class file!\n" ); CG_LogFuncEnd(); return qfalse; } } qboolean CG_LoadUsablesStrings( void ) { char fileRoute[MAX_QPATH]; char mapRoute[MAX_QPATH]; char buffer[20000]; int32_t file_len; char *textPtr, *token; fileHandle_t f; int32_t i; int32_t strLen; CG_LogFuncBegin(); //setup the file route Com_sprintf( mapRoute, sizeof( mapRoute ), "%s", cgs.mapname ); strLen = strlen( mapRoute ); //*sigh* remove the bsp bit if ( strLen > 4 && !Q_stricmp( mapRoute + strLen-4, ".bsp" ) ) mapRoute[strLen-4] = '\0'; //check for language CG_LanguageFilename( mapRoute, "usables", fileRoute ); file_len = trap_FS_FOpenFile( fileRoute, &f, FS_READ ); if (f == 0) { // TODO logging return qfalse; } //It's assumed most maps won't have this feature, so just exit 'gracefully' if ( file_len<=1 ) { //CG_Printf( S_COLOR_YELLOW "WARNING: No file named %s was found. If the server \n", fileRoute ); trap_FS_FCloseFile( f ); CG_LogFuncEnd(); return qfalse; } //fill the buffer with the file data memset( &buffer, 0, sizeof( buffer ) ); trap_FS_Read( buffer, file_len, f ); buffer[file_len] = '0'; trap_FS_FCloseFile( f ); if ( !buffer[0] ) { CG_LocLogger(LL_ERROR, "ERROR: Attempted to load %s, but no data was inside!\n", fileRoute ); CG_LogFuncEnd(); return qfalse; } COM_BeginParseSession(); textPtr = buffer; i = 0; //used for the main arrays indices while( 1 ) { token = COM_Parse( &textPtr ); if ( !token[0] ) break; if ( !Q_strncmp( token, "UsableDescriptions", 18 ) ) { token = COM_Parse( &textPtr ); if ( Q_strncmp( token, "{", 1 ) != 0 ) { CG_LocLogger(LL_ERROR, "ERROR: UsableDescriptions had no opening brace ( { )!\n" ); continue; } token = COM_Parse( &textPtr ); //expected format is 'id' 'string' while ( Q_strncmp( token, "}", 1 ) ) { if ( !token[0] ) break; if ( !Q_strncmp( token, "UsableEntities", 14 ) ) { SkipBracedSection( &textPtr ); continue; } else { //parse past the ID num token = COM_ParseExt( &textPtr, qfalse ); //copy the line of text if( token[0] ) { Q_strncpyz( cgs.scannableStrings[i], token, sizeof( cgs.scannableStrings[i] ) ); i++; } token = COM_Parse( &textPtr ); } } } } CG_LogFuncEnd(); return qtrue; }