2012-08-04 10:54:37 +00:00
// Copyright (C) 1999-2000 Id Software, Inc.
2012-01-22 21:34:33 +00:00
//
// ui_players.c
# include "ui_local.h"
2013-09-04 15:58:49 +00:00
# include "ui_logger.h"
2012-01-22 21:34:33 +00:00
2014-11-08 10:59:05 +00:00
enum ui_playersTimer_e {
UI_TIMER_WEAPON_DELAY = 250 ,
UI_TIMER_WEAPON_SWITCH = 300 ,
UI_TIMER_ATTACK = 500 ,
UI_TIMER_MUZZLE_FLASH = 20 ,
UI_TIMER_LAND = 130 ,
UI_TIMER_JUMP = 1000 ,
UI_TIMER_GESTURE = 2300
} ;
2012-01-22 21:34:33 +00:00
2014-11-08 10:59:05 +00:00
static const int32_t JUMP_HEIGHT = 56 ;
2012-01-22 21:34:33 +00:00
2014-11-08 10:59:05 +00:00
static const double SWINGSPEED = 0.2 ; //TiM - 0.3
2012-01-22 21:34:33 +00:00
2014-11-08 10:59:05 +00:00
static const double SPIN_SPEED = 0.9 ;
static const int32_t COAST_TIME = 1000 ;
2012-01-22 21:34:33 +00:00
2014-11-08 10:59:05 +00:00
static int32_t dp_realtime ;
static float jumpHeight ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
//TiM : Bolton Table
stringID_table_t BoltonTable [ BOLTON_MAX + 1 ] =
{
{ ENUM2STRING ( BOLTON_HEAD ) } ,
{ ENUM2STRING ( BOLTON_TORSO ) } ,
{ ENUM2STRING ( BOLTON_LEGS ) } ,
{ NULL , - 1 }
} ;
2012-01-22 21:34:33 +00:00
/*
= = = = = = = = = = = = = = =
UI_PlayerInfo_SetWeapon
= = = = = = = = = = = = = = =
*/
static void UI_PlayerInfo_SetWeapon ( playerInfo_t * pi , weapon_t weaponNum ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
gitem_t * item ;
char path [ MAX_QPATH ] ;
pi - > currentWeapon = weaponNum ;
tryagain :
pi - > realWeapon = weaponNum ;
pi - > weaponModel = 0 ;
pi - > barrelModel = 0 ;
pi - > flashModel = 0 ;
2012-08-04 10:54:37 +00:00
if ( weaponNum = = WP_0 ) {
2012-01-22 21:34:33 +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 ) {
2012-08-04 10:54:37 +00:00
pi - > weaponModel = trap_R_RegisterModel ( item - > world_model ) ;
2012-01-22 21:34:33 +00:00
}
2012-08-04 10:54:37 +00:00
if ( pi - > weaponModel = = 0 )
{
if ( weaponNum = = WP_5 )
{
weaponNum = WP_0 ;
2012-01-22 21:34:33 +00:00
goto tryagain ;
}
2012-08-04 10:54:37 +00:00
weaponNum = WP_5 ;
2012-01-22 21:34:33 +00:00
goto tryagain ;
}
2012-08-04 10:54:37 +00:00
strcpy ( path , item - > world_model ) ;
COM_StripExtension ( path , path ) ;
2012-01-22 21:34:33 +00:00
strcat ( path , " _flash.md3 " ) ;
pi - > flashModel = trap_R_RegisterModel ( path ) ;
switch ( weaponNum ) {
2012-08-04 10:54:37 +00:00
case WP_8 :
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
2012-01-22 21:34:33 +00:00
break ;
2012-08-04 10:54:37 +00:00
case WP_10 :
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
2012-01-22 21:34:33 +00:00
break ;
2012-08-04 10:54:37 +00:00
case WP_5 :
MAKERGB ( pi - > flashDlightColor , 0 , 0 , 0 ) ;
2012-01-22 21:34:33 +00:00
break ;
2012-08-04 10:54:37 +00:00
case WP_13 :
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
2012-01-22 21:34:33 +00:00
break ;
2012-08-04 10:54:37 +00:00
case WP_1 :
//MAKERGB( pi->flashDlightColor, 0.6, 0.6, 1 );
2012-01-22 21:34:33 +00:00
break ;
2012-08-04 10:54:37 +00:00
case WP_6 :
MAKERGB ( pi - > flashDlightColor , 0.16 , 0.16 , 1 ) ;
2012-01-22 21:34:33 +00:00
break ;
2012-08-04 10:54:37 +00:00
case WP_7 :
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
2012-01-22 21:34:33 +00:00
break ;
2012-08-04 10:54:37 +00:00
case WP_4 :
MAKERGB ( pi - > flashDlightColor , 1 , 0.6 , 0.6 ) ;
2012-01-22 21:34:33 +00:00
break ;
2012-08-04 10:54:37 +00:00
case WP_9 :
MAKERGB ( pi - > flashDlightColor , 0.6 , 0.6 , 1 ) ;
2012-01-22 21:34:33 +00:00
break ;
default :
MAKERGB ( pi - > flashDlightColor , 1 , 1 , 1 ) ;
break ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_ForceLegsAnim
= = = = = = = = = = = = = = =
*/
2013-08-16 12:58:47 +00:00
static void UI_ForceLegsAnim ( playerInfo_t * pi , int32_t anim ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
pi - > legsAnim = ( ( pi - > legsAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim ;
2012-08-04 10:54:37 +00:00
if ( anim = = BOTH_JUMP1 ) {
2012-01-22 21:34:33 +00:00
pi - > legsAnimationTimer = UI_TIMER_JUMP ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_SetLegsAnim
= = = = = = = = = = = = = = =
*/
2013-08-16 12:58:47 +00:00
static void UI_SetLegsAnim ( playerInfo_t * pi , int32_t anim ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
if ( pi - > pendingLegsAnim ) {
anim = pi - > pendingLegsAnim ;
pi - > pendingLegsAnim = 0 ;
}
UI_ForceLegsAnim ( pi , anim ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_ForceTorsoAnim
= = = = = = = = = = = = = = =
*/
2013-08-16 12:58:47 +00:00
static void UI_ForceTorsoAnim ( playerInfo_t * pi , int32_t anim ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
pi - > torsoAnim = ( ( pi - > torsoAnim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | anim ;
2012-08-04 10:54:37 +00:00
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
2012-01-22 21:34:33 +00:00
pi - > torsoAnimationTimer = UI_TIMER_ATTACK ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_SetTorsoAnim
= = = = = = = = = = = = = = =
*/
2013-08-16 12:58:47 +00:00
static void UI_SetTorsoAnim ( playerInfo_t * pi , int32_t anim ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
if ( pi - > pendingTorsoAnim ) {
anim = pi - > pendingTorsoAnim ;
pi - > pendingTorsoAnim = 0 ;
}
UI_ForceTorsoAnim ( pi , anim ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_TorsoSequencing
= = = = = = = = = = = = = = =
*/
static void UI_TorsoSequencing ( playerInfo_t * pi ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2013-08-16 12:58:47 +00:00
int32_t currentAnim ;
2012-01-22 21:34:33 +00:00
currentAnim = pi - > torsoAnim & ~ ANIM_TOGGLEBIT ;
2012-08-04 10:54:37 +00:00
if ( pi - > weapon ! = pi - > currentWeapon & & ! pi - > upperEmoting ) {
if ( currentAnim ! = TORSO_DROPWEAP1 ) {
2012-01-22 21:34:33 +00:00
pi - > torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH ;
2012-08-04 10:54:37 +00:00
UI_ForceTorsoAnim ( pi , TORSO_DROPWEAP1 ) ;
2012-01-22 21:34:33 +00:00
}
}
if ( pi - > torsoAnimationTimer > 0 ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
2012-08-04 10:54:37 +00:00
/*if( currentAnim == TORSO_GESTURE ) {
2012-01-22 21:34:33 +00:00
UI_SetTorsoAnim ( pi , TORSO_STAND ) ;
return ;
2012-08-04 10:54:37 +00:00
} */
if ( currentAnim = = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) ) { //BOTH_ATTACK1 22 = ANIM_ATTACK
//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 )
{
UI_SetTorsoAnim ( pi , BOTH_STAND1 ) ; //TORSO_STAND
}
else
{
UI_SetTorsoAnim ( pi , BOTH_STAND4 ) ; //TORSO_STAND
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
2012-08-04 10:54:37 +00:00
if ( currentAnim = = TORSO_DROPWEAP1 ) {
2012-01-22 21:34:33 +00:00
UI_PlayerInfo_SetWeapon ( pi , pi - > weapon ) ;
pi - > torsoAnimationTimer = UI_TIMER_WEAPON_SWITCH ;
2012-08-04 10:54:37 +00:00
UI_ForceTorsoAnim ( pi , TORSO_RAISEWEAP1 ) ; //TORSO_RAISE
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
2012-08-04 10:54:37 +00:00
if ( currentAnim = = TORSO_RAISEWEAP1 ) {
UI_SetTorsoAnim ( pi , BOTH_STAND1 ) ; //STAND2
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_LegsSequencing
= = = = = = = = = = = = = = =
*/
static void UI_LegsSequencing ( playerInfo_t * pi ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2013-08-16 12:58:47 +00:00
int32_t currentAnim ;
2012-01-22 21:34:33 +00:00
currentAnim = pi - > legsAnim & ~ ANIM_TOGGLEBIT ;
if ( pi - > legsAnimationTimer > 0 ) {
2012-08-04 10:54:37 +00:00
if ( currentAnim = = BOTH_JUMP1 ) {
2012-01-22 21:34:33 +00:00
jumpHeight = JUMP_HEIGHT * sin ( M_PI * ( UI_TIMER_JUMP - pi - > legsAnimationTimer ) / UI_TIMER_JUMP ) ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
2012-08-04 10:54:37 +00:00
if ( currentAnim = = BOTH_JUMP1 ) {
UI_ForceLegsAnim ( pi , BOTH_LAND1 ) ;
2012-01-22 21:34:33 +00:00
pi - > legsAnimationTimer = UI_TIMER_LAND ;
jumpHeight = 0 ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
2012-08-04 10:54:37 +00:00
if ( currentAnim = = BOTH_LAND1 ) {
UI_SetLegsAnim ( pi , BOTH_STAND1 ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = =
UI_PositionEntityOnTag
= = = = = = = = = = = = = = = = = = = = = =
*/
static void UI_PositionEntityOnTag ( refEntity_t * entity , const refEntity_t * parent ,
clipHandle_t parentModel , char * tagName ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2013-08-16 12:58:47 +00:00
int32_t i ;
2012-01-22 21:34:33 +00:00
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
2017-09-30 19:49:00 +00:00
MatrixMultiply ( lerped . axis , ( ( refEntity_t * ) parent ) - > axis , entity - > axis ) ;
2012-01-22 21:34:33 +00:00
entity - > backlerp = parent - > backlerp ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = =
UI_PositionRotatedEntityOnTag
= = = = = = = = = = = = = = = = = = = = = =
*/
static void UI_PositionRotatedEntityOnTag ( refEntity_t * entity , const refEntity_t * parent ,
clipHandle_t parentModel , char * tagName ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2013-08-16 12:58:47 +00:00
int32_t i ;
2012-01-22 21:34:33 +00:00
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
2017-09-30 19:49:00 +00:00
MatrixMultiply ( entity - > axis , ( ( refEntity_t * ) parent ) - > axis , tempAxis ) ;
MatrixMultiply ( lerped . axis , tempAxis , entity - > axis ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_SetLerpFrameAnimation
= = = = = = = = = = = = = = =
*/
2013-08-16 12:58:47 +00:00
static void UI_SetLerpFrameAnimation ( playerInfo_t * ci , lerpFrame_t * lf , int32_t newAnimation ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
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 ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_RunLerpFrame
= = = = = = = = = = = = = = =
*/
2013-08-16 12:58:47 +00:00
static void UI_RunLerpFrame ( playerInfo_t * ci , lerpFrame_t * lf , int32_t newAnimation ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
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 ;
2012-08-04 10:54:37 +00:00
/*if ( anim->numFrames < 0 ) {
UI_SetLerpFrameAnimation ( ci , lf , BOTH_STAND1 ) ;
} */
2012-01-22 21:34:33 +00:00
if ( dp_realtime < lf - > animationTime ) {
lf - > frameTime = lf - > animationTime ; // initial lerp
} else {
lf - > frameTime = lf - > oldFrameTime + anim - > frameLerp ;
}
2013-08-16 12:58:47 +00:00
int32_t f = ( lf - > frameTime - lf - > animationTime ) / anim - > frameLerp ;
2012-01-22 21:34:33 +00:00
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 {
2013-08-16 13:43:41 +00:00
lf - > backlerp = 1.0 - ( float ) ( dp_realtime - lf - > oldFrameTime ) / ( lf - > frameTime - lf - > oldFrameTime ) ;
2012-01-22 21:34:33 +00:00
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_PlayerAnimation
= = = = = = = = = = = = = = =
*/
2013-08-16 13:43:41 +00:00
static void UI_PlayerAnimation ( playerInfo_t * pi , int32_t * legsOld , int32_t * legs , float * legsBackLerp ,
int32_t * torsoOld , int32_t * torso , float * torsoBackLerp ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
// legs animation
2012-08-04 10:54:37 +00:00
pi - > legsAnimationTimer - = uis . frametime ;
2012-01-22 21:34:33 +00:00
if ( pi - > legsAnimationTimer < 0 ) {
pi - > legsAnimationTimer = 0 ;
}
UI_LegsSequencing ( pi ) ;
2012-08-04 10:54:37 +00:00
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 ) ;
2012-01-22 21:34:33 +00:00
} else {
UI_RunLerpFrame ( pi , & pi - > legs , pi - > legsAnim ) ;
}
* legsOld = pi - > legs . oldFrame ;
* legs = pi - > legs . frame ;
* legsBackLerp = pi - > legs . backlerp ;
// torso animation
2012-08-04 10:54:37 +00:00
pi - > torsoAnimationTimer - = uis . frametime ;
2012-01-22 21:34:33 +00:00
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 ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = = = = =
UI_SwingAngles
= = = = = = = = = = = = = = = = = =
*/
2013-08-16 13:43:41 +00:00
static void UI_SwingAngles ( float destination , float swingTolerance , float clampTolerance ,
float speed , float * angle , qboolean * swinging ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2013-08-16 13:43:41 +00:00
float swing ;
float move ;
float scale ;
2012-01-22 21:34:33 +00:00
if ( ! * swinging ) {
// see if a swing should be started
swing = AngleSubtract ( * angle , destination ) ;
if ( swing > swingTolerance | | swing < - swingTolerance ) {
* swinging = qtrue ;
}
}
if ( ! * swinging ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
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 ) {
2012-08-04 10:54:37 +00:00
move = uis . frametime * scale * speed ;
2012-01-22 21:34:33 +00:00
if ( move > = swing ) {
move = swing ;
* swinging = qfalse ;
}
* angle = AngleMod ( * angle + move ) ;
} else if ( swing < 0 ) {
2012-08-04 10:54:37 +00:00
move = uis . frametime * scale * - speed ;
2012-01-22 21:34:33 +00:00
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 ) ) ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_PlayerAngles
= = = = = = = = = = = = = = =
*/
static void UI_PlayerAngles ( playerInfo_t * pi , vec3_t legs [ 3 ] , vec3_t torso [ 3 ] , vec3_t head [ 3 ] ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
vec3_t legsAngles , torsoAngles , headAngles ;
2013-08-16 13:43:41 +00:00
float dest ;
2012-01-22 21:34:33 +00:00
VectorCopy ( pi - > viewAngles , headAngles ) ;
headAngles [ YAW ] = AngleMod ( headAngles [ YAW ] ) ;
VectorClear ( legsAngles ) ;
VectorClear ( torsoAngles ) ;
// --------- yaw -------------
// allow yaw to drift a bit
2012-08-04 10:54:37 +00:00
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 ) ) {
2012-01-22 21:34:33 +00:00
// 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
2012-08-04 10:54:37 +00:00
if ( ! uis . spinView ) {
2013-08-12 22:49:39 +00:00
legsAngles [ YAW ] = headAngles [ YAW ] ;
torsoAngles [ YAW ] = headAngles [ YAW ] ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
// 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 ] ;
}
2012-01-22 21:34:33 +00:00
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 ;
}
2012-08-04 10:54:37 +00:00
UI_SwingAngles ( dest , 15 , 30 , 0.1 , & pi - > torso . pitchAngle , & pi - > torso . pitching ) ;
2012-01-22 21:34:33 +00:00
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 ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_PlayerFloatSprite
= = = = = = = = = = = = = = =
*/
static void UI_PlayerFloatSprite ( playerInfo_t * pi , vec3_t origin , qhandle_t shader ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
refEntity_t ent ;
memset ( & ent , 0 , sizeof ( ent ) ) ;
VectorCopy ( origin , ent . origin ) ;
ent . origin [ 2 ] + = 48 ;
ent . reType = RT_SPRITE ;
ent . customShader = shader ;
2012-08-04 10:54:37 +00:00
ent . data . sprite . radius = 10 ;
2012-01-22 21:34:33 +00:00
ent . renderfx = 0 ;
trap_R_AddRefEntityToScene ( & ent ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_DrawPlayer
= = = = = = = = = = = = = = =
*/
2013-08-16 13:43:41 +00:00
void UI_DrawPlayer ( float x , float y , float w , float h , vec3_t pOrigin , playerInfo_t * pi , int32_t time ) { //RPG-X : TiM- Origin added
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
refdef_t refdef ;
refEntity_t legs ;
refEntity_t torso ;
refEntity_t head ;
refEntity_t gun ;
refEntity_t flash ;
vec3_t origin ;
2013-08-16 12:58:47 +00:00
int32_t renderfx ;
2012-08-04 10:54:37 +00:00
vec3_t mins = { - 16 , - 24 , - 24 } ;
2012-01-22 21:34:33 +00:00
vec3_t maxs = { 16 , 16 , 32 } ;
2013-08-16 13:43:41 +00:00
float len ;
float xx ;
2012-01-22 21:34:33 +00:00
if ( ! pi - > legsModel | | ! pi - > torsoModel | | ! pi - > headModel | | ! pi - > animations [ 0 ] . numFrames ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
dp_realtime = time ;
if ( pi - > pendingWeapon ! = - 1 & & dp_realtime > pi - > weaponTimer ) {
pi - > weapon = pi - > pendingWeapon ;
pi - > lastWeapon = pi - > pendingWeapon ;
2017-09-30 19:49:00 +00:00
pi - > pendingWeapon = static_cast < weapon_t > ( - 1 ) ;
2012-01-22 21:34:33 +00:00
pi - > weaponTimer = 0 ;
2012-08-04 10:54:37 +00:00
/*if( pi->currentWeapon != pi->weapon ) {
trap_S_StartLocalSound ( trap_S_RegisterSound ( " sound/weapons/change.wav " ) , CHAN_LOCAL ) ;
} */
2012-01-22 21:34:33 +00:00
}
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 ;
2013-08-16 13:43:41 +00:00
refdef . fov_x = ( int32_t ) ( ( 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
2012-01-22 21:34:33 +00:00
xx = refdef . width / tan ( refdef . fov_x / 360 * M_PI ) ;
refdef . fov_y = atan2 ( refdef . height , xx ) ;
2012-08-04 10:54:37 +00:00
refdef . fov_y * = ( 360 / M_PI ) ;
2012-01-22 21:34:33 +00:00
// calculate distance so the player nearly fills the box
2012-08-04 10:54:37 +00:00
//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
2012-01-22 21:34:33 +00:00
refdef . time = dp_realtime ;
trap_R_ClearScene ( ) ;
2012-08-04 10:54:37 +00:00
//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
2013-08-16 12:58:47 +00:00
int32_t anim = irandom ( BOTH_STAND1_RANDOM2 , BOTH_STAND1_RANDOM11 ) ;
2012-08-04 10:54:37 +00:00
//make sure we can play this emote
if ( pi - > animations [ anim ] . numFrames > 0 ) {
UI_ForceLegsAnim ( pi , anim ) ;
UI_ForceTorsoAnim ( pi , anim ) ;
//play lower
2013-08-16 13:43:41 +00:00
pi - > legsAnimationTimer = pi - > animations [ anim ] . numFrames * pi - > animations [ anim ] . frameLerp * ( ( float ) uis . realtime / ( float ) dp_realtime ) ;
2012-08-04 10:54:37 +00:00
pi - > lowerEmoting = qtrue ;
2013-08-16 13:43:41 +00:00
pi - > torsoAnimationTimer = pi - > animations [ anim ] . numFrames * pi - > animations [ anim ] . frameLerp * ( ( float ) uis . realtime / ( float ) dp_realtime ) ;
2012-08-04 10:54:37 +00:00
pi - > upperEmoting = qtrue ;
pi - > nextEmoteTime = uis . realtime + ( irandom ( 10 , 20 ) * 1000 ) + pi - > legsAnimationTimer ;
}
else {
pi - > nextEmoteTime = uis . realtime + ( irandom ( 3 , 8 ) * 1000 ) ;
}
}
2012-01-22 21:34:33 +00:00
// 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 ) ;
2012-08-04 10:54:37 +00:00
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 ) ) ;
2012-01-22 21:34:33 +00:00
trap_R_AddRefEntityToScene ( & legs ) ;
if ( ! legs . hModel ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
//
// add the torso
//
torso . hModel = pi - > torsoModel ;
if ( ! torso . hModel ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
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 ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
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-08-04 10:54:37 +00:00
if ( pi - > currentWeapon ! = WP_0 ) {
2012-01-22 21:34:33 +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 ) {
2012-08-04 10:54:37 +00:00
UI_PlayerFloatSprite ( pi , origin , trap_R_RegisterShaderNoMip ( " sprites/chat " ) ) ;
2012-01-22 21:34:33 +00:00
}
//
// add an accent light
2012-08-04 10:54:37 +00:00
// TiM: Holy Hell. This explains why the models are washed out when overBrightBits is active. O_o
// 500 is WAY too high
2012-01-22 21:34:33 +00:00
//
origin [ 0 ] - = 100 ; // + = behind, - = in front
origin [ 1 ] + = 100 ; // + = left, - = right
origin [ 2 ] + = 100 ; // + = above, - = below
2012-08-04 10:54:37 +00:00
trap_R_AddLightToScene ( origin , 100 , 1.0 , 1.0 , 1.0 ) ; //500
2012-01-22 21:34:33 +00:00
origin [ 0 ] - = 100 ;
origin [ 1 ] - = 100 ;
origin [ 2 ] - = 100 ;
2012-08-04 10:54:37 +00:00
trap_R_AddLightToScene ( origin , 100 , 1.0 , 0.0 , 0.0 ) ;
2012-01-22 21:34:33 +00:00
trap_R_RenderScene ( & refdef ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = = =
UI_ParseAnimationFile
= = = = = = = = = = = = = = = = = = = = = =
*/
static qboolean UI_ParseAnimationFile ( const char * filename , animation_t * animations ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
char * text_p , * prev ;
2013-08-16 12:58:47 +00:00
int32_t len ;
int32_t i ;
2012-01-22 21:34:33 +00:00
char * token ;
2013-08-16 13:43:41 +00:00
float fps ;
2013-08-16 12:58:47 +00:00
int32_t skip ;
2012-01-22 21:34:33 +00:00
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 ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return qfalse ;
}
if ( len > = ( sizeof ( text ) - 1 ) ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " File %s too long \n " , filename ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
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 ) ;
2012-08-04 10:54:37 +00:00
if ( ! token [ 0 ] ) {
2012-01-22 21:34:33 +00:00
break ;
}
if ( ! Q_stricmp ( token , " footsteps " ) ) {
token = COM_Parse ( & text_p ) ;
2012-08-04 10:54:37 +00:00
if ( ! token [ 0 ] ) {
2012-01-22 21:34:33 +00:00
break ;
}
continue ;
} else if ( ! Q_stricmp ( token , " headoffset " ) ) {
for ( i = 0 ; i < 3 ; i + + ) {
token = COM_Parse ( & text_p ) ;
2012-08-04 10:54:37 +00:00
if ( ! token [ 0 ] ) {
2012-01-22 21:34:33 +00:00
break ;
}
}
continue ;
} else if ( ! Q_stricmp ( token , " sex " ) ) {
token = COM_Parse ( & text_p ) ;
2012-08-04 10:54:37 +00:00
if ( ! token [ 0 ] ) {
break ;
}
continue ;
} else if ( ! Q_stricmp ( token , " soundpath " ) ) {
token = COM_Parse ( & text_p ) ;
if ( ! token [ 0 ] ) {
2012-01-22 21:34:33 +00:00
break ;
}
continue ;
}
// if it is a number, start parsing animations
if ( token [ 0 ] > = ' 0 ' & & token [ 0 ] < = ' 9 ' ) {
text_p = prev ; // unget the token
break ;
}
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_WARN , " unknown token '%s' is %s \n " , token , filename ) ; //Reclassn this as error?
2012-01-22 21:34:33 +00:00
}
// read information for each frame
for ( i = 0 ; i < MAX_ANIMATIONS ; i + + ) {
token = COM_Parse ( & text_p ) ;
2012-08-04 10:54:37 +00:00
if ( ! token [ 0 ] ) {
2012-01-22 21:34:33 +00:00
break ;
}
animations [ i ] . firstFrame = atoi ( token ) ;
// leg only frames are adjusted to not count the upper body only frames
2012-08-04 10:54:37 +00:00
if ( i = = LEGS_KNEEL1 ) {
skip = animations [ LEGS_KNEEL1 ] . firstFrame - animations [ TORSO_ACTIVATEMEDKIT1 ] . firstFrame ;
2012-01-22 21:34:33 +00:00
}
2012-08-04 10:54:37 +00:00
if ( i > = LEGS_KNEEL1 ) {
2012-01-22 21:34:33 +00:00
animations [ i ] . firstFrame - = skip ;
}
token = COM_Parse ( & text_p ) ;
2012-08-04 10:54:37 +00:00
if ( ! token [ 0 ] ) {
2012-01-22 21:34:33 +00:00
break ;
}
animations [ i ] . numFrames = atoi ( token ) ;
token = COM_Parse ( & text_p ) ;
2012-08-04 10:54:37 +00:00
if ( ! token [ 0 ] ) {
2012-01-22 21:34:33 +00:00
break ;
}
animations [ i ] . loopFrames = atoi ( token ) ;
token = COM_Parse ( & text_p ) ;
2012-08-04 10:54:37 +00:00
if ( ! token [ 0 ] ) {
2012-01-22 21:34:33 +00:00
break ;
}
fps = atof ( token ) ;
if ( fps = = 0 ) {
fps = 1 ;
}
animations [ i ] . frameLerp = 1000 / fps ;
animations [ i ] . initialLerp = 1000 / fps ;
}
if ( i ! = MAX_ANIMATIONS ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " parsing animation file: %s " , filename ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-08-04 10:54:37 +00:00
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 ) ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
}
/*
= = = = = = = = = = = = = = = = = = = = =
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 )
{
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2017-09-30 19:49:00 +00:00
const char * skinStar ;
2012-08-04 10:54:37 +00:00
char skinSetName [ MAX_QPATH ] ;
char skinSetRoute [ MAX_QPATH ] ;
char * token ;
char * textPtr ;
char buffer [ 5000 ] ;
2013-08-16 12:58:47 +00:00
int32_t len ;
2012-08-04 10:54:37 +00:00
fileHandle_t f ;
2013-08-16 12:58:47 +00:00
int32_t n , i ;
int32_t noBlinking = trap_Cvar_VariableValue ( " cg_noBlinkingHeads " ) ;
2012-08-04 10:54:37 +00:00
if ( ( skinStar = strstr ( skinSetFrame , " * " ) ) = = NULL )
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " No '*' specified in model skin set! \n " ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
else
{
//star is at front
if ( skinStar = = skinSetFrame )
{
skinStar + + ;
Com_sprintf ( skinSetName , sizeof ( skinSetName ) , " %s%s " , skinName , skinStar ) ;
}
//star is at end
2013-08-16 12:58:47 +00:00
else if ( ( int32_t ) ( skinStar - skinSetFrame ) + 1 = = ( int32_t ) strlen ( skinSetFrame ) )
2012-08-04 10:54:37 +00:00
{
Q_strncpyz ( skinSetName , skinSetFrame , strlen ( skinSetFrame ) ) ;
Q_strcat ( skinSetName , sizeof ( skinSetName ) , skinName ) ;
}
else
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " The '*' in %s must be on either the start or end, not the middle. \n " , skinSetFrame ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
}
2013-09-05 17:18:14 +00:00
//CUI_Logger( LL_DEBUG, "skinSetName = %s \n", skinSetName );
2012-08-04 10:54:37 +00:00
Com_sprintf ( skinSetRoute , sizeof ( skinSetRoute ) , " models/players_rpgx/%s/%s.skinset " , charName , skinSetName ) ;
len = trap_FS_FOpenFile ( skinSetRoute , & f , FS_READ ) ;
if ( len < = 0 )
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Could not open file: %s \n " , skinSetRoute ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
if ( len > sizeof ( buffer ) - 1 )
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Imported file is too big for buffer: %s. Len is %i \n " , skinSetRoute , len ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
trap_FS_Read ( buffer , len , f ) ;
trap_FS_FCloseFile ( f ) ;
if ( ! buffer [ 0 ] )
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Could not import data from %s \n " , skinSetRoute ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
buffer [ len ] = ' \0 ' ;
textPtr = buffer ;
token = COM_Parse ( & textPtr ) ;
if ( Q_stricmp ( token , " { " ) )
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Skinset %s did not start with a '{' \n " , skinSetRoute ) ;
2012-08-04 10:54:37 +00:00
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
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_WARN , " Couldn't load headSkinBlink: %s \n " , token ) ;
2012-08-04 10:54:37 +00:00
}
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 )
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Minimum blink time was larger than maximum blink time. \n " ) ;
2012-08-04 10:54:37 +00:00
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 ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Couldn't load torsoSkin: %s \n " , token ) ;
2012-08-04 10:54:37 +00:00
}
continue ;
}
else if ( ! Q_stricmpn ( token , " legsSkin " , 8 ) ) {
if ( COM_ParseString ( & textPtr , & token ) ) {
continue ;
}
pi - > legsSkin = trap_R_RegisterSkin ( token ) ;
if ( ! pi - > legsSkin ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Couldn't load legsSkin: %s \n " , token ) ;
2012-08-04 10:54:37 +00:00
}
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 ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Couldn't load headSkin: %s \n " , token ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
continue ;
}
if ( ! Q_stricmpn ( token , " } " , 1 ) ) {
break ;
}
}
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-08-04 10:54:37 +00:00
fileHandle_t file ;
2013-08-16 12:58:47 +00:00
int32_t file_len ;
2012-08-04 10:54:37 +00:00
char charText [ 20000 ] ;
2012-09-10 19:26:13 +00:00
char * textPtr ;
2012-08-04 10:54:37 +00:00
char fileName [ MAX_QPATH ] ;
2013-08-16 12:58:47 +00:00
int32_t i , n ;
2012-08-04 10:54:37 +00:00
char * token ;
char legsFileRoute [ MAX_QPATH ] ;
qboolean didAnims = qfalse ;
qboolean skinSetFound = qfalse ;
//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 ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
//Another error... if text is WAY bigger than our available buffer O_O
if ( file_len > = sizeof ( charText ) - 1 ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Model Data File %s too long... WAY too long \n " , fileName ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 ] ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " No data found in model data buffer! \n " ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return qfalse ;
}
2012-08-04 10:54:37 +00:00
if ( Q_stricmp ( token , " { " ) ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Missing { in %s \n " , fileName ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
while ( 1 ) {
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 ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_WARN , " Was unable to load file %s. \n " , token ) ;
2012-08-04 10:54:37 +00:00
}
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 ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Unable to load legs model: %s \n " , token ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 ) ;
2013-09-05 17:18:14 +00:00
//UI_Logger( LL_DEBUG, "Torsomodel passed as %s, %i\n", token, (int32_t)ci->torsoModel);
2012-08-04 10:54:37 +00:00
if ( ! pi - > torsoModel ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Unable to load torso model: %s \n " , token ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Unable to load head model: %s \n " , token ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_WARN , " Unable to load bolton model: %s \n " , token ) ;
2012-08-04 10:54:37 +00:00
}
i + + ;
if ( i > MAX_BOLTONS - 1 ) {
break ;
}
}
}
2013-09-05 17:18:14 +00:00
//UI_Logger( LL_DEBUG, "Index: %i, Name: %s, Handle: %i\n", ci->boltonTags[ci->numBoltOns].modelBase, ci->boltonTags[ci->numBoltOns].tagName, ci->boltonTags[ci->numBoltOns].tagModel );
2012-08-04 10:54:37 +00:00
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 ;
}
2017-09-30 19:49:00 +00:00
pi - > hasRanks = static_cast < qboolean > ( n ) ;
2012-08-04 10:54:37 +00:00
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 ) )
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_WARN , " Could not load data from specified skin set in char: %s. Attempting to load default. \n " , charName ) ;
2012-08-04 10:54:37 +00:00
}
else
{
skinSetFound = qtrue ;
}
continue ;
}
}
if ( ! skinSetFound )
{
2012-09-10 19:26:13 +00:00
if ( ! UI_ParseSkinSetDataFile ( pi , va ( " %s_* " , modelName ) , charName , skinName ) )
2012-08-04 10:54:37 +00:00
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Tried loading default skin set, however it failed. \n " ) ;
2012-08-04 10:54:37 +00:00
}
}
//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 ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " One or more necessary model files weren't loaded from %s \n " , fileName ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
if ( ! pi - > headSkin | | ! pi - > torsoSkin | | ! pi - > legsSkin ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " One or more necessary skin files weren't loaded from %s \n " , fileName ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 :(
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Was unable to calculate location of animation.cfg for %s \n " , fileName ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
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 " ) ;
2013-09-05 17:18:14 +00:00
//UI_Logger( LL_WARN, "Failed to load animation file specified in model config, attempting to load %s\n", legsFileRoute );
2012-08-04 10:54:37 +00:00
//Parse it
if ( ! UI_ParseAnimationFile ( legsFileRoute , pi - > animations ) ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Tried loading anim data from location %s, however nothing was valid. \n " , legsFileRoute ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
}
else {
if ( ! legsFileRoute [ 0 ] ) {
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_ERROR , " Couldn't load/locate any player animation data for player: %s. \n " , charName ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
}
//holy fudgenuggets. after all that checking, we actually made it to the end and have a valid freaking
//model! OWNED!
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return qtrue ;
}
2012-08-04 10:54:37 +00:00
2012-01-22 21:34:33 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = =
UI_RegisterClientModelname
= = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2012-08-04 10:54:37 +00:00
qboolean UI_RegisterClientModelname ( playerInfo_t * pi , const char * modelSkinName ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-08-04 10:54:37 +00:00
char charName [ MAX_QPATH ] ;
2012-01-22 21:34:33 +00:00
char modelName [ MAX_QPATH ] ;
char skinName [ MAX_QPATH ] ;
2012-08-04 10:54:37 +00:00
//char filename[MAX_QPATH];
char * model , * skin ;
//char *slash;
2013-08-16 12:58:47 +00:00
int32_t len ;
2012-01-22 21:34:33 +00:00
pi - > torsoModel = 0 ;
pi - > headModel = 0 ;
if ( ! modelSkinName [ 0 ] ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return qfalse ;
}
2012-08-04 10:54:37 +00:00
Q_strncpyz ( charName , modelSkinName , sizeof ( charName ) ) ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
//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 ) ;
2013-08-16 12:58:47 +00:00
Q_strncpyz ( charName , modelSkinName , ( ( int32_t ) len - ( int32_t ) strlen ( model ) ) + 1 ) ;
2012-08-04 10:54:37 +00:00
}
2013-09-05 17:18:14 +00:00
//UI_Logger( LL_DEBUG, "%s\n", newInfo.charName);
2012-08-04 10:54:37 +00:00
//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 ) ) ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
if ( model & & ! model [ 1 ] )
{ //if we had a slash, but nothing after, clear it
* model = 0 ;
}
2012-01-22 21:34:33 +00:00
} else {
2012-08-04 10:54:37 +00:00
//*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 ] ) {
2013-08-16 12:58:47 +00:00
Q_strncpyz ( modelName , model , ( int32_t ) strlen ( model ) ) ;
2012-08-04 10:54:37 +00:00
}
}
Q_strncpyz ( skinName , " default " , sizeof ( skinName ) ) ;
if ( skin & & ! skin [ 1 ] ) {
* skin = 0 ;
}
} else {
//*skin++;
skin + + ;
2013-08-16 12:58:47 +00:00
Q_strncpyz ( modelName , model , ( ( int32_t ) len - ( int32_t ) strlen ( skin ) ) ) ;
2012-08-04 10:54:37 +00:00
Q_strncpyz ( skinName , skin , sizeof ( skinName ) ) ;
}
//Q_strncpyz( newInfo.skinName, slash + 1, sizeof( newInfo.skinName ) );
// truncate modelName
* model = 0 ;
2012-01-22 21:34:33 +00:00
}
// load cmodels before models so filecache works
2012-08-04 10:54:37 +00:00
//try loading the main model
if ( ! UI_ParseModelDataFile ( pi , charName , modelName , skinName ) )
{
2013-09-05 17:18:14 +00:00
UI_Logger ( LL_WARN , " Was unable to parse model file for character: %s/%s/%s \n " , charName , modelName , skinName ) ;
2012-08-04 10:54:37 +00:00
//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
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-08-04 10:54:37 +00:00
return qfalse ;
}
}
}
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return qtrue ;
}
/*
= = = = = = = = = = = = = = =
UI_PlayerInfo_SetModel
= = = = = = = = = = = = = = =
*/
2012-08-04 10:54:37 +00:00
void UI_PlayerInfo_SetModel ( playerInfo_t * pi , const char * model ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2012-01-22 21:34:33 +00:00
memset ( pi , 0 , sizeof ( * pi ) ) ;
2012-08-04 10:54:37 +00:00
UI_RegisterClientModelname ( pi , model ) ;
Q_strncpyz ( pi - > modelName , model , sizeof ( pi - > modelName ) ) ;
pi - > weapon = WP_0 ;
2012-01-22 21:34:33 +00:00
pi - > currentWeapon = pi - > weapon ;
pi - > lastWeapon = pi - > weapon ;
2017-09-30 19:49:00 +00:00
pi - > pendingWeapon = static_cast < weapon_t > ( - 1 ) ;
2012-01-22 21:34:33 +00:00
pi - > weaponTimer = 0 ;
pi - > chat = qfalse ;
pi - > newModel = qtrue ;
UI_PlayerInfo_SetWeapon ( pi , pi - > weapon ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}
/*
= = = = = = = = = = = = = = =
UI_PlayerInfo_SetInfo
= = = = = = = = = = = = = = =
*/
2013-08-16 13:43:41 +00:00
void UI_PlayerInfo_SetInfo ( playerInfo_t * pi , int32_t legsAnim , int32_t torsoAnim , vec3_t viewAngles , vec3_t moveAngles , weapon_t weaponNumber , float height , float weight , qboolean chat ) {
2013-09-04 15:58:49 +00:00
UI_LogFuncBegin ( ) ;
2013-08-16 12:58:47 +00:00
int32_t currentAnim ;
2012-01-22 21:34:33 +00:00
weapon_t weaponNum ;
pi - > chat = chat ;
// view angles
VectorCopy ( viewAngles , pi - > viewAngles ) ;
// move angles
VectorCopy ( moveAngles , pi - > moveAngles ) ;
2012-08-04 10:54:37 +00:00
//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 ) ;
2012-01-22 21:34:33 +00:00
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 ;
2017-09-30 19:49:00 +00:00
pi - > pendingWeapon = static_cast < weapon_t > ( - 1 ) ;
2012-01-22 21:34:33 +00:00
pi - > weaponTimer = 0 ;
UI_PlayerInfo_SetWeapon ( pi , pi - > weapon ) ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
// weapon
if ( weaponNumber = = - 1 ) {
2017-09-30 19:49:00 +00:00
pi - > pendingWeapon = static_cast < weapon_t > ( - 1 ) ;
2012-01-22 21:34:33 +00:00
pi - > weaponTimer = 0 ;
}
2012-08-04 10:54:37 +00:00
else if ( weaponNumber ! = WP_0 ) {
2012-01-22 21:34:33 +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-08-04 10:54:37 +00:00
pi - > weapon = pi - > currentWeapon = WP_0 ;
2012-01-22 21:34:33 +00:00
UI_PlayerInfo_SetWeapon ( pi , pi - > weapon ) ;
jumpHeight = 0 ;
pi - > pendingLegsAnim = 0 ;
UI_ForceLegsAnim ( pi , legsAnim ) ;
pi - > pendingTorsoAnim = 0 ;
UI_ForceTorsoAnim ( pi , torsoAnim ) ;
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
return ;
}
// leg animation
currentAnim = pi - > legsAnim & ~ ANIM_TOGGLEBIT ;
2012-08-04 10:54:37 +00:00
if ( legsAnim ! = BOTH_JUMP1 & & ( currentAnim = = BOTH_JUMP1 | | currentAnim = = BOTH_LAND1 ) ) {
2012-01-22 21:34:33 +00:00
pi - > pendingLegsAnim = legsAnim ;
}
else if ( legsAnim ! = currentAnim ) {
jumpHeight = 0 ;
pi - > pendingLegsAnim = 0 ;
UI_ForceLegsAnim ( pi , legsAnim ) ;
}
// torso animation
2012-08-04 10:54:37 +00:00
//if ( torsoAnim == TORSO_STAND || torsoAnim == TORSO_STAND2) //TiM: TORSO_STAND2
2013-09-04 15:58:49 +00:00
torsoAnim = UI_GetAnim ( ANIM_IDLE , pi - > currentWeapon , qtrue ) ;
2012-01-22 21:34:33 +00:00
2012-08-04 10:54:37 +00:00
//if ( torsoAnim == TORSO_ATTACK || torsoAnim == TORSO_ATTACK2 )
if ( torsoAnim = = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) )
{
torsoAnim = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) ;
2012-01-22 21:34:33 +00:00
pi - > muzzleFlashTime = dp_realtime + UI_TIMER_MUZZLE_FLASH ;
//FIXME play firing sound here
}
currentAnim = pi - > torsoAnim & ~ ANIM_TOGGLEBIT ;
2012-08-04 10:54:37 +00:00
if ( weaponNum ! = pi - > currentWeapon | | currentAnim = = TORSO_RAISEWEAP1 | | currentAnim = = TORSO_DROPWEAP1 ) {
2012-01-22 21:34:33 +00:00
pi - > pendingTorsoAnim = torsoAnim ;
}
2012-08-04 10:54:37 +00:00
else if ( ( /*currentAnim == TORSO_GESTURE ||*/ currentAnim = = UI_GetAnim ( ANIM_ATTACK , pi - > currentWeapon , qtrue ) ) & & ( torsoAnim ! = currentAnim ) ) {
2012-01-22 21:34:33 +00:00
pi - > pendingTorsoAnim = torsoAnim ;
}
else if ( torsoAnim ! = currentAnim ) {
pi - > pendingTorsoAnim = 0 ;
UI_ForceTorsoAnim ( pi , torsoAnim ) ;
}
2013-09-04 15:58:49 +00:00
UI_LogFuncEnd ( ) ;
2012-01-22 21:34:33 +00:00
}