2011-06-01 12:20:56 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
//
// ui_players.c
# include "ui_local.h"
# define UI_TIMER_GESTURE 2300
# define UI_TIMER_JUMP 1000
# define UI_TIMER_LAND 130
# define UI_TIMER_WEAPON_SWITCH 300
# define UI_TIMER_ATTACK 500
# define UI_TIMER_MUZZLE_FLASH 20
# define UI_TIMER_WEAPON_DELAY 250
# define JUMP_HEIGHT 56
# define SWINGSPEED 0.2 //TiM - 0.3
# define SPIN_SPEED 0.9
# define COAST_TIME 1000
static int dp_realtime ;
static float jumpHeight ;
//TiM : Bolton Table
stringID_table_t BoltonTable [ BOLTON_MAX + 1 ] =
{
2011-06-15 06:46:11 +00:00
{ ENUM2STRING ( BOLTON_HEAD ) } ,
{ ENUM2STRING ( BOLTON_TORSO ) } ,
{ ENUM2STRING ( BOLTON_LEGS ) } ,
{ NULL , - 1 }
2011-06-01 12:20:56 +00:00
} ;
/*
= = = = = = = = = = = = = = =
UI_PlayerInfo_SetWeapon
= = = = = = = = = = = = = = =
*/
static void UI_PlayerInfo_SetWeapon ( playerInfo_t * pi , weapon_t weaponNum ) {
gitem_t * item ;
char path [ MAX_QPATH ] ;
pi - > currentWeapon = weaponNum ;
tryagain :
pi - > realWeapon = weaponNum ;
pi - > weaponModel = 0 ;
pi - > barrelModel = 0 ;
pi - > flashModel = 0 ;
2012-03-16 12:05:41 +00:00
if ( weaponNum = = WP_0 ) {
2011-06-01 12:20:56 +00:00
return ;
}
for ( item = bg_itemlist + 1 ; item - > classname ; item + + ) {
if ( item - > giType ! = IT_WEAPON ) {
continue ;
}
if ( item - > giTag = = weaponNum ) {
break ;
}
}
if ( item - > classname ) {
pi - > weaponModel = trap_R_RegisterModel ( item - > world_model ) ;
}
if ( pi - > weaponModel = = 0 )
{
2012-03-16 12:05:41 +00:00
if ( weaponNum = = WP_5 )
2011-06-01 12:20:56 +00:00
{
2012-03-16 12:05:41 +00:00
weaponNum = WP_0 ;
2011-06-01 12:20:56 +00:00
goto tryagain ;
}
2012-03-16 12:05:41 +00:00
weaponNum = WP_5 ;
2011-06-01 12:20:56 +00:00
goto tryagain ;
}
strcpy ( path , item - > world_model ) ;
COM_StripExtension ( path , path ) ;
strcat ( path , " _flash.md3 " ) ;
pi - > flashModel = trap_R_RegisterModel ( path ) ;
switch ( weaponNum ) {
2012-03-16 12:05:41 +00:00
case WP_8 :
2011-06-01 12:20:56 +00:00
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
break ;
2012-03-16 12:05:41 +00:00
case WP_10 :
2011-06-01 12:20:56 +00:00
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
break ;
2012-03-16 12:05:41 +00:00
case WP_5 :
2011-06-01 12:20:56 +00:00
MAKERGB ( pi - > flashDlightColor , 0 , 0 , 0 ) ;
break ;
2012-03-16 12:05:41 +00:00
case WP_13 :
2011-06-01 12:20:56 +00:00
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
break ;
2012-03-16 12:05:41 +00:00
case WP_1 :
2011-06-01 12:20:56 +00:00
//MAKERGB( pi->flashDlightColor, 0.6, 0.6, 1 );
break ;
2012-03-16 12:05:41 +00:00
case WP_6 :
2011-06-01 12:20:56 +00:00
MAKERGB ( pi - > flashDlightColor , 0.16 , 0.16 , 1 ) ;
break ;
2012-03-16 12:05:41 +00:00
case WP_7 :
2011-06-01 12:20:56 +00:00
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
break ;
2012-03-16 12:05:41 +00:00
case WP_4 :
2011-06-01 12:20:56 +00:00
MAKERGB ( pi - > flashDlightColor , 1 , 0.6 , 0.6 ) ;
break ;
2012-03-16 12:05:41 +00:00
case WP_9 :
2011-06-01 12:20:56 +00:00
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
break ;
default :
MAKERGB ( pi - > flashDlightColor , 1 , 1 , 1 ) ;
break ;
}
}
/*
= = = = = = = = = = = = = = =
UI_ForceLegsAnim
= = = = = = = = = = = = = = =
*/
static void UI_ForceLegsAnim ( playerInfo_t * pi , int anim ) {
pi - > legsAnim = ( ( pi - > legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim ;
if ( anim = = BOTH_JUMP1 ) {
pi - > legsAnimationTimer = UI_TIMER_JUMP ;
}
}
/*
= = = = = = = = = = = = = = =
UI_SetLegsAnim
= = = = = = = = = = = = = = =
*/
static void UI_SetLegsAnim ( playerInfo_t * pi , int anim ) {
if ( pi - > pendingLegsAnim ) {
anim = pi - > pendingLegsAnim ;
pi - > pendingLegsAnim = 0 ;
}
UI_ForceLegsAnim ( pi , anim ) ;
}
/*
= = = = = = = = = = = = = = =
UI_ForceTorsoAnim
= = = = = = = = = = = = = = =
*/
static void UI_ForceTorsoAnim ( playerInfo_t * pi , int anim ) {
pi - > torsoAnim = ( ( pi - > torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim ;
/*.if ( anim == TORSO_GESTURE ) {
pi - > torsoAnimationTimer = UI_TIMER_GESTURE ;
} */
if ( anim = = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) ) { //BOTH_ATTACK1 //Hack ROFL. Code can't see the ANIM defines from here. ANIM_ATTACK = 22
pi - > torsoAnimationTimer = UI_TIMER_ATTACK ;
}
}
/*
= = = = = = = = = = = = = = =
UI_SetTorsoAnim
= = = = = = = = = = = = = = =
*/
static void UI_SetTorsoAnim ( playerInfo_t * pi , int anim ) {
if ( pi - > pendingTorsoAnim ) {
anim = pi - > pendingTorsoAnim ;
pi - > pendingTorsoAnim = 0 ;
}
UI_ForceTorsoAnim ( pi , anim ) ;
}
/*
= = = = = = = = = = = = = = =
UI_TorsoSequencing
= = = = = = = = = = = = = = =
*/
static void UI_TorsoSequencing ( playerInfo_t * pi ) {
int currentAnim ;
currentAnim = pi - > torsoAnim & ~ ANIM_TOGGLEBIT ;
if ( pi - > weapon ! = pi - > currentWeapon & & ! pi - > upperEmoting ) {
if ( currentAnim ! = TORSO_DROPWEAP1 ) {
pi - > torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH ;
UI_ForceTorsoAnim ( pi , TORSO_DROPWEAP1 ) ;
}
}
if ( pi - > torsoAnimationTimer > 0 ) {
return ;
}
/*if( currentAnim == TORSO_GESTURE ) {
UI_SetTorsoAnim ( pi , TORSO_STAND ) ;
return ;
} */
if ( currentAnim = = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) ) { //BOTH_ATTACK1 22 = ANIM_ATTACK
2012-03-16 12:05:41 +00:00
//if ( pi->currentWeapon == WP_0 || pi->currentWeapon == WP_5 )
if ( pi - > currentWeapon ! = WP_6
& & pi - > currentWeapon ! = WP_7
& & pi - > currentWeapon ! = WP_8
& & pi - > currentWeapon ! = WP_9 )
2011-06-01 12:20:56 +00:00
{
UI_SetTorsoAnim ( pi , BOTH_STAND1 ) ; //TORSO_STAND
}
else
{
UI_SetTorsoAnim ( pi , BOTH_STAND4 ) ; //TORSO_STAND
}
return ;
}
if ( currentAnim = = TORSO_DROPWEAP1 ) {
UI_PlayerInfo_SetWeapon ( pi , pi - > weapon ) ;
pi - > torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH ;
UI_ForceTorsoAnim ( pi , TORSO_RAISEWEAP1 ) ; //TORSO_RAISE
return ;
}
if ( currentAnim = = TORSO_RAISEWEAP1 ) {
UI_SetTorsoAnim ( pi , BOTH_STAND1 ) ; //STAND2
return ;
}
//TiM: Was playing a non-loop emote, so go back to default now
if ( pi - > upperEmoting ) {
if ( ! pi - > upperLoopEmote )
{
UI_SetTorsoAnim ( pi , BOTH_STAND1 ) ;
pi - > upperEmoting = qfalse ;
}
else
{
UI_SetTorsoAnim ( pi , pi - > upperLoopEmote ) ;
pi - > upperEmoting = qfalse ;
}
return ;
}
}
/*
= = = = = = = = = = = = = = =
UI_LegsSequencing
= = = = = = = = = = = = = = =
*/
static void UI_LegsSequencing ( playerInfo_t * pi ) {
int currentAnim ;
currentAnim = pi - > legsAnim & ~ ANIM_TOGGLEBIT ;
if ( pi - > legsAnimationTimer > 0 ) {
if ( currentAnim = = BOTH_JUMP1 ) {
jumpHeight = JUMP_HEIGHT * sin ( M_PI * ( UI_TIMER_JUMP - pi - > legsAnimationTimer ) / UI_TIMER_JUMP ) ;
}
return ;
}
if ( currentAnim = = BOTH_JUMP1 ) {
UI_ForceLegsAnim ( pi , BOTH_LAND1 ) ;
pi - > legsAnimationTimer = UI_TIMER_LAND ;
jumpHeight = 0 ;
return ;
}
if ( currentAnim = = BOTH_LAND1 ) {
UI_SetLegsAnim ( pi , BOTH_STAND1 ) ;
return ;
}
//TiM: Was playing a non-loop emote, so go back to default now
if ( pi - > lowerEmoting ) {
if ( ! pi - > lowerLoopEmote )
{
UI_SetLegsAnim ( pi , BOTH_STAND1 ) ;
pi - > lowerEmoting = qfalse ;
}
else
{
UI_SetLegsAnim ( pi , pi - > lowerLoopEmote ) ;
pi - > lowerEmoting = qfalse ;
}
return ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = =
UI_PositionEntityOnTag
= = = = = = = = = = = = = = = = = = = = = =
*/
static void UI_PositionEntityOnTag ( refEntity_t * entity , const refEntity_t * parent ,
clipHandle_t parentModel , char * tagName ) {
int i ;
orientation_t lerped ;
// lerp the tag
trap_CM_LerpTag ( & lerped , parentModel , parent - > oldframe , parent - > frame ,
1.0 - parent - > backlerp , tagName ) ;
// FIXME: allow origin offsets along tag?
VectorCopy ( parent - > origin , entity - > origin ) ;
for ( i = 0 ; i < 3 ; i + + ) {
VectorMA ( entity - > origin , lerped . origin [ i ] , parent - > axis [ i ] , entity - > origin ) ;
}
// cast away const because of compiler problems
MatrixMultiply ( lerped . axis , ( ( refEntity_t * ) parent ) - > axis , entity - > axis ) ;
entity - > backlerp = parent - > backlerp ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
UI_PositionRotatedEntityOnTag
= = = = = = = = = = = = = = = = = = = = = =
*/
static void UI_PositionRotatedEntityOnTag ( refEntity_t * entity , const refEntity_t * parent ,
clipHandle_t parentModel , char * tagName ) {
int i ;
orientation_t lerped ;
vec3_t tempAxis [ 3 ] ;
// lerp the tag
trap_CM_LerpTag ( & lerped , parentModel , parent - > oldframe , parent - > frame ,
1.0 - parent - > backlerp , tagName ) ;
// FIXME: allow origin offsets along tag?
VectorCopy ( parent - > origin , entity - > origin ) ;
for ( i = 0 ; i < 3 ; i + + ) {
VectorMA ( entity - > origin , lerped . origin [ i ] , parent - > axis [ i ] , entity - > origin ) ;
}
// cast away const because of compiler problems
MatrixMultiply ( entity - > axis , ( ( refEntity_t * ) parent ) - > axis , tempAxis ) ;
MatrixMultiply ( lerped . axis , tempAxis , entity - > axis ) ;
}
/*
= = = = = = = = = = = = = = =
UI_SetLerpFrameAnimation
= = = = = = = = = = = = = = =
*/
static void UI_SetLerpFrameAnimation ( playerInfo_t * ci , lerpFrame_t * lf , int newAnimation ) {
animation_t * anim ;
lf - > animationNumber = newAnimation ;
newAnimation & = ~ ANIM_TOGGLEBIT ;
if ( newAnimation < 0 | | newAnimation > = MAX_ANIMATIONS ) {
trap_Error ( va ( " Bad animation number: %i " , newAnimation ) ) ;
}
anim = & ci - > animations [ newAnimation ] ;
lf - > animation = anim ;
lf - > animationTime = lf - > frameTime + anim - > initialLerp ;
}
/*
= = = = = = = = = = = = = = =
UI_RunLerpFrame
= = = = = = = = = = = = = = =
*/
static void UI_RunLerpFrame ( playerInfo_t * ci , lerpFrame_t * lf , int newAnimation ) {
int f ;
animation_t * anim ;
// see if the animation sequence is switching
if ( newAnimation ! = lf - > animationNumber | | ! lf - > animation ) {
UI_SetLerpFrameAnimation ( ci , lf , newAnimation ) ;
}
// if we have passed the current frame, move it to
// oldFrame and calculate a new frame
if ( dp_realtime > = lf - > frameTime ) {
lf - > oldFrame = lf - > frame ;
lf - > oldFrameTime = lf - > frameTime ;
// get the next frame based on the animation
anim = lf - > animation ;
/*if ( anim->numFrames < 0 ) {
UI_SetLerpFrameAnimation ( ci , lf , BOTH_STAND1 ) ;
} */
if ( dp_realtime < lf - > animationTime ) {
lf - > frameTime = lf - > animationTime ; // initial lerp
} else {
lf - > frameTime = lf - > oldFrameTime + anim - > frameLerp ;
}
f = ( lf - > frameTime - lf - > animationTime ) / anim - > frameLerp ;
if ( f > = anim - > numFrames ) {
f - = anim - > numFrames ;
if ( anim - > loopFrames ) {
f % = anim - > loopFrames ;
f + = anim - > numFrames - anim - > loopFrames ;
} else {
f = anim - > numFrames - 1 ;
// the animation is stuck at the end, so it
// can immediately transition to another sequence
lf - > frameTime = dp_realtime ;
}
}
lf - > frame = anim - > firstFrame + f ;
if ( dp_realtime > lf - > frameTime ) {
lf - > frameTime = dp_realtime ;
}
}
if ( lf - > frameTime > dp_realtime + 200 ) {
lf - > frameTime = dp_realtime ;
}
if ( lf - > oldFrameTime > dp_realtime ) {
lf - > oldFrameTime = dp_realtime ;
}
// calculate current lerp value
if ( lf - > frameTime = = lf - > oldFrameTime ) {
lf - > backlerp = 0 ;
} else {
lf - > backlerp = 1.0 - ( float ) ( dp_realtime - lf - > oldFrameTime ) / ( lf - > frameTime - lf - > oldFrameTime ) ;
}
}
/*
= = = = = = = = = = = = = = =
UI_PlayerAnimation
= = = = = = = = = = = = = = =
*/
static void UI_PlayerAnimation ( playerInfo_t * pi , int * legsOld , int * legs , float * legsBackLerp ,
int * torsoOld , int * torso , float * torsoBackLerp ) {
// legs animation
pi - > legsAnimationTimer - = uis . frametime ;
if ( pi - > legsAnimationTimer < 0 ) {
pi - > legsAnimationTimer = 0 ;
}
UI_LegsSequencing ( pi ) ;
if ( pi - > legs . yawing & & ( ( pi - > legsAnim & ~ ANIM_TOGGLEBIT ) = = BOTH_STAND1
| | ( pi - > legsAnim & ~ ANIM_TOGGLEBIT ) = = BOTH_STAND2
| | ( pi - > legsAnim & ~ ANIM_TOGGLEBIT ) = = BOTH_STAND4 ) )
{
UI_RunLerpFrame ( pi , & pi - > legs , LEGS_TURN1 ) ;
} else {
UI_RunLerpFrame ( pi , & pi - > legs , pi - > legsAnim ) ;
}
* legsOld = pi - > legs . oldFrame ;
* legs = pi - > legs . frame ;
* legsBackLerp = pi - > legs . backlerp ;
// torso animation
pi - > torsoAnimationTimer - = uis . frametime ;
if ( pi - > torsoAnimationTimer < 0 ) {
pi - > torsoAnimationTimer = 0 ;
}
UI_TorsoSequencing ( pi ) ;
UI_RunLerpFrame ( pi , & pi - > torso , pi - > torsoAnim ) ;
* torsoOld = pi - > torso . oldFrame ;
* torso = pi - > torso . frame ;
* torsoBackLerp = pi - > torso . backlerp ;
}
/*
= = = = = = = = = = = = = = = = = =
UI_SwingAngles
= = = = = = = = = = = = = = = = = =
*/
static void UI_SwingAngles ( float destination , float swingTolerance , float clampTolerance ,
float speed , float * angle , qboolean * swinging ) {
float swing ;
float move ;
float scale ;
if ( ! * swinging ) {
// see if a swing should be started
swing = AngleSubtract ( * angle , destination ) ;
if ( swing > swingTolerance | | swing < - swingTolerance ) {
* swinging = qtrue ;
}
}
if ( ! * swinging ) {
return ;
}
// modify the speed depending on the delta
// so it doesn't seem so linear
swing = AngleSubtract ( destination , * angle ) ;
scale = fabs ( swing ) ;
if ( scale < swingTolerance * 0.5 ) {
scale = 0.5 ;
} else if ( scale < swingTolerance ) {
scale = 1.0 ;
} else {
scale = 2.0 ;
}
// swing towards the destination angle
if ( swing > = 0 ) {
move = uis . frametime * scale * speed ;
if ( move > = swing ) {
move = swing ;
* swinging = qfalse ;
}
* angle = AngleMod ( * angle + move ) ;
} else if ( swing < 0 ) {
move = uis . frametime * scale * - speed ;
if ( move < = swing ) {
move = swing ;
* swinging = qfalse ;
}
* angle = AngleMod ( * angle + move ) ;
}
// clamp to no more than tolerance
swing = AngleSubtract ( destination , * angle ) ;
if ( swing > clampTolerance ) {
* angle = AngleMod ( destination - ( clampTolerance - 1 ) ) ;
} else if ( swing < - clampTolerance ) {
* angle = AngleMod ( destination + ( clampTolerance - 1 ) ) ;
}
}
/*
= = = = = = = = = = = = = = = = = = = = = =
UI_MovedirAdjustment
= = = = = = = = = = = = = = = = = = = = = =
*/
/*static float UI_MovedirAdjustment( playerInfo_t *pi ) {
vec3_t relativeAngles ;
vec3_t moveVector ;
VectorSubtract ( pi - > viewAngles , pi - > moveAngles , relativeAngles ) ;
AngleVectors ( relativeAngles , moveVector , NULL , NULL ) ;
if ( Q_fabs ( moveVector [ 0 ] ) < 0.01 ) {
moveVector [ 0 ] = 0.0 ;
}
if ( Q_fabs ( moveVector [ 1 ] ) < 0.01 ) {
moveVector [ 1 ] = 0.0 ;
}
if ( moveVector [ 1 ] = = 0 & & moveVector [ 0 ] > 0 ) {
return 0 ;
}
if ( moveVector [ 1 ] < 0 & & moveVector [ 0 ] > 0 ) {
return 22 ;
}
if ( moveVector [ 1 ] < 0 & & moveVector [ 0 ] = = 0 ) {
return 45 ;
}
if ( moveVector [ 1 ] < 0 & & moveVector [ 0 ] < 0 ) {
return - 22 ;
}
if ( moveVector [ 1 ] = = 0 & & moveVector [ 0 ] < 0 ) {
return 0 ;
}
if ( moveVector [ 1 ] > 0 & & moveVector [ 0 ] < 0 ) {
return 22 ;
}
if ( moveVector [ 1 ] > 0 & & moveVector [ 0 ] = = 0 ) {
return - 45 ;
}
return - 22 ;
} */
/*
= = = = = = = = = = = = = = =
UI_PlayerAngles
= = = = = = = = = = = = = = =
*/
static void UI_PlayerAngles ( playerInfo_t * pi , vec3_t legs [ 3 ] , vec3_t torso [ 3 ] , vec3_t head [ 3 ] ) {
vec3_t legsAngles , torsoAngles , headAngles ;
float dest ;
float adjust ;
VectorCopy ( pi - > viewAngles , headAngles ) ;
headAngles [ YAW ] = AngleMod ( headAngles [ YAW ] ) ;
VectorClear ( legsAngles ) ;
VectorClear ( torsoAngles ) ;
// --------- yaw -------------
// allow yaw to drift a bit
if ( ( pi - > legsAnim & ~ ANIM_TOGGLEBIT ) ! = UI_GetAnim ( ANIM_IDLE , pi - > currentWeapon , qfalse ) //TORSO_STAND2
| | ( pi - > torsoAnim & ~ ANIM_TOGGLEBIT ) ! = UI_GetAnim ( ANIM_IDLE , pi - > currentWeapon , qtrue ) ) {
// if not standing still, always point all in the same direction
pi - > torso . yawing = qtrue ; // always center
pi - > torso . pitching = qtrue ; // always center
pi - > legs . yawing = qtrue ; // always center
}
// adjust legs for movement dir
if ( ! uis . spinView ) {
//adjust = UI_MovedirAdjustment( pi ); //TiM: Do we really need this?
adjust = 0 ;
legsAngles [ YAW ] = headAngles [ YAW ] + adjust ;
torsoAngles [ YAW ] = headAngles [ YAW ] + /*0.25 **/ adjust ;
// torso
UI_SwingAngles ( torsoAngles [ YAW ] , 25 , 90 , SWINGSPEED , & pi - > torso . yawAngle , & pi - > torso . yawing ) ;
UI_SwingAngles ( legsAngles [ YAW ] , 40 , 90 , SWINGSPEED , & pi - > legs . yawAngle , & pi - > legs . yawing ) ;
}
else {
pi - > torso . yawAngle = headAngles [ YAW ] ;
pi - > legs . yawAngle = headAngles [ YAW ] ;
}
torsoAngles [ YAW ] = pi - > torso . yawAngle ;
legsAngles [ YAW ] = pi - > legs . yawAngle ;
// --------- pitch -------------
// only show a fraction of the pitch angle in the torso
if ( headAngles [ PITCH ] > 180 ) {
dest = ( - 360 + headAngles [ PITCH ] ) * 0.75 ;
} else {
dest = headAngles [ PITCH ] * 0.75 ;
}
UI_SwingAngles ( dest , 15 , 30 , 0.1 , & pi - > torso . pitchAngle , & pi - > torso . pitching ) ;
torsoAngles [ PITCH ] = pi - > torso . pitchAngle ;
// pull the angles back out of the hierarchial chain
AnglesSubtract ( headAngles , torsoAngles , headAngles ) ;
AnglesSubtract ( torsoAngles , legsAngles , torsoAngles ) ;
AnglesToAxis ( legsAngles , legs ) ;
AnglesToAxis ( torsoAngles , torso ) ;
AnglesToAxis ( headAngles , head ) ;
}
/*
= = = = = = = = = = = = = = =
UI_PlayerFloatSprite
= = = = = = = = = = = = = = =
*/
static void UI_PlayerFloatSprite ( playerInfo_t * pi , vec3_t origin , qhandle_t shader ) {
refEntity_t ent ;
memset ( & ent , 0 , sizeof ( ent ) ) ;
VectorCopy ( origin , ent . origin ) ;
ent . origin [ 2 ] + = 48 ;
ent . reType = RT_SPRITE ;
ent . customShader = shader ;
ent . data . sprite . radius = 10 ;
ent . renderfx = 0 ;
trap_R_AddRefEntityToScene ( & ent ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
UI_MachinegunSpinAngle
= = = = = = = = = = = = = = = = = = = = = =
*/
/*float UI_MachinegunSpinAngle( playerInfo_t *pi ) {
int delta ;
float angle ;
float speed ;
int torsoAnim ;
delta = dp_realtime - pi - > barrelTime ;
if ( pi - > barrelSpinning ) {
angle = pi - > barrelAngle + delta * SPIN_SPEED ;
} else {
if ( delta > COAST_TIME ) {
delta = COAST_TIME ;
}
speed = 0.5 * ( SPIN_SPEED + ( float ) ( COAST_TIME - delta ) / COAST_TIME ) ;
angle = pi - > barrelAngle + delta * speed ;
}
torsoAnim = pi - > torsoAnim & ~ ANIM_TOGGLEBIT ;
if ( torsoAnim = = TORSO_ATTACK2 ) {
torsoAnim = TORSO_ATTACK ;
}
if ( pi - > barrelSpinning = = ! ( torsoAnim = = TORSO_ATTACK ) ) {
pi - > barrelTime = dp_realtime ;
pi - > barrelAngle = AngleMod ( angle ) ;
pi - > barrelSpinning = ! ! ( torsoAnim = = TORSO_ATTACK ) ;
}
return angle ;
} */
/*
= = = = = = = = = = = = = = =
UI_DrawPlayer
= = = = = = = = = = = = = = =
*/
void UI_DrawPlayer ( float x , float y , float w , float h , vec3_t pOrigin , playerInfo_t * pi , int time ) { //RPG-X : TiM- Origin added
refdef_t refdef ;
refEntity_t legs ;
refEntity_t torso ;
refEntity_t head ;
refEntity_t gun ;
refEntity_t flash ;
vec3_t origin ;
int renderfx ;
vec3_t mins = { - 16 , - 24 , - 24 } ;
vec3_t maxs = { 16 , 16 , 32 } ;
float len ;
float xx ;
int anim ;
if ( ! pi - > legsModel | | ! pi - > torsoModel | | ! pi - > headModel | | ! pi - > animations [ 0 ] . numFrames ) {
return ;
}
dp_realtime = time ;
if ( pi - > pendingWeapon ! = - 1 & & dp_realtime > pi - > weaponTimer ) {
pi - > weapon = pi - > pendingWeapon ;
pi - > lastWeapon = pi - > pendingWeapon ;
pi - > pendingWeapon = - 1 ;
pi - > weaponTimer = 0 ;
/*if( pi->currentWeapon != pi->weapon ) {
trap_S_StartLocalSound ( trap_S_RegisterSound ( " sound/weapons/change.wav " ) , CHAN_LOCAL ) ;
} */
}
UI_AdjustFrom640 ( & x , & y , & w , & h ) ;
y - = jumpHeight ;
memset ( & refdef , 0 , sizeof ( refdef ) ) ;
memset ( & legs , 0 , sizeof ( legs ) ) ;
memset ( & torso , 0 , sizeof ( torso ) ) ;
memset ( & head , 0 , sizeof ( head ) ) ;
refdef . rdflags = RDF_NOWORLDMODEL ;
AxisClear ( refdef . viewaxis ) ;
refdef . x = x ;
refdef . y = y ;
refdef . width = w ;
refdef . height = h ;
refdef . fov_x = ( int ) ( ( float ) refdef . width / 640.0f * 10.0f ) ; //RPG-X : TiM- 90.0f //Anyone else noticed how the high FOV value distorted the model horribly in the menus? O_o
xx = refdef . width / tan ( refdef . fov_x / 360 * M_PI ) ;
refdef . fov_y = atan2 ( refdef . height , xx ) ;
refdef . fov_y * = ( 360 / M_PI ) ;
// calculate distance so the player nearly fills the box
//len = 0.7f * ( maxs[2] - mins[2] );
//origin[0] = len / tan( DEG2RAD(refdef.fov_x) * 0.5 );
//origin[1] = 0.5 * ( mins[1] + maxs[1] );
//origin[2] = -0.5 * ( mins[2] + maxs[2] );
len = 0.35f * ( maxs [ 2 ] - mins [ 2 ] ) ; //TiM: 0.35f
origin [ 0 ] = ( len / tan ( DEG2RAD ( refdef . fov_x ) * 0.5 ) ) + pOrigin [ 0 ] ; //0.5 //Z scale - Conventional 3d, not Q3 ;)
origin [ 1 ] = 0.5 * ( mins [ 1 ] + maxs [ 1 ] ) + pOrigin [ 1 ] ; //Xscale, adding numbers pushes the model to the left
origin [ 2 ] = - 0.5 * ( mins [ 2 ] + maxs [ 2 ] ) + pOrigin [ 2 ] ; //yScale, adding numbers pushes up
refdef . time = dp_realtime ;
trap_R_ClearScene ( ) ;
//spinView
if ( uis . spinView )
{
pi - > viewAngles [ YAW ] = AngleNormalize360 ( ( uis . cursorx - uis . cursorpx ) + uis . lastYaw ) ;
if ( ! trap_Key_IsDown ( K_MOUSE1 ) )
{
uis . spinView = qfalse ;
uis . lastYaw = pi - > viewAngles [ YAW ] ;
}
}
//TiM: random emote functionality :)
//first init the timer so this will start a minute after loading the menu
if ( pi - > randomEmote & & pi - > nextEmoteTime = = 0 ) {
pi - > nextEmoteTime = uis . realtime + ( irandom ( 15 , 20 ) * 1000 ) ;
}
//whup, time to play a random emote
if ( pi - > randomEmote & & uis . realtime > pi - > nextEmoteTime ) {
//randomly pick an anim
anim = irandom ( BOTH_STAND1_RANDOM2 , BOTH_STAND1_RANDOM11 ) ;
//make sure we can play this emote
if ( pi - > animations [ anim ] . numFrames > 0 ) {
UI_ForceLegsAnim ( pi , anim ) ;
UI_ForceTorsoAnim ( pi , anim ) ;
//play lower
pi - > legsAnimationTimer = pi - > animations [ anim ] . numFrames * pi - > animations [ anim ] . frameLerp * ( ( float ) uis . realtime / ( float ) dp_realtime ) ;
pi - > lowerEmoting = qtrue ;
pi - > torsoAnimationTimer = pi - > animations [ anim ] . numFrames * pi - > animations [ anim ] . frameLerp * ( ( float ) uis . realtime / ( float ) dp_realtime ) ;
pi - > upperEmoting = qtrue ;
pi - > nextEmoteTime = uis . realtime + ( irandom ( 10 , 20 ) * 1000 ) + pi - > legsAnimationTimer ;
}
else {
pi - > nextEmoteTime = uis . realtime + ( irandom ( 3 , 8 ) * 1000 ) ;
}
}
// get the rotation information
UI_PlayerAngles ( pi , legs . axis , torso . axis , head . axis ) ;
// get the animation state (after rotation, to allow feet shuffle)
UI_PlayerAnimation ( pi , & legs . oldframe , & legs . frame , & legs . backlerp ,
& torso . oldframe , & torso . frame , & torso . backlerp ) ;
renderfx = RF_LIGHTING_ORIGIN | RF_NOSHADOW ;
//
// add the legs
//
legs . hModel = pi - > legsModel ;
legs . customSkin = pi - > legsSkin ;
VectorCopy ( origin , legs . origin ) ;
VectorCopy ( origin , legs . lightingOrigin ) ;
legs . renderfx = renderfx ;
VectorCopy ( legs . origin , legs . oldorigin ) ;
VectorScale ( legs . axis [ 0 ] , pi - > height , legs . axis [ 0 ] ) ;
VectorScale ( legs . axis [ 1 ] , ( pi - > height * pi - > weight ) , legs . axis [ 1 ] ) ; //weight... i think
VectorScale ( legs . axis [ 2 ] , pi - > height , legs . axis [ 2 ] ) ;
legs . origin [ 2 ] = legs . origin [ 2 ] - ( 24.0f * ( 1.0f - pi - > height ) ) ;
trap_R_AddRefEntityToScene ( & legs ) ;
if ( ! legs . hModel ) {
return ;
}
//
// add the torso
//
torso . hModel = pi - > torsoModel ;
if ( ! torso . hModel ) {
return ;
}
torso . customSkin = pi - > torsoSkin ;
VectorCopy ( origin , torso . lightingOrigin ) ;
UI_PositionRotatedEntityOnTag ( & torso , & legs , pi - > legsModel , " tag_torso " ) ;
torso . renderfx = renderfx ;
trap_R_AddRefEntityToScene ( & torso ) ;
//
// add the head
//
head . hModel = pi - > headModel ;
if ( ! head . hModel ) {
return ;
}
head . customSkin = pi - > headSkin ;
VectorCopy ( origin , head . lightingOrigin ) ;
UI_PositionRotatedEntityOnTag ( & head , & torso , pi - > torsoModel , " tag_head " ) ;
head . renderfx = renderfx ;
trap_R_AddRefEntityToScene ( & head ) ;
//
// add the gun
//
2012-03-16 12:05:41 +00:00
if ( pi - > currentWeapon ! = WP_0 ) {
2011-06-01 12:20:56 +00:00
memset ( & gun , 0 , sizeof ( gun ) ) ;
gun . hModel = pi - > weaponModel ;
VectorCopy ( origin , gun . lightingOrigin ) ;
UI_PositionEntityOnTag ( & gun , & torso , pi - > torsoModel , " tag_weapon " ) ;
gun . renderfx = renderfx ;
trap_R_AddRefEntityToScene ( & gun ) ;
}
//
// 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/chat " ) ) ;
}
//
// add an accent light
// TiM: Holy Hell. This explains why the models are washed out when overBrightBits is active. O_o
// 500 is WAY too high
//
origin [ 0 ] - = 100 ; // + = behind, - = in front
origin [ 1 ] + = 100 ; // + = left, - = right
origin [ 2 ] + = 100 ; // + = above, - = below
trap_R_AddLightToScene ( origin , 100 , 1.0 , 1.0 , 1.0 ) ; //500
origin [ 0 ] - = 100 ;
origin [ 1 ] - = 100 ;
origin [ 2 ] - = 100 ;
trap_R_AddLightToScene ( origin , 100 , 1.0 , 0.0 , 0.0 ) ;
trap_R_RenderScene ( & refdef ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
UI_RegisterClientSkin
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*extern char* BG_RegisterRace( const char *name );
static qboolean UI_RegisterClientSkin ( playerInfo_t * pi , const char * modelName , const char * skinName ) {
char filename [ MAX_QPATH ] ;
Com_sprintf ( filename , sizeof ( filename ) , " models/players2/%s/lower_%s.skin " , modelName , skinName ) ;
pi - > legsSkin = trap_R_RegisterSkin ( filename ) ;
Com_sprintf ( filename , sizeof ( filename ) , " models/players2/%s/upper_%s.skin " , modelName , skinName ) ;
pi - > torsoSkin = trap_R_RegisterSkin ( filename ) ;
Com_sprintf ( filename , sizeof ( filename ) , " models/players2/%s/head_%s.skin " , modelName , skinName ) ;
pi - > headSkin = trap_R_RegisterSkin ( filename ) ;
Com_sprintf ( filename , sizeof ( filename ) , " models/players2/%s/groups.cfg " , modelName ) ;
strcpy ( pi - > race , BG_RegisterRace ( 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 [ 0 ] ) {
break ;
}
if ( ! Q_stricmp ( token , " footsteps " ) ) {
token = COM_Parse ( & text_p ) ;
if ( ! token [ 0 ] ) {
break ;
}
continue ;
} else if ( ! Q_stricmp ( token , " headoffset " ) ) {
for ( i = 0 ; i < 3 ; i + + ) {
token = COM_Parse ( & text_p ) ;
if ( ! token [ 0 ] ) {
break ;
}
}
continue ;
} else if ( ! Q_stricmp ( token , " sex " ) ) {
token = COM_Parse ( & text_p ) ;
if ( ! token [ 0 ] ) {
break ;
}
continue ;
} else if ( ! Q_stricmp ( token , " soundpath " ) ) {
token = COM_Parse ( & text_p ) ;
if ( ! token [ 0 ] ) {
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 [ 0 ] ) {
break ;
}
animations [ i ] . firstFrame = atoi ( token ) ;
// leg only frames are adjusted to not count the upper body only frames
if ( i = = LEGS_KNEEL1 ) {
skip = animations [ LEGS_KNEEL1 ] . firstFrame - animations [ TORSO_ACTIVATEMEDKIT1 ] . firstFrame ;
}
if ( i > = LEGS_KNEEL1 ) {
animations [ i ] . firstFrame - = skip ;
}
token = COM_Parse ( & text_p ) ;
if ( ! token [ 0 ] ) {
break ;
}
animations [ i ] . numFrames = atoi ( token ) ;
token = COM_Parse ( & text_p ) ;
if ( ! token [ 0 ] ) {
break ;
}
animations [ i ] . loopFrames = atoi ( token ) ;
token = COM_Parse ( & text_p ) ;
if ( ! token [ 0 ] ) {
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_InitModelData
by TiM
Initialize default values
in case the crazy modder
left out some of the keys .
In most cases , the fields
will just be left blank .
No point in using extra
resources if they weren ' t
specified .
= = = = = = = = = = = = = = = = = = = = = =
*/
static void UI_InitModelData ( playerInfo_t * pi ) {
pi - > hasRanks = qfalse ;
//initialize all model + skin data as 0, so it can be told if they don't get
//values assigned in the script parser, in which case we exit.
pi - > headModel = 0 ;
pi - > torsoModel = 0 ;
pi - > legsModel = 0 ;
pi - > headSkin = 0 ;
pi - > headSkinBlink = 0 ; //doesn't matter if left 0; won't end the parser
pi - > torsoSkin = 0 ;
pi - > legsSkin = 0 ;
//doesn't matter if left 0
pi - > headBlinkTime . minSeconds = 0 ;
pi - > headBlinkTime . maxSeconds = 0 ;
pi - > nextTalkTime = 0 ;
pi - > currentTalkSkin = 0 ;
pi - > headSkinTalk [ 0 ] = 0 ;
pi - > headSkinTalk [ 1 ] = 0 ;
pi - > headSkinTalk [ 2 ] = 0 ;
pi - > headSkinTalk [ 3 ] = 0 ;
memset ( & pi - > boltonTags , 0 , sizeof ( pi - > boltonTags ) ) ;
}
/*
= = = = = = = = = = = = = = = = = = = = =
UI_ParseSkinSetDataFile
by TiM
Parses a separate . skinset
file to get the skin data
for this model .
= = = = = = = = = = = = = = = = = = = = = =
*/
static qboolean UI_ParseSkinSetDataFile ( playerInfo_t * pi , const char * skinSetFrame , const char * charName , const char * skinName )
{
char * skinStar ;
char skinSetName [ MAX_QPATH ] ;
char skinSetRoute [ MAX_QPATH ] ;
char * token ;
char * textPtr ;
char buffer [ 5000 ] ;
int len ;
fileHandle_t f ;
int n , i ;
int noBlinking = trap_Cvar_VariableValue ( " cg_noBlinkingHeads " ) ;
if ( ( skinStar = strstr ( skinSetFrame , " * " ) ) = = NULL )
{
Com_Printf ( S_COLOR_RED " ERROR: No '*' specified in model skin set! \n " ) ;
return qfalse ;
}
else
{
//star is at front
if ( skinStar = = skinSetFrame )
{
skinStar + + ;
Com_sprintf ( skinSetName , sizeof ( skinSetName ) , " %s%s " , skinName , skinStar ) ;
}
//star is at end
else if ( ( int ) ( skinStar - skinSetFrame ) + 1 = = ( int ) strlen ( skinSetFrame ) )
{
Q_strncpyz ( skinSetName , skinSetFrame , strlen ( skinSetFrame ) ) ;
Q_strcat ( skinSetName , sizeof ( skinSetName ) , skinName ) ;
}
else
{
Com_Printf ( " ERROR: The '*' in %s must be on either the start or end, not the middle. \n " , skinSetFrame ) ;
return qfalse ;
}
}
//Com_Printf( S_COLOR_RED "DEBUG: skinSetName = %s \n", skinSetName );
Com_sprintf ( skinSetRoute , sizeof ( skinSetRoute ) , " models/players_rpgx/%s/%s.skinset " , charName , skinSetName ) ;
len = trap_FS_FOpenFile ( skinSetRoute , & f , FS_READ ) ;
if ( len < = 0 )
{
Com_Printf ( S_COLOR_RED " ERROR: Could not open file: %s \n " , skinSetRoute ) ;
return qfalse ;
}
if ( len > sizeof ( buffer ) - 1 )
{
Com_Printf ( S_COLOR_RED " ERROR: Imported file is too big for buffer: %s. Len is %i \n " , skinSetRoute , len ) ;
return qfalse ;
}
trap_FS_Read ( buffer , len , f ) ;
trap_FS_FCloseFile ( f ) ;
if ( ! buffer [ 0 ] )
{
Com_Printf ( S_COLOR_RED " ERROR: Could not import data from %s \n " , skinSetRoute ) ;
return qfalse ;
}
buffer [ len ] = ' \0 ' ;
textPtr = buffer ;
token = COM_Parse ( & textPtr ) ;
if ( Q_stricmp ( token , " { " ) )
{
Com_Printf ( S_COLOR_RED " ERROR: Skinset %s did not start with a '{' \n " , skinSetRoute ) ;
return qfalse ;
}
else
{
while ( 1 )
{ //while we don't hit the closing brace
token = COM_Parse ( & textPtr ) ; //parse
if ( ! token [ 0 ] ) { //error check
break ;
}
//head skin when blinking
//must be before headskin, or the damn thing will think the two are the same :P
if ( ! Q_stricmpn ( token , " headSkinBlink " , 13 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
if ( ! noBlinking ) {
pi - > headSkinBlink = trap_R_RegisterSkin ( token ) ;
}
if ( ! noBlinking & & ! pi - > headSkinBlink ) {
//We'll alert them, but not cancel the loop
Com_Printf ( S_COLOR_RED " WARNING: Couldn't load headSkinBlink: %s \n " , token ) ;
}
continue ;
}
//head blink time
else if ( ! Q_stricmpn ( token , " headBlinkTime " , 13 ) )
{
//Done this way so we know we got two valid args b4 proceeding
if ( COM_ParseInt ( & textPtr , & n ) ) { //first arg
SkipRestOfLine ( & textPtr ) ;
continue ;
}
if ( COM_ParseInt ( & textPtr , & i ) ) { //2nd arg
SkipRestOfLine ( & textPtr ) ;
continue ;
}
//Bug: if the stupid n00b of a modder made
//the minimum time larger than the max time >.<
if ( n > i )
{
Com_Printf ( S_COLOR_RED " ERROR: Minimum blink time was larger than maximum blink time. \n " ) ;
continue ;
}
if ( ! noBlinking ) {
pi - > headBlinkTime . minSeconds = n ;
pi - > headBlinkTime . maxSeconds = i ;
}
continue ;
}
else if ( ! Q_stricmpn ( token , " torsoSkin " , 9 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
pi - > torsoSkin = trap_R_RegisterSkin ( token ) ;
if ( ! pi - > torsoSkin ) {
Com_Printf ( S_COLOR_RED " ERROR: Couldn't load torsoSkin: %s \n " , token ) ;
}
continue ;
}
else if ( ! Q_stricmpn ( token , " legsSkin " , 8 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
pi - > legsSkin = trap_R_RegisterSkin ( token ) ;
if ( ! pi - > legsSkin ) {
Com_Printf ( S_COLOR_RED " ERROR: Couldn't load legsSkin: %s \n " , token ) ;
}
continue ;
}
else if ( ! Q_stricmpn ( token , " headSkinTalk " , 12 ) )
{
SkipBracedSection ( & textPtr ) ;
continue ;
}
//head skin
else if ( ! Q_stricmp ( token , " headSkin " ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
pi - > headSkin = trap_R_RegisterSkin ( token ) ;
if ( ! pi - > headSkin ) {
Com_Printf ( S_COLOR_RED " ERROR: Couldn't load headSkin: %s \n " , token ) ;
return qfalse ;
}
continue ;
}
if ( ! Q_stricmpn ( token , " } " , 1 ) ) {
break ;
}
}
}
return qtrue ;
}
/*
= = = = = = = = = = = = = = = = = = = = = =
UI_ParseModelDataFile
by TiM
Reads in the . model file
needed to put together
a character model .
= = = = = = = = = = = = = = = = = = = = = =
*/
qboolean UI_ParseModelDataFile ( playerInfo_t * pi , const char * charName ,
const char * modelName , const char * skinName ) {
fileHandle_t file ;
int file_len ;
char charText [ 20000 ] ;
char * textPtr , * prevValue ;
char fileName [ MAX_QPATH ] ;
//char animPath[MAX_QPATH];
int i , n ;
char * token ;
char legsFileRoute [ MAX_QPATH ] ;
qboolean didAnims = qfalse ;
qboolean skinSetFound = qfalse ;
int noBlinking ;
noBlinking = trap_Cvar_VariableValue ( " cg_noBlinkingHeads " ) ;
//size_t strLen;
//create the file route
Com_sprintf ( fileName , sizeof ( fileName ) , " models/players_rpgx/%s/%s.model " , charName , modelName ) ;
//Okay... gotta get the hang of ANSI C text parsing >.<
//first... I guess load the file
file_len = trap_FS_FOpenFile ( fileName , & file , FS_READ ) ;
//Error handle
//if length was 0, ie file not found or was empty
if ( file_len < = 0 ) {
return qfalse ;
}
//Another error... if text is WAY bigger than our available buffer O_O
if ( file_len > = sizeof ( charText ) - 1 ) {
Com_Printf ( S_COLOR_RED " Model Data File %s too long... WAY too long \n " , fileName ) ;
return qfalse ;
}
//initialize the buffer
memset ( charText , 0 , sizeof ( charText ) ) ;
//read data into char array
//i guess we use a char array so we can actually specify size/width.
trap_FS_Read ( charText , file_len , file ) ;
//I guess this is needed to mark the EOF.
charText [ file_len ] = 0 ;
//Free memory. Close Files
trap_FS_FCloseFile ( file ) ;
//default values if needed
UI_InitModelData ( pi ) ;
//Used to just clear any previous parse temp data
COM_BeginParseSession ( ) ;
//transfer our data from a char array to a char ptr.
//needed for the parsing func methinks
textPtr = charText ;
token = COM_Parse ( & textPtr ) ; //COM_Parse seems to work by splitting up each line of text by the spaces,
//and then removes that chunk from the original
//Okay, we should have the beginning variable first... which should be a '{'
//from the looks of this, I think we have to do this after
//every parse call. O_O
if ( ! token [ 0 ] ) {
Com_Printf ( S_COLOR_RED " No data found in model data buffer! \n " ) ;
return qfalse ;
}
if ( Q_stricmp ( token , " { " ) ) {
Com_Printf ( S_COLOR_RED " Missing { in %s \n " , fileName ) ;
return qfalse ;
}
while ( 1 ) {
prevValue = textPtr ; //set a backup
token = COM_Parse ( & textPtr ) ;
if ( ! token [ 0 ] | | ! token ) { //we've hit the end of the file. w00t! exit!
break ;
}
//if we randomly find a brace in here (ie a sub-struct that may have no header)
//just skip it. :P
if ( ! Q_stricmpn ( token , " { " , 1 ) ) {
SkipBracedSection ( & textPtr ) ;
}
if ( ! Q_stricmpn ( token , " animsConfig " , 11 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
//no valid anim file found. Don't give up hope though.
//We have a backup resort at the end if need be. :)
if ( ( didAnims = UI_ParseAnimationFile ( token , pi - > animations ) ) = = qfalse ) {
Com_Printf ( S_COLOR_RED " WARNING: Was unable to load file %s. \n " , token ) ;
}
continue ;
}
//playermodel gender
else if ( ! Q_stricmpn ( token , " sex " , 3 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
if ( token [ 0 ] = = ' f ' | | token [ 0 ] = = ' F ' ) {
pi - > gender = GENDER_FEMALE ;
} else if ( token [ 0 ] = = ' n ' | | token [ 0 ] = = ' N ' ) {
pi - > gender = GENDER_NEUTER ;
} else {
pi - > gender = GENDER_MALE ;
}
continue ;
}
//character's legs model
else if ( ! Q_stricmpn ( token , " legsModel " , 9 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
pi - > legsModel = trap_R_RegisterModel ( token ) ;
if ( ! pi - > legsModel ) {
Com_Printf ( S_COLOR_RED " ERROR: Unable to load legs model: %s \n " , token ) ;
return qfalse ;
}
//if loaded no anims yet, copy the legs route to this variable,
//and we'll try again at the end of the function
//if ( ci->animIndex == -1 ) {
Q_strncpyz ( legsFileRoute , token , sizeof ( legsFileRoute ) ) ;
//} Actually. just copy it regardless. Just in case
continue ;
}
//character's torso model
else if ( ! Q_stricmpn ( token , " torsoModel " , 10 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
pi - > torsoModel = trap_R_RegisterModel ( token ) ;
//Com_Printf("Torsomodel passed as %s, %i\n", token, (int)ci->torsoModel);
if ( ! pi - > torsoModel ) {
Com_Printf ( S_COLOR_RED " ERROR: Unable to load torso model: %s \n " , token ) ;
return qfalse ;
}
continue ;
}
//character's headmodel
else if ( ! Q_stricmpn ( token , " headModel " , 9 ) ) {
//return true = no extra text found on this line - bad! O_O!
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
pi - > headModel = trap_R_RegisterModel ( token ) ;
if ( ! pi - > headModel ) {
Com_Printf ( S_COLOR_RED " ERROR: Unable to load head model: %s \n " , token ) ;
return qfalse ;
}
continue ;
}
// Custom bolton models... oi O_o
else if ( ! Q_stricmpn ( token , " boltonModels " , 12 ) ) {
//needed coz '{' could also be on next line
token = COM_Parse ( & textPtr ) ;
if ( ! token [ 0 ] ) { //if that was it
break ;
} else { //else, if next character is '{'
if ( ! Q_stricmpn ( token , " { " , 1 ) ) {
token = COM_Parse ( & textPtr ) ;
if ( ! token [ 0 ] ) {
break ;
}
//loop till we hit the end of the brackets
i = 0 ;
while ( Q_stricmp ( token , " } " ) ) {
if ( ! Q_stricmpn ( token , " BOLTON_ " , 7 ) ) {
pi - > boltonTags [ i ] . modelBase = GetIDForString ( BoltonTable , token ) ;
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
if ( ! Q_stricmpn ( token , " tag_ " , 4 ) ) {
Q_strncpyz ( pi - > boltonTags [ i ] . tagName , token , sizeof ( pi - > boltonTags [ i ] . tagName ) ) ;
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
pi - > boltonTags [ i ] . tagModel = trap_R_RegisterModel ( token ) ;
if ( ! pi - > boltonTags [ i ] . tagModel ) {
Com_Printf ( S_COLOR_RED " WARNING: Unable to load bolton model: %s \n " , token ) ;
}
i + + ;
if ( i > MAX_BOLTONS - 1 ) {
break ;
}
}
}
//Com_Printf("Index: %i, Name: %s, Handle: %i\n", ci->boltonTags[ci->numBoltOns].modelBase, ci->boltonTags[ci->numBoltOns].tagName, ci->boltonTags[ci->numBoltOns].tagModel );
token = COM_Parse ( & textPtr ) ;
if ( ! token [ 0 ] ) {
break ;
}
}
}
}
}
//whether char is allowed to wear ranks
else if ( ! Q_stricmpn ( token , " hasRanks " , 8 ) ) {
if ( COM_ParseInt ( & textPtr , & n ) ) {
continue ;
}
pi - > hasRanks = n ;
continue ;
}
//TiM - The skinset is defined
else if ( ! Q_stricmpn ( token , " skinSet " , 7 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
if ( ! UI_ParseSkinSetDataFile ( pi , token , charName , skinName ) )
{
Com_Printf ( S_COLOR_RED " WARNING: Could not load data from specified skin set in char: %s. Attempting to load default. \n " , charName ) ;
}
else
{
skinSetFound = qtrue ;
}
continue ;
}
}
if ( ! skinSetFound )
{
if ( ! UI_ParseSkinSetDataFile ( pi , va ( " %s_* " , modelName , skinName ) , charName , skinName ) )
{
Com_Printf ( S_COLOR_RED " ERROR: Tried loading default skin set, however it failed. \n " ) ;
}
}
//if any of the models or skins were left blank, then output false. Coz we need them. :P
if ( ! pi - > headModel | | ! pi - > torsoModel | | ! pi - > legsModel ) {
Com_Printf ( S_COLOR_RED " One or more necessary model files weren't loaded from %s \n " , fileName ) ;
return qfalse ;
}
if ( ! pi - > headSkin | | ! pi - > torsoSkin | | ! pi - > legsSkin ) {
Com_Printf ( S_COLOR_RED " One or more necessary skin files weren't loaded from %s \n " , fileName ) ;
return qfalse ;
}
//if modder specified no animations file route, or they did, and it sucked (ie -1 ),
//Then try looking for one in the same directory as the lower.mdr file
//k... the goal of this is to take a string like
//models/players_rpgx/crewman_male/lower.mdr
//and turn it into
//models/players_rpgx/crewman_male/animation.cfg
if ( ! didAnims & & strlen ( legsFileRoute ) > 0 ) {
//get length of file route
i = strlen ( legsFileRoute ) ;
while ( 1 ) {
//if we looped all the way to the end.... ie BAD
if ( i < = 0 ) {
//we obviously have no animation directory :(
Com_Printf ( S_COLOR_RED " ERROR: Was unable to calculate location of animation.cfg for %s \n " , fileName ) ;
return qfalse ;
}
//if this is the first '/' we come across from going from the end to the start
if ( legsFileRoute [ i ] = = ' / ' ) {
//copy i bytes of data from token to animpath (effectively giving us the route, with no file)
Q_strncpyz ( legsFileRoute , legsFileRoute , ( i = i + 2 ) ) ; //+2 for the null char these things auto assign at the end... i think
break ; //won't work without it anyway :P
}
i - - ;
}
//add animation.cfg to the end of the string
Q_strcat ( legsFileRoute , sizeof ( legsFileRoute ) , " animation.cfg " ) ;
//Com_Printf( S_COLOR_RED "WARNING: Failed to load animation file specified in model config, attempting to load %s\n", legsFileRoute );
//Parse it
if ( ! UI_ParseAnimationFile ( legsFileRoute , pi - > animations ) ) {
Com_Printf ( " Tried loading anim data from location %s, however nothing was valid. \n " , legsFileRoute ) ;
return qfalse ;
}
}
else {
if ( ! legsFileRoute [ 0 ] ) {
Com_Printf ( S_COLOR_RED " Couldn't load/locate any player animation data for player: %s. \n " , charName ) ;
return qfalse ;
}
}
//holy fudgenuggets. after all that checking, we actually made it to the end and have a valid freaking
//model! OWNED!
return qtrue ;
}
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
UI_RegisterClientModelname
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
qboolean UI_RegisterClientModelname ( playerInfo_t * pi , const char * modelSkinName ) {
char charName [ MAX_QPATH ] ;
char modelName [ MAX_QPATH ] ;
char skinName [ MAX_QPATH ] ;
//char filename[MAX_QPATH];
char * model , * skin ;
//char *slash;
int len ;
pi - > torsoModel = 0 ;
pi - > headModel = 0 ;
if ( ! modelSkinName [ 0 ] ) {
return qfalse ;
}
Q_strncpyz ( charName , modelSkinName , sizeof ( charName ) ) ;
/*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 ;
} */
//step 1, take the first bit of the string and put it in the charName var.
if ( ( model = strchr ( charName , ' / ' ) ) = = NULL ) { //if there's no slash
Q_strncpyz ( charName , modelSkinName , sizeof ( charName ) ) ; //just set it
} else { //otherwise, isolate the first bit, and copy that
len = strlen ( modelSkinName ) ;
Q_strncpyz ( charName , modelSkinName , ( ( int ) len - ( int ) strlen ( model ) ) + 1 ) ;
}
//Com_Printf("%s\n", newInfo.charName);
//slash = strchr( newInfo.modelName, '/' );
if ( ! model | | ! model [ 1 ] ) {
// modelName didn not include a skin name
//Q_strncpyz( newInfo.skinName, "default", sizeof( newInfo.skinName ) );
Q_strncpyz ( modelName , " main " , sizeof ( modelName ) ) ;
Q_strncpyz ( skinName , " default " , sizeof ( skinName ) ) ;
if ( model & & ! model [ 1 ] )
{ //if we had a slash, but nothing after, clear it
* model = 0 ;
}
} else {
//*model++; //bypass the slash
model + + ;
len = strlen ( model ) ;
skin = strchr ( model , ' / ' ) ;
//if there was a model defined, but no skin
if ( ! skin | | ! skin [ 1 ] ) {
//no skin, but I'm guessing we gotz a model at least
if ( ! skin ) {
Q_strncpyz ( modelName , model , sizeof ( modelName ) ) ;
}
else {
if ( ! skin [ 1 ] ) {
Q_strncpyz ( modelName , model , ( int ) strlen ( model ) ) ;
}
}
Q_strncpyz ( skinName , " default " , sizeof ( skinName ) ) ;
if ( skin & & ! skin [ 1 ] ) {
* skin = 0 ;
}
} else {
//*skin++;
skin + + ;
Q_strncpyz ( modelName , model , ( ( int ) len - ( int ) strlen ( skin ) ) ) ;
Q_strncpyz ( skinName , skin , sizeof ( skinName ) ) ;
}
//Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
// truncate modelName
* model = 0 ;
}
// load cmodels before models so filecache works
//try loading the main model
if ( ! UI_ParseModelDataFile ( pi , charName , modelName , skinName ) )
{
Com_Printf ( S_COLOR_RED " Was unable to parse model file for character: %s/%s/%s \n " , charName , modelName , skinName ) ;
//if that fails, try and load the model's default data at least
if ( ! UI_ParseModelDataFile ( pi , charName , DEFAULT_MODEL , DEFAULT_SKIN ) )
{
//if THAT fails, try loading our defualt char, with the specfied char's model and skin parms
if ( ! UI_ParseModelDataFile ( pi , ui_defaultChar . string , modelName , skinName ) )
{
if ( ! UI_ParseModelDataFile ( pi , DEFAULT_CHAR , DEFAULT_MODEL , DEFAULT_SKIN ) )
{
//if all else fails, try and load the normal default model
return qfalse ;
}
}
}
}
/*Com_sprintf( filename, sizeof( filename ), "models/players2/%s/lower.mdr", modelName );
pi - > legsModel = trap_R_RegisterModel ( filename ) ;
if ( ! pi - > legsModel )
{
Com_sprintf ( filename , sizeof ( filename ) , " models/players2/%s/lower.md3 " , modelName ) ;
pi - > legsModel = trap_R_RegisterModel ( filename ) ;
if ( ! pi - > legsModel )
{
Com_Printf ( S_COLOR_RED " Failed to load model file %s \n " , filename ) ;
return qfalse ;
}
}
Com_sprintf ( filename , sizeof ( filename ) , " models/players2/%s/upper.mdr " , modelName ) ;
pi - > torsoModel = trap_R_RegisterModel ( filename ) ;
if ( ! pi - > torsoModel )
{
Com_sprintf ( filename , sizeof ( filename ) , " models/players2/%s/upper.md3 " , modelName ) ;
pi - > torsoModel = trap_R_RegisterModel ( filename ) ;
if ( ! pi - > torsoModel ) {
Com_Printf ( S_COLOR_RED " Failed to load model file %s \n " , filename ) ;
return qfalse ;
}
}
Com_sprintf ( filename , sizeof ( filename ) , " models/players2/%s/head.md3 " , modelName ) ;
pi - > headModel = trap_R_RegisterModel ( filename ) ;
if ( ! pi - > headModel )
{
Com_Printf ( S_COLOR_RED " 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/players2/%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 ) ;
Q_strncpyz ( pi - > modelName , model , sizeof ( pi - > modelName ) ) ;
2012-03-16 12:05:41 +00:00
pi - > weapon = WP_0 ;
2011-06-01 12:20:56 +00:00
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 , float height , float weight , qboolean chat ) {
int currentAnim ;
weapon_t weaponNum ;
pi - > chat = chat ;
// view angles
VectorCopy ( viewAngles , pi - > viewAngles ) ;
// move angles
VectorCopy ( moveAngles , pi - > moveAngles ) ;
//TiM : Clamp weight and height
pi - > height = height ;
pi - > weight = weight ;
if ( ! pi - > weight )
pi - > weight = 1.0f ;
if ( ! pi - > height )
pi - > height = 1.0f ;
pi - > height = Com_Clamp ( 0.9f , 1.15f , pi - > height ) ;
pi - > weight = Com_Clamp ( 0.9f , 1.1f , pi - > weight ) ;
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 ;
}
2012-03-16 12:05:41 +00:00
else if ( weaponNumber ! = WP_0 ) {
2011-06-01 12:20:56 +00:00
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 ;
2012-03-16 12:05:41 +00:00
pi - > weapon = pi - > currentWeapon = WP_0 ;
2011-06-01 12:20:56 +00:00
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 ! = BOTH_JUMP1 & & ( currentAnim = = BOTH_JUMP1 | | currentAnim = = BOTH_LAND1 ) ) {
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) //TiM: TORSO_STAND2
if ( torsoAnim = = UI_GetAnim ( ANIM_IDLE , pi - > currentWeapon , qtrue ) )
{
2012-03-16 12:05:41 +00:00
/*if ( weaponNum == WP_0 || weaponNum == WP_5 )
2011-06-01 12:20:56 +00:00
{
torsoAnim = TORSO_STAND2 ;
}
else
{
torsoAnim = TORSO_STAND2 ;
} */
2012-03-16 12:05:41 +00:00
/*if ( weaponNum == WP_6 || weaponNum == WP_7 )
2011-06-01 12:20:56 +00:00
{
torsoAnim = TORSO_STAND ;
}
else
{
torsoAnim = TORSO_STAND2 ;
} */
torsoAnim = UI_GetAnim ( ANIM_IDLE , pi - > currentWeapon , qtrue ) ;
}
//if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 )
if ( torsoAnim = = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) )
{
2012-03-16 12:05:41 +00:00
/*if ( weaponNum == WP_0 || weaponNum == WP_5 )
2011-06-01 12:20:56 +00:00
{
torsoAnim = TORSO_ATTACK2 ;
}
else
{
torsoAnim = TORSO_ATTACK ;
} */
2012-03-16 12:05:41 +00:00
/*if ( weaponNum == WP_6 || weaponNum == WP_7 )
2011-06-01 12:20:56 +00:00
{
torsoAnim = TORSO_ATTACK ;
}
else
{
torsoAnim = TORSO_ATTACK2 ;
} */
torsoAnim = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) ;
pi - > muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH ;
//FIXME play firing sound here
}
currentAnim = pi - > torsoAnim & ~ ANIM_TOGGLEBIT ;
if ( weaponNum ! = pi - > currentWeapon | | currentAnim = = TORSO_RAISEWEAP1 | | currentAnim = = TORSO_DROPWEAP1 ) {
pi - > pendingTorsoAnim = torsoAnim ;
}
else if ( ( /*currentAnim == TORSO_GESTURE ||*/ currentAnim = = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) ) & & ( torsoAnim ! = currentAnim ) ) {
pi - > pendingTorsoAnim = torsoAnim ;
}
else if ( torsoAnim ! = currentAnim ) {
pi - > pendingTorsoAnim = 0 ;
UI_ForceTorsoAnim ( pi , torsoAnim ) ;
}
}