mirror of
https://github.com/ioquake/jedi-academy.git
synced 2024-11-26 06:01:04 +00:00
2957 lines
73 KiB
C
2957 lines
73 KiB
C
// BG_PAnimate.c
|
|
|
|
#include "q_shared.h"
|
|
#include "bg_public.h"
|
|
#include "bg_strap.h"
|
|
#include "bg_local.h"
|
|
#include "anims.h"
|
|
#include "../cgame/animtable.h"
|
|
#ifdef QAGAME
|
|
#include "g_local.h"
|
|
#endif
|
|
|
|
#ifdef CGAME
|
|
#include "../namespace_begin.h"
|
|
extern sfxHandle_t trap_S_RegisterSound( const char *sample);
|
|
extern int trap_FX_RegisterEffect( const char *file);
|
|
#include "../namespace_end.h"
|
|
#endif
|
|
|
|
/*
|
|
==============================================================================
|
|
BEGIN: Animation utility functions (sequence checking)
|
|
==============================================================================
|
|
*/
|
|
//Called regardless of pm validity:
|
|
|
|
// VVFIXME - Most of these functions are totally stateless and stupid. Don't
|
|
// need multiple copies of this, but it's much easier (and less likely to
|
|
// break in the future) if I keep separate namespace versions now.
|
|
#include "../namespace_begin.h"
|
|
|
|
qboolean BG_SaberStanceAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_STAND1://not really a saberstance anim, actually... "saber off" stance
|
|
case BOTH_STAND2://single-saber, medium style
|
|
case BOTH_SABERFAST_STANCE://single-saber, fast style
|
|
case BOTH_SABERSLOW_STANCE://single-saber, strong style
|
|
case BOTH_SABERSTAFF_STANCE://saber staff style
|
|
case BOTH_SABERDUAL_STANCE://dual saber style
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_CrouchAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_SIT1: //# Normal chair sit.
|
|
case BOTH_SIT2: //# Lotus position.
|
|
case BOTH_SIT3: //# Sitting in tired position: elbows on knees
|
|
case BOTH_CROUCH1: //# Transition from standing to crouch
|
|
case BOTH_CROUCH1IDLE: //# Crouching idle
|
|
case BOTH_CROUCH1WALK: //# Walking while crouched
|
|
case BOTH_CROUCH1WALKBACK: //# Walking while crouched
|
|
case BOTH_CROUCH2TOSTAND1: //# going from crouch2 to stand1
|
|
case BOTH_CROUCH3: //# Desann crouching down to Kyle (cin 9)
|
|
case BOTH_KNEES1: //# Tavion on her knees
|
|
case BOTH_CROUCHATTACKBACK1://FIXME: not if in middle of anim?
|
|
case BOTH_ROLL_STAB:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InSpecialJump( int anim )
|
|
{
|
|
switch ( (anim) )
|
|
{
|
|
case BOTH_WALL_RUN_RIGHT:
|
|
case BOTH_WALL_RUN_RIGHT_STOP:
|
|
case BOTH_WALL_RUN_RIGHT_FLIP:
|
|
case BOTH_WALL_RUN_LEFT:
|
|
case BOTH_WALL_RUN_LEFT_STOP:
|
|
case BOTH_WALL_RUN_LEFT_FLIP:
|
|
case BOTH_WALL_FLIP_RIGHT:
|
|
case BOTH_WALL_FLIP_LEFT:
|
|
case BOTH_FLIP_BACK1:
|
|
case BOTH_FLIP_BACK2:
|
|
case BOTH_FLIP_BACK3:
|
|
case BOTH_WALL_FLIP_BACK1:
|
|
case BOTH_BUTTERFLY_LEFT:
|
|
case BOTH_BUTTERFLY_RIGHT:
|
|
case BOTH_BUTTERFLY_FL1:
|
|
case BOTH_BUTTERFLY_FR1:
|
|
case BOTH_FJSS_TR_BL:
|
|
case BOTH_FJSS_TL_BR:
|
|
case BOTH_FORCELEAP2_T__B_:
|
|
case BOTH_JUMPFLIPSLASHDOWN1://#
|
|
case BOTH_JUMPFLIPSTABDOWN://#
|
|
case BOTH_JUMPATTACK6:
|
|
case BOTH_JUMPATTACK7:
|
|
case BOTH_ARIAL_LEFT:
|
|
case BOTH_ARIAL_RIGHT:
|
|
case BOTH_ARIAL_F1:
|
|
case BOTH_CARTWHEEL_LEFT:
|
|
case BOTH_CARTWHEEL_RIGHT:
|
|
|
|
case BOTH_FORCELONGLEAP_START:
|
|
case BOTH_FORCELONGLEAP_ATTACK:
|
|
case BOTH_FORCEWALLRUNFLIP_START:
|
|
case BOTH_FORCEWALLRUNFLIP_END:
|
|
case BOTH_FORCEWALLRUNFLIP_ALT:
|
|
case BOTH_FLIP_ATTACK7:
|
|
case BOTH_FLIP_HOLD7:
|
|
case BOTH_FLIP_LAND:
|
|
case BOTH_A7_SOULCAL:
|
|
return qtrue;
|
|
}
|
|
if ( BG_InReboundJump( anim ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
if ( BG_InReboundHold( anim ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
if ( BG_InReboundRelease( anim ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
if ( BG_InBackFlip( anim ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InSaberStandAnim( int anim )
|
|
{
|
|
switch ( (anim) )
|
|
{
|
|
case BOTH_SABERFAST_STANCE:
|
|
case BOTH_STAND2:
|
|
case BOTH_SABERSLOW_STANCE:
|
|
case BOTH_SABERDUAL_STANCE:
|
|
case BOTH_SABERSTAFF_STANCE:
|
|
return qtrue;
|
|
default:
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean BG_InReboundJump( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_FORCEWALLREBOUND_FORWARD:
|
|
case BOTH_FORCEWALLREBOUND_LEFT:
|
|
case BOTH_FORCEWALLREBOUND_BACK:
|
|
case BOTH_FORCEWALLREBOUND_RIGHT:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InReboundHold( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_FORCEWALLHOLD_FORWARD:
|
|
case BOTH_FORCEWALLHOLD_LEFT:
|
|
case BOTH_FORCEWALLHOLD_BACK:
|
|
case BOTH_FORCEWALLHOLD_RIGHT:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InReboundRelease( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_FORCEWALLRELEASE_FORWARD:
|
|
case BOTH_FORCEWALLRELEASE_LEFT:
|
|
case BOTH_FORCEWALLRELEASE_BACK:
|
|
case BOTH_FORCEWALLRELEASE_RIGHT:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InBackFlip( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_FLIP_BACK1:
|
|
case BOTH_FLIP_BACK2:
|
|
case BOTH_FLIP_BACK3:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_DirectFlippingAnim( int anim )
|
|
{
|
|
switch ( (anim) )
|
|
{
|
|
case BOTH_FLIP_F: //# Flip forward
|
|
case BOTH_FLIP_B: //# Flip backwards
|
|
case BOTH_FLIP_L: //# Flip left
|
|
case BOTH_FLIP_R: //# Flip right
|
|
return qtrue;
|
|
break;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SaberInAttack( int move )
|
|
{
|
|
if ( move >= LS_A_TL2BR && move <= LS_A_T2B )
|
|
{
|
|
return qtrue;
|
|
}
|
|
switch ( move )
|
|
{
|
|
case LS_A_BACK:
|
|
case LS_A_BACK_CR:
|
|
case LS_A_BACKSTAB:
|
|
case LS_ROLL_STAB:
|
|
case LS_A_LUNGE:
|
|
case LS_A_JUMP_T__B_:
|
|
case LS_A_FLIP_STAB:
|
|
case LS_A_FLIP_SLASH:
|
|
case LS_JUMPATTACK_DUAL:
|
|
case LS_JUMPATTACK_ARIAL_LEFT:
|
|
case LS_JUMPATTACK_ARIAL_RIGHT:
|
|
case LS_JUMPATTACK_CART_LEFT:
|
|
case LS_JUMPATTACK_CART_RIGHT:
|
|
case LS_JUMPATTACK_STAFF_LEFT:
|
|
case LS_JUMPATTACK_STAFF_RIGHT:
|
|
case LS_BUTTERFLY_LEFT:
|
|
case LS_BUTTERFLY_RIGHT:
|
|
case LS_A_BACKFLIP_ATK:
|
|
case LS_SPINATTACK_DUAL:
|
|
case LS_SPINATTACK:
|
|
case LS_LEAP_ATTACK:
|
|
case LS_SWOOP_ATTACK_RIGHT:
|
|
case LS_SWOOP_ATTACK_LEFT:
|
|
case LS_TAUNTAUN_ATTACK_RIGHT:
|
|
case LS_TAUNTAUN_ATTACK_LEFT:
|
|
case LS_KICK_F:
|
|
case LS_KICK_B:
|
|
case LS_KICK_R:
|
|
case LS_KICK_L:
|
|
case LS_KICK_S:
|
|
case LS_KICK_BF:
|
|
case LS_KICK_RL:
|
|
case LS_KICK_F_AIR:
|
|
case LS_KICK_B_AIR:
|
|
case LS_KICK_R_AIR:
|
|
case LS_KICK_L_AIR:
|
|
case LS_STABDOWN:
|
|
case LS_STABDOWN_STAFF:
|
|
case LS_STABDOWN_DUAL:
|
|
case LS_DUAL_SPIN_PROTECT:
|
|
case LS_STAFF_SOULCAL:
|
|
case LS_A1_SPECIAL:
|
|
case LS_A2_SPECIAL:
|
|
case LS_A3_SPECIAL:
|
|
case LS_UPSIDE_DOWN_ATTACK:
|
|
case LS_PULL_ATTACK_STAB:
|
|
case LS_PULL_ATTACK_SWING:
|
|
case LS_SPINATTACK_ALORA:
|
|
case LS_DUAL_FB:
|
|
case LS_DUAL_LR:
|
|
case LS_HILT_BASH:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SaberInKata( int saberMove )
|
|
{
|
|
switch ( saberMove )
|
|
{
|
|
case LS_A1_SPECIAL:
|
|
case LS_A2_SPECIAL:
|
|
case LS_A3_SPECIAL:
|
|
case LS_DUAL_SPIN_PROTECT:
|
|
case LS_STAFF_SOULCAL:
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InKataAnim(int anim)
|
|
{
|
|
switch (anim)
|
|
{
|
|
case BOTH_A6_SABERPROTECT:
|
|
case BOTH_A7_SOULCAL:
|
|
case BOTH_A1_SPECIAL:
|
|
case BOTH_A2_SPECIAL:
|
|
case BOTH_A3_SPECIAL:
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SaberInSpecial( int move )
|
|
{
|
|
switch( move )
|
|
{
|
|
case LS_A_BACK:
|
|
case LS_A_BACK_CR:
|
|
case LS_A_BACKSTAB:
|
|
case LS_ROLL_STAB:
|
|
case LS_A_LUNGE:
|
|
case LS_A_JUMP_T__B_:
|
|
case LS_A_FLIP_STAB:
|
|
case LS_A_FLIP_SLASH:
|
|
case LS_JUMPATTACK_DUAL:
|
|
case LS_JUMPATTACK_ARIAL_LEFT:
|
|
case LS_JUMPATTACK_ARIAL_RIGHT:
|
|
case LS_JUMPATTACK_CART_LEFT:
|
|
case LS_JUMPATTACK_CART_RIGHT:
|
|
case LS_JUMPATTACK_STAFF_LEFT:
|
|
case LS_JUMPATTACK_STAFF_RIGHT:
|
|
case LS_BUTTERFLY_LEFT:
|
|
case LS_BUTTERFLY_RIGHT:
|
|
case LS_A_BACKFLIP_ATK:
|
|
case LS_SPINATTACK_DUAL:
|
|
case LS_SPINATTACK:
|
|
case LS_LEAP_ATTACK:
|
|
case LS_SWOOP_ATTACK_RIGHT:
|
|
case LS_SWOOP_ATTACK_LEFT:
|
|
case LS_TAUNTAUN_ATTACK_RIGHT:
|
|
case LS_TAUNTAUN_ATTACK_LEFT:
|
|
case LS_KICK_F:
|
|
case LS_KICK_B:
|
|
case LS_KICK_R:
|
|
case LS_KICK_L:
|
|
case LS_KICK_S:
|
|
case LS_KICK_BF:
|
|
case LS_KICK_RL:
|
|
case LS_KICK_F_AIR:
|
|
case LS_KICK_B_AIR:
|
|
case LS_KICK_R_AIR:
|
|
case LS_KICK_L_AIR:
|
|
case LS_STABDOWN:
|
|
case LS_STABDOWN_STAFF:
|
|
case LS_STABDOWN_DUAL:
|
|
case LS_DUAL_SPIN_PROTECT:
|
|
case LS_STAFF_SOULCAL:
|
|
case LS_A1_SPECIAL:
|
|
case LS_A2_SPECIAL:
|
|
case LS_A3_SPECIAL:
|
|
case LS_UPSIDE_DOWN_ATTACK:
|
|
case LS_PULL_ATTACK_STAB:
|
|
case LS_PULL_ATTACK_SWING:
|
|
case LS_SPINATTACK_ALORA:
|
|
case LS_DUAL_FB:
|
|
case LS_DUAL_LR:
|
|
case LS_HILT_BASH:
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_KickMove( int move )
|
|
{
|
|
switch( move )
|
|
{
|
|
case LS_KICK_F:
|
|
case LS_KICK_B:
|
|
case LS_KICK_R:
|
|
case LS_KICK_L:
|
|
case LS_KICK_S:
|
|
case LS_KICK_BF:
|
|
case LS_KICK_RL:
|
|
case LS_KICK_F_AIR:
|
|
case LS_KICK_B_AIR:
|
|
case LS_KICK_R_AIR:
|
|
case LS_KICK_L_AIR:
|
|
case LS_HILT_BASH:
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SaberInIdle( int move )
|
|
{
|
|
switch ( move )
|
|
{
|
|
case LS_NONE:
|
|
case LS_READY:
|
|
case LS_DRAW:
|
|
case LS_PUTAWAY:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InExtraDefenseSaberMove( int move )
|
|
{
|
|
switch ( move )
|
|
{
|
|
case LS_SPINATTACK_DUAL:
|
|
case LS_SPINATTACK:
|
|
case LS_DUAL_SPIN_PROTECT:
|
|
case LS_STAFF_SOULCAL:
|
|
case LS_A1_SPECIAL:
|
|
case LS_A2_SPECIAL:
|
|
case LS_A3_SPECIAL:
|
|
case LS_JUMPATTACK_DUAL:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_FlippingAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_FLIP_F: //# Flip forward
|
|
case BOTH_FLIP_B: //# Flip backwards
|
|
case BOTH_FLIP_L: //# Flip left
|
|
case BOTH_FLIP_R: //# Flip right
|
|
case BOTH_WALL_RUN_RIGHT_FLIP:
|
|
case BOTH_WALL_RUN_LEFT_FLIP:
|
|
case BOTH_WALL_FLIP_RIGHT:
|
|
case BOTH_WALL_FLIP_LEFT:
|
|
case BOTH_FLIP_BACK1:
|
|
case BOTH_FLIP_BACK2:
|
|
case BOTH_FLIP_BACK3:
|
|
case BOTH_WALL_FLIP_BACK1:
|
|
//Not really flips, but...
|
|
case BOTH_WALL_RUN_RIGHT:
|
|
case BOTH_WALL_RUN_LEFT:
|
|
case BOTH_WALL_RUN_RIGHT_STOP:
|
|
case BOTH_WALL_RUN_LEFT_STOP:
|
|
case BOTH_BUTTERFLY_LEFT:
|
|
case BOTH_BUTTERFLY_RIGHT:
|
|
case BOTH_BUTTERFLY_FL1:
|
|
case BOTH_BUTTERFLY_FR1:
|
|
//
|
|
case BOTH_ARIAL_LEFT:
|
|
case BOTH_ARIAL_RIGHT:
|
|
case BOTH_ARIAL_F1:
|
|
case BOTH_CARTWHEEL_LEFT:
|
|
case BOTH_CARTWHEEL_RIGHT:
|
|
case BOTH_JUMPFLIPSLASHDOWN1:
|
|
case BOTH_JUMPFLIPSTABDOWN:
|
|
case BOTH_JUMPATTACK6:
|
|
case BOTH_JUMPATTACK7:
|
|
//JKA
|
|
case BOTH_FORCEWALLRUNFLIP_END:
|
|
case BOTH_FORCEWALLRUNFLIP_ALT:
|
|
case BOTH_FLIP_ATTACK7:
|
|
case BOTH_A7_SOULCAL:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SpinningSaberAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
//level 1 - FIXME: level 1 will have *no* spins
|
|
case BOTH_T1_BR_BL:
|
|
case BOTH_T1__R__L:
|
|
case BOTH_T1__R_BL:
|
|
case BOTH_T1_TR_BL:
|
|
case BOTH_T1_BR_TL:
|
|
case BOTH_T1_BR__L:
|
|
case BOTH_T1_TL_BR:
|
|
case BOTH_T1__L_BR:
|
|
case BOTH_T1__L__R:
|
|
case BOTH_T1_BL_BR:
|
|
case BOTH_T1_BL__R:
|
|
case BOTH_T1_BL_TR:
|
|
//level 2
|
|
case BOTH_T2_BR__L:
|
|
case BOTH_T2_BR_BL:
|
|
case BOTH_T2__R_BL:
|
|
case BOTH_T2__L_BR:
|
|
case BOTH_T2_BL_BR:
|
|
case BOTH_T2_BL__R:
|
|
//level 3
|
|
case BOTH_T3_BR__L:
|
|
case BOTH_T3_BR_BL:
|
|
case BOTH_T3__R_BL:
|
|
case BOTH_T3__L_BR:
|
|
case BOTH_T3_BL_BR:
|
|
case BOTH_T3_BL__R:
|
|
//level 4
|
|
case BOTH_T4_BR__L:
|
|
case BOTH_T4_BR_BL:
|
|
case BOTH_T4__R_BL:
|
|
case BOTH_T4__L_BR:
|
|
case BOTH_T4_BL_BR:
|
|
case BOTH_T4_BL__R:
|
|
//level 5
|
|
case BOTH_T5_BR_BL:
|
|
case BOTH_T5__R__L:
|
|
case BOTH_T5__R_BL:
|
|
case BOTH_T5_TR_BL:
|
|
case BOTH_T5_BR_TL:
|
|
case BOTH_T5_BR__L:
|
|
case BOTH_T5_TL_BR:
|
|
case BOTH_T5__L_BR:
|
|
case BOTH_T5__L__R:
|
|
case BOTH_T5_BL_BR:
|
|
case BOTH_T5_BL__R:
|
|
case BOTH_T5_BL_TR:
|
|
//level 6
|
|
case BOTH_T6_BR_TL:
|
|
case BOTH_T6__R_TL:
|
|
case BOTH_T6__R__L:
|
|
case BOTH_T6__R_BL:
|
|
case BOTH_T6_TR_TL:
|
|
case BOTH_T6_TR__L:
|
|
case BOTH_T6_TR_BL:
|
|
case BOTH_T6_T__TL:
|
|
case BOTH_T6_T__BL:
|
|
case BOTH_T6_TL_BR:
|
|
case BOTH_T6__L_BR:
|
|
case BOTH_T6__L__R:
|
|
case BOTH_T6_TL__R:
|
|
case BOTH_T6_TL_TR:
|
|
case BOTH_T6__L_TR:
|
|
case BOTH_T6__L_T_:
|
|
case BOTH_T6_BL_T_:
|
|
case BOTH_T6_BR__L:
|
|
case BOTH_T6_BR_BL:
|
|
case BOTH_T6_BL_BR:
|
|
case BOTH_T6_BL__R:
|
|
case BOTH_T6_BL_TR:
|
|
//level 7
|
|
case BOTH_T7_BR_TL:
|
|
case BOTH_T7_BR__L:
|
|
case BOTH_T7_BR_BL:
|
|
case BOTH_T7__R__L:
|
|
case BOTH_T7__R_BL:
|
|
case BOTH_T7_TR__L:
|
|
case BOTH_T7_T___R:
|
|
case BOTH_T7_TL_BR:
|
|
case BOTH_T7__L_BR:
|
|
case BOTH_T7__L__R:
|
|
case BOTH_T7_BL_BR:
|
|
case BOTH_T7_BL__R:
|
|
case BOTH_T7_BL_TR:
|
|
case BOTH_T7_TL_TR:
|
|
case BOTH_T7_T__BR:
|
|
case BOTH_T7__L_TR:
|
|
case BOTH_V7_BL_S7:
|
|
//special
|
|
//case BOTH_A2_STABBACK1:
|
|
case BOTH_ATTACK_BACK:
|
|
case BOTH_CROUCHATTACKBACK1:
|
|
case BOTH_BUTTERFLY_LEFT:
|
|
case BOTH_BUTTERFLY_RIGHT:
|
|
case BOTH_FJSS_TR_BL:
|
|
case BOTH_FJSS_TL_BR:
|
|
case BOTH_JUMPFLIPSLASHDOWN1:
|
|
case BOTH_JUMPFLIPSTABDOWN:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SaberInSpecialAttack( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_A2_STABBACK1:
|
|
case BOTH_ATTACK_BACK:
|
|
case BOTH_CROUCHATTACKBACK1:
|
|
case BOTH_ROLL_STAB:
|
|
case BOTH_BUTTERFLY_LEFT:
|
|
case BOTH_BUTTERFLY_RIGHT:
|
|
case BOTH_BUTTERFLY_FL1:
|
|
case BOTH_BUTTERFLY_FR1:
|
|
case BOTH_FJSS_TR_BL:
|
|
case BOTH_FJSS_TL_BR:
|
|
case BOTH_LUNGE2_B__T_:
|
|
case BOTH_FORCELEAP2_T__B_:
|
|
case BOTH_JUMPFLIPSLASHDOWN1://#
|
|
case BOTH_JUMPFLIPSTABDOWN://#
|
|
case BOTH_JUMPATTACK6:
|
|
case BOTH_JUMPATTACK7:
|
|
case BOTH_SPINATTACK6:
|
|
case BOTH_SPINATTACK7:
|
|
case BOTH_FORCELONGLEAP_ATTACK:
|
|
case BOTH_VS_ATR_S:
|
|
case BOTH_VS_ATL_S:
|
|
case BOTH_VT_ATR_S:
|
|
case BOTH_VT_ATL_S:
|
|
case BOTH_A7_KICK_F:
|
|
case BOTH_A7_KICK_B:
|
|
case BOTH_A7_KICK_R:
|
|
case BOTH_A7_KICK_L:
|
|
case BOTH_A7_KICK_S:
|
|
case BOTH_A7_KICK_BF:
|
|
case BOTH_A7_KICK_RL:
|
|
case BOTH_A7_KICK_F_AIR:
|
|
case BOTH_A7_KICK_B_AIR:
|
|
case BOTH_A7_KICK_R_AIR:
|
|
case BOTH_A7_KICK_L_AIR:
|
|
case BOTH_STABDOWN:
|
|
case BOTH_STABDOWN_STAFF:
|
|
case BOTH_STABDOWN_DUAL:
|
|
case BOTH_A6_SABERPROTECT:
|
|
case BOTH_A7_SOULCAL:
|
|
case BOTH_A1_SPECIAL:
|
|
case BOTH_A2_SPECIAL:
|
|
case BOTH_A3_SPECIAL:
|
|
case BOTH_FLIP_ATTACK7:
|
|
case BOTH_PULL_IMPALE_STAB:
|
|
case BOTH_PULL_IMPALE_SWING:
|
|
case BOTH_ALORA_SPIN_SLASH:
|
|
case BOTH_A6_FB:
|
|
case BOTH_A6_LR:
|
|
case BOTH_A7_HILT:
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_KickingAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_A7_KICK_F:
|
|
case BOTH_A7_KICK_B:
|
|
case BOTH_A7_KICK_R:
|
|
case BOTH_A7_KICK_L:
|
|
case BOTH_A7_KICK_S:
|
|
case BOTH_A7_KICK_BF:
|
|
case BOTH_A7_KICK_RL:
|
|
case BOTH_A7_KICK_F_AIR:
|
|
case BOTH_A7_KICK_B_AIR:
|
|
case BOTH_A7_KICK_R_AIR:
|
|
case BOTH_A7_KICK_L_AIR:
|
|
case BOTH_A7_HILT:
|
|
//NOT kicks, but do kick traces anyway
|
|
case BOTH_GETUP_BROLL_B:
|
|
case BOTH_GETUP_BROLL_F:
|
|
case BOTH_GETUP_FROLL_B:
|
|
case BOTH_GETUP_FROLL_F:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
int BG_InGrappleMove(int anim)
|
|
{
|
|
switch (anim)
|
|
{
|
|
case BOTH_KYLE_GRAB:
|
|
case BOTH_KYLE_MISS:
|
|
return 1; //grabbing at someone
|
|
case BOTH_KYLE_PA_1:
|
|
case BOTH_KYLE_PA_2:
|
|
return 2; //beating the shit out of someone
|
|
case BOTH_PLAYER_PA_1:
|
|
case BOTH_PLAYER_PA_2:
|
|
case BOTH_PLAYER_PA_FLY:
|
|
return 3; //getting the shit beaten out of you
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int BG_BrokenParryForAttack( int move )
|
|
{
|
|
//Our attack was knocked away by a knockaway parry
|
|
//FIXME: need actual anims for this
|
|
//FIXME: need to know which side of the saber was hit! For now, we presume the saber gets knocked away from the center
|
|
switch ( saberMoveData[move].startQuad )
|
|
{
|
|
case Q_B:
|
|
return LS_V1_B_;
|
|
break;
|
|
case Q_BR:
|
|
return LS_V1_BR;
|
|
break;
|
|
case Q_R:
|
|
return LS_V1__R;
|
|
break;
|
|
case Q_TR:
|
|
return LS_V1_TR;
|
|
break;
|
|
case Q_T:
|
|
return LS_V1_T_;
|
|
break;
|
|
case Q_TL:
|
|
return LS_V1_TL;
|
|
break;
|
|
case Q_L:
|
|
return LS_V1__L;
|
|
break;
|
|
case Q_BL:
|
|
return LS_V1_BL;
|
|
break;
|
|
}
|
|
return LS_NONE;
|
|
}
|
|
|
|
int BG_BrokenParryForParry( int move )
|
|
{
|
|
//FIXME: need actual anims for this
|
|
//FIXME: need to know which side of the saber was hit! For now, we presume the saber gets knocked away from the center
|
|
switch ( move )
|
|
{
|
|
case LS_PARRY_UP:
|
|
//Hmm... since we don't know what dir the hit came from, randomly pick knock down or knock back
|
|
if ( Q_irand( 0, 1 ) )
|
|
{
|
|
return LS_H1_B_;
|
|
}
|
|
else
|
|
{
|
|
return LS_H1_T_;
|
|
}
|
|
break;
|
|
case LS_PARRY_UR:
|
|
return LS_H1_TR;
|
|
break;
|
|
case LS_PARRY_UL:
|
|
return LS_H1_TL;
|
|
break;
|
|
case LS_PARRY_LR:
|
|
return LS_H1_BR;
|
|
break;
|
|
case LS_PARRY_LL:
|
|
return LS_H1_BL;
|
|
break;
|
|
case LS_READY:
|
|
return LS_H1_B_;//???
|
|
break;
|
|
}
|
|
return LS_NONE;
|
|
}
|
|
|
|
int BG_KnockawayForParry( int move )
|
|
{
|
|
//FIXME: need actual anims for this
|
|
//FIXME: need to know which side of the saber was hit! For now, we presume the saber gets knocked away from the center
|
|
switch ( move )
|
|
{
|
|
case BLOCKED_TOP://LS_PARRY_UP:
|
|
return LS_K1_T_;//push up
|
|
break;
|
|
case BLOCKED_UPPER_RIGHT://LS_PARRY_UR:
|
|
default://case LS_READY:
|
|
return LS_K1_TR;//push up, slightly to right
|
|
break;
|
|
case BLOCKED_UPPER_LEFT://LS_PARRY_UL:
|
|
return LS_K1_TL;//push up and to left
|
|
break;
|
|
case BLOCKED_LOWER_RIGHT://LS_PARRY_LR:
|
|
return LS_K1_BR;//push down and to left
|
|
break;
|
|
case BLOCKED_LOWER_LEFT://LS_PARRY_LL:
|
|
return LS_K1_BL;//push down and to right
|
|
break;
|
|
}
|
|
//return LS_NONE;
|
|
}
|
|
|
|
qboolean BG_InRoll( playerState_t *ps, int anim )
|
|
{
|
|
switch ( (anim) )
|
|
{
|
|
case BOTH_GETUP_BROLL_B:
|
|
case BOTH_GETUP_BROLL_F:
|
|
case BOTH_GETUP_BROLL_L:
|
|
case BOTH_GETUP_BROLL_R:
|
|
case BOTH_GETUP_FROLL_B:
|
|
case BOTH_GETUP_FROLL_F:
|
|
case BOTH_GETUP_FROLL_L:
|
|
case BOTH_GETUP_FROLL_R:
|
|
case BOTH_ROLL_F:
|
|
case BOTH_ROLL_B:
|
|
case BOTH_ROLL_R:
|
|
case BOTH_ROLL_L:
|
|
if ( ps->legsTimer > 0 )
|
|
{
|
|
return qtrue;
|
|
}
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InSpecialDeathAnim( int anim )
|
|
{
|
|
switch( anim )
|
|
{
|
|
case BOTH_DEATH_ROLL: //# Death anim from a roll
|
|
case BOTH_DEATH_FLIP: //# Death anim from a flip
|
|
case BOTH_DEATH_SPIN_90_R: //# Death anim when facing 90 degrees right
|
|
case BOTH_DEATH_SPIN_90_L: //# Death anim when facing 90 degrees left
|
|
case BOTH_DEATH_SPIN_180: //# Death anim when facing backwards
|
|
case BOTH_DEATH_LYING_UP: //# Death anim when lying on back
|
|
case BOTH_DEATH_LYING_DN: //# Death anim when lying on front
|
|
case BOTH_DEATH_FALLING_DN: //# Death anim when falling on face
|
|
case BOTH_DEATH_FALLING_UP: //# Death anim when falling on back
|
|
case BOTH_DEATH_CROUCHED: //# Death anim when crouched
|
|
return qtrue;
|
|
break;
|
|
default:
|
|
return qfalse;
|
|
break;
|
|
}
|
|
}
|
|
|
|
qboolean BG_InDeathAnim ( int anim )
|
|
{//Purposely does not cover stumbledeath and falldeath...
|
|
switch( anim )
|
|
{
|
|
case BOTH_DEATH1: //# First Death anim
|
|
case BOTH_DEATH2: //# Second Death anim
|
|
case BOTH_DEATH3: //# Third Death anim
|
|
case BOTH_DEATH4: //# Fourth Death anim
|
|
case BOTH_DEATH5: //# Fifth Death anim
|
|
case BOTH_DEATH6: //# Sixth Death anim
|
|
case BOTH_DEATH7: //# Seventh Death anim
|
|
case BOTH_DEATH8: //#
|
|
case BOTH_DEATH9: //#
|
|
case BOTH_DEATH10: //#
|
|
case BOTH_DEATH11: //#
|
|
case BOTH_DEATH12: //#
|
|
case BOTH_DEATH13: //#
|
|
case BOTH_DEATH14: //#
|
|
case BOTH_DEATH14_UNGRIP: //# Desann's end death (cin #35)
|
|
case BOTH_DEATH14_SITUP: //# Tavion sitting up after having been thrown (cin #23)
|
|
case BOTH_DEATH15: //#
|
|
case BOTH_DEATH16: //#
|
|
case BOTH_DEATH17: //#
|
|
case BOTH_DEATH18: //#
|
|
case BOTH_DEATH19: //#
|
|
case BOTH_DEATH20: //#
|
|
case BOTH_DEATH21: //#
|
|
case BOTH_DEATH22: //#
|
|
case BOTH_DEATH23: //#
|
|
case BOTH_DEATH24: //#
|
|
case BOTH_DEATH25: //#
|
|
|
|
case BOTH_DEATHFORWARD1: //# First Death in which they get thrown forward
|
|
case BOTH_DEATHFORWARD2: //# Second Death in which they get thrown forward
|
|
case BOTH_DEATHFORWARD3: //# Tavion's falling in cin# 23
|
|
case BOTH_DEATHBACKWARD1: //# First Death in which they get thrown backward
|
|
case BOTH_DEATHBACKWARD2: //# Second Death in which they get thrown backward
|
|
|
|
case BOTH_DEATH1IDLE: //# Idle while close to death
|
|
case BOTH_LYINGDEATH1: //# Death to play when killed lying down
|
|
case BOTH_STUMBLEDEATH1: //# Stumble forward and fall face first death
|
|
case BOTH_FALLDEATH1: //# Fall forward off a high cliff and splat death - start
|
|
case BOTH_FALLDEATH1INAIR: //# Fall forward off a high cliff and splat death - loop
|
|
case BOTH_FALLDEATH1LAND: //# Fall forward off a high cliff and splat death - hit bottom
|
|
//# #sep case BOTH_ DEAD POSES # Should be last frame of corresponding previous anims
|
|
case BOTH_DEAD1: //# First Death finished pose
|
|
case BOTH_DEAD2: //# Second Death finished pose
|
|
case BOTH_DEAD3: //# Third Death finished pose
|
|
case BOTH_DEAD4: //# Fourth Death finished pose
|
|
case BOTH_DEAD5: //# Fifth Death finished pose
|
|
case BOTH_DEAD6: //# Sixth Death finished pose
|
|
case BOTH_DEAD7: //# Seventh Death finished pose
|
|
case BOTH_DEAD8: //#
|
|
case BOTH_DEAD9: //#
|
|
case BOTH_DEAD10: //#
|
|
case BOTH_DEAD11: //#
|
|
case BOTH_DEAD12: //#
|
|
case BOTH_DEAD13: //#
|
|
case BOTH_DEAD14: //#
|
|
case BOTH_DEAD15: //#
|
|
case BOTH_DEAD16: //#
|
|
case BOTH_DEAD17: //#
|
|
case BOTH_DEAD18: //#
|
|
case BOTH_DEAD19: //#
|
|
case BOTH_DEAD20: //#
|
|
case BOTH_DEAD21: //#
|
|
case BOTH_DEAD22: //#
|
|
case BOTH_DEAD23: //#
|
|
case BOTH_DEAD24: //#
|
|
case BOTH_DEAD25: //#
|
|
case BOTH_DEADFORWARD1: //# First thrown forward death finished pose
|
|
case BOTH_DEADFORWARD2: //# Second thrown forward death finished pose
|
|
case BOTH_DEADBACKWARD1: //# First thrown backward death finished pose
|
|
case BOTH_DEADBACKWARD2: //# Second thrown backward death finished pose
|
|
case BOTH_LYINGDEAD1: //# Killed lying down death finished pose
|
|
case BOTH_STUMBLEDEAD1: //# Stumble forward death finished pose
|
|
case BOTH_FALLDEAD1LAND: //# Fall forward and splat death finished pose
|
|
//# #sep case BOTH_ DEAD TWITCH/FLOP # React to being shot from death poses
|
|
case BOTH_DEADFLOP1: //# React to being shot from First Death finished pose
|
|
case BOTH_DEADFLOP2: //# React to being shot from Second Death finished pose
|
|
case BOTH_DISMEMBER_HEAD1: //#
|
|
case BOTH_DISMEMBER_TORSO1: //#
|
|
case BOTH_DISMEMBER_LLEG: //#
|
|
case BOTH_DISMEMBER_RLEG: //#
|
|
case BOTH_DISMEMBER_RARM: //#
|
|
case BOTH_DISMEMBER_LARM: //#
|
|
return qtrue;
|
|
break;
|
|
default:
|
|
return BG_InSpecialDeathAnim( anim );
|
|
break;
|
|
}
|
|
}
|
|
|
|
qboolean BG_InKnockDownOnly( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_KNOCKDOWN1:
|
|
case BOTH_KNOCKDOWN2:
|
|
case BOTH_KNOCKDOWN3:
|
|
case BOTH_KNOCKDOWN4:
|
|
case BOTH_KNOCKDOWN5:
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InSaberLockOld( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_BF2LOCK:
|
|
case BOTH_BF1LOCK:
|
|
case BOTH_CWCIRCLELOCK:
|
|
case BOTH_CCWCIRCLELOCK:
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InSaberLock( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_LK_S_DL_S_L_1: //lock if I'm using single vs. a dual
|
|
case BOTH_LK_S_DL_T_L_1: //lock if I'm using single vs. a dual
|
|
case BOTH_LK_S_ST_S_L_1: //lock if I'm using single vs. a staff
|
|
case BOTH_LK_S_ST_T_L_1: //lock if I'm using single vs. a staff
|
|
case BOTH_LK_S_S_S_L_1: //lock if I'm using single vs. a single and I initiated
|
|
case BOTH_LK_S_S_T_L_1: //lock if I'm using single vs. a single and I initiated
|
|
case BOTH_LK_DL_DL_S_L_1: //lock if I'm using dual vs. dual and I initiated
|
|
case BOTH_LK_DL_DL_T_L_1: //lock if I'm using dual vs. dual and I initiated
|
|
case BOTH_LK_DL_ST_S_L_1: //lock if I'm using dual vs. a staff
|
|
case BOTH_LK_DL_ST_T_L_1: //lock if I'm using dual vs. a staff
|
|
case BOTH_LK_DL_S_S_L_1: //lock if I'm using dual vs. a single
|
|
case BOTH_LK_DL_S_T_L_1: //lock if I'm using dual vs. a single
|
|
case BOTH_LK_ST_DL_S_L_1: //lock if I'm using staff vs. dual
|
|
case BOTH_LK_ST_DL_T_L_1: //lock if I'm using staff vs. dual
|
|
case BOTH_LK_ST_ST_S_L_1: //lock if I'm using staff vs. a staff and I initiated
|
|
case BOTH_LK_ST_ST_T_L_1: //lock if I'm using staff vs. a staff and I initiated
|
|
case BOTH_LK_ST_S_S_L_1: //lock if I'm using staff vs. a single
|
|
case BOTH_LK_ST_S_T_L_1: //lock if I'm using staff vs. a single
|
|
case BOTH_LK_S_S_S_L_2:
|
|
case BOTH_LK_S_S_T_L_2:
|
|
case BOTH_LK_DL_DL_S_L_2:
|
|
case BOTH_LK_DL_DL_T_L_2:
|
|
case BOTH_LK_ST_ST_S_L_2:
|
|
case BOTH_LK_ST_ST_T_L_2:
|
|
return qtrue;
|
|
break;
|
|
default:
|
|
return BG_InSaberLockOld( anim );
|
|
break;
|
|
}
|
|
//return qfalse;
|
|
}
|
|
|
|
//Called only where pm is valid (not all require pm, but some do):
|
|
qboolean PM_InCartwheel( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_ARIAL_LEFT:
|
|
case BOTH_ARIAL_RIGHT:
|
|
case BOTH_ARIAL_F1:
|
|
case BOTH_CARTWHEEL_LEFT:
|
|
case BOTH_CARTWHEEL_RIGHT:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_InKnockDownOnGround( playerState_t *ps )
|
|
{
|
|
switch ( ps->legsAnim )
|
|
{
|
|
case BOTH_KNOCKDOWN1:
|
|
case BOTH_KNOCKDOWN2:
|
|
case BOTH_KNOCKDOWN3:
|
|
case BOTH_KNOCKDOWN4:
|
|
case BOTH_KNOCKDOWN5:
|
|
case BOTH_RELEASED:
|
|
//if ( PM_AnimLength( g_entities[ps->clientNum].client->clientInfo.animFileIndex, (animNumber_t)ps->legsAnim ) - ps->legsAnimTimer > 300 )
|
|
{//at end of fall down anim
|
|
return qtrue;
|
|
}
|
|
break;
|
|
case BOTH_GETUP1:
|
|
case BOTH_GETUP2:
|
|
case BOTH_GETUP3:
|
|
case BOTH_GETUP4:
|
|
case BOTH_GETUP5:
|
|
case BOTH_GETUP_CROUCH_F1:
|
|
case BOTH_GETUP_CROUCH_B1:
|
|
case BOTH_FORCE_GETUP_F1:
|
|
case BOTH_FORCE_GETUP_F2:
|
|
case BOTH_FORCE_GETUP_B1:
|
|
case BOTH_FORCE_GETUP_B2:
|
|
case BOTH_FORCE_GETUP_B3:
|
|
case BOTH_FORCE_GETUP_B4:
|
|
case BOTH_FORCE_GETUP_B5:
|
|
case BOTH_FORCE_GETUP_B6:
|
|
if ( BG_AnimLength( 0, (animNumber_t)ps->legsAnim ) - ps->legsTimer < 500 )
|
|
{//at beginning of getup anim
|
|
return qtrue;
|
|
}
|
|
break;
|
|
case BOTH_GETUP_BROLL_B:
|
|
case BOTH_GETUP_BROLL_F:
|
|
case BOTH_GETUP_BROLL_L:
|
|
case BOTH_GETUP_BROLL_R:
|
|
case BOTH_GETUP_FROLL_B:
|
|
case BOTH_GETUP_FROLL_F:
|
|
case BOTH_GETUP_FROLL_L:
|
|
case BOTH_GETUP_FROLL_R:
|
|
if ( BG_AnimLength( 0, (animNumber_t)ps->legsAnim ) - ps->legsTimer < 500 )
|
|
{//at beginning of getup anim
|
|
return qtrue;
|
|
}
|
|
break;
|
|
case BOTH_LK_DL_ST_T_SB_1_L:
|
|
if ( ps->legsTimer < 1000 )
|
|
{
|
|
return qtrue;
|
|
}
|
|
break;
|
|
case BOTH_PLAYER_PA_3_FLY:
|
|
if ( ps->legsTimer < 300 )
|
|
{
|
|
return qtrue;
|
|
}
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_StabDownAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_STABDOWN:
|
|
case BOTH_STABDOWN_STAFF:
|
|
case BOTH_STABDOWN_DUAL:
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
int PM_SaberBounceForAttack( int move )
|
|
{
|
|
switch ( saberMoveData[move].startQuad )
|
|
{
|
|
case Q_B:
|
|
case Q_BR:
|
|
return LS_B1_BR;
|
|
break;
|
|
case Q_R:
|
|
return LS_B1__R;
|
|
break;
|
|
case Q_TR:
|
|
return LS_B1_TR;
|
|
break;
|
|
case Q_T:
|
|
return LS_B1_T_;
|
|
break;
|
|
case Q_TL:
|
|
return LS_B1_TL;
|
|
break;
|
|
case Q_L:
|
|
return LS_B1__L;
|
|
break;
|
|
case Q_BL:
|
|
return LS_B1_BL;
|
|
break;
|
|
}
|
|
return LS_NONE;
|
|
}
|
|
|
|
int PM_SaberDeflectionForQuad( int quad )
|
|
{
|
|
switch ( quad )
|
|
{
|
|
case Q_B:
|
|
return LS_D1_B_;
|
|
break;
|
|
case Q_BR:
|
|
return LS_D1_BR;
|
|
break;
|
|
case Q_R:
|
|
return LS_D1__R;
|
|
break;
|
|
case Q_TR:
|
|
return LS_D1_TR;
|
|
break;
|
|
case Q_T:
|
|
return LS_D1_T_;
|
|
break;
|
|
case Q_TL:
|
|
return LS_D1_TL;
|
|
break;
|
|
case Q_L:
|
|
return LS_D1__L;
|
|
break;
|
|
case Q_BL:
|
|
return LS_D1_BL;
|
|
break;
|
|
}
|
|
return LS_NONE;
|
|
}
|
|
|
|
qboolean PM_SaberInDeflect( int move )
|
|
{
|
|
if ( move >= LS_D1_BR && move <= LS_D1_B_ )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_SaberInParry( int move )
|
|
{
|
|
if ( move >= LS_PARRY_UP && move <= LS_PARRY_LL )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_SaberInKnockaway( int move )
|
|
{
|
|
if ( move >= LS_K1_T_ && move <= LS_K1_BL )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_SaberInReflect( int move )
|
|
{
|
|
if ( move >= LS_REFLECT_UP && move <= LS_REFLECT_LL )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_SaberInStart( int move )
|
|
{
|
|
if ( move >= LS_S_TL2BR && move <= LS_S_T2B )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_SaberInReturn( int move )
|
|
{
|
|
if ( move >= LS_R_TL2BR && move <= LS_R_T2B )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SaberInReturn( int move )
|
|
{
|
|
return PM_SaberInReturn( move );
|
|
}
|
|
|
|
qboolean PM_InSaberAnim( int anim )
|
|
{
|
|
if ( (anim) >= BOTH_A1_T__B_ && (anim) <= BOTH_H1_S1_BR )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_InKnockDown( playerState_t *ps )
|
|
{
|
|
switch ( (ps->legsAnim) )
|
|
{
|
|
case BOTH_KNOCKDOWN1:
|
|
case BOTH_KNOCKDOWN2:
|
|
case BOTH_KNOCKDOWN3:
|
|
case BOTH_KNOCKDOWN4:
|
|
case BOTH_KNOCKDOWN5:
|
|
return qtrue;
|
|
break;
|
|
case BOTH_GETUP1:
|
|
case BOTH_GETUP2:
|
|
case BOTH_GETUP3:
|
|
case BOTH_GETUP4:
|
|
case BOTH_GETUP5:
|
|
case BOTH_FORCE_GETUP_F1:
|
|
case BOTH_FORCE_GETUP_F2:
|
|
case BOTH_FORCE_GETUP_B1:
|
|
case BOTH_FORCE_GETUP_B2:
|
|
case BOTH_FORCE_GETUP_B3:
|
|
case BOTH_FORCE_GETUP_B4:
|
|
case BOTH_FORCE_GETUP_B5:
|
|
case BOTH_GETUP_BROLL_B:
|
|
case BOTH_GETUP_BROLL_F:
|
|
case BOTH_GETUP_BROLL_L:
|
|
case BOTH_GETUP_BROLL_R:
|
|
case BOTH_GETUP_FROLL_B:
|
|
case BOTH_GETUP_FROLL_F:
|
|
case BOTH_GETUP_FROLL_L:
|
|
case BOTH_GETUP_FROLL_R:
|
|
if ( ps->legsTimer )
|
|
{
|
|
return qtrue;
|
|
}
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_PainAnim( int anim )
|
|
{
|
|
switch ( (anim) )
|
|
{
|
|
case BOTH_PAIN1: //# First take pain anim
|
|
case BOTH_PAIN2: //# Second take pain anim
|
|
case BOTH_PAIN3: //# Third take pain anim
|
|
case BOTH_PAIN4: //# Fourth take pain anim
|
|
case BOTH_PAIN5: //# Fifth take pain anim - from behind
|
|
case BOTH_PAIN6: //# Sixth take pain anim - from behind
|
|
case BOTH_PAIN7: //# Seventh take pain anim - from behind
|
|
case BOTH_PAIN8: //# Eigth take pain anim - from behind
|
|
case BOTH_PAIN9: //#
|
|
case BOTH_PAIN10: //#
|
|
case BOTH_PAIN11: //#
|
|
case BOTH_PAIN12: //#
|
|
case BOTH_PAIN13: //#
|
|
case BOTH_PAIN14: //#
|
|
case BOTH_PAIN15: //#
|
|
case BOTH_PAIN16: //#
|
|
case BOTH_PAIN17: //#
|
|
case BOTH_PAIN18: //#
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_JumpingAnim( int anim )
|
|
{
|
|
switch ( (anim) )
|
|
{
|
|
case BOTH_JUMP1: //# Jump - wind-up and leave ground
|
|
case BOTH_INAIR1: //# In air loop (from jump)
|
|
case BOTH_LAND1: //# Landing (from in air loop)
|
|
case BOTH_LAND2: //# Landing Hard (from a great height)
|
|
case BOTH_JUMPBACK1: //# Jump backwards - wind-up and leave ground
|
|
case BOTH_INAIRBACK1: //# In air loop (from jump back)
|
|
case BOTH_LANDBACK1: //# Landing backwards(from in air loop)
|
|
case BOTH_JUMPLEFT1: //# Jump left - wind-up and leave ground
|
|
case BOTH_INAIRLEFT1: //# In air loop (from jump left)
|
|
case BOTH_LANDLEFT1: //# Landing left(from in air loop)
|
|
case BOTH_JUMPRIGHT1: //# Jump right - wind-up and leave ground
|
|
case BOTH_INAIRRIGHT1: //# In air loop (from jump right)
|
|
case BOTH_LANDRIGHT1: //# Landing right(from in air loop)
|
|
case BOTH_FORCEJUMP1: //# Jump - wind-up and leave ground
|
|
case BOTH_FORCEINAIR1: //# In air loop (from jump)
|
|
case BOTH_FORCELAND1: //# Landing (from in air loop)
|
|
case BOTH_FORCEJUMPBACK1: //# Jump backwards - wind-up and leave ground
|
|
case BOTH_FORCEINAIRBACK1: //# In air loop (from jump back)
|
|
case BOTH_FORCELANDBACK1: //# Landing backwards(from in air loop)
|
|
case BOTH_FORCEJUMPLEFT1: //# Jump left - wind-up and leave ground
|
|
case BOTH_FORCEINAIRLEFT1: //# In air loop (from jump left)
|
|
case BOTH_FORCELANDLEFT1: //# Landing left(from in air loop)
|
|
case BOTH_FORCEJUMPRIGHT1: //# Jump right - wind-up and leave ground
|
|
case BOTH_FORCEINAIRRIGHT1: //# In air loop (from jump right)
|
|
case BOTH_FORCELANDRIGHT1: //# Landing right(from in air loop)
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_LandingAnim( int anim )
|
|
{
|
|
switch ( (anim) )
|
|
{
|
|
case BOTH_LAND1: //# Landing (from in air loop)
|
|
case BOTH_LAND2: //# Landing Hard (from a great height)
|
|
case BOTH_LANDBACK1: //# Landing backwards(from in air loop)
|
|
case BOTH_LANDLEFT1: //# Landing left(from in air loop)
|
|
case BOTH_LANDRIGHT1: //# Landing right(from in air loop)
|
|
case BOTH_FORCELAND1: //# Landing (from in air loop)
|
|
case BOTH_FORCELANDBACK1: //# Landing backwards(from in air loop)
|
|
case BOTH_FORCELANDLEFT1: //# Landing left(from in air loop)
|
|
case BOTH_FORCELANDRIGHT1: //# Landing right(from in air loop)
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_SpinningAnim( int anim )
|
|
{
|
|
/*
|
|
switch ( anim )
|
|
{
|
|
//FIXME: list any other spinning anims
|
|
default:
|
|
break;
|
|
}
|
|
*/
|
|
return BG_SpinningSaberAnim( anim );
|
|
}
|
|
|
|
qboolean PM_InOnGroundAnim ( int anim )
|
|
{
|
|
switch( anim )
|
|
{
|
|
case BOTH_DEAD1:
|
|
case BOTH_DEAD2:
|
|
case BOTH_DEAD3:
|
|
case BOTH_DEAD4:
|
|
case BOTH_DEAD5:
|
|
case BOTH_DEADFORWARD1:
|
|
case BOTH_DEADBACKWARD1:
|
|
case BOTH_DEADFORWARD2:
|
|
case BOTH_DEADBACKWARD2:
|
|
case BOTH_LYINGDEATH1:
|
|
case BOTH_LYINGDEAD1:
|
|
case BOTH_SLEEP1: //# laying on back-rknee up-rhand on torso
|
|
case BOTH_KNOCKDOWN1: //#
|
|
case BOTH_KNOCKDOWN2: //#
|
|
case BOTH_KNOCKDOWN3: //#
|
|
case BOTH_KNOCKDOWN4: //#
|
|
case BOTH_KNOCKDOWN5: //#
|
|
case BOTH_GETUP1:
|
|
case BOTH_GETUP2:
|
|
case BOTH_GETUP3:
|
|
case BOTH_GETUP4:
|
|
case BOTH_GETUP5:
|
|
case BOTH_GETUP_CROUCH_F1:
|
|
case BOTH_GETUP_CROUCH_B1:
|
|
case BOTH_FORCE_GETUP_F1:
|
|
case BOTH_FORCE_GETUP_F2:
|
|
case BOTH_FORCE_GETUP_B1:
|
|
case BOTH_FORCE_GETUP_B2:
|
|
case BOTH_FORCE_GETUP_B3:
|
|
case BOTH_FORCE_GETUP_B4:
|
|
case BOTH_FORCE_GETUP_B5:
|
|
case BOTH_FORCE_GETUP_B6:
|
|
case BOTH_GETUP_BROLL_B:
|
|
case BOTH_GETUP_BROLL_F:
|
|
case BOTH_GETUP_BROLL_L:
|
|
case BOTH_GETUP_BROLL_R:
|
|
case BOTH_GETUP_FROLL_B:
|
|
case BOTH_GETUP_FROLL_F:
|
|
case BOTH_GETUP_FROLL_L:
|
|
case BOTH_GETUP_FROLL_R:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_InRollComplete( playerState_t *ps, int anim )
|
|
{
|
|
switch ( (anim) )
|
|
{
|
|
case BOTH_ROLL_F:
|
|
case BOTH_ROLL_B:
|
|
case BOTH_ROLL_R:
|
|
case BOTH_ROLL_L:
|
|
if ( ps->legsTimer < 1 )
|
|
{
|
|
return qtrue;
|
|
}
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_CanRollFromSoulCal( playerState_t *ps )
|
|
{
|
|
if ( ps->legsAnim == BOTH_A7_SOULCAL
|
|
&& ps->legsTimer < 700
|
|
&& ps->legsTimer > 250 )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SuperBreakLoseAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_LK_S_DL_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_S_DL_T_SB_1_L: //super break I lost
|
|
case BOTH_LK_S_ST_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_S_ST_T_SB_1_L: //super break I lost
|
|
case BOTH_LK_S_S_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_S_S_T_SB_1_L: //super break I lost
|
|
case BOTH_LK_DL_DL_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_DL_DL_T_SB_1_L: //super break I lost
|
|
case BOTH_LK_DL_ST_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_DL_ST_T_SB_1_L: //super break I lost
|
|
case BOTH_LK_DL_S_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_DL_S_T_SB_1_L: //super break I lost
|
|
case BOTH_LK_ST_DL_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_ST_DL_T_SB_1_L: //super break I lost
|
|
case BOTH_LK_ST_ST_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_ST_ST_T_SB_1_L: //super break I lost
|
|
case BOTH_LK_ST_S_S_SB_1_L: //super break I lost
|
|
case BOTH_LK_ST_S_T_SB_1_L: //super break I lost
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SuperBreakWinAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_LK_S_DL_S_SB_1_W: //super break I won
|
|
case BOTH_LK_S_DL_T_SB_1_W: //super break I won
|
|
case BOTH_LK_S_ST_S_SB_1_W: //super break I won
|
|
case BOTH_LK_S_ST_T_SB_1_W: //super break I won
|
|
case BOTH_LK_S_S_S_SB_1_W: //super break I won
|
|
case BOTH_LK_S_S_T_SB_1_W: //super break I won
|
|
case BOTH_LK_DL_DL_S_SB_1_W: //super break I won
|
|
case BOTH_LK_DL_DL_T_SB_1_W: //super break I won
|
|
case BOTH_LK_DL_ST_S_SB_1_W: //super break I won
|
|
case BOTH_LK_DL_ST_T_SB_1_W: //super break I won
|
|
case BOTH_LK_DL_S_S_SB_1_W: //super break I won
|
|
case BOTH_LK_DL_S_T_SB_1_W: //super break I won
|
|
case BOTH_LK_ST_DL_S_SB_1_W: //super break I won
|
|
case BOTH_LK_ST_DL_T_SB_1_W: //super break I won
|
|
case BOTH_LK_ST_ST_S_SB_1_W: //super break I won
|
|
case BOTH_LK_ST_ST_T_SB_1_W: //super break I won
|
|
case BOTH_LK_ST_S_S_SB_1_W: //super break I won
|
|
case BOTH_LK_ST_S_T_SB_1_W: //super break I won
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
|
|
qboolean BG_SaberLockBreakAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_BF1BREAK:
|
|
case BOTH_BF2BREAK:
|
|
case BOTH_CWCIRCLEBREAK:
|
|
case BOTH_CCWCIRCLEBREAK:
|
|
case BOTH_LK_S_DL_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_S_DL_S_B_1_W: //normal break I won
|
|
case BOTH_LK_S_DL_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_S_DL_T_B_1_W: //normal break I won
|
|
case BOTH_LK_S_ST_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_S_ST_S_B_1_W: //normal break I won
|
|
case BOTH_LK_S_ST_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_S_ST_T_B_1_W: //normal break I won
|
|
case BOTH_LK_S_S_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_S_S_S_B_1_W: //normal break I won
|
|
case BOTH_LK_S_S_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_S_S_T_B_1_W: //normal break I won
|
|
case BOTH_LK_DL_DL_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_DL_DL_S_B_1_W: //normal break I won
|
|
case BOTH_LK_DL_DL_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_DL_DL_T_B_1_W: //normal break I won
|
|
case BOTH_LK_DL_ST_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_DL_ST_S_B_1_W: //normal break I won
|
|
case BOTH_LK_DL_ST_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_DL_ST_T_B_1_W: //normal break I won
|
|
case BOTH_LK_DL_S_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_DL_S_S_B_1_W: //normal break I won
|
|
case BOTH_LK_DL_S_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_DL_S_T_B_1_W: //normal break I won
|
|
case BOTH_LK_ST_DL_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_ST_DL_S_B_1_W: //normal break I won
|
|
case BOTH_LK_ST_DL_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_ST_DL_T_B_1_W: //normal break I won
|
|
case BOTH_LK_ST_ST_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_ST_ST_S_B_1_W: //normal break I won
|
|
case BOTH_LK_ST_ST_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_ST_ST_T_B_1_W: //normal break I won
|
|
case BOTH_LK_ST_S_S_B_1_L: //normal break I lost
|
|
case BOTH_LK_ST_S_S_B_1_W: //normal break I won
|
|
case BOTH_LK_ST_S_T_B_1_L: //normal break I lost
|
|
case BOTH_LK_ST_S_T_B_1_W: //normal break I won
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return (BG_SuperBreakLoseAnim(anim)||BG_SuperBreakWinAnim(anim));
|
|
}
|
|
|
|
|
|
qboolean BG_FullBodyTauntAnim( int anim )
|
|
{
|
|
switch ( anim )
|
|
{
|
|
case BOTH_GESTURE1:
|
|
case BOTH_DUAL_TAUNT:
|
|
case BOTH_STAFF_TAUNT:
|
|
case BOTH_BOW:
|
|
case BOTH_MEDITATE:
|
|
case BOTH_SHOWOFF_FAST:
|
|
case BOTH_SHOWOFF_MEDIUM:
|
|
case BOTH_SHOWOFF_STRONG:
|
|
case BOTH_SHOWOFF_DUAL:
|
|
case BOTH_SHOWOFF_STAFF:
|
|
case BOTH_VICTORY_FAST:
|
|
case BOTH_VICTORY_MEDIUM:
|
|
case BOTH_VICTORY_STRONG:
|
|
case BOTH_VICTORY_DUAL:
|
|
case BOTH_VICTORY_STAFF:
|
|
return qtrue;
|
|
break;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
|
|
/*
|
|
=============
|
|
BG_AnimLength
|
|
|
|
Get the "length" of an anim given the local anim index (which skeleton)
|
|
and anim number. Obviously does not take things like the length of the
|
|
anim while force speeding (as an example) and whatnot into account.
|
|
=============
|
|
*/
|
|
int BG_AnimLength( int index, animNumber_t anim )
|
|
{
|
|
if (anim >= MAX_ANIMATIONS)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return bgAllAnims[index].anims[anim].numFrames * fabs((float)(bgAllAnims[index].anims[anim].frameLerp));
|
|
}
|
|
|
|
//just use whatever pm->animations is
|
|
int PM_AnimLength( int index, animNumber_t anim )
|
|
{
|
|
if (anim >= MAX_ANIMATIONS || !pm->animations)
|
|
{
|
|
return -1;
|
|
}
|
|
if ( anim < 0 )
|
|
{
|
|
Com_Error(ERR_DROP,"ERROR: anim %d < 0\n", anim );
|
|
}
|
|
return pm->animations[anim].numFrames * fabs((float)(pm->animations[anim].frameLerp));
|
|
}
|
|
|
|
void PM_DebugLegsAnim(int anim)
|
|
{
|
|
int oldAnim = (pm->ps->legsAnim);
|
|
int newAnim = (anim);
|
|
|
|
if (oldAnim < MAX_TOTALANIMATIONS && oldAnim >= BOTH_DEATH1 &&
|
|
newAnim < MAX_TOTALANIMATIONS && newAnim >= BOTH_DEATH1)
|
|
{
|
|
Com_Printf("OLD: %s\n", animTable[oldAnim]);
|
|
Com_Printf("NEW: %s\n", animTable[newAnim]);
|
|
}
|
|
}
|
|
|
|
qboolean PM_SaberInTransition( int move )
|
|
{
|
|
if ( move >= LS_T1_BR__R && move <= LS_T1_BL__L )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean BG_SaberInTransitionAny( int move )
|
|
{
|
|
if ( PM_SaberInStart( move ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
else if ( PM_SaberInTransition( move ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
else if ( PM_SaberInReturn( move ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
/*
|
|
==============================================================================
|
|
END: Animation utility functions (sequence checking)
|
|
==============================================================================
|
|
*/
|
|
|
|
void BG_FlipPart(playerState_t *ps, int part)
|
|
{
|
|
if (part == SETANIM_TORSO)
|
|
{
|
|
if (ps->torsoFlip)
|
|
{
|
|
ps->torsoFlip = qfalse;
|
|
}
|
|
else
|
|
{
|
|
ps->torsoFlip = qtrue;
|
|
}
|
|
}
|
|
else if (part == SETANIM_LEGS)
|
|
{
|
|
if (ps->legsFlip)
|
|
{
|
|
ps->legsFlip = qfalse;
|
|
}
|
|
else
|
|
{
|
|
ps->legsFlip = qtrue;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef Q3_VM
|
|
char BGPAFtext[60000];
|
|
#endif
|
|
qboolean BGPAFtextLoaded = qfalse;
|
|
animation_t bgHumanoidAnimations[MAX_TOTALANIMATIONS]; //humanoid animations are the only ones that are statically allocated.
|
|
|
|
//#define CONVENIENT_ANIMATION_FILE_DEBUG_THING
|
|
|
|
#ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING
|
|
void SpewDebugStuffToFile()
|
|
{
|
|
fileHandle_t f;
|
|
int i = 0;
|
|
|
|
trap_FS_FOpenFile("file_of_debug_stuff_MP.txt", &f, FS_WRITE);
|
|
|
|
if (!f)
|
|
{
|
|
return;
|
|
}
|
|
|
|
BGPAFtext[0] = 0;
|
|
|
|
while (i < MAX_ANIMATIONS)
|
|
{
|
|
strcat(BGPAFtext, va("%i %i\n", i, bgHumanoidAnimations[i].frameLerp));
|
|
i++;
|
|
}
|
|
|
|
trap_FS_Write(BGPAFtext, strlen(BGPAFtext), f);
|
|
trap_FS_FCloseFile(f);
|
|
}
|
|
#endif
|
|
|
|
bgLoadedAnim_t bgAllAnims[MAX_ANIM_FILES];
|
|
int bgNumAllAnims = 2; //start off at 2, because 0 will always be assigned to humanoid, and 1 will always be rockettrooper
|
|
|
|
//ALWAYS call on game/cgame init
|
|
void BG_InitAnimsets(void)
|
|
{
|
|
memset(&bgAllAnims, 0, sizeof(bgAllAnims));
|
|
BGPAFtextLoaded = qfalse; // VVFIXME - The PC doesn't seem to need this, but why?
|
|
}
|
|
|
|
//ALWAYS call on game/cgame shutdown
|
|
void BG_ClearAnimsets(void)
|
|
{
|
|
/*
|
|
int i = 1;
|
|
|
|
while (i < bgNumAllAnims)
|
|
{
|
|
if (bgAllAnims[i].anims)
|
|
{
|
|
strap_TrueFree((void **)&bgAllAnims[i].anims);
|
|
}
|
|
i++;
|
|
}
|
|
*/
|
|
}
|
|
|
|
animation_t *BG_AnimsetAlloc(void)
|
|
{
|
|
assert (bgNumAllAnims < MAX_ANIM_FILES);
|
|
bgAllAnims[bgNumAllAnims].anims = (animation_t *) BG_Alloc(sizeof(animation_t)*MAX_TOTALANIMATIONS);
|
|
|
|
return bgAllAnims[bgNumAllAnims].anims;
|
|
}
|
|
|
|
void BG_AnimsetFree(animation_t *animset)
|
|
{
|
|
/*
|
|
if (!animset)
|
|
{
|
|
return;
|
|
}
|
|
|
|
strap_TrueFree((void **)&animset);
|
|
|
|
#ifdef _DEBUG
|
|
if (animset)
|
|
{
|
|
assert(!"Failed to free anim set");
|
|
}
|
|
#endif
|
|
*/
|
|
}
|
|
|
|
#ifndef QAGAME //none of this is actually needed serverside. Could just be moved to cgame code but it's here since it
|
|
//used to tie in a lot with the anim loading stuff.
|
|
stringID_table_t animEventTypeTable[MAX_ANIM_EVENTS+1] =
|
|
{
|
|
ENUM2STRING(AEV_SOUND), //# animID AEV_SOUND framenum soundpath randomlow randomhi chancetoplay
|
|
ENUM2STRING(AEV_FOOTSTEP), //# animID AEV_FOOTSTEP framenum footstepType
|
|
ENUM2STRING(AEV_EFFECT), //# animID AEV_EFFECT framenum effectpath boltName
|
|
ENUM2STRING(AEV_FIRE), //# animID AEV_FIRE framenum altfire chancetofire
|
|
ENUM2STRING(AEV_MOVE), //# animID AEV_MOVE framenum forwardpush rightpush uppush
|
|
ENUM2STRING(AEV_SOUNDCHAN), //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay
|
|
//must be terminated
|
|
NULL,-1
|
|
};
|
|
|
|
stringID_table_t footstepTypeTable[NUM_FOOTSTEP_TYPES+1] =
|
|
{
|
|
ENUM2STRING(FOOTSTEP_R),
|
|
ENUM2STRING(FOOTSTEP_L),
|
|
ENUM2STRING(FOOTSTEP_HEAVY_R),
|
|
ENUM2STRING(FOOTSTEP_HEAVY_L),
|
|
//must be terminated
|
|
NULL,-1
|
|
};
|
|
|
|
int CheckAnimFrameForEventType( animevent_t *animEvents, int keyFrame, animEventType_t eventType )
|
|
{
|
|
int i;
|
|
|
|
for ( i = 0; i < MAX_ANIM_EVENTS; i++ )
|
|
{
|
|
if ( animEvents[i].keyFrame == keyFrame )
|
|
{//there is an animevent on this frame already
|
|
if ( animEvents[i].eventType == eventType )
|
|
{//and it is of the same type
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
//nope
|
|
return -1;
|
|
}
|
|
|
|
void ParseAnimationEvtBlock(const char *aeb_filename, animevent_t *animEvents, animation_t *animations, int *i,const char **text_p)
|
|
{
|
|
const char *token;
|
|
int num, n, animNum, keyFrame, lowestVal, highestVal, curAnimEvent, lastAnimEvent = 0;
|
|
animEventType_t eventType;
|
|
char stringData[MAX_QPATH];
|
|
|
|
// get past starting bracket
|
|
while(1)
|
|
{
|
|
token = COM_Parse( text_p );
|
|
if ( !Q_stricmp( token, "{" ) )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
//NOTE: instead of a blind increment, increase the index
|
|
// this way if we have an event on an anim that already
|
|
// has an event of that type, it stomps it
|
|
|
|
// read information for each frame
|
|
while ( 1 )
|
|
{
|
|
if ( lastAnimEvent >= MAX_ANIM_EVENTS )
|
|
{
|
|
Com_Error( ERR_DROP, "ParseAnimationEvtBlock: number events in animEvent file %s > MAX_ANIM_EVENTS(%i)", aeb_filename, MAX_ANIM_EVENTS );
|
|
return;
|
|
}
|
|
// Get base frame of sequence
|
|
token = COM_Parse( text_p );
|
|
if ( !token || !token[0])
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( !Q_stricmp( token, "}" ) ) // At end of block
|
|
{
|
|
break;
|
|
}
|
|
|
|
//Compare to same table as animations used
|
|
// so we don't have to use actual numbers for animation first frames,
|
|
// just need offsets.
|
|
//This way when animation numbers change, this table won't have to be updated,
|
|
// at least not much.
|
|
animNum = GetIDForString(animTable, token);
|
|
if(animNum == -1)
|
|
{//Unrecognized ANIM ENUM name, or we're skipping this line, keep going till you get a good one
|
|
Com_Printf(S_COLOR_YELLOW"WARNING: Unknown token %s in animEvent file %s\n", token, aeb_filename );
|
|
while (token[0])
|
|
{
|
|
token = COM_ParseExt( text_p, qfalse ); //returns empty string when next token is EOL
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if ( animations[animNum].numFrames == 0 )
|
|
{//we don't use this anim
|
|
Com_Printf(S_COLOR_YELLOW"WARNING: %s animevents.cfg: anim %s not used by this model\n", aeb_filename, token);
|
|
//skip this entry
|
|
SkipRestOfLine( text_p );
|
|
continue;
|
|
}
|
|
|
|
token = COM_Parse( text_p );
|
|
eventType = (animEventType_t)GetIDForString(animEventTypeTable, token);
|
|
if ( eventType == AEV_NONE || eventType == -1 )
|
|
{//Unrecognized ANIM EVENT TYOE, or we're skipping this line, keep going till you get a good one
|
|
//Com_Printf(S_COLOR_YELLOW"WARNING: Unknown token %s in animEvent file %s\n", token, aeb_filename );
|
|
continue;
|
|
}
|
|
|
|
//set our start frame
|
|
keyFrame = animations[animNum].firstFrame;
|
|
// Get offset to frame within sequence
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
keyFrame += atoi( token );
|
|
|
|
//see if this frame already has an event of this type on it, if so, overwrite it
|
|
curAnimEvent = CheckAnimFrameForEventType( animEvents, keyFrame, eventType );
|
|
if ( curAnimEvent == -1 )
|
|
{//this anim frame doesn't already have an event of this type on it
|
|
curAnimEvent = lastAnimEvent;
|
|
}
|
|
|
|
//now that we know which event index we're going to plug the data into, start doing it
|
|
animEvents[curAnimEvent].eventType = eventType;
|
|
animEvents[curAnimEvent].keyFrame = keyFrame;
|
|
|
|
//now read out the proper data based on the type
|
|
switch ( animEvents[curAnimEvent].eventType )
|
|
{
|
|
case AEV_SOUNDCHAN: //# animID AEV_SOUNDCHAN framenum CHANNEL soundpath randomlow randomhi chancetoplay
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
if ( stricmp( token, "CHAN_VOICE_ATTEN" ) == 0 )
|
|
{
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_VOICE_ATTEN;
|
|
}
|
|
else if ( stricmp( token, "CHAN_VOICE_GLOBAL" ) == 0 )
|
|
{
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_VOICE_GLOBAL;
|
|
}
|
|
else if ( stricmp( token, "CHAN_ANNOUNCER" ) == 0 )
|
|
{
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_ANNOUNCER;
|
|
}
|
|
else if ( stricmp( token, "CHAN_BODY" ) == 0 )
|
|
{
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_BODY;
|
|
}
|
|
else if ( stricmp( token, "CHAN_WEAPON" ) == 0 )
|
|
{
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_WEAPON;
|
|
}
|
|
else if ( stricmp( token, "CHAN_VOICE" ) == 0 )
|
|
{
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_VOICE;
|
|
}
|
|
else
|
|
{
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDCHANNEL] = CHAN_AUTO;
|
|
}
|
|
//fall through to normal sound
|
|
case AEV_SOUND: //# animID AEV_SOUND framenum soundpath randomlow randomhi chancetoplay
|
|
//get soundstring
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
strcpy(stringData, token);
|
|
//get lowest value
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
lowestVal = atoi( token );
|
|
//get highest value
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
highestVal = atoi( token );
|
|
//Now precache all the sounds
|
|
//NOTE: If we can be assured sequential handles, we can store sound indices
|
|
// instead of strings, unfortunately, if these sounds were previously
|
|
// registered, we cannot be guaranteed sequential indices. Thus an array
|
|
if(lowestVal && highestVal)
|
|
{
|
|
//assert(highestVal - lowestVal < MAX_RANDOM_ANIM_SOUNDS);
|
|
if ((highestVal-lowestVal) >= MAX_RANDOM_ANIM_SOUNDS)
|
|
{
|
|
highestVal = lowestVal + (MAX_RANDOM_ANIM_SOUNDS-1);
|
|
}
|
|
for ( n = lowestVal, num = AED_SOUNDINDEX_START; n <= highestVal && num <= AED_SOUNDINDEX_END; n++, num++ )
|
|
{
|
|
if (stringData[0] == '*')
|
|
{ //FIXME? Would be nice to make custom sounds work with animEvents.
|
|
animEvents[curAnimEvent].eventData[num] = 0;
|
|
}
|
|
else
|
|
{
|
|
animEvents[curAnimEvent].eventData[num] = trap_S_RegisterSound( va( stringData, n ) );
|
|
}
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_SOUND_NUMRANDOMSNDS] = num - 1;
|
|
}
|
|
else
|
|
{
|
|
if (stringData[0] == '*')
|
|
{ //FIXME? Would be nice to make custom sounds work with animEvents.
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDINDEX_START] = 0;
|
|
}
|
|
else
|
|
{
|
|
animEvents[curAnimEvent].eventData[AED_SOUNDINDEX_START] = trap_S_RegisterSound( stringData );
|
|
}
|
|
#ifndef FINAL_BUILD
|
|
if ( !animEvents[curAnimEvent].eventData[AED_SOUNDINDEX_START] &&
|
|
stringData[0] != '*')
|
|
{//couldn't register it - file not found
|
|
Com_Printf( S_COLOR_RED "ParseAnimationSndBlock: sound %s does not exist (animevents.cfg %s)!\n", stringData, aeb_filename );
|
|
}
|
|
#endif
|
|
animEvents[curAnimEvent].eventData[AED_SOUND_NUMRANDOMSNDS] = 0;
|
|
}
|
|
//get probability
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_SOUND_PROBABILITY] = atoi( token );
|
|
break;
|
|
case AEV_FOOTSTEP: //# animID AEV_FOOTSTEP framenum footstepType
|
|
//get footstep type
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_FOOTSTEP_TYPE] = GetIDForString(footstepTypeTable, token);
|
|
//get probability
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_FOOTSTEP_PROBABILITY] = atoi( token );
|
|
break;
|
|
case AEV_EFFECT: //# animID AEV_EFFECT framenum effectpath boltName
|
|
//get effect index
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_EFFECTINDEX] = trap_FX_RegisterEffect( token );
|
|
//get bolt index
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
if ( Q_stricmp( "none", token ) != 0 && Q_stricmp( "NULL", token ) != 0 )
|
|
{//actually are specifying a bolt to use
|
|
if (!animEvents[curAnimEvent].stringData)
|
|
{ //eh, whatever. no dynamic stuff, so this will do.
|
|
animEvents[curAnimEvent].stringData = (char *) BG_Alloc(2048);
|
|
}
|
|
strcpy(animEvents[curAnimEvent].stringData, token);
|
|
}
|
|
//NOTE: this string will later be used to add a bolt and store the index, as below:
|
|
//animEvent->eventData[AED_BOLTINDEX] = gi.G2API_AddBolt( ¢->gent->ghoul2[cent->gent->playerModel], animEvent->stringData );
|
|
//get probability
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_EFFECT_PROBABILITY] = atoi( token );
|
|
break;
|
|
case AEV_FIRE: //# animID AEV_FIRE framenum altfire chancetofire
|
|
//get altfire
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_FIRE_ALT] = atoi( token );
|
|
//get probability
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_FIRE_PROBABILITY] = atoi( token );
|
|
break;
|
|
case AEV_MOVE: //# animID AEV_MOVE framenum forwardpush rightpush uppush
|
|
//get forward push
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_MOVE_FWD] = atoi( token );
|
|
//get right push
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_MOVE_RT] = atoi( token );
|
|
//get upwards push
|
|
token = COM_Parse( text_p );
|
|
if ( !token )
|
|
{//WARNING! BAD TABLE!
|
|
break;
|
|
}
|
|
animEvents[curAnimEvent].eventData[AED_MOVE_UP] = atoi( token );
|
|
break;
|
|
default: //unknown?
|
|
SkipRestOfLine( text_p );
|
|
continue;
|
|
break;
|
|
}
|
|
|
|
if ( curAnimEvent == lastAnimEvent )
|
|
{
|
|
lastAnimEvent++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
======================
|
|
BG_ParseAnimationEvtFile
|
|
|
|
Read a configuration file containing animation events
|
|
models/players/kyle/animevents.cfg, etc
|
|
|
|
This file's presence is not required
|
|
|
|
======================
|
|
*/
|
|
bgLoadedEvents_t bgAllEvents[MAX_ANIM_FILES];
|
|
int bgNumAnimEvents = 1;
|
|
static int bg_animParseIncluding = 0;
|
|
int BG_ParseAnimationEvtFile( const char *as_filename, int animFileIndex, int eventFileIndex )
|
|
{
|
|
const char *text_p;
|
|
int len;
|
|
const char *token;
|
|
char text[80000];
|
|
char sfilename[MAX_QPATH];
|
|
fileHandle_t f;
|
|
int i, j, upper_i, lower_i;
|
|
int usedIndex = -1;
|
|
animevent_t *legsAnimEvents;
|
|
animevent_t *torsoAnimEvents;
|
|
animation_t *animations;
|
|
int forcedIndex;
|
|
|
|
assert(animFileIndex < MAX_ANIM_FILES);
|
|
assert(eventFileIndex < MAX_ANIM_FILES);
|
|
|
|
if (eventFileIndex == -1)
|
|
{
|
|
forcedIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
forcedIndex = eventFileIndex;
|
|
}
|
|
|
|
if (bg_animParseIncluding <= 0)
|
|
{ //if we should be parsing an included file, skip this part
|
|
if ( bgAllEvents[forcedIndex].eventsParsed )
|
|
{//already cached this one
|
|
return forcedIndex;
|
|
}
|
|
}
|
|
|
|
legsAnimEvents = bgAllEvents[forcedIndex].legsAnimEvents;
|
|
torsoAnimEvents = bgAllEvents[forcedIndex].torsoAnimEvents;
|
|
animations = bgAllAnims[animFileIndex].anims;
|
|
|
|
if (bg_animParseIncluding <= 0)
|
|
{ //if we should be parsing an included file, skip this part
|
|
//Go through and see if this filename is already in the table.
|
|
i = 0;
|
|
while (i < bgNumAnimEvents && forcedIndex != 0)
|
|
{
|
|
if (!Q_stricmp(as_filename, bgAllEvents[i].filename))
|
|
{ //looks like we have it already.
|
|
return i;
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
// Load and parse animevents.cfg file
|
|
Com_sprintf( sfilename, sizeof( sfilename ), "%sanimevents.cfg", as_filename );
|
|
|
|
if (bg_animParseIncluding <= 0)
|
|
{ //should already be done if we're including
|
|
//initialize anim event array
|
|
for( i = 0; i < MAX_ANIM_EVENTS; i++ )
|
|
{
|
|
//Type of event
|
|
torsoAnimEvents[i].eventType = AEV_NONE;
|
|
legsAnimEvents[i].eventType = AEV_NONE;
|
|
//Frame to play event on
|
|
torsoAnimEvents[i].keyFrame = -1;
|
|
legsAnimEvents[i].keyFrame = -1;
|
|
//we allow storage of one string, temporarily (in case we have to look up an index later, then make sure to set stringData to NULL so we only do the look-up once)
|
|
torsoAnimEvents[i].stringData = NULL;
|
|
legsAnimEvents[i].stringData = NULL;
|
|
//Unique IDs, can be soundIndex of sound file to play OR effect index or footstep type, etc.
|
|
for ( j = 0; j < AED_ARRAY_SIZE; j++ )
|
|
{
|
|
torsoAnimEvents[i].eventData[j] = -1;
|
|
legsAnimEvents[i].eventData[j] = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// load the file
|
|
len = trap_FS_FOpenFile( sfilename, &f, FS_READ );
|
|
if ( len <= 0 )
|
|
{//no file
|
|
goto fin;
|
|
}
|
|
if ( len >= sizeof( text ) - 1 )
|
|
{
|
|
trap_FS_FCloseFile(f);
|
|
#ifndef FINAL_BUILD
|
|
Com_Error(ERR_DROP, "File %s too long\n", sfilename );
|
|
#else
|
|
Com_Printf( "File %s too long\n", sfilename );
|
|
#endif
|
|
goto fin;
|
|
}
|
|
|
|
trap_FS_Read( text, len, f );
|
|
text[len] = 0;
|
|
trap_FS_FCloseFile( f );
|
|
|
|
// parse the text
|
|
text_p = text;
|
|
upper_i =0;
|
|
lower_i =0;
|
|
|
|
// read information for batches of sounds (UPPER or LOWER)
|
|
while ( 1 )
|
|
{
|
|
// Get base frame of sequence
|
|
token = COM_Parse( &text_p );
|
|
if ( !token || !token[0] )
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ( !Q_stricmp(token,"include") ) // grab from another animevents.cfg
|
|
{//NOTE: you REALLY should NOT do this after the main block of UPPERSOUNDS and LOWERSOUNDS
|
|
const char *include_filename = COM_Parse( &text_p );
|
|
if ( include_filename != NULL )
|
|
{
|
|
char fullIPath[MAX_QPATH];
|
|
strcpy(fullIPath, va("models/players/%s/", include_filename));
|
|
bg_animParseIncluding++;
|
|
BG_ParseAnimationEvtFile( fullIPath, animFileIndex, forcedIndex );
|
|
bg_animParseIncluding--;
|
|
}
|
|
}
|
|
|
|
if ( !Q_stricmp(token,"UPPEREVENTS") ) // A batch of upper sounds
|
|
{
|
|
ParseAnimationEvtBlock( as_filename, torsoAnimEvents, animations, &upper_i, &text_p );
|
|
}
|
|
|
|
else if ( !Q_stricmp(token,"LOWEREVENTS") ) // A batch of lower sounds
|
|
{
|
|
ParseAnimationEvtBlock( as_filename, legsAnimEvents, animations, &lower_i, &text_p );
|
|
}
|
|
}
|
|
|
|
usedIndex = forcedIndex;
|
|
fin:
|
|
//Mark this anim set so that we know we tried to load he sounds, don't care if the load failed
|
|
if (bg_animParseIncluding <= 0)
|
|
{ //if we should be parsing an included file, skip this part
|
|
bgAllEvents[forcedIndex].eventsParsed = qtrue;
|
|
strcpy(bgAllEvents[forcedIndex].filename, as_filename);
|
|
if (forcedIndex)
|
|
{
|
|
bgNumAnimEvents++;
|
|
}
|
|
}
|
|
|
|
return usedIndex;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
======================
|
|
BG_ParseAnimationFile
|
|
|
|
Read a configuration file containing animation coutns and rates
|
|
models/players/visor/animation.cfg, etc
|
|
|
|
======================
|
|
*/
|
|
int BG_ParseAnimationFile(const char *filename, animation_t *animset, qboolean isHumanoid)
|
|
{
|
|
char *text_p;
|
|
int len;
|
|
int i;
|
|
char *token;
|
|
float fps;
|
|
int skip;
|
|
int usedIndex = -1;
|
|
int nextIndex = bgNumAllAnims;
|
|
qboolean dynAlloc = qfalse;
|
|
qboolean wasLoaded = qfalse;
|
|
#ifndef Q3_VM
|
|
char BGPAFtext[60000];
|
|
#endif
|
|
|
|
fileHandle_t f;
|
|
int animNum;
|
|
|
|
if (!isHumanoid)
|
|
{
|
|
i = 0;
|
|
while (i < bgNumAllAnims)
|
|
{ //see if it's been loaded already
|
|
if (!Q_stricmp(bgAllAnims[i].filename, filename))
|
|
{
|
|
animset = bgAllAnims[i].anims;
|
|
return i; //alright, we already have it.
|
|
}
|
|
i++;
|
|
}
|
|
|
|
//Looks like it has not yet been loaded. Allocate space for the anim set if we need to, and continue along.
|
|
if (!animset)
|
|
{
|
|
if (strstr(filename, "players/_humanoid/"))
|
|
{ //then use the static humanoid set.
|
|
animset = bgHumanoidAnimations;
|
|
nextIndex = 0;
|
|
}
|
|
else if (strstr(filename, "players/rockettrooper/"))
|
|
{ //rockettrooper always index 1
|
|
nextIndex = 1;
|
|
animset = BG_AnimsetAlloc();
|
|
dynAlloc = qtrue; //so we know to free this memory in case we have to return early. Don't want any leaks.
|
|
|
|
if (!animset)
|
|
{
|
|
assert(!"Anim set alloc failed!");
|
|
return -1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
animset = BG_AnimsetAlloc();
|
|
dynAlloc = qtrue; //so we know to free this memory in case we have to return early. Don't want any leaks.
|
|
|
|
if (!animset)
|
|
{
|
|
assert(!"Anim set alloc failed!");
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
{
|
|
assert(animset);
|
|
}
|
|
#endif
|
|
|
|
// load the file
|
|
if (!BGPAFtextLoaded || !isHumanoid)
|
|
{ //rww - We are always using the same animation config now. So only load it once.
|
|
len = trap_FS_FOpenFile( filename, &f, FS_READ );
|
|
if ( (len <= 0) || (len >= sizeof( BGPAFtext ) - 1) )
|
|
{
|
|
if (dynAlloc)
|
|
{
|
|
BG_AnimsetFree(animset);
|
|
}
|
|
if (len > 0)
|
|
{
|
|
Com_Error(ERR_DROP, "%s exceeds the allowed game-side animation buffer!", filename);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
trap_FS_Read( BGPAFtext, len, f );
|
|
BGPAFtext[len] = 0;
|
|
trap_FS_FCloseFile( f );
|
|
}
|
|
else
|
|
{
|
|
if (dynAlloc)
|
|
{
|
|
assert(!"Should not have allocated dynamically for humanoid");
|
|
BG_AnimsetFree(animset);
|
|
}
|
|
return 0; //humanoid index
|
|
}
|
|
|
|
// parse the text
|
|
text_p = BGPAFtext;
|
|
skip = 0; // quiet the compiler warning
|
|
|
|
//FIXME: have some way of playing anims backwards... negative numFrames?
|
|
|
|
//initialize anim array so that from 0 to MAX_ANIMATIONS, set default values of 0 1 0 100
|
|
for(i = 0; i < MAX_ANIMATIONS; i++)
|
|
{
|
|
animset[i].firstFrame = 0;
|
|
animset[i].numFrames = 0;
|
|
animset[i].loopFrames = -1;
|
|
animset[i].frameLerp = 100;
|
|
}
|
|
|
|
// read information for each frame
|
|
while(1)
|
|
{
|
|
token = COM_Parse( (const char **)(&text_p) );
|
|
|
|
if ( !token || !token[0])
|
|
{
|
|
break;
|
|
}
|
|
|
|
animNum = GetIDForString(animTable, token);
|
|
if(animNum == -1)
|
|
{
|
|
//#ifndef FINAL_BUILD
|
|
#ifdef _DEBUG
|
|
Com_Printf(S_COLOR_RED"WARNING: Unknown token %s in %s\n", token, filename);
|
|
while (token[0])
|
|
{
|
|
token = COM_ParseExt( (const char **) &text_p, qfalse ); //returns empty string when next token is EOL
|
|
}
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
token = COM_Parse( (const char **)(&text_p) );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
animset[animNum].firstFrame = atoi( token );
|
|
|
|
token = COM_Parse( (const char **)(&text_p) );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
animset[animNum].numFrames = atoi( token );
|
|
|
|
token = COM_Parse( (const char **)(&text_p) );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
animset[animNum].loopFrames = atoi( token );
|
|
|
|
token = COM_Parse( (const char **)(&text_p) );
|
|
if ( !token )
|
|
{
|
|
break;
|
|
}
|
|
fps = atof( token );
|
|
if ( fps == 0 )
|
|
{
|
|
fps = 1;//Don't allow divide by zero error
|
|
}
|
|
if ( fps < 0 )
|
|
{//backwards
|
|
animset[animNum].frameLerp = floor(1000.0f / fps);
|
|
}
|
|
else
|
|
{
|
|
animset[animNum].frameLerp = ceil(1000.0f / fps);
|
|
}
|
|
}
|
|
/*
|
|
#ifdef _DEBUG
|
|
//Check the array, and print the ones that have nothing in them.
|
|
for(i = 0; i < MAX_ANIMATIONS; i++)
|
|
{
|
|
if (animTable[i].name != NULL) // This animation reference exists.
|
|
{
|
|
if (animset[i].firstFrame <= 0 && animset[i].numFrames <=0)
|
|
{ // This is an empty animation reference.
|
|
Com_Printf("***ANIMTABLE reference #%d (%s) is empty!\n", i, animTable[i].name);
|
|
}
|
|
}
|
|
}
|
|
#endif // _DEBUG
|
|
*/
|
|
#ifdef CONVENIENT_ANIMATION_FILE_DEBUG_THING
|
|
SpewDebugStuffToFile();
|
|
#endif
|
|
|
|
wasLoaded = BGPAFtextLoaded;
|
|
|
|
if (isHumanoid)
|
|
{
|
|
bgAllAnims[0].anims = animset;
|
|
strcpy(bgAllAnims[0].filename, filename);
|
|
BGPAFtextLoaded = qtrue;
|
|
|
|
usedIndex = 0;
|
|
}
|
|
else
|
|
{
|
|
bgAllAnims[nextIndex].anims = animset;
|
|
strcpy(bgAllAnims[nextIndex].filename, filename);
|
|
|
|
usedIndex = bgNumAllAnims;
|
|
|
|
if (nextIndex > 1)
|
|
{ //don't bother increasing the number if this ended up as a humanoid/rockettrooper load.
|
|
bgNumAllAnims++;
|
|
}
|
|
else
|
|
{
|
|
BGPAFtextLoaded = qtrue;
|
|
usedIndex = nextIndex;
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (!wasLoaded && BGPAFtextLoaded)
|
|
{ //just loaded humanoid skel - we always want the rockettrooper to be after it, in slot 1
|
|
#ifdef _DEBUG
|
|
assert(BG_ParseAnimationFile("models/players/rockettrooper/animation.cfg", NULL, qfalse) == 1);
|
|
#else
|
|
BG_ParseAnimationFile("models/players/rockettrooper/animation.cfg", NULL, qfalse);
|
|
#endif
|
|
}
|
|
*/
|
|
|
|
return usedIndex;
|
|
}
|
|
|
|
/*
|
|
===================
|
|
LEGS Animations
|
|
Base animation for overall body
|
|
===================
|
|
*/
|
|
static void BG_StartLegsAnim( playerState_t *ps, int anim )
|
|
{
|
|
if ( ps->pm_type >= PM_DEAD )
|
|
{
|
|
assert(!BG_InDeathAnim(anim));
|
|
//please let me know if this assert fires on you (ideally before you close/ignore it) -rww
|
|
|
|
//vehicles are allowed to do this.. IF it's a vehicle death anim
|
|
if (ps->clientNum < MAX_CLIENTS || anim != BOTH_VT_DEATH1)
|
|
{
|
|
return;
|
|
}
|
|
}
|
|
if ( ps->legsTimer > 0 )
|
|
{
|
|
return; // a high priority animation is running
|
|
}
|
|
|
|
if (ps->legsAnim == anim)
|
|
{
|
|
BG_FlipPart(ps, SETANIM_LEGS);
|
|
}
|
|
#ifdef QAGAME
|
|
else if (g_entities[ps->clientNum].s.legsAnim == anim)
|
|
{ //toggled anim to one anim then back to the one we were at previously in
|
|
//one frame, indicating that anim should be restarted.
|
|
BG_FlipPart(ps, SETANIM_LEGS);
|
|
}
|
|
#endif
|
|
ps->legsAnim = anim;
|
|
|
|
/*
|
|
if ( pm->debugLevel ) {
|
|
Com_Printf("%d: StartLegsAnim %d, on client#%d\n", pm->cmd.serverTime, anim, pm->ps->clientNum);
|
|
}
|
|
*/
|
|
}
|
|
|
|
void PM_ContinueLegsAnim( int anim ) {
|
|
if ( ( pm->ps->legsAnim ) == anim ) {
|
|
return;
|
|
}
|
|
if ( pm->ps->legsTimer > 0 ) {
|
|
return; // a high priority animation is running
|
|
}
|
|
|
|
BG_StartLegsAnim( pm->ps, anim );
|
|
}
|
|
|
|
void PM_ForceLegsAnim( int anim) {
|
|
if (BG_InSpecialJump(pm->ps->legsAnim) &&
|
|
pm->ps->legsTimer > 0 &&
|
|
!BG_InSpecialJump(anim))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (BG_InRoll(pm->ps, pm->ps->legsAnim) &&
|
|
pm->ps->legsTimer > 0 &&
|
|
!BG_InRoll(pm->ps, anim))
|
|
{
|
|
return;
|
|
}
|
|
|
|
pm->ps->legsTimer = 0;
|
|
BG_StartLegsAnim( pm->ps, anim );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
===================
|
|
TORSO Animations
|
|
Override animations for upper body
|
|
===================
|
|
*/
|
|
void BG_StartTorsoAnim( playerState_t *ps, int anim )
|
|
{
|
|
if ( ps->pm_type >= PM_DEAD )
|
|
{
|
|
assert(!BG_InDeathAnim(anim));
|
|
//please let me know if this assert fires on you (ideally before you close/ignore it) -rww
|
|
return;
|
|
}
|
|
|
|
if (ps->torsoAnim == anim)
|
|
{
|
|
BG_FlipPart(ps, SETANIM_TORSO);
|
|
}
|
|
#ifdef QAGAME
|
|
else if (g_entities[ps->clientNum].s.torsoAnim == anim)
|
|
{ //toggled anim to one anim then back to the one we were at previously in
|
|
//one frame, indicating that anim should be restarted.
|
|
BG_FlipPart(ps, SETANIM_TORSO);
|
|
}
|
|
#endif
|
|
ps->torsoAnim = anim;
|
|
}
|
|
|
|
void PM_StartTorsoAnim( int anim )
|
|
{
|
|
BG_StartTorsoAnim(pm->ps, anim);
|
|
}
|
|
|
|
|
|
/*
|
|
-------------------------
|
|
PM_SetLegsAnimTimer
|
|
-------------------------
|
|
*/
|
|
void BG_SetLegsAnimTimer(playerState_t *ps, int time)
|
|
{
|
|
ps->legsTimer = time;
|
|
|
|
if (ps->legsTimer < 0 && time != -1 )
|
|
{//Cap timer to 0 if was counting down, but let it be -1 if that was intentional. NOTENOTE Yeah this seems dumb, but it mirrors SP.
|
|
ps->legsTimer = 0;
|
|
}
|
|
}
|
|
|
|
void PM_SetLegsAnimTimer(int time)
|
|
{
|
|
BG_SetLegsAnimTimer(pm->ps, time);
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
PM_SetTorsoAnimTimer
|
|
-------------------------
|
|
*/
|
|
void BG_SetTorsoAnimTimer(playerState_t *ps, int time )
|
|
{
|
|
ps->torsoTimer = time;
|
|
|
|
if (ps->torsoTimer < 0 && time != -1 )
|
|
{//Cap timer to 0 if was counting down, but let it be -1 if that was intentional. NOTENOTE Yeah this seems dumb, but it mirrors SP.
|
|
ps->torsoTimer = 0;
|
|
}
|
|
}
|
|
|
|
void PM_SetTorsoAnimTimer(int time )
|
|
{
|
|
BG_SetTorsoAnimTimer(pm->ps, time);
|
|
}
|
|
|
|
void BG_SaberStartTransAnim( int saberAnimLevel, int anim, float *animSpeed, int broken )
|
|
{
|
|
if ( ( (anim) >= BOTH_T1_BR__R &&
|
|
(anim) <= BOTH_T1_BL_TL ) ||
|
|
( (anim) >= BOTH_T2_BR__R &&
|
|
(anim) <= BOTH_T2_BL_TL ) ||
|
|
( (anim) >= BOTH_T3_BR__R &&
|
|
(anim) <= BOTH_T3_BL_TL ) )
|
|
{
|
|
if ( saberAnimLevel == FORCE_LEVEL_1 )
|
|
{
|
|
*animSpeed *= 1.5f;
|
|
}
|
|
else if ( saberAnimLevel == FORCE_LEVEL_3 )
|
|
{
|
|
*animSpeed *= 0.75f;
|
|
}
|
|
|
|
if (broken & (1<<BROKENLIMB_RARM))
|
|
{
|
|
*animSpeed *= 0.5f;
|
|
}
|
|
else if (broken & (1<<BROKENLIMB_LARM))
|
|
{
|
|
*animSpeed *= 0.65f;
|
|
}
|
|
}
|
|
else if (broken && PM_InSaberAnim(anim))
|
|
{
|
|
if (broken & (1<<BROKENLIMB_RARM))
|
|
{
|
|
*animSpeed *= 0.5f;
|
|
}
|
|
else if (broken & (1<<BROKENLIMB_LARM))
|
|
{
|
|
*animSpeed *= 0.65f;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
-------------------------
|
|
PM_SetAnimFinal
|
|
-------------------------
|
|
*/
|
|
qboolean PM_RunningAnim( int anim );
|
|
qboolean PM_WalkingAnim( int anim );
|
|
|
|
void BG_SetAnimFinal(playerState_t *ps, animation_t *animations,
|
|
int setAnimParts,int anim,int setAnimFlags,
|
|
int blendTime) // default blendTime=350
|
|
{
|
|
float editAnimSpeed = 1;
|
|
|
|
if (!animations)
|
|
{
|
|
return;
|
|
}
|
|
|
|
assert(anim > -1);
|
|
assert(animations[anim].firstFrame > 0 || animations[anim].numFrames > 0);
|
|
|
|
//NOTE: Setting blendTime here breaks actual blending..
|
|
blendTime = 0;
|
|
|
|
BG_SaberStartTransAnim(ps->fd.saberAnimLevel, anim, &editAnimSpeed, ps->brokenLimbs);
|
|
|
|
// Set torso anim
|
|
if (setAnimParts & SETANIM_TORSO)
|
|
{
|
|
// Don't reset if it's already running the anim
|
|
if( !(setAnimFlags & SETANIM_FLAG_RESTART) && (ps->torsoAnim) == anim )
|
|
{
|
|
goto setAnimLegs;
|
|
}
|
|
// or if a more important anim is running
|
|
if( !(setAnimFlags & SETANIM_FLAG_OVERRIDE) && ((ps->torsoTimer > 0)||(ps->torsoTimer == -1)) )
|
|
{
|
|
goto setAnimLegs;
|
|
}
|
|
|
|
BG_StartTorsoAnim(ps, anim);
|
|
|
|
if (setAnimFlags & SETANIM_FLAG_HOLD)
|
|
{
|
|
if (setAnimFlags & SETANIM_FLAG_HOLDLESS)
|
|
{ // Make sure to only wait in full 1/20 sec server frame intervals.
|
|
int dur;
|
|
int speedDif;
|
|
|
|
dur = (animations[anim].numFrames-1) * fabs((float)(animations[anim].frameLerp));
|
|
speedDif = dur - (dur * editAnimSpeed);
|
|
dur += speedDif;
|
|
if (dur > 1)
|
|
{
|
|
ps->torsoTimer = dur-1;
|
|
}
|
|
else
|
|
{
|
|
ps->torsoTimer = fabs((float)(animations[anim].frameLerp));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ps->torsoTimer = ((animations[anim].numFrames ) * fabs((float)(animations[anim].frameLerp)));
|
|
}
|
|
|
|
if (ps->fd.forcePowersActive & (1 << FP_RAGE))
|
|
{
|
|
ps->torsoTimer /= 1.7;
|
|
}
|
|
}
|
|
}
|
|
|
|
setAnimLegs:
|
|
// Set legs anim
|
|
if (setAnimParts & SETANIM_LEGS)
|
|
{
|
|
// Don't reset if it's already running the anim
|
|
if( !(setAnimFlags & SETANIM_FLAG_RESTART) && (ps->legsAnim) == anim )
|
|
{
|
|
goto setAnimDone;
|
|
}
|
|
// or if a more important anim is running
|
|
if( !(setAnimFlags & SETANIM_FLAG_OVERRIDE) && ((ps->legsTimer > 0)||(ps->legsTimer == -1)) )
|
|
{
|
|
goto setAnimDone;
|
|
}
|
|
|
|
BG_StartLegsAnim(ps, anim);
|
|
|
|
if (setAnimFlags & SETANIM_FLAG_HOLD)
|
|
{
|
|
if (setAnimFlags & SETANIM_FLAG_HOLDLESS)
|
|
{ // Make sure to only wait in full 1/20 sec server frame intervals.
|
|
int dur;
|
|
int speedDif;
|
|
|
|
dur = (animations[anim].numFrames-1) * fabs((float)(animations[anim].frameLerp));
|
|
speedDif = dur - (dur * editAnimSpeed);
|
|
dur += speedDif;
|
|
if (dur > 1)
|
|
{
|
|
ps->legsTimer = dur-1;
|
|
}
|
|
else
|
|
{
|
|
ps->legsTimer = fabs((float)(animations[anim].frameLerp));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ps->legsTimer = ((animations[anim].numFrames ) * fabs((float)(animations[anim].frameLerp)));
|
|
}
|
|
|
|
if (PM_RunningAnim(anim) ||
|
|
PM_WalkingAnim(anim)) //these guys are ok, they don't actually reference pm
|
|
{
|
|
if (ps->fd.forcePowersActive & (1 << FP_RAGE))
|
|
{
|
|
ps->legsTimer /= 1.3;
|
|
}
|
|
else if (ps->fd.forcePowersActive & (1 << FP_SPEED))
|
|
{
|
|
ps->legsTimer /= 1.7;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
setAnimDone:
|
|
return;
|
|
}
|
|
|
|
void PM_SetAnimFinal(int setAnimParts,int anim,int setAnimFlags,
|
|
int blendTime) // default blendTime=350
|
|
{
|
|
BG_SetAnimFinal(pm->ps, pm->animations, setAnimParts, anim, setAnimFlags, blendTime);
|
|
}
|
|
|
|
|
|
qboolean BG_HasAnimation(int animIndex, int animation)
|
|
{
|
|
animation_t *animations;
|
|
|
|
//must be a valid anim number
|
|
if ( animation < 0 || animation >= MAX_ANIMATIONS )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
//Must have a file index entry
|
|
if( animIndex < 0 || animIndex > bgNumAllAnims )
|
|
return qfalse;
|
|
|
|
animations = bgAllAnims[animIndex].anims;
|
|
|
|
//No frames, no anim
|
|
if ( animations[animation].numFrames == 0 )
|
|
return qfalse;
|
|
|
|
//Has the sequence
|
|
return qtrue;
|
|
}
|
|
|
|
int BG_PickAnim( int animIndex, int minAnim, int maxAnim )
|
|
{
|
|
int anim;
|
|
int count = 0;
|
|
|
|
do
|
|
{
|
|
anim = Q_irand(minAnim, maxAnim);
|
|
count++;
|
|
}
|
|
while ( !BG_HasAnimation( animIndex, anim ) && count < 1000 );
|
|
|
|
if (count == 1000)
|
|
{ //guess we just don't have a death anim then.
|
|
return -1;
|
|
}
|
|
|
|
return anim;
|
|
}
|
|
|
|
//I want to be able to use this on a playerstate even when we are not the focus
|
|
//of a pmove too so I have ported it to true BGishness.
|
|
//Please do not reference pm in this function or any functions that it calls,
|
|
//or I will cry. -rww
|
|
void BG_SetAnim(playerState_t *ps, animation_t *animations, int setAnimParts,int anim,int setAnimFlags, int blendTime)
|
|
{
|
|
if (!animations)
|
|
{
|
|
animations = bgAllAnims[0].anims;
|
|
}
|
|
|
|
if (animations[anim].firstFrame == 0 && animations[anim].numFrames == 0)
|
|
{
|
|
if (anim == BOTH_RUNBACK1 ||
|
|
anim == BOTH_WALKBACK1 ||
|
|
anim == BOTH_RUN1)
|
|
{ //hack for droids
|
|
anim = BOTH_WALK2;
|
|
}
|
|
|
|
if (animations[anim].firstFrame == 0 && animations[anim].numFrames == 0)
|
|
{ //still? Just return then I guess.
|
|
return;
|
|
}
|
|
}
|
|
|
|
/*
|
|
if (BG_InSpecialJump(anim))
|
|
{
|
|
setAnimFlags |= SETANIM_FLAG_RESTART;
|
|
}
|
|
*/
|
|
//Don't know why I put this here originally but it's messing stuff up now and it isn't needed.
|
|
|
|
// if (BG_InRoll(ps, ps->legsAnim))
|
|
// { //never interrupt a roll
|
|
// return;
|
|
// }
|
|
|
|
if (setAnimFlags&SETANIM_FLAG_OVERRIDE)
|
|
{
|
|
if (setAnimParts & SETANIM_TORSO)
|
|
{
|
|
if( (setAnimFlags & SETANIM_FLAG_RESTART) || (ps->torsoAnim) != anim )
|
|
{
|
|
BG_SetTorsoAnimTimer(ps, 0);
|
|
}
|
|
}
|
|
if (setAnimParts & SETANIM_LEGS)
|
|
{
|
|
if( (setAnimFlags & SETANIM_FLAG_RESTART) || (ps->legsAnim) != anim )
|
|
{
|
|
BG_SetLegsAnimTimer(ps, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
BG_SetAnimFinal(ps, animations, setAnimParts, anim, setAnimFlags, blendTime);
|
|
}
|
|
|
|
void PM_SetAnim(int setAnimParts,int anim,int setAnimFlags, int blendTime)
|
|
{
|
|
BG_SetAnim(pm->ps, pm->animations, setAnimParts, anim, setAnimFlags, blendTime);
|
|
}
|
|
|
|
#include "../namespace_end.h" // End of animation utilities
|