📄 cg_players.c
字号:
Com_sprintf( filename, sizeof( filename ), "models/players/%s/%supper_%s.skin", modelName, teamName, skinName );
ci->torsoSkin = trap_R_RegisterSkin( filename );
if (!ci->torsoSkin) {
Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/%supper_%s.skin", modelName, teamName, skinName );
ci->torsoSkin = trap_R_RegisterSkin( filename );
if (!ci->torsoSkin) {
Com_Printf( "Torso skin load failure: %s\n", filename );
}
}
*/
if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "lower", "skin" ) ) {
ci->legsSkin = trap_R_RegisterSkin( filename );
}
if (!ci->legsSkin) {
Com_Printf( "Leg skin load failure: %s\n", filename );
}
if ( CG_FindClientModelFile( filename, sizeof(filename), ci, teamName, modelName, skinName, "upper", "skin" ) ) {
ci->torsoSkin = trap_R_RegisterSkin( filename );
}
if (!ci->torsoSkin) {
Com_Printf( "Torso skin load failure: %s\n", filename );
}
if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headModelName, headSkinName, "head", "skin" ) ) {
ci->headSkin = trap_R_RegisterSkin( filename );
}
if (!ci->headSkin) {
Com_Printf( "Head skin load failure: %s\n", filename );
}
// if any skins failed to load
if ( !ci->legsSkin || !ci->torsoSkin || !ci->headSkin ) {
return qfalse;
}
return qtrue;
}
/*
==========================
CG_RegisterClientModelname
==========================
*/
static qboolean CG_RegisterClientModelname( clientInfo_t *ci, const char *modelName, const char *skinName, const char *headModelName, const char *headSkinName, const char *teamName ) {
char filename[MAX_QPATH*2];
const char *headName;
char newTeamName[MAX_QPATH*2];
if ( headModelName[0] == '\0' ) {
headName = modelName;
}
else {
headName = headModelName;
}
Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
ci->legsModel = trap_R_RegisterModel( filename );
if ( !ci->legsModel ) {
Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/lower.md3", modelName );
ci->legsModel = trap_R_RegisterModel( filename );
if ( !ci->legsModel ) {
Com_Printf( "Failed to load model file %s\n", filename );
return qfalse;
}
}
Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
ci->torsoModel = trap_R_RegisterModel( filename );
if ( !ci->torsoModel ) {
Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/upper.md3", modelName );
ci->torsoModel = trap_R_RegisterModel( filename );
if ( !ci->torsoModel ) {
Com_Printf( "Failed to load model file %s\n", filename );
return qfalse;
}
}
if( headName[0] == '*' ) {
Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", &headModelName[1], &headModelName[1] );
}
else {
Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", headName );
}
ci->headModel = trap_R_RegisterModel( filename );
// if the head model could not be found and we didn't load from the heads folder try to load from there
if ( !ci->headModel && headName[0] != '*' ) {
Com_sprintf( filename, sizeof( filename ), "models/players/heads/%s/%s.md3", headModelName, headModelName );
ci->headModel = trap_R_RegisterModel( filename );
}
if ( !ci->headModel ) {
Com_Printf( "Failed to load model file %s\n", filename );
return qfalse;
}
// if any skins failed to load, return failure
if ( !CG_RegisterClientSkin( ci, teamName, modelName, skinName, headName, headSkinName ) ) {
if ( teamName && *teamName) {
Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", teamName, modelName, skinName, headName, headSkinName );
if( ci->team == TEAM_BLUE ) {
Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_BLUETEAM_NAME);
}
else {
Com_sprintf(newTeamName, sizeof(newTeamName), "%s/", DEFAULT_REDTEAM_NAME);
}
if ( !CG_RegisterClientSkin( ci, newTeamName, modelName, skinName, headName, headSkinName ) ) {
Com_Printf( "Failed to load skin file: %s : %s : %s, %s : %s\n", newTeamName, modelName, skinName, headName, headSkinName );
return qfalse;
}
} else {
Com_Printf( "Failed to load skin file: %s : %s, %s : %s\n", modelName, skinName, headName, headSkinName );
return qfalse;
}
}
// load the animations
Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
if ( !CG_ParseAnimationFile( filename, ci ) ) {
Com_sprintf( filename, sizeof( filename ), "models/players/characters/%s/animation.cfg", modelName );
if ( !CG_ParseAnimationFile( filename, ci ) ) {
Com_Printf( "Failed to load animation file %s\n", filename );
return qfalse;
}
}
if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "skin" ) ) {
ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
}
else if ( CG_FindClientHeadFile( filename, sizeof(filename), ci, teamName, headName, headSkinName, "icon", "tga" ) ) {
ci->modelIcon = trap_R_RegisterShaderNoMip( filename );
}
if ( !ci->modelIcon ) {
return qfalse;
}
return qtrue;
}
/*
====================
CG_ColorFromString
====================
*/
static void CG_ColorFromString( const char *v, vec3_t color ) {
int val;
VectorClear( color );
val = atoi( v );
if ( val < 1 || val > 7 ) {
VectorSet( color, 1, 1, 1 );
return;
}
if ( val & 1 ) {
color[2] = 1.0f;
}
if ( val & 2 ) {
color[1] = 1.0f;
}
if ( val & 4 ) {
color[0] = 1.0f;
}
}
/*
===================
CG_LoadClientInfo
Load it now, taking the disk hits.
This will usually be deferred to a safe time
===================
*/
static void CG_LoadClientInfo( clientInfo_t *ci ) {
const char *dir, *fallback;
int i, modelloaded;
const char *s;
int clientNum;
char teamname[MAX_QPATH];
teamname[0] = 0;
#ifdef MISSIONPACK
if( cgs.gametype >= GT_TEAM) {
if( ci->team == TEAM_BLUE ) {
Q_strncpyz(teamname, cg_blueTeamName.string, sizeof(teamname) );
} else {
Q_strncpyz(teamname, cg_redTeamName.string, sizeof(teamname) );
}
}
if( teamname[0] ) {
strcat( teamname, "/" );
}
#endif
modelloaded = qtrue;
if ( !CG_RegisterClientModelname( ci, ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname ) ) {
if ( cg_buildScript.integer ) {
CG_Error( "CG_RegisterClientModelname( %s, %s, %s, %s %s ) failed", ci->modelName, ci->skinName, ci->headModelName, ci->headSkinName, teamname );
}
// fall back to default team name
if( cgs.gametype >= GT_TEAM) {
// keep skin name
if( ci->team == TEAM_BLUE ) {
Q_strncpyz(teamname, DEFAULT_BLUETEAM_NAME, sizeof(teamname) );
} else {
Q_strncpyz(teamname, DEFAULT_REDTEAM_NAME, sizeof(teamname) );
}
if ( !CG_RegisterClientModelname( ci, DEFAULT_TEAM_MODEL, ci->skinName, DEFAULT_TEAM_HEAD, ci->skinName, teamname ) ) {
CG_Error( "DEFAULT_TEAM_MODEL / skin (%s/%s) failed to register", DEFAULT_TEAM_MODEL, ci->skinName );
}
} else {
if ( !CG_RegisterClientModelname( ci, DEFAULT_MODEL, "default", DEFAULT_MODEL, "default", teamname ) ) {
CG_Error( "DEFAULT_MODEL (%s) failed to register", DEFAULT_MODEL );
}
}
modelloaded = qfalse;
}
ci->newAnims = qfalse;
if ( ci->torsoModel ) {
orientation_t tag;
// if the torso model has the "tag_flag"
if ( trap_R_LerpTag( &tag, ci->torsoModel, 0, 0, 1, "tag_flag" ) ) {
ci->newAnims = qtrue;
}
}
// sounds
dir = ci->modelName;
fallback = (cgs.gametype >= GT_TEAM) ? DEFAULT_TEAM_MODEL : DEFAULT_MODEL;
for ( i = 0 ; i < MAX_CUSTOM_SOUNDS ; i++ ) {
s = cg_customSoundNames[i];
if ( !s ) {
break;
}
ci->sounds[i] = 0;
// if the model didn't load use the sounds of the default model
if (modelloaded) {
ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", dir, s + 1), qfalse );
}
if ( !ci->sounds[i] ) {
ci->sounds[i] = trap_S_RegisterSound( va("sound/player/%s/%s", fallback, s + 1), qfalse );
}
}
ci->deferred = qfalse;
// reset any existing players and bodies, because they might be in bad
// frames for this new model
clientNum = ci - cgs.clientinfo;
for ( i = 0 ; i < MAX_GENTITIES ; i++ ) {
if ( cg_entities[i].currentState.clientNum == clientNum
&& cg_entities[i].currentState.eType == ET_PLAYER ) {
CG_ResetPlayerEntity( &cg_entities[i] );
}
}
}
/*
======================
CG_CopyClientInfoModel
======================
*/
static void CG_CopyClientInfoModel( clientInfo_t *from, clientInfo_t *to ) {
VectorCopy( from->headOffset, to->headOffset );
to->footsteps = from->footsteps;
to->gender = from->gender;
to->legsModel = from->legsModel;
to->legsSkin = from->legsSkin;
to->torsoModel = from->torsoModel;
to->torsoSkin = from->torsoSkin;
to->headModel = from->headModel;
to->headSkin = from->headSkin;
to->modelIcon = from->modelIcon;
to->newAnims = from->newAnims;
memcpy( to->animations, from->animations, sizeof( to->animations ) );
memcpy( to->sounds, from->sounds, sizeof( to->sounds ) );
}
/*
======================
CG_ScanForExistingClientInfo
======================
*/
static qboolean CG_ScanForExistingClientInfo( clientInfo_t *ci ) {
int i;
clientInfo_t *match;
for ( i = 0 ; i < cgs.maxclients ; i++ ) {
match = &cgs.clientinfo[ i ];
if ( !match->infoValid ) {
continue;
}
if ( match->deferred ) {
continue;
}
if ( !Q_stricmp( ci->modelName, match->modelName )
&& !Q_stricmp( ci->skinName, match->skinName )
&& !Q_stricmp( ci->headModelName, match->headModelName )
&& !Q_stricmp( ci->headSkinName, match->headSkinName )
&& !Q_stricmp( ci->blueTeam, match->blueTeam )
&& !Q_stricmp( ci->redTeam, match->redTeam )
&& (cgs.gametype < GT_TEAM || ci->team == match->team) ) {
// this clientinfo is identical, so use it's handles
ci->deferred = qfalse;
CG_CopyClientInfoModel( match, ci );
return qtrue;
}
}
// nothing matches, so defer the load
return qfalse;
}
/*
======================
CG_SetDeferredClientInfo
We aren't going to load it now, so grab some other
client's info to use until we have some spare time.
======================
*/
static void CG_SetDeferredClientInfo( clientInfo_t *ci ) {
int i;
clientInfo_t *match;
// if someone else is already the same models and skins we
// can just load the client info
for ( i = 0 ; i < cgs.maxclients ; i++ ) {
match = &cgs.clientinfo[ i ];
if ( !match->infoValid || match->deferred ) {
continue;
}
if ( Q_stricmp( ci->skinName, match->skinName ) ||
Q_stricmp( ci->modelName, match->modelName ) ||
// Q_stricmp( ci->headModelName, match->headModelName ) ||
// Q_stricmp( ci->headSkinName, match->headSkinName ) ||
(cgs.gametype >= GT_TEAM && ci->team != match->team) ) {
continue;
}
// just load the real info cause it uses the same models and skins
CG_LoadClientInfo( ci );
return;
}
// if we are in teamplay, only grab a model if the skin is correct
if ( cgs.gametype >= GT_TEAM ) {
for ( i = 0 ; i < cgs.maxclients ; i++ ) {
match = &cgs.clientinfo[ i ];
if ( !match->infoValid || match->deferred ) {
continue;
}
if ( Q_stricmp( ci->skinName, match->skinName ) ||
(cgs.gametype >= GT_TEAM && ci->team != match->team) ) {
continue;
}
ci->deferred = qtrue;
CG_CopyClientInfoModel( match, ci );
return;
}
// load the full model, because we don't ever want to show
// an improper team skin. This will cause a hitch for the first
// player, when the second enters. Combat shouldn't be going on
// yet, so it shouldn't matter
CG_LoadClientInfo( ci );
return;
}
// find the first valid clientinfo and grab its stuff
for ( i = 0 ; i < cgs.maxclients ; i++ ) {
match = &cgs.clientinfo[ i ];
if ( !match->infoValid ) {
continue;
}
ci->deferred = qtrue;
CG_CopyClientInfoModel( match, ci );
return;
}
// we should never get here...
CG_Printf( "CG_SetDeferredClientInfo: no valid clients!\n" );
CG_LoadClientInfo( ci );
}
/*
======================
CG_NewClientInfo
======================
*/
void CG_NewClientInfo( int clientNum ) {
clientInfo_t *ci;
clientInfo_t newInfo;
const char *configstring;
const char *v;
char *slash;
ci = &cgs.clientinfo[clientNum];
configstring = CG_ConfigString( clientNum + CS_PLAYERS );
if ( !configstring[0] ) {
memset( ci, 0, sizeof( *ci ) );
return; // player just left
}
// build into a temp buffer so the defer checks can use
// the old value
memset( &newInfo, 0, sizeof( newInfo ) );
// isolate the player's name
v = Info_ValueForKey(configstring, "n");
Q_strncpyz( newInfo.name, v, sizeof( newInfo.name ) );
// colors
v = Info_ValueForKey( configstring, "c1" );
CG_ColorFromString( v, newInfo.color1 );
v = Info_ValueForKey( configstring, "c2" );
CG_ColorFromString( v, newInfo.color2 );
// bot skill
v = Info_ValueForKey( configstring, "skill" );
newInfo.botSkill = atoi( v );
// handicap
v = Info_ValueForKey( configstring, "hc" );
newInfo.handicap = atoi( v );
// wins
v = Info_ValueForKey( configstring, "w" );
newInfo.wins = atoi( v );
// losses
v = Info_ValueForKey( configstring, "l" );
newInfo.losses = atoi( v );
// team
v = Info_ValueForKey( configstring, "t" );
newInfo.team = atoi( v );
// team task
v = Info_ValueForKey( configstring, "tt" );
newInfo.teamTask = atoi(v);
// team leader
v = Info_ValueForKey( configstring, "tl" );
newInfo.teamLeader = atoi(v);
v = Info_ValueForKey( configstring, "g_redteam" );
Q_strncpyz(newInfo.redTeam, v, MAX_TEAMNAME);
v = Info_ValueForKey( configstring, "g_blueteam" );
Q_strncpyz(newInfo.blueTeam, v, MAX_TEAMNAME);
// model
v = Info_ValueForKey( configstring, "model" );
if ( cg_forceModel.integer ) {
// forcemodel makes everyone use a single model
// to prevent load hitches
char modelStr[MAX_QPATH];
char *skin;
if( cgs.gametype >= GT_TEAM ) {
Q_strncpyz( newInfo.modelName, DEFAULT_TEAM_MODEL, sizeof( newInfo.modelName ) );
Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
} else {
trap_Cvar_VariableStringBuffer( "model", modelStr, sizeof( modelStr ) );
if ( ( skin = strchr( modelStr, '/' ) ) == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -