📄 ui_players.c
字号:
VectorCopy( origin, barrel.lightingOrigin );
barrel.renderfx = renderfx;
barrel.hModel = pi->barrelModel;
angles[YAW] = 0;
angles[PITCH] = 0;
angles[ROLL] = UI_MachinegunSpinAngle( pi );
if( pi->realWeapon == WP_GAUNTLET || pi->realWeapon == WP_BFG ) {
angles[PITCH] = angles[ROLL];
angles[ROLL] = 0;
}
AnglesToAxis( angles, barrel.axis );
UI_PositionRotatedEntityOnTag( &barrel, &gun, pi->weaponModel, "tag_barrel");
trap_R_AddRefEntityToScene( &barrel );
}
//
// add muzzle flash
//
if ( dp_realtime <= pi->muzzleFlashTime ) {
if ( pi->flashModel ) {
memset( &flash, 0, sizeof(flash) );
flash.hModel = pi->flashModel;
VectorCopy( origin, flash.lightingOrigin );
UI_PositionEntityOnTag( &flash, &gun, pi->weaponModel, "tag_flash");
flash.renderfx = renderfx;
trap_R_AddRefEntityToScene( &flash );
}
// make a dlight for the flash
if ( pi->flashDlightColor[0] || pi->flashDlightColor[1] || pi->flashDlightColor[2] ) {
trap_R_AddLightToScene( flash.origin, 200 + (rand()&31), pi->flashDlightColor[0],
pi->flashDlightColor[1], pi->flashDlightColor[2] );
}
}
//
// add the chat icon
//
if ( pi->chat ) {
UI_PlayerFloatSprite( pi, origin, trap_R_RegisterShaderNoMip( "sprites/balloon3" ) );
}
//
// add an accent light
//
origin[0] -= 100; // + = behind, - = in front
origin[1] += 100; // + = left, - = right
origin[2] += 100; // + = above, - = below
trap_R_AddLightToScene( origin, 500, 1.0, 1.0, 1.0 );
origin[0] -= 100;
origin[1] -= 100;
origin[2] -= 100;
trap_R_AddLightToScene( origin, 500, 1.0, 0.0, 0.0 );
trap_R_RenderScene( &refdef );
}
/*
==========================
UI_RegisterClientSkin
==========================
*/
static qboolean UI_RegisterClientSkin( playerInfo_t *pi, const char *modelName, const char *skinName ) {
char filename[MAX_QPATH];
Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower_%s.skin", modelName, skinName );
pi->legsSkin = trap_R_RegisterSkin( filename );
Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper_%s.skin", modelName, skinName );
pi->torsoSkin = trap_R_RegisterSkin( filename );
Com_sprintf( filename, sizeof( filename ), "models/players/%s/head_%s.skin", modelName, skinName );
pi->headSkin = trap_R_RegisterSkin( filename );
if ( !pi->legsSkin || !pi->torsoSkin || !pi->headSkin ) {
return qfalse;
}
return qtrue;
}
/*
======================
UI_ParseAnimationFile
======================
*/
static qboolean UI_ParseAnimationFile( const char *filename, animation_t *animations ) {
char *text_p, *prev;
int len;
int i;
char *token;
float fps;
int skip;
char text[20000];
fileHandle_t f;
memset( animations, 0, sizeof( animation_t ) * MAX_ANIMATIONS );
// load the file
len = trap_FS_FOpenFile( filename, &f, FS_READ );
if ( len <= 0 ) {
return qfalse;
}
if ( len >= ( sizeof( text ) - 1 ) ) {
Com_Printf( "File %s too long\n", filename );
return qfalse;
}
trap_FS_Read( text, len, f );
text[len] = 0;
trap_FS_FCloseFile( f );
// parse the text
text_p = text;
skip = 0; // quite the compiler warning
// read optional parameters
while ( 1 ) {
prev = text_p; // so we can unget
token = COM_Parse( &text_p );
if ( !token ) {
break;
}
if ( !Q_stricmp( token, "footsteps" ) ) {
token = COM_Parse( &text_p );
if ( !token ) {
break;
}
continue;
} else if ( !Q_stricmp( token, "headoffset" ) ) {
for ( i = 0 ; i < 3 ; i++ ) {
token = COM_Parse( &text_p );
if ( !token ) {
break;
}
}
continue;
} else if ( !Q_stricmp( token, "sex" ) ) {
token = COM_Parse( &text_p );
if ( !token ) {
break;
}
continue;
}
// if it is a number, start parsing animations
if ( token[0] >= '0' && token[0] <= '9' ) {
text_p = prev; // unget the token
break;
}
Com_Printf( "unknown token '%s' is %s\n", token, filename );
}
// read information for each frame
for ( i = 0 ; i < MAX_ANIMATIONS ; i++ ) {
token = COM_Parse( &text_p );
if ( !token ) {
break;
}
animations[i].firstFrame = atoi( token );
// leg only frames are adjusted to not count the upper body only frames
if ( i == LEGS_WALKCR ) {
skip = animations[LEGS_WALKCR].firstFrame - animations[TORSO_GESTURE].firstFrame;
}
if ( i >= LEGS_WALKCR ) {
animations[i].firstFrame -= skip;
}
token = COM_Parse( &text_p );
if ( !token ) {
break;
}
animations[i].numFrames = atoi( token );
token = COM_Parse( &text_p );
if ( !token ) {
break;
}
animations[i].loopFrames = atoi( token );
token = COM_Parse( &text_p );
if ( !token ) {
break;
}
fps = atof( token );
if ( fps == 0 ) {
fps = 1;
}
animations[i].frameLerp = 1000 / fps;
animations[i].initialLerp = 1000 / fps;
}
if ( i != MAX_ANIMATIONS ) {
Com_Printf( "Error parsing animation file: %s", filename );
return qfalse;
}
return qtrue;
}
/*
==========================
UI_RegisterClientModelname
==========================
*/
qboolean UI_RegisterClientModelname( playerInfo_t *pi, const char *modelSkinName ) {
char modelName[MAX_QPATH];
char skinName[MAX_QPATH];
char filename[MAX_QPATH];
char *slash;
pi->torsoModel = 0;
pi->headModel = 0;
if ( !modelSkinName[0] ) {
return qfalse;
}
Q_strncpyz( modelName, modelSkinName, sizeof( modelName ) );
slash = strchr( modelName, '/' );
if ( !slash ) {
// modelName did not include a skin name
Q_strncpyz( skinName, "default", sizeof( skinName ) );
} else {
Q_strncpyz( skinName, slash + 1, sizeof( skinName ) );
// truncate modelName
*slash = 0;
}
// load cmodels before models so filecache works
Com_sprintf( filename, sizeof( filename ), "models/players/%s/lower.md3", modelName );
pi->legsModel = trap_R_RegisterModel( filename );
if ( !pi->legsModel ) {
Com_Printf( "Failed to load model file %s\n", filename );
return qfalse;
}
Com_sprintf( filename, sizeof( filename ), "models/players/%s/upper.md3", modelName );
pi->torsoModel = trap_R_RegisterModel( filename );
if ( !pi->torsoModel ) {
Com_Printf( "Failed to load model file %s\n", filename );
return qfalse;
}
Com_sprintf( filename, sizeof( filename ), "models/players/%s/head.md3", modelName );
pi->headModel = trap_R_RegisterModel( filename );
if ( !pi->headModel ) {
Com_Printf( "Failed to load model file %s\n", filename );
return qfalse;
}
// if any skins failed to load, fall back to default
if ( !UI_RegisterClientSkin( pi, modelName, skinName ) ) {
if ( !UI_RegisterClientSkin( pi, modelName, "default" ) ) {
Com_Printf( "Failed to load skin file: %s : %s\n", modelName, skinName );
return qfalse;
}
}
// load the animations
Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg", modelName );
if ( !UI_ParseAnimationFile( filename, pi->animations ) ) {
Com_Printf( "Failed to load animation file %s\n", filename );
return qfalse;
}
return qtrue;
}
/*
===============
UI_PlayerInfo_SetModel
===============
*/
void UI_PlayerInfo_SetModel( playerInfo_t *pi, const char *model ) {
memset( pi, 0, sizeof(*pi) );
UI_RegisterClientModelname( pi, model );
pi->weapon = WP_MACHINEGUN;
pi->currentWeapon = pi->weapon;
pi->lastWeapon = pi->weapon;
pi->pendingWeapon = -1;
pi->weaponTimer = 0;
pi->chat = qfalse;
pi->newModel = qtrue;
UI_PlayerInfo_SetWeapon( pi, pi->weapon );
}
/*
===============
UI_PlayerInfo_SetInfo
===============
*/
void UI_PlayerInfo_SetInfo( playerInfo_t *pi, int legsAnim, int torsoAnim, vec3_t viewAngles, vec3_t moveAngles, weapon_t weaponNumber, qboolean chat ) {
int currentAnim;
weapon_t weaponNum;
pi->chat = chat;
// view angles
VectorCopy( viewAngles, pi->viewAngles );
// move angles
VectorCopy( moveAngles, pi->moveAngles );
if ( pi->newModel ) {
pi->newModel = qfalse;
jumpHeight = 0;
pi->pendingLegsAnim = 0;
UI_ForceLegsAnim( pi, legsAnim );
pi->legs.yawAngle = viewAngles[YAW];
pi->legs.yawing = qfalse;
pi->pendingTorsoAnim = 0;
UI_ForceTorsoAnim( pi, torsoAnim );
pi->torso.yawAngle = viewAngles[YAW];
pi->torso.yawing = qfalse;
if ( weaponNumber != -1 ) {
pi->weapon = weaponNumber;
pi->currentWeapon = weaponNumber;
pi->lastWeapon = weaponNumber;
pi->pendingWeapon = -1;
pi->weaponTimer = 0;
UI_PlayerInfo_SetWeapon( pi, pi->weapon );
}
return;
}
// weapon
if ( weaponNumber == -1 ) {
pi->pendingWeapon = -1;
pi->weaponTimer = 0;
}
else if ( weaponNumber != WP_NONE ) {
pi->pendingWeapon = weaponNumber;
pi->weaponTimer = dp_realtime + UI_TIMER_WEAPON_DELAY;
}
weaponNum = pi->lastWeapon;
pi->weapon = weaponNum;
if ( torsoAnim == BOTH_DEATH1 || legsAnim == BOTH_DEATH1 ) {
torsoAnim = legsAnim = BOTH_DEATH1;
pi->weapon = pi->currentWeapon = WP_NONE;
UI_PlayerInfo_SetWeapon( pi, pi->weapon );
jumpHeight = 0;
pi->pendingLegsAnim = 0;
UI_ForceLegsAnim( pi, legsAnim );
pi->pendingTorsoAnim = 0;
UI_ForceTorsoAnim( pi, torsoAnim );
return;
}
// leg animation
currentAnim = pi->legsAnim & ~ANIM_TOGGLEBIT;
if ( legsAnim != LEGS_JUMP && ( currentAnim == LEGS_JUMP || currentAnim == LEGS_LAND ) ) {
pi->pendingLegsAnim = legsAnim;
}
else if ( legsAnim != currentAnim ) {
jumpHeight = 0;
pi->pendingLegsAnim = 0;
UI_ForceLegsAnim( pi, legsAnim );
}
// torso animation
if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2 ) {
if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
torsoAnim = TORSO_STAND2;
}
else {
torsoAnim = TORSO_STAND;
}
}
if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 ) {
if ( weaponNum == WP_NONE || weaponNum == WP_GAUNTLET ) {
torsoAnim = TORSO_ATTACK2;
}
else {
torsoAnim = TORSO_ATTACK;
}
pi->muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH;
//FIXME play firing sound here
}
currentAnim = pi->torsoAnim & ~ANIM_TOGGLEBIT;
if ( weaponNum != pi->currentWeapon || currentAnim == TORSO_RAISE || currentAnim == TORSO_DROP ) {
pi->pendingTorsoAnim = torsoAnim;
}
else if ( ( currentAnim == TORSO_GESTURE || currentAnim == TORSO_ATTACK ) && ( torsoAnim != currentAnim ) ) {
pi->pendingTorsoAnim = torsoAnim;
}
else if ( torsoAnim != currentAnim ) {
pi->pendingTorsoAnim = 0;
UI_ForceTorsoAnim( pi, torsoAnim );
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -