mirror of
https://github.com/ioquake/jedi-academy.git
synced 2024-11-29 15:32:19 +00:00
4143 lines
121 KiB
C
4143 lines
121 KiB
C
#include "q_shared.h"
|
|
#include "bg_public.h"
|
|
#include "bg_local.h"
|
|
#include "w_saber.h"
|
|
|
|
#include "../namespace_begin.h"
|
|
extern qboolean BG_SabersOff( playerState_t *ps );
|
|
saberInfo_t *BG_MySaber( int clientNum, int saberNum );
|
|
|
|
int PM_irand_timesync(int val1, int val2)
|
|
{
|
|
int i;
|
|
|
|
i = (val1-1) + (Q_random( &pm->cmd.serverTime )*(val2 - val1)) + 1;
|
|
if (i < val1)
|
|
{
|
|
i = val1;
|
|
}
|
|
if (i > val2)
|
|
{
|
|
i = val2;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
void BG_ForcePowerDrain( playerState_t *ps, forcePowers_t forcePower, int overrideAmt )
|
|
{
|
|
//take away the power
|
|
int drain = overrideAmt;
|
|
|
|
/*
|
|
if (ps->powerups[PW_FORCE_BOON])
|
|
{
|
|
return;
|
|
}
|
|
*/
|
|
//No longer grant infinite force with boon.
|
|
|
|
if ( !drain )
|
|
{
|
|
drain = forcePowerNeeded[ps->fd.forcePowerLevel[forcePower]][forcePower];
|
|
}
|
|
if ( !drain )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (forcePower == FP_LEVITATION)
|
|
{ //special case
|
|
int jumpDrain = 0;
|
|
|
|
if (ps->velocity[2] > 250)
|
|
{
|
|
jumpDrain = 20;
|
|
}
|
|
else if (ps->velocity[2] > 200)
|
|
{
|
|
jumpDrain = 16;
|
|
}
|
|
else if (ps->velocity[2] > 150)
|
|
{
|
|
jumpDrain = 12;
|
|
}
|
|
else if (ps->velocity[2] > 100)
|
|
{
|
|
jumpDrain = 8;
|
|
}
|
|
else if (ps->velocity[2] > 50)
|
|
{
|
|
jumpDrain = 6;
|
|
}
|
|
else if (ps->velocity[2] > 0)
|
|
{
|
|
jumpDrain = 4;
|
|
}
|
|
|
|
if (jumpDrain)
|
|
{
|
|
if (ps->fd.forcePowerLevel[FP_LEVITATION])
|
|
{ //don't divide by 0!
|
|
jumpDrain /= ps->fd.forcePowerLevel[FP_LEVITATION];
|
|
}
|
|
}
|
|
|
|
ps->fd.forcePower -= jumpDrain;
|
|
if ( ps->fd.forcePower < 0 )
|
|
{
|
|
ps->fd.forcePower = 0;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ps->fd.forcePower -= drain;
|
|
if ( ps->fd.forcePower < 0 )
|
|
{
|
|
ps->fd.forcePower = 0;
|
|
}
|
|
}
|
|
|
|
qboolean BG_EnoughForcePowerForMove( int cost )
|
|
{
|
|
if ( pm->ps->fd.forcePower < cost )
|
|
{
|
|
PM_AddEvent( EV_NOAMMO );
|
|
return qfalse;
|
|
}
|
|
|
|
return qtrue;
|
|
}
|
|
|
|
// Silly, but I'm replacing these macros so they are shorter!
|
|
#define AFLAG_IDLE (SETANIM_FLAG_NORMAL)
|
|
#define AFLAG_ACTIVE (SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS)
|
|
#define AFLAG_WAIT (SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS)
|
|
#define AFLAG_FINISH (SETANIM_FLAG_HOLD)
|
|
|
|
//FIXME: add the alternate anims for each style?
|
|
saberMoveData_t saberMoveData[LS_MOVE_MAX] = {// NB:randomized
|
|
// name anim(do all styles?)startQ endQ setanimflag blend, blocking chain_idle chain_attack trailLen
|
|
{"None", BOTH_STAND1, Q_R, Q_R, AFLAG_IDLE, 350, BLK_NO, LS_NONE, LS_NONE, 0 }, // LS_NONE = 0,
|
|
|
|
// General movements with saber
|
|
{"Ready", BOTH_STAND2, Q_R, Q_R, AFLAG_IDLE, 350, BLK_WIDE, LS_READY, LS_S_R2L, 0 }, // LS_READY,
|
|
{"Draw", BOTH_STAND1TO2, Q_R, Q_R, AFLAG_FINISH, 350, BLK_NO, LS_READY, LS_S_R2L, 0 }, // LS_DRAW,
|
|
{"Putaway", BOTH_STAND2TO1, Q_R, Q_R, AFLAG_FINISH, 350, BLK_NO, LS_READY, LS_S_R2L, 0 }, // LS_PUTAWAY,
|
|
|
|
// Attacks
|
|
//UL2LR
|
|
{"TL2BR Att", BOTH_A1_TL_BR, Q_TL, Q_BR, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_R_TL2BR, LS_R_TL2BR, 200 }, // LS_A_TL2BR
|
|
//SLASH LEFT
|
|
{"L2R Att", BOTH_A1__L__R, Q_L, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_R_L2R, LS_R_L2R, 200 }, // LS_A_L2R
|
|
//LL2UR
|
|
{"BL2TR Att", BOTH_A1_BL_TR, Q_BL, Q_TR, AFLAG_ACTIVE, 50, BLK_TIGHT, LS_R_BL2TR, LS_R_BL2TR, 200 }, // LS_A_BL2TR
|
|
//LR2UL
|
|
{"BR2TL Att", BOTH_A1_BR_TL, Q_BR, Q_TL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_R_BR2TL, LS_R_BR2TL, 200 }, // LS_A_BR2TL
|
|
//SLASH RIGHT
|
|
{"R2L Att", BOTH_A1__R__L, Q_R, Q_L, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_R_R2L, LS_R_R2L, 200 },// LS_A_R2L
|
|
//UR2LL
|
|
{"TR2BL Att", BOTH_A1_TR_BL, Q_TR, Q_BL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_R_TR2BL, LS_R_TR2BL, 200 }, // LS_A_TR2BL
|
|
//SLASH DOWN
|
|
{"T2B Att", BOTH_A1_T__B_, Q_T, Q_B, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_R_T2B, LS_R_T2B, 200 }, // LS_A_T2B
|
|
//special attacks
|
|
{"Back Stab", BOTH_A2_STABBACK1, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_BACKSTAB
|
|
{"Back Att", BOTH_ATTACK_BACK, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_BACK
|
|
{"CR Back Att", BOTH_CROUCHATTACKBACK1,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_BACK_CR
|
|
{"RollStab", BOTH_ROLL_STAB, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_ROLL_STAB
|
|
{"Lunge Att", BOTH_LUNGE2_B__T_, Q_B, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_LUNGE
|
|
{"Jump Att", BOTH_FORCELEAP2_T__B_,Q_T, Q_B, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_JUMP_T__B_
|
|
{"Flip Stab", BOTH_JUMPFLIPSTABDOWN,Q_R, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1_T___R, 200 }, // LS_A_FLIP_STAB
|
|
{"Flip Slash", BOTH_JUMPFLIPSLASHDOWN1,Q_L,Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__R_T_, 200 }, // LS_A_FLIP_SLASH
|
|
{"DualJump Atk",BOTH_JUMPATTACK6, Q_R, Q_BL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1_BL_TR, 200 }, // LS_JUMPATTACK_DUAL
|
|
|
|
{"DualJumpAtkL_A",BOTH_ARIAL_LEFT, Q_R, Q_TL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_A_TL2BR, 200 }, // LS_JUMPATTACK_ARIAL_LEFT
|
|
{"DualJumpAtkR_A",BOTH_ARIAL_RIGHT, Q_R, Q_TR, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_A_TR2BL, 200 }, // LS_JUMPATTACK_ARIAL_RIGHT
|
|
|
|
{"DualJumpAtkL_A",BOTH_CARTWHEEL_LEFT, Q_R,Q_TL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1_TL_BR, 200 }, // LS_JUMPATTACK_CART_LEFT
|
|
{"DualJumpAtkR_A",BOTH_CARTWHEEL_RIGHT, Q_R,Q_TR, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1_TR_BL, 200 }, // LS_JUMPATTACK_CART_RIGHT
|
|
|
|
{"DualJumpAtkLStaff", BOTH_BUTTERFLY_FL1,Q_R,Q_L, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__L__R, 200 }, // LS_JUMPATTACK_STAFF_LEFT
|
|
{"DualJumpAtkRStaff", BOTH_BUTTERFLY_FR1,Q_R,Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__R__L, 200 }, // LS_JUMPATTACK_STAFF_RIGHT
|
|
|
|
{"ButterflyLeft", BOTH_BUTTERFLY_LEFT,Q_R,Q_L, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__L__R, 200 }, // LS_BUTTERFLY_LEFT
|
|
{"ButterflyRight", BOTH_BUTTERFLY_RIGHT,Q_R,Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__R__L, 200 }, // LS_BUTTERFLY_RIGHT
|
|
|
|
{"BkFlip Atk", BOTH_JUMPATTACK7, Q_B, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1_T___R, 200 }, // LS_A_BACKFLIP_ATK
|
|
{"DualSpinAtk", BOTH_SPINATTACK6, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SPINATTACK_DUAL
|
|
{"StfSpinAtk", BOTH_SPINATTACK7, Q_L, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SPINATTACK
|
|
{"LngLeapAtk", BOTH_FORCELONGLEAP_ATTACK,Q_R,Q_L, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_LEAP_ATTACK
|
|
{"SwoopAtkR", BOTH_VS_ATR_S, Q_R, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SWOOP_ATTACK_RIGHT
|
|
{"SwoopAtkL", BOTH_VS_ATL_S, Q_L, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SWOOP_ATTACK_LEFT
|
|
{"TauntaunAtkR",BOTH_VT_ATR_S, Q_R, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_TAUNTAUN_ATTACK_RIGHT
|
|
{"TauntaunAtkL",BOTH_VT_ATL_S, Q_L, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_TAUNTAUN_ATTACK_LEFT
|
|
{"StfKickFwd", BOTH_A7_KICK_F, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_F
|
|
{"StfKickBack", BOTH_A7_KICK_B, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_B
|
|
{"StfKickRight",BOTH_A7_KICK_R, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_R
|
|
{"StfKickLeft", BOTH_A7_KICK_L, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_L
|
|
{"StfKickSpin", BOTH_A7_KICK_S, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_S_R2L, 200 }, // LS_KICK_S
|
|
{"StfKickBkFwd",BOTH_A7_KICK_BF, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_S_R2L, 200 }, // LS_KICK_BF
|
|
{"StfKickSplit",BOTH_A7_KICK_RL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_S_R2L, 200 }, // LS_KICK_RL
|
|
{"StfKickFwdAir",BOTH_A7_KICK_F_AIR,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_F_AIR
|
|
{"StfKickBackAir",BOTH_A7_KICK_B_AIR,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_B_AIR
|
|
{"StfKickRightAir",BOTH_A7_KICK_R_AIR,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_R_AIR
|
|
{"StfKickLeftAir",BOTH_A7_KICK_L_AIR,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_L_AIR
|
|
{"StabDown", BOTH_STABDOWN, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_STABDOWN
|
|
{"StabDownStf", BOTH_STABDOWN_STAFF,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_STABDOWN_STAFF
|
|
{"StabDownDual",BOTH_STABDOWN_DUAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_STABDOWN_DUAL
|
|
{"dualspinprot",BOTH_A6_SABERPROTECT,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 500 }, // LS_DUAL_SPIN_PROTECT
|
|
{"StfSoulCal", BOTH_A7_SOULCAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 500 }, // LS_STAFF_SOULCAL
|
|
{"specialfast", BOTH_A1_SPECIAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 2000}, // LS_A1_SPECIAL
|
|
{"specialmed", BOTH_A2_SPECIAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 2000}, // LS_A2_SPECIAL
|
|
{"specialstr", BOTH_A3_SPECIAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 2000}, // LS_A3_SPECIAL
|
|
{"upsidedwnatk",BOTH_FLIP_ATTACK7, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200}, // LS_UPSIDE_DOWN_ATTACK
|
|
{"pullatkstab", BOTH_PULL_IMPALE_STAB,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200}, // LS_PULL_ATTACK_STAB
|
|
{"pullatkswing",BOTH_PULL_IMPALE_SWING,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200}, // LS_PULL_ATTACK_SWING
|
|
{"AloraSpinAtk",BOTH_ALORA_SPIN_SLASH,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SPINATTACK_ALORA
|
|
{"Dual FB Atk", BOTH_A6_FB, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_DUAL_FB
|
|
{"Dual LR Atk", BOTH_A6_LR, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_DUAL_LR
|
|
{"StfHiltBash", BOTH_A7_HILT, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_HILT_BASH
|
|
|
|
//starts
|
|
{"TL2BR St", BOTH_S1_S1_TL, Q_R, Q_TL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_A_TL2BR, LS_A_TL2BR, 200 }, // LS_S_TL2BR
|
|
{"L2R St", BOTH_S1_S1__L, Q_R, Q_L, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_A_L2R, LS_A_L2R, 200 }, // LS_S_L2R
|
|
{"BL2TR St", BOTH_S1_S1_BL, Q_R, Q_BL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_A_BL2TR, LS_A_BL2TR, 200 }, // LS_S_BL2TR
|
|
{"BR2TL St", BOTH_S1_S1_BR, Q_R, Q_BR, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_A_BR2TL, LS_A_BR2TL, 200 }, // LS_S_BR2TL
|
|
{"R2L St", BOTH_S1_S1__R, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_A_R2L, LS_A_R2L, 200 }, // LS_S_R2L
|
|
{"TR2BL St", BOTH_S1_S1_TR, Q_R, Q_TR, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_A_TR2BL, LS_A_TR2BL, 200 }, // LS_S_TR2BL
|
|
{"T2B St", BOTH_S1_S1_T_, Q_R, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_A_T2B, LS_A_T2B, 200 }, // LS_S_T2B
|
|
|
|
//returns
|
|
{"TL2BR Ret", BOTH_R1_BR_S1, Q_BR, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_TL2BR
|
|
{"L2R Ret", BOTH_R1__R_S1, Q_R, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_L2R
|
|
{"BL2TR Ret", BOTH_R1_TR_S1, Q_TR, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_BL2TR
|
|
{"BR2TL Ret", BOTH_R1_TL_S1, Q_TL, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_BR2TL
|
|
{"R2L Ret", BOTH_R1__L_S1, Q_L, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_R2L
|
|
{"TR2BL Ret", BOTH_R1_BL_S1, Q_BL, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_TR2BL
|
|
{"T2B Ret", BOTH_R1_B__S1, Q_B, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_T2B
|
|
|
|
//Transitions
|
|
{"BR2R Trans", BOTH_T1_BR__R, Q_BR, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_A_R2L, 150 }, //# Fast arc bottom right to right
|
|
{"BR2TR Trans", BOTH_T1_BR_TR, Q_BR, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_TR2BL, 150 }, //# Fast arc bottom right to top right (use: BOTH_T1_TR_BR)
|
|
{"BR2T Trans", BOTH_T1_BR_T_, Q_BR, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_T2B, 150 }, //# Fast arc bottom right to top (use: BOTH_T1_T__BR)
|
|
{"BR2TL Trans", BOTH_T1_BR_TL, Q_BR, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_A_TL2BR, 150 }, //# Fast weak spin bottom right to top left
|
|
{"BR2L Trans", BOTH_T1_BR__L, Q_BR, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_A_L2R, 150 }, //# Fast weak spin bottom right to left
|
|
{"BR2BL Trans", BOTH_T1_BR_BL, Q_BR, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_A_BL2TR, 150 }, //# Fast weak spin bottom right to bottom left
|
|
{"R2BR Trans", BOTH_T1__R_BR, Q_R, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_A_BR2TL, 150 }, //# Fast arc right to bottom right (use: BOTH_T1_BR__R)
|
|
{"R2TR Trans", BOTH_T1__R_TR, Q_R, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_TR2BL, 150 }, //# Fast arc right to top right
|
|
{"R2T Trans", BOTH_T1__R_T_, Q_R, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_T2B, 150 }, //# Fast ar right to top (use: BOTH_T1_T___R)
|
|
{"R2TL Trans", BOTH_T1__R_TL, Q_R, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_A_TL2BR, 150 }, //# Fast arc right to top left
|
|
{"R2L Trans", BOTH_T1__R__L, Q_R, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_A_L2R, 150 }, //# Fast weak spin right to left
|
|
{"R2BL Trans", BOTH_T1__R_BL, Q_R, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_A_BL2TR, 150 }, //# Fast weak spin right to bottom left
|
|
{"TR2BR Trans", BOTH_T1_TR_BR, Q_TR, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_A_BR2TL, 150 }, //# Fast arc top right to bottom right
|
|
{"TR2R Trans", BOTH_T1_TR__R, Q_TR, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_A_R2L, 150 }, //# Fast arc top right to right (use: BOTH_T1__R_TR)
|
|
{"TR2T Trans", BOTH_T1_TR_T_, Q_TR, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_T2B, 150 }, //# Fast arc top right to top (use: BOTH_T1_T__TR)
|
|
{"TR2TL Trans", BOTH_T1_TR_TL, Q_TR, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_A_TL2BR, 150 }, //# Fast arc top right to top left
|
|
{"TR2L Trans", BOTH_T1_TR__L, Q_TR, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_A_L2R, 150 }, //# Fast arc top right to left
|
|
{"TR2BL Trans", BOTH_T1_TR_BL, Q_TR, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_A_BL2TR, 150 }, //# Fast weak spin top right to bottom left
|
|
{"T2BR Trans", BOTH_T1_T__BR, Q_T, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_A_BR2TL, 150 }, //# Fast arc top to bottom right
|
|
{"T2R Trans", BOTH_T1_T___R, Q_T, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_A_R2L, 150 }, //# Fast arc top to right
|
|
{"T2TR Trans", BOTH_T1_T__TR, Q_T, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_TR2BL, 150 }, //# Fast arc top to top right
|
|
{"T2TL Trans", BOTH_T1_T__TL, Q_T, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_A_TL2BR, 150 }, //# Fast arc top to top left
|
|
{"T2L Trans", BOTH_T1_T___L, Q_T, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_A_L2R, 150 }, //# Fast arc top to left
|
|
{"T2BL Trans", BOTH_T1_T__BL, Q_T, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_A_BL2TR, 150 }, //# Fast arc top to bottom left
|
|
{"TL2BR Trans", BOTH_T1_TL_BR, Q_TL, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_A_BR2TL, 150 }, //# Fast weak spin top left to bottom right
|
|
{"TL2R Trans", BOTH_T1_TL__R, Q_TL, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_A_R2L, 150 }, //# Fast arc top left to right (use: BOTH_T1__R_TL)
|
|
{"TL2TR Trans", BOTH_T1_TL_TR, Q_TL, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_TR2BL, 150 }, //# Fast arc top left to top right (use: BOTH_T1_TR_TL)
|
|
{"TL2T Trans", BOTH_T1_TL_T_, Q_TL, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_T2B, 150 }, //# Fast arc top left to top (use: BOTH_T1_T__TL)
|
|
{"TL2L Trans", BOTH_T1_TL__L, Q_TL, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_A_L2R, 150 }, //# Fast arc top left to left (use: BOTH_T1__L_TL)
|
|
{"TL2BL Trans", BOTH_T1_TL_BL, Q_TL, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_A_BL2TR, 150 }, //# Fast arc top left to bottom left
|
|
{"L2BR Trans", BOTH_T1__L_BR, Q_L, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_A_BR2TL, 150 }, //# Fast weak spin left to bottom right
|
|
{"L2R Trans", BOTH_T1__L__R, Q_L, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_A_R2L, 150 }, //# Fast weak spin left to right
|
|
{"L2TR Trans", BOTH_T1__L_TR, Q_L, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_TR2BL, 150 }, //# Fast arc left to top right (use: BOTH_T1_TR__L)
|
|
{"L2T Trans", BOTH_T1__L_T_, Q_L, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_T2B, 150 }, //# Fast arc left to top (use: BOTH_T1_T___L)
|
|
{"L2TL Trans", BOTH_T1__L_TL, Q_L, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_A_TL2BR, 150 }, //# Fast arc left to top left
|
|
{"L2BL Trans", BOTH_T1__L_BL, Q_L, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_A_BL2TR, 150 }, //# Fast arc left to bottom left (use: BOTH_T1_BL__L)
|
|
{"BL2BR Trans", BOTH_T1_BL_BR, Q_BL, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_A_BR2TL, 150 }, //# Fast weak spin bottom left to bottom right
|
|
{"BL2R Trans", BOTH_T1_BL__R, Q_BL, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_A_R2L, 150 }, //# Fast weak spin bottom left to right
|
|
{"BL2TR Trans", BOTH_T1_BL_TR, Q_BL, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_TR2BL, 150 }, //# Fast weak spin bottom left to top right
|
|
{"BL2T Trans", BOTH_T1_BL_T_, Q_BL, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_A_T2B, 150 }, //# Fast arc bottom left to top (use: BOTH_T1_T__BL)
|
|
{"BL2TL Trans", BOTH_T1_BL_TL, Q_BL, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_A_TL2BR, 150 }, //# Fast arc bottom left to top left (use: BOTH_T1_TL_BL)
|
|
{"BL2L Trans", BOTH_T1_BL__L, Q_BL, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_A_L2R, 150 }, //# Fast arc bottom left to left
|
|
|
|
//Bounces
|
|
{"Bounce BR", BOTH_B1_BR___, Q_BR, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_T1_BR_TR, 150 },
|
|
{"Bounce R", BOTH_B1__R___, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_T1__R__L, 150 },
|
|
{"Bounce TR", BOTH_B1_TR___, Q_TR, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_TR_TL, 150 },
|
|
{"Bounce T", BOTH_B1_T____, Q_T, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_T__BL, 150 },
|
|
{"Bounce TL", BOTH_B1_TL___, Q_TL, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_T1_TL_TR, 150 },
|
|
{"Bounce L", BOTH_B1__L___, Q_L, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_T1__L__R, 150 },
|
|
{"Bounce BL", BOTH_B1_BL___, Q_BL, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_T1_BL_TR, 150 },
|
|
|
|
//Deflected attacks (like bounces, but slide off enemy saber, not straight back)
|
|
{"Deflect BR", BOTH_D1_BR___, Q_BR, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_T1_BR_TR, 150 },
|
|
{"Deflect R", BOTH_D1__R___, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_T1__R__L, 150 },
|
|
{"Deflect TR", BOTH_D1_TR___, Q_TR, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_TR_TL, 150 },
|
|
{"Deflect T", BOTH_B1_T____, Q_T, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_T__BL, 150 },
|
|
{"Deflect TL", BOTH_D1_TL___, Q_TL, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_T1_TL_TR, 150 },
|
|
{"Deflect L", BOTH_D1__L___, Q_L, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_T1__L__R, 150 },
|
|
{"Deflect BL", BOTH_D1_BL___, Q_BL, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_T1_BL_TR, 150 },
|
|
{"Deflect B", BOTH_D1_B____, Q_B, Q_B, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_T__BL, 150 },
|
|
|
|
//Reflected attacks
|
|
{"Reflected BR",BOTH_V1_BR_S1, Q_BR, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_BR
|
|
{"Reflected R", BOTH_V1__R_S1, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1__R
|
|
{"Reflected TR",BOTH_V1_TR_S1, Q_TR, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_TR
|
|
{"Reflected T", BOTH_V1_T__S1, Q_T, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_T_
|
|
{"Reflected TL",BOTH_V1_TL_S1, Q_TL, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_TL
|
|
{"Reflected L", BOTH_V1__L_S1, Q_L, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1__L
|
|
{"Reflected BL",BOTH_V1_BL_S1, Q_BL, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_BL
|
|
{"Reflected B", BOTH_V1_B__S1, Q_B, Q_B, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_B_
|
|
|
|
// Broken parries
|
|
{"BParry Top", BOTH_H1_S1_T_, Q_T, Q_B, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UP,
|
|
{"BParry UR", BOTH_H1_S1_TR, Q_TR, Q_BL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UR,
|
|
{"BParry UL", BOTH_H1_S1_TL, Q_TL, Q_BR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UL,
|
|
{"BParry LR", BOTH_H1_S1_BL, Q_BL, Q_TR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LR,
|
|
{"BParry Bot", BOTH_H1_S1_B_, Q_B, Q_T, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LL
|
|
{"BParry LL", BOTH_H1_S1_BR, Q_BR, Q_TL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LL
|
|
|
|
// Knockaways
|
|
{"Knock Top", BOTH_K1_S1_T_, Q_R, Q_T, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_T1_T__BR, 150 }, // LS_PARRY_UP,
|
|
{"Knock UR", BOTH_K1_S1_TR, Q_R, Q_TR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_T1_TR__R, 150 }, // LS_PARRY_UR,
|
|
{"Knock UL", BOTH_K1_S1_TL, Q_R, Q_TL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BR2TL, LS_T1_TL__L, 150 }, // LS_PARRY_UL,
|
|
{"Knock LR", BOTH_K1_S1_BL, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_T1_BL_TL, 150 }, // LS_PARRY_LR,
|
|
{"Knock LL", BOTH_K1_S1_BR, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_T1_BR_TR, 150 }, // LS_PARRY_LL
|
|
|
|
// Parry
|
|
{"Parry Top", BOTH_P1_S1_T_, Q_R, Q_T, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_A_T2B, 150 }, // LS_PARRY_UP,
|
|
{"Parry UR", BOTH_P1_S1_TR, Q_R, Q_TL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_A_TR2BL, 150 }, // LS_PARRY_UR,
|
|
{"Parry UL", BOTH_P1_S1_TL, Q_R, Q_TR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BR2TL, LS_A_TL2BR, 150 }, // LS_PARRY_UL,
|
|
{"Parry LR", BOTH_P1_S1_BL, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_A_BR2TL, 150 }, // LS_PARRY_LR,
|
|
{"Parry LL", BOTH_P1_S1_BR, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_A_BL2TR, 150 }, // LS_PARRY_LL
|
|
|
|
// Reflecting a missile
|
|
{"Reflect Top", BOTH_P1_S1_T_, Q_R, Q_T, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_A_T2B, 300 }, // LS_PARRY_UP,
|
|
{"Reflect UR", BOTH_P1_S1_TL, Q_R, Q_TR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BR2TL, LS_A_TL2BR, 300 }, // LS_PARRY_UR,
|
|
{"Reflect UL", BOTH_P1_S1_TR, Q_R, Q_TL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_BL2TR, LS_A_TR2BL, 300 }, // LS_PARRY_UL,
|
|
{"Reflect LR", BOTH_P1_S1_BR, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_A_BL2TR, 300 }, // LS_PARRY_LR
|
|
{"Reflect LL", BOTH_P1_S1_BL, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_A_BR2TL, 300 }, // LS_PARRY_LL,
|
|
};
|
|
|
|
|
|
int transitionMove[Q_NUM_QUADS][Q_NUM_QUADS] =
|
|
{
|
|
LS_NONE, //Can't transition to same pos!
|
|
LS_T1_BR__R,//40
|
|
LS_T1_BR_TR,
|
|
LS_T1_BR_T_,
|
|
LS_T1_BR_TL,
|
|
LS_T1_BR__L,
|
|
LS_T1_BR_BL,
|
|
LS_NONE, //No transitions to bottom, and no anims start there, so shouldn't need any
|
|
LS_T1__R_BR,//46
|
|
LS_NONE, //Can't transition to same pos!
|
|
LS_T1__R_TR,
|
|
LS_T1__R_T_,
|
|
LS_T1__R_TL,
|
|
LS_T1__R__L,
|
|
LS_T1__R_BL,
|
|
LS_NONE, //No transitions to bottom, and no anims start there, so shouldn't need any
|
|
LS_T1_TR_BR,//52
|
|
LS_T1_TR__R,
|
|
LS_NONE, //Can't transition to same pos!
|
|
LS_T1_TR_T_,
|
|
LS_T1_TR_TL,
|
|
LS_T1_TR__L,
|
|
LS_T1_TR_BL,
|
|
LS_NONE, //No transitions to bottom, and no anims start there, so shouldn't need any
|
|
LS_T1_T__BR,//58
|
|
LS_T1_T___R,
|
|
LS_T1_T__TR,
|
|
LS_NONE, //Can't transition to same pos!
|
|
LS_T1_T__TL,
|
|
LS_T1_T___L,
|
|
LS_T1_T__BL,
|
|
LS_NONE, //No transitions to bottom, and no anims start there, so shouldn't need any
|
|
LS_T1_TL_BR,//64
|
|
LS_T1_TL__R,
|
|
LS_T1_TL_TR,
|
|
LS_T1_TL_T_,
|
|
LS_NONE, //Can't transition to same pos!
|
|
LS_T1_TL__L,
|
|
LS_T1_TL_BL,
|
|
LS_NONE, //No transitions to bottom, and no anims start there, so shouldn't need any
|
|
LS_T1__L_BR,//70
|
|
LS_T1__L__R,
|
|
LS_T1__L_TR,
|
|
LS_T1__L_T_,
|
|
LS_T1__L_TL,
|
|
LS_NONE, //Can't transition to same pos!
|
|
LS_T1__L_BL,
|
|
LS_NONE, //No transitions to bottom, and no anims start there, so shouldn't need any
|
|
LS_T1_BL_BR,//76
|
|
LS_T1_BL__R,
|
|
LS_T1_BL_TR,
|
|
LS_T1_BL_T_,
|
|
LS_T1_BL_TL,
|
|
LS_T1_BL__L,
|
|
LS_NONE, //Can't transition to same pos!
|
|
LS_NONE, //No transitions to bottom, and no anims start there, so shouldn't need any
|
|
LS_T1_BL_BR,//NOTE: there are no transitions from bottom, so re-use the bottom right transitions
|
|
LS_T1_BR__R,
|
|
LS_T1_BR_TR,
|
|
LS_T1_BR_T_,
|
|
LS_T1_BR_TL,
|
|
LS_T1_BR__L,
|
|
LS_T1_BR_BL,
|
|
LS_NONE //No transitions to bottom, and no anims start there, so shouldn't need any
|
|
};
|
|
|
|
saberMoveName_t PM_AttackMoveForQuad( int quad )
|
|
{
|
|
switch ( quad )
|
|
{
|
|
case Q_B:
|
|
case Q_BR:
|
|
return LS_A_BR2TL;
|
|
break;
|
|
case Q_R:
|
|
return LS_A_R2L;
|
|
break;
|
|
case Q_TR:
|
|
return LS_A_TR2BL;
|
|
break;
|
|
case Q_T:
|
|
return LS_A_T2B;
|
|
break;
|
|
case Q_TL:
|
|
return LS_A_TL2BR;
|
|
break;
|
|
case Q_L:
|
|
return LS_A_L2R;
|
|
break;
|
|
case Q_BL:
|
|
return LS_A_BL2TR;
|
|
break;
|
|
}
|
|
return LS_NONE;
|
|
}
|
|
|
|
qboolean PM_SaberKataDone(int curmove, int newmove);
|
|
|
|
int PM_SaberAnimTransitionAnim( int curmove, int newmove )
|
|
{
|
|
int retmove = newmove;
|
|
if ( curmove == LS_READY )
|
|
{//just standing there
|
|
switch ( newmove )
|
|
{
|
|
case LS_A_TL2BR:
|
|
case LS_A_L2R:
|
|
case LS_A_BL2TR:
|
|
case LS_A_BR2TL:
|
|
case LS_A_R2L:
|
|
case LS_A_TR2BL:
|
|
case LS_A_T2B:
|
|
//transition is the start
|
|
retmove = LS_S_TL2BR + (newmove-LS_A_TL2BR);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
switch ( newmove )
|
|
{
|
|
//transitioning to ready pose
|
|
case LS_READY:
|
|
switch ( curmove )
|
|
{
|
|
//transitioning from an attack
|
|
case LS_A_TL2BR:
|
|
case LS_A_L2R:
|
|
case LS_A_BL2TR:
|
|
case LS_A_BR2TL:
|
|
case LS_A_R2L:
|
|
case LS_A_TR2BL:
|
|
case LS_A_T2B:
|
|
//transition is the return
|
|
retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR);
|
|
break;
|
|
}
|
|
break;
|
|
//transitioning to an attack
|
|
case LS_A_TL2BR:
|
|
case LS_A_L2R:
|
|
case LS_A_BL2TR:
|
|
case LS_A_BR2TL:
|
|
case LS_A_R2L:
|
|
case LS_A_TR2BL:
|
|
case LS_A_T2B:
|
|
if ( newmove == curmove )
|
|
{
|
|
//going into an attack
|
|
if ( PM_SaberKataDone( curmove, newmove ) )
|
|
{//done with this kata, must return to ready before attack again
|
|
retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR);
|
|
}
|
|
else
|
|
{//okay to chain to another attack
|
|
retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
|
|
}
|
|
}
|
|
else if ( saberMoveData[curmove].endQuad == saberMoveData[newmove].startQuad )
|
|
{//new move starts from same quadrant
|
|
retmove = newmove;
|
|
}
|
|
else
|
|
{
|
|
switch ( curmove )
|
|
{
|
|
//transitioning from an attack
|
|
case LS_A_TL2BR:
|
|
case LS_A_L2R:
|
|
case LS_A_BL2TR:
|
|
case LS_A_BR2TL:
|
|
case LS_A_R2L:
|
|
case LS_A_TR2BL:
|
|
case LS_A_T2B:
|
|
case LS_D1_BR:
|
|
case LS_D1__R:
|
|
case LS_D1_TR:
|
|
case LS_D1_T_:
|
|
case LS_D1_TL:
|
|
case LS_D1__L:
|
|
case LS_D1_BL:
|
|
case LS_D1_B_:
|
|
retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
|
|
break;
|
|
//transitioning from a return
|
|
case LS_R_TL2BR:
|
|
case LS_R_L2R:
|
|
case LS_R_BL2TR:
|
|
case LS_R_BR2TL:
|
|
case LS_R_R2L:
|
|
case LS_R_TR2BL:
|
|
case LS_R_T2B:
|
|
//transitioning from a bounce
|
|
/*
|
|
case LS_BOUNCE_UL2LL:
|
|
case LS_BOUNCE_LL2UL:
|
|
case LS_BOUNCE_L2LL:
|
|
case LS_BOUNCE_L2UL:
|
|
case LS_BOUNCE_UR2LR:
|
|
case LS_BOUNCE_LR2UR:
|
|
case LS_BOUNCE_R2LR:
|
|
case LS_BOUNCE_R2UR:
|
|
case LS_BOUNCE_TOP:
|
|
case LS_OVER_UR2UL:
|
|
case LS_OVER_UL2UR:
|
|
case LS_BOUNCE_UR:
|
|
case LS_BOUNCE_UL:
|
|
case LS_BOUNCE_LR:
|
|
case LS_BOUNCE_LL:
|
|
*/
|
|
//transitioning from a parry/reflection/knockaway/broken parry
|
|
case LS_PARRY_UP:
|
|
case LS_PARRY_UR:
|
|
case LS_PARRY_UL:
|
|
case LS_PARRY_LR:
|
|
case LS_PARRY_LL:
|
|
case LS_REFLECT_UP:
|
|
case LS_REFLECT_UR:
|
|
case LS_REFLECT_UL:
|
|
case LS_REFLECT_LR:
|
|
case LS_REFLECT_LL:
|
|
case LS_K1_T_:
|
|
case LS_K1_TR:
|
|
case LS_K1_TL:
|
|
case LS_K1_BR:
|
|
case LS_K1_BL:
|
|
case LS_V1_BR:
|
|
case LS_V1__R:
|
|
case LS_V1_TR:
|
|
case LS_V1_T_:
|
|
case LS_V1_TL:
|
|
case LS_V1__L:
|
|
case LS_V1_BL:
|
|
case LS_V1_B_:
|
|
case LS_H1_T_:
|
|
case LS_H1_TR:
|
|
case LS_H1_TL:
|
|
case LS_H1_BR:
|
|
case LS_H1_BL:
|
|
retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
|
|
break;
|
|
//NB: transitioning from transitions is fine
|
|
}
|
|
}
|
|
break;
|
|
//transitioning to any other anim is not supported
|
|
}
|
|
}
|
|
|
|
if ( retmove == LS_NONE )
|
|
{
|
|
return newmove;
|
|
}
|
|
|
|
return retmove;
|
|
}
|
|
|
|
extern qboolean BG_InKnockDown( int anim );
|
|
saberMoveName_t PM_CheckStabDown( void )
|
|
{
|
|
vec3_t faceFwd, facingAngles;
|
|
vec3_t fwd;
|
|
bgEntity_t *ent = NULL;
|
|
trace_t tr;
|
|
//yeah, vm's may complain, but.. who cares!
|
|
vec3_t trmins = {-15, -15, -15};
|
|
vec3_t trmaxs = {15, 15, 15};
|
|
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
if ( saber1
|
|
&& (saber1->saberFlags&SFL_NO_STABDOWN) )
|
|
{
|
|
return LS_NONE;
|
|
}
|
|
if ( saber2
|
|
&& (saber2->saberFlags&SFL_NO_STABDOWN) )
|
|
{
|
|
return LS_NONE;
|
|
}
|
|
|
|
if ( pm->ps->groundEntityNum == ENTITYNUM_NONE )
|
|
{//sorry must be on ground!
|
|
return LS_NONE;
|
|
}
|
|
if ( pm->ps->clientNum < MAX_CLIENTS )
|
|
{//player
|
|
pm->ps->velocity[2] = 0;
|
|
pm->cmd.upmove = 0;
|
|
}
|
|
|
|
VectorSet(facingAngles, 0, pm->ps->viewangles[YAW], 0);
|
|
AngleVectors( facingAngles, faceFwd, NULL, NULL );
|
|
|
|
//FIXME: need to only move forward until we bump into our target...?
|
|
VectorMA(pm->ps->origin, 164.0f, faceFwd, fwd);
|
|
|
|
pm->trace(&tr, pm->ps->origin, trmins, trmaxs, fwd, pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
if (tr.entityNum < ENTITYNUM_WORLD)
|
|
{
|
|
ent = PM_BGEntForNum(tr.entityNum);
|
|
}
|
|
|
|
if ( ent &&
|
|
(ent->s.eType == ET_PLAYER || ent->s.eType == ET_NPC) &&
|
|
BG_InKnockDown( ent->s.legsAnim ) )
|
|
{//guy is on the ground below me, do a top-down attack
|
|
if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
|
|
{
|
|
return LS_STABDOWN_DUAL;
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
|
|
{
|
|
return LS_STABDOWN_STAFF;
|
|
}
|
|
else
|
|
{
|
|
return LS_STABDOWN;
|
|
}
|
|
}
|
|
return LS_NONE;
|
|
}
|
|
|
|
int PM_SaberMoveQuadrantForMovement( usercmd_t *ucmd )
|
|
{
|
|
if ( ucmd->rightmove > 0 )
|
|
{//moving right
|
|
if ( ucmd->forwardmove > 0 )
|
|
{//forward right = TL2BR slash
|
|
return Q_TL;
|
|
}
|
|
else if ( ucmd->forwardmove < 0 )
|
|
{//backward right = BL2TR uppercut
|
|
return Q_BL;
|
|
}
|
|
else
|
|
{//just right is a left slice
|
|
return Q_L;
|
|
}
|
|
}
|
|
else if ( ucmd->rightmove < 0 )
|
|
{//moving left
|
|
if ( ucmd->forwardmove > 0 )
|
|
{//forward left = TR2BL slash
|
|
return Q_TR;
|
|
}
|
|
else if ( ucmd->forwardmove < 0 )
|
|
{//backward left = BR2TL uppercut
|
|
return Q_BR;
|
|
}
|
|
else
|
|
{//just left is a right slice
|
|
return Q_R;
|
|
}
|
|
}
|
|
else
|
|
{//not moving left or right
|
|
if ( ucmd->forwardmove > 0 )
|
|
{//forward= T2B slash
|
|
return Q_T;
|
|
}
|
|
else if ( ucmd->forwardmove < 0 )
|
|
{//backward= T2B slash //or B2T uppercut?
|
|
return Q_T;
|
|
}
|
|
else
|
|
{//Not moving at all
|
|
return Q_R;
|
|
}
|
|
}
|
|
}
|
|
|
|
//===================================================================
|
|
qboolean PM_SaberInBounce( int move )
|
|
{
|
|
if ( move >= LS_B1_BR && move <= LS_B1_BL )
|
|
{
|
|
return qtrue;
|
|
}
|
|
if ( move >= LS_D1_BR && move <= LS_D1_BL )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_SaberInTransition( int move );
|
|
|
|
int saberMoveTransitionAngle[Q_NUM_QUADS][Q_NUM_QUADS] =
|
|
{
|
|
0,//Q_BR,Q_BR,
|
|
45,//Q_BR,Q_R,
|
|
90,//Q_BR,Q_TR,
|
|
135,//Q_BR,Q_T,
|
|
180,//Q_BR,Q_TL,
|
|
215,//Q_BR,Q_L,
|
|
270,//Q_BR,Q_BL,
|
|
45,//Q_BR,Q_B,
|
|
45,//Q_R,Q_BR,
|
|
0,//Q_R,Q_R,
|
|
45,//Q_R,Q_TR,
|
|
90,//Q_R,Q_T,
|
|
135,//Q_R,Q_TL,
|
|
180,//Q_R,Q_L,
|
|
215,//Q_R,Q_BL,
|
|
90,//Q_R,Q_B,
|
|
90,//Q_TR,Q_BR,
|
|
45,//Q_TR,Q_R,
|
|
0,//Q_TR,Q_TR,
|
|
45,//Q_TR,Q_T,
|
|
90,//Q_TR,Q_TL,
|
|
135,//Q_TR,Q_L,
|
|
180,//Q_TR,Q_BL,
|
|
135,//Q_TR,Q_B,
|
|
135,//Q_T,Q_BR,
|
|
90,//Q_T,Q_R,
|
|
45,//Q_T,Q_TR,
|
|
0,//Q_T,Q_T,
|
|
45,//Q_T,Q_TL,
|
|
90,//Q_T,Q_L,
|
|
135,//Q_T,Q_BL,
|
|
180,//Q_T,Q_B,
|
|
180,//Q_TL,Q_BR,
|
|
135,//Q_TL,Q_R,
|
|
90,//Q_TL,Q_TR,
|
|
45,//Q_TL,Q_T,
|
|
0,//Q_TL,Q_TL,
|
|
45,//Q_TL,Q_L,
|
|
90,//Q_TL,Q_BL,
|
|
135,//Q_TL,Q_B,
|
|
215,//Q_L,Q_BR,
|
|
180,//Q_L,Q_R,
|
|
135,//Q_L,Q_TR,
|
|
90,//Q_L,Q_T,
|
|
45,//Q_L,Q_TL,
|
|
0,//Q_L,Q_L,
|
|
45,//Q_L,Q_BL,
|
|
90,//Q_L,Q_B,
|
|
270,//Q_BL,Q_BR,
|
|
215,//Q_BL,Q_R,
|
|
180,//Q_BL,Q_TR,
|
|
135,//Q_BL,Q_T,
|
|
90,//Q_BL,Q_TL,
|
|
45,//Q_BL,Q_L,
|
|
0,//Q_BL,Q_BL,
|
|
45,//Q_BL,Q_B,
|
|
45,//Q_B,Q_BR,
|
|
90,//Q_B,Q_R,
|
|
135,//Q_B,Q_TR,
|
|
180,//Q_B,Q_T,
|
|
135,//Q_B,Q_TL,
|
|
90,//Q_B,Q_L,
|
|
45,//Q_B,Q_BL,
|
|
0//Q_B,Q_B,
|
|
};
|
|
|
|
int PM_SaberAttackChainAngle( int move1, int move2 )
|
|
{
|
|
if ( move1 == -1 || move2 == -1 )
|
|
{
|
|
return -1;
|
|
}
|
|
return saberMoveTransitionAngle[saberMoveData[move1].endQuad][saberMoveData[move2].startQuad];
|
|
}
|
|
|
|
qboolean PM_SaberKataDone(int curmove, int newmove)
|
|
{
|
|
if (pm->ps->m_iVehicleNum)
|
|
{ //never continue kata on vehicle
|
|
if (pm->ps->saberAttackChainCount > 0)
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
if ( pm->ps->fd.saberAnimLevel == SS_DESANN || pm->ps->fd.saberAnimLevel == SS_TAVION )
|
|
{//desann and tavion can link up as many attacks as they want
|
|
return qfalse;
|
|
}
|
|
|
|
if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
|
|
{
|
|
//TEMP: for now, let staff attacks infinitely chain
|
|
return qfalse;
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
|
|
{
|
|
//TEMP: for now, let staff attacks infinitely chain
|
|
return qfalse;
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_3 )
|
|
{
|
|
if ( curmove == LS_NONE || newmove == LS_NONE )
|
|
{
|
|
if ( pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_3 && pm->ps->saberAttackChainCount > PM_irand_timesync( 0, 1 ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
else if ( pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 3 ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
else if ( pm->ps->saberAttackChainCount > 0 )
|
|
{
|
|
int chainAngle = PM_SaberAttackChainAngle( curmove, newmove );
|
|
if ( chainAngle < 135 || chainAngle > 215 )
|
|
{//if trying to chain to a move that doesn't continue the momentum
|
|
return qtrue;
|
|
}
|
|
else if ( chainAngle == 180 )
|
|
{//continues the momentum perfectly, allow it to chain 66% of the time
|
|
if ( pm->ps->saberAttackChainCount > 1 )
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
else
|
|
{//would continue the movement somewhat, 50% chance of continuing
|
|
if ( pm->ps->saberAttackChainCount > 2 )
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{//Perhaps have chainAngle influence fast and medium chains as well? For now, just do level 3.
|
|
if (newmove == LS_A_TL2BR ||
|
|
newmove == LS_A_L2R ||
|
|
newmove == LS_A_BL2TR ||
|
|
newmove == LS_A_BR2TL ||
|
|
newmove == LS_A_R2L ||
|
|
newmove == LS_A_TR2BL )
|
|
{ //lower chaining tolerance for spinning saber anims
|
|
int chainTolerance;
|
|
|
|
if (pm->ps->fd.saberAnimLevel == FORCE_LEVEL_1)
|
|
{
|
|
chainTolerance = 5;
|
|
}
|
|
else
|
|
{
|
|
chainTolerance = 3;
|
|
}
|
|
|
|
if (pm->ps->saberAttackChainCount >= chainTolerance && PM_irand_timesync(1, pm->ps->saberAttackChainCount) > chainTolerance)
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_2 && pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 5 ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
void PM_SetAnimFrame( playerState_t *gent, int frame, qboolean torso, qboolean legs )
|
|
{
|
|
gent->saberLockFrame = frame;
|
|
}
|
|
|
|
int PM_SaberLockWinAnim( qboolean victory, qboolean superBreak )
|
|
{
|
|
int winAnim = -1;
|
|
switch ( pm->ps->torsoAnim )
|
|
{
|
|
/*
|
|
default:
|
|
#ifndef FINAL_BUILD
|
|
Com_Printf( S_COLOR_RED"ERROR-PM_SaberLockBreak: %s not in saberlock anim, anim = (%d)%s\n", pm->gent->NPC_type, pm->ps->torsoAnim, animTable[pm->ps->torsoAnim].name );
|
|
#endif
|
|
*/
|
|
case BOTH_BF2LOCK:
|
|
if ( superBreak )
|
|
{
|
|
winAnim = BOTH_LK_S_S_T_SB_1_W;
|
|
}
|
|
else if ( !victory )
|
|
{
|
|
winAnim = BOTH_BF1BREAK;
|
|
}
|
|
else
|
|
{
|
|
pm->ps->saberMove = LS_A_T2B;
|
|
winAnim = BOTH_A3_T__B_;
|
|
}
|
|
break;
|
|
case BOTH_BF1LOCK:
|
|
if ( superBreak )
|
|
{
|
|
winAnim = BOTH_LK_S_S_T_SB_1_W;
|
|
}
|
|
else if ( !victory )
|
|
{
|
|
winAnim = BOTH_KNOCKDOWN4;
|
|
}
|
|
else
|
|
{
|
|
pm->ps->saberMove = LS_K1_T_;
|
|
winAnim = BOTH_K1_S1_T_;
|
|
}
|
|
break;
|
|
case BOTH_CWCIRCLELOCK:
|
|
if ( superBreak )
|
|
{
|
|
winAnim = BOTH_LK_S_S_S_SB_1_W;
|
|
}
|
|
else if ( !victory )
|
|
{
|
|
pm->ps->saberMove = LS_V1_BL;//pm->ps->saberBounceMove =
|
|
pm->ps->saberBlocked = BLOCKED_PARRY_BROKEN;
|
|
winAnim = BOTH_V1_BL_S1;
|
|
}
|
|
else
|
|
{
|
|
winAnim = BOTH_CWCIRCLEBREAK;
|
|
}
|
|
break;
|
|
case BOTH_CCWCIRCLELOCK:
|
|
if ( superBreak )
|
|
{
|
|
winAnim = BOTH_LK_S_S_S_SB_1_W;
|
|
}
|
|
else if ( !victory )
|
|
{
|
|
pm->ps->saberMove = LS_V1_BR;//pm->ps->saberBounceMove =
|
|
pm->ps->saberBlocked = BLOCKED_PARRY_BROKEN;
|
|
winAnim = BOTH_V1_BR_S1;
|
|
}
|
|
else
|
|
{
|
|
winAnim = BOTH_CCWCIRCLEBREAK;
|
|
}
|
|
break;
|
|
default:
|
|
//must be using new system:
|
|
break;
|
|
}
|
|
if ( winAnim != -1 )
|
|
{
|
|
PM_SetAnim( SETANIM_BOTH, winAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 );
|
|
pm->ps->weaponTime = pm->ps->torsoTimer;
|
|
pm->ps->saberBlocked = BLOCKED_NONE;
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
/*
|
|
if ( superBreak
|
|
&& winAnim != BOTH_LK_ST_DL_T_SB_1_W )
|
|
{//going to attack with saber, do a saber trail
|
|
pm->ps->SaberActivateTrail( 200 );
|
|
}
|
|
*/
|
|
}
|
|
return winAnim;
|
|
}
|
|
|
|
// Need to avoid nesting namespaces!
|
|
#include "../namespace_end.h"
|
|
#ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^
|
|
|
|
#include "g_local.h"
|
|
extern void NPC_SetAnim(gentity_t *ent, int setAnimParts, int anim, int setAnimFlags);
|
|
extern gentity_t g_entities[];
|
|
|
|
#elif defined CGAME
|
|
|
|
#include "../cgame/cg_local.h" //ahahahahhahahaha@$!$!
|
|
|
|
#endif
|
|
#include "../namespace_begin.h"
|
|
|
|
int PM_SaberLockLoseAnim( playerState_t *genemy, qboolean victory, qboolean superBreak )
|
|
{
|
|
int loseAnim = -1;
|
|
switch ( genemy->torsoAnim )
|
|
{
|
|
/*
|
|
default:
|
|
#ifndef FINAL_BUILD
|
|
Com_Printf( S_COLOR_RED"ERROR-PM_SaberLockBreak: %s not in saberlock anim, anim = (%d)%s\n", genemy->NPC_type, genemy->client->ps.torsoAnim, animTable[genemy->client->ps.torsoAnim].name );
|
|
#endif
|
|
*/
|
|
case BOTH_BF2LOCK:
|
|
if ( superBreak )
|
|
{
|
|
loseAnim = BOTH_LK_S_S_T_SB_1_L;
|
|
}
|
|
else if ( !victory )
|
|
{
|
|
loseAnim = BOTH_BF1BREAK;
|
|
}
|
|
else
|
|
{
|
|
if ( !victory )
|
|
{//no-one won
|
|
genemy->saberMove = LS_K1_T_;
|
|
loseAnim = BOTH_K1_S1_T_;
|
|
}
|
|
else
|
|
{//FIXME: this anim needs to transition back to ready when done
|
|
loseAnim = BOTH_BF1BREAK;
|
|
}
|
|
}
|
|
break;
|
|
case BOTH_BF1LOCK:
|
|
if ( superBreak )
|
|
{
|
|
loseAnim = BOTH_LK_S_S_T_SB_1_L;
|
|
}
|
|
else if ( !victory )
|
|
{
|
|
loseAnim = BOTH_KNOCKDOWN4;
|
|
}
|
|
else
|
|
{
|
|
if ( !victory )
|
|
{//no-one won
|
|
genemy->saberMove = LS_A_T2B;
|
|
loseAnim = BOTH_A3_T__B_;
|
|
}
|
|
else
|
|
{
|
|
loseAnim = BOTH_KNOCKDOWN4;
|
|
}
|
|
}
|
|
break;
|
|
case BOTH_CWCIRCLELOCK:
|
|
if ( superBreak )
|
|
{
|
|
loseAnim = BOTH_LK_S_S_S_SB_1_L;
|
|
}
|
|
else if ( !victory )
|
|
{
|
|
genemy->saberMove = LS_V1_BL;//genemy->saberBounceMove =
|
|
genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
|
|
loseAnim = BOTH_V1_BL_S1;
|
|
}
|
|
else
|
|
{
|
|
if ( !victory )
|
|
{//no-one won
|
|
loseAnim = BOTH_CCWCIRCLEBREAK;
|
|
}
|
|
else
|
|
{
|
|
genemy->saberMove = LS_V1_BL;//genemy->saberBounceMove =
|
|
genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
|
|
loseAnim = BOTH_V1_BL_S1;
|
|
/*
|
|
genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_H1_BR;
|
|
genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN;
|
|
loseAnim = BOTH_H1_S1_BL;
|
|
*/
|
|
}
|
|
}
|
|
break;
|
|
case BOTH_CCWCIRCLELOCK:
|
|
if ( superBreak )
|
|
{
|
|
loseAnim = BOTH_LK_S_S_S_SB_1_L;
|
|
}
|
|
else if ( !victory )
|
|
{
|
|
genemy->saberMove = LS_V1_BR;//genemy->saberBounceMove =
|
|
genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
|
|
loseAnim = BOTH_V1_BR_S1;
|
|
}
|
|
else
|
|
{
|
|
if ( !victory )
|
|
{//no-one won
|
|
loseAnim = BOTH_CWCIRCLEBREAK;
|
|
}
|
|
else
|
|
{
|
|
genemy->saberMove = LS_V1_BR;//genemy->saberBounceMove =
|
|
genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
|
|
loseAnim = BOTH_V1_BR_S1;
|
|
/*
|
|
genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_H1_BL;
|
|
genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN;
|
|
loseAnim = BOTH_H1_S1_BR;
|
|
*/
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
if ( loseAnim != -1 )
|
|
{
|
|
#ifdef QAGAME
|
|
NPC_SetAnim( &g_entities[genemy->clientNum], SETANIM_BOTH, loseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
|
|
genemy->weaponTime = genemy->torsoTimer;// + 250;
|
|
#endif
|
|
genemy->saberBlocked = BLOCKED_NONE;
|
|
genemy->weaponstate = WEAPON_READY;
|
|
}
|
|
return loseAnim;
|
|
}
|
|
|
|
int PM_SaberLockResultAnim( playerState_t *duelist, qboolean superBreak, qboolean won )
|
|
{
|
|
int baseAnim = duelist->torsoAnim;
|
|
switch ( baseAnim )
|
|
{
|
|
case BOTH_LK_S_S_S_L_2: //lock if I'm using single vs. a single and other intitiated
|
|
baseAnim = BOTH_LK_S_S_S_L_1;
|
|
break;
|
|
case BOTH_LK_S_S_T_L_2: //lock if I'm using single vs. a single and other initiated
|
|
baseAnim = BOTH_LK_S_S_T_L_1;
|
|
break;
|
|
case BOTH_LK_DL_DL_S_L_2: //lock if I'm using dual vs. dual and other initiated
|
|
baseAnim = BOTH_LK_DL_DL_S_L_1;
|
|
break;
|
|
case BOTH_LK_DL_DL_T_L_2: //lock if I'm using dual vs. dual and other initiated
|
|
baseAnim = BOTH_LK_DL_DL_T_L_1;
|
|
break;
|
|
case BOTH_LK_ST_ST_S_L_2: //lock if I'm using staff vs. a staff and other initiated
|
|
baseAnim = BOTH_LK_ST_ST_S_L_1;
|
|
break;
|
|
case BOTH_LK_ST_ST_T_L_2: //lock if I'm using staff vs. a staff and other initiated
|
|
baseAnim = BOTH_LK_ST_ST_T_L_1;
|
|
break;
|
|
}
|
|
//what kind of break?
|
|
if ( !superBreak )
|
|
{
|
|
baseAnim -= 2;
|
|
}
|
|
else if ( superBreak )
|
|
{
|
|
baseAnim += 1;
|
|
}
|
|
else
|
|
{//WTF? Not a valid result
|
|
return -1;
|
|
}
|
|
//win or lose?
|
|
if ( won )
|
|
{
|
|
baseAnim += 1;
|
|
}
|
|
|
|
//play the anim and hold it
|
|
#ifdef QAGAME
|
|
//server-side: set it on the other guy, too
|
|
if ( duelist->clientNum == pm->ps->clientNum )
|
|
{//me
|
|
PM_SetAnim( SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 );
|
|
}
|
|
else
|
|
{//other guy
|
|
NPC_SetAnim( &g_entities[duelist->clientNum], SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
|
|
}
|
|
#else
|
|
PM_SetAnim( SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 );
|
|
#endif
|
|
|
|
if ( superBreak
|
|
&& !won )
|
|
{//if you lose a superbreak, you're defenseless
|
|
/*
|
|
//Taken care of in SetSaberBoxSize()
|
|
//make saberent not block
|
|
gentity_t *saberent = &g_entities[duelist->client->ps.saberEntityNum];
|
|
if ( saberent )
|
|
{
|
|
VectorClear(saberent->mins);
|
|
VectorClear(saberent->maxs);
|
|
G_SetOrigin(saberent, duelist->currentOrigin);
|
|
}
|
|
*/
|
|
#ifdef QAGAME
|
|
if ( 1 )
|
|
#else
|
|
if ( duelist->clientNum == pm->ps->clientNum )
|
|
#endif
|
|
{
|
|
//set sabermove to none
|
|
duelist->saberMove = LS_NONE;
|
|
//Hold the anim a little longer than it is
|
|
duelist->torsoTimer += 250;
|
|
}
|
|
}
|
|
|
|
#ifdef QAGAME
|
|
if ( 1 )
|
|
#else
|
|
if ( duelist->clientNum == pm->ps->clientNum )
|
|
#endif
|
|
{
|
|
//no attacking during this anim
|
|
duelist->weaponTime = duelist->torsoTimer;
|
|
duelist->saberBlocked = BLOCKED_NONE;
|
|
/*
|
|
if ( superBreak
|
|
&& won
|
|
&& baseAnim != BOTH_LK_ST_DL_T_SB_1_W )
|
|
{//going to attack with saber, do a saber trail
|
|
duelist->client->ps.SaberActivateTrail( 200 );
|
|
}
|
|
*/
|
|
}
|
|
return baseAnim;
|
|
}
|
|
|
|
void PM_SaberLockBreak( playerState_t *genemy, qboolean victory, int strength )
|
|
{
|
|
int winAnim = BOTH_STAND1, loseAnim = BOTH_STAND1;
|
|
//qboolean punishLoser = qfalse;
|
|
qboolean noKnockdown = qfalse;
|
|
qboolean singleVsSingle = qtrue;
|
|
qboolean superBreak = (strength+pm->ps->saberLockHits > Q_irand(2,4));
|
|
|
|
winAnim = PM_SaberLockWinAnim( victory, superBreak );
|
|
if ( winAnim != -1 )
|
|
{//a single vs. single break
|
|
loseAnim = PM_SaberLockLoseAnim( genemy, victory, superBreak );
|
|
}
|
|
else
|
|
{//must be a saberlock that's not between single and single...
|
|
singleVsSingle = qfalse;
|
|
winAnim = PM_SaberLockResultAnim( pm->ps, superBreak, qtrue );
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
loseAnim = PM_SaberLockResultAnim( genemy, superBreak, qfalse );
|
|
genemy->weaponstate = WEAPON_READY;
|
|
}
|
|
|
|
if ( victory )
|
|
{ //someone lost the lock, so punish them by knocking them down
|
|
if ( pm->ps->saberLockHits && !superBreak )
|
|
{//there was some over-power in the win, but not enough to superbreak
|
|
vec3_t oppDir;
|
|
|
|
int strength = 8;
|
|
|
|
VectorSubtract(genemy->origin, pm->ps->origin, oppDir);
|
|
VectorNormalize(oppDir);
|
|
|
|
if (noKnockdown)
|
|
{
|
|
if (!genemy->saberEntityNum)
|
|
{ //if he has already lost his saber then just knock him down
|
|
noKnockdown = qfalse;
|
|
}
|
|
}
|
|
|
|
if (!noKnockdown && BG_KnockDownable(genemy))
|
|
{
|
|
genemy->forceHandExtend = HANDEXTEND_KNOCKDOWN;
|
|
genemy->forceHandExtendTime = pm->cmd.serverTime + 1100;
|
|
genemy->forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
|
|
|
|
genemy->otherKiller = pm->ps->clientNum;
|
|
genemy->otherKillerTime = pm->cmd.serverTime + 5000;
|
|
genemy->otherKillerDebounceTime = pm->cmd.serverTime + 100;
|
|
//genemy->otherKillerMOD = MOD_UNKNOWN;
|
|
//genemy->otherKillerVehWeapon = 0;
|
|
//genemy->otherKillerWeaponType = WP_NONE;
|
|
|
|
genemy->velocity[0] = oppDir[0]*(strength*40);
|
|
genemy->velocity[1] = oppDir[1]*(strength*40);
|
|
genemy->velocity[2] = 100;
|
|
}
|
|
|
|
pm->checkDuelLoss = genemy->clientNum+1;
|
|
|
|
pm->ps->saberEventFlags |= SEF_LOCK_WON;
|
|
}
|
|
}
|
|
else
|
|
{ //If no one lost, then shove each player away from the other
|
|
vec3_t oppDir;
|
|
|
|
int strength = 4;
|
|
|
|
VectorSubtract(genemy->origin, pm->ps->origin, oppDir);
|
|
VectorNormalize(oppDir);
|
|
genemy->velocity[0] = oppDir[0]*(strength*40);
|
|
genemy->velocity[1] = oppDir[1]*(strength*40);
|
|
genemy->velocity[2] = 150;
|
|
|
|
VectorSubtract(pm->ps->origin, genemy->origin, oppDir);
|
|
VectorNormalize(oppDir);
|
|
pm->ps->velocity[0] = oppDir[0]*(strength*40);
|
|
pm->ps->velocity[1] = oppDir[1]*(strength*40);
|
|
pm->ps->velocity[2] = 150;
|
|
|
|
genemy->forceHandExtend = HANDEXTEND_WEAPONREADY;
|
|
}
|
|
|
|
pm->ps->weaponTime = 0;
|
|
genemy->weaponTime = 0;
|
|
|
|
pm->ps->saberLockTime = genemy->saberLockTime = 0;
|
|
pm->ps->saberLockFrame = genemy->saberLockFrame = 0;
|
|
pm->ps->saberLockEnemy = genemy->saberLockEnemy = 0;
|
|
|
|
pm->ps->forceHandExtend = HANDEXTEND_WEAPONREADY;
|
|
|
|
PM_AddEvent( EV_JUMP );
|
|
if ( !victory )
|
|
{//no-one won
|
|
BG_AddPredictableEventToPlayerstate(EV_JUMP, 0, genemy);
|
|
}
|
|
else
|
|
{
|
|
if ( PM_irand_timesync( 0, 1 ) )
|
|
{
|
|
BG_AddPredictableEventToPlayerstate(EV_JUMP, PM_irand_timesync( 0, 75 ), genemy);
|
|
}
|
|
}
|
|
}
|
|
|
|
qboolean BG_CheckIncrementLockAnim( int anim, int winOrLose )
|
|
{
|
|
qboolean increment = qfalse;//???
|
|
//RULE: if you are the first style in the lock anim, you advance from LOSING position to WINNING position
|
|
// if you are the second style in the lock anim, you advance from WINNING position to LOSING position
|
|
switch ( anim )
|
|
{
|
|
//increment to win:
|
|
case BOTH_LK_DL_DL_S_L_1: //lock if I'm using dual vs. dual and I initiated
|
|
case BOTH_LK_DL_DL_S_L_2: //lock if I'm using dual vs. dual and other initiated
|
|
case BOTH_LK_DL_DL_T_L_1: //lock if I'm using dual vs. dual and I initiated
|
|
case BOTH_LK_DL_DL_T_L_2: //lock if I'm using dual vs. dual and other initiated
|
|
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_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_S_S_S_L_1: //lock if I'm using single vs. a single and I initiated
|
|
case BOTH_LK_S_S_T_L_2: //lock if I'm using single vs. a single and other 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_ST_ST_T_L_1: //lock if I'm using staff vs. a staff and I initiated
|
|
case BOTH_LK_ST_ST_T_L_2: //lock if I'm using staff vs. a staff and other initiated
|
|
if ( winOrLose == SABERLOCK_WIN )
|
|
{
|
|
increment = qtrue;
|
|
}
|
|
else
|
|
{
|
|
increment = qfalse;
|
|
}
|
|
break;
|
|
|
|
//decrement to win:
|
|
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_S_S_L_2: //lock if I'm using single vs. a single and other intitiated
|
|
case BOTH_LK_S_S_T_L_1: //lock if I'm using single vs. a single and I initiated
|
|
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_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_S_L_2: //lock if I'm using staff vs. a staff and other initiated
|
|
if ( winOrLose == SABERLOCK_WIN )
|
|
{
|
|
increment = qfalse;
|
|
}
|
|
else
|
|
{
|
|
increment = qtrue;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return increment;
|
|
}
|
|
|
|
extern qboolean ValidAnimFileIndex ( int index );
|
|
void PM_SaberLocked( void )
|
|
{
|
|
int remaining = 0;
|
|
playerState_t *genemy;
|
|
bgEntity_t *eGenemy = PM_BGEntForNum(pm->ps->saberLockEnemy);
|
|
|
|
if (!eGenemy)
|
|
{
|
|
return;
|
|
}
|
|
|
|
genemy = eGenemy->playerState;
|
|
|
|
if ( !genemy )
|
|
{
|
|
return;
|
|
}
|
|
/*if ( ( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_BF1LOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK )
|
|
&& ( (genemy->torsoAnim) == BOTH_BF2LOCK ||
|
|
(genemy->torsoAnim) == BOTH_BF1LOCK ||
|
|
(genemy->torsoAnim) == BOTH_CWCIRCLELOCK ||
|
|
(genemy->torsoAnim) == BOTH_CCWCIRCLELOCK )
|
|
)
|
|
*/ //yeah..
|
|
if (pm->ps->saberLockFrame &&
|
|
genemy->saberLockFrame &&
|
|
BG_InSaberLock(pm->ps->torsoAnim) &&
|
|
BG_InSaberLock(genemy->torsoAnim))
|
|
{
|
|
float dist = 0;
|
|
|
|
pm->ps->torsoTimer = 0;
|
|
pm->ps->weaponTime = 0;
|
|
genemy->torsoTimer = 0;
|
|
genemy->weaponTime = 0;
|
|
|
|
dist = DistanceSquared(pm->ps->origin,genemy->origin);
|
|
if ( dist < 64 || dist > 6400 )
|
|
{//between 8 and 80 from each other
|
|
PM_SaberLockBreak( genemy, qfalse, 0 );
|
|
return;
|
|
}
|
|
/*
|
|
//NOTE: time-out is handled around where PM_SaberLocked is called
|
|
if ( pm->ps->saberLockTime <= pm->cmd.serverTime + 500 )
|
|
{//lock just ended
|
|
PM_SaberLockBreak( genemy, qfalse, 0 );
|
|
return;
|
|
}
|
|
*/
|
|
if ( pm->ps->saberLockAdvance )
|
|
{//holding attack
|
|
animation_t *anim;
|
|
float currentFrame;
|
|
int curFrame;
|
|
int strength = 1;
|
|
|
|
pm->ps->saberLockAdvance = qfalse;
|
|
|
|
anim = &pm->animations[pm->ps->torsoAnim];
|
|
|
|
currentFrame = pm->ps->saberLockFrame;
|
|
|
|
strength = pm->ps->fd.forcePowerLevel[FP_SABER_OFFENSE]+1;
|
|
|
|
//advance/decrement my frame number
|
|
if ( BG_InSaberLockOld( pm->ps->torsoAnim ) )
|
|
{ //old locks
|
|
if ( (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_BF2LOCK )
|
|
{
|
|
curFrame = floor( currentFrame )-strength;
|
|
//drop my frame one
|
|
if ( curFrame <= anim->firstFrame )
|
|
{//I won! Break out
|
|
PM_SaberLockBreak( genemy, qtrue, strength );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
|
|
remaining = curFrame-anim->firstFrame;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curFrame = ceil( currentFrame )+strength;
|
|
//advance my frame one
|
|
if ( curFrame >= anim->firstFrame+anim->numFrames )
|
|
{//I won! Break out
|
|
PM_SaberLockBreak( genemy, qtrue, strength );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
|
|
remaining = anim->firstFrame+anim->numFrames-curFrame;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{ //new locks
|
|
if ( BG_CheckIncrementLockAnim( pm->ps->torsoAnim, SABERLOCK_WIN ) )
|
|
{
|
|
curFrame = ceil( currentFrame )+strength;
|
|
//advance my frame one
|
|
if ( curFrame >= anim->firstFrame+anim->numFrames )
|
|
{//I won! Break out
|
|
PM_SaberLockBreak( genemy, qtrue, strength );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
|
|
remaining = anim->firstFrame+anim->numFrames-curFrame;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
curFrame = floor( currentFrame )-strength;
|
|
//drop my frame one
|
|
if ( curFrame <= anim->firstFrame )
|
|
{//I won! Break out
|
|
PM_SaberLockBreak( genemy, qtrue, strength );
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
|
|
remaining = curFrame-anim->firstFrame;
|
|
}
|
|
}
|
|
}
|
|
if ( !PM_irand_timesync( 0, 2 ) )
|
|
{
|
|
PM_AddEvent( EV_JUMP );
|
|
}
|
|
//advance/decrement enemy frame number
|
|
anim = &pm->animations[(genemy->torsoAnim)];
|
|
|
|
if ( BG_InSaberLockOld( genemy->torsoAnim ) )
|
|
{
|
|
if ( (genemy->torsoAnim) == BOTH_CWCIRCLELOCK ||
|
|
(genemy->torsoAnim) == BOTH_BF1LOCK )
|
|
{
|
|
if ( !PM_irand_timesync( 0, 2 ) )
|
|
{
|
|
BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy);
|
|
}
|
|
PM_SetAnimFrame( genemy, anim->firstFrame+remaining, qtrue, qtrue );
|
|
}
|
|
else
|
|
{
|
|
PM_SetAnimFrame( genemy, anim->firstFrame+anim->numFrames-remaining, qtrue, qtrue );
|
|
}
|
|
}
|
|
else
|
|
{//new locks
|
|
if ( BG_CheckIncrementLockAnim( genemy->torsoAnim, SABERLOCK_LOSE ) )
|
|
{
|
|
if ( !PM_irand_timesync( 0, 2 ) )
|
|
{
|
|
BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy);
|
|
}
|
|
PM_SetAnimFrame( genemy, anim->firstFrame+anim->numFrames-remaining, qtrue, qtrue );
|
|
}
|
|
else
|
|
{
|
|
PM_SetAnimFrame( genemy, anim->firstFrame+remaining, qtrue, qtrue );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{//something broke us out of it
|
|
PM_SaberLockBreak( genemy, qfalse, 0 );
|
|
}
|
|
}
|
|
|
|
qboolean PM_SaberInBrokenParry( int move )
|
|
{
|
|
if ( move >= LS_V1_BR && move <= LS_V1_B_ )
|
|
{
|
|
return qtrue;
|
|
}
|
|
if ( move >= LS_H1_T_ && move <= LS_H1_BL )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
|
|
int PM_BrokenParryForParry( int move )
|
|
{
|
|
switch ( move )
|
|
{
|
|
case LS_PARRY_UP:
|
|
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_BL;
|
|
break;
|
|
case LS_PARRY_LL:
|
|
return LS_H1_BR;
|
|
break;
|
|
case LS_READY:
|
|
return LS_H1_B_;
|
|
break;
|
|
}
|
|
return LS_NONE;
|
|
}
|
|
|
|
#define BACK_STAB_DISTANCE 128
|
|
|
|
qboolean PM_CanBackstab(void)
|
|
{
|
|
trace_t tr;
|
|
vec3_t flatAng;
|
|
vec3_t fwd, back;
|
|
vec3_t trmins = {-15, -15, -8};
|
|
vec3_t trmaxs = {15, 15, 8};
|
|
|
|
VectorCopy(pm->ps->viewangles, flatAng);
|
|
flatAng[PITCH] = 0;
|
|
|
|
AngleVectors(flatAng, fwd, 0, 0);
|
|
|
|
back[0] = pm->ps->origin[0] - fwd[0]*BACK_STAB_DISTANCE;
|
|
back[1] = pm->ps->origin[1] - fwd[1]*BACK_STAB_DISTANCE;
|
|
back[2] = pm->ps->origin[2] - fwd[2]*BACK_STAB_DISTANCE;
|
|
|
|
pm->trace(&tr, pm->ps->origin, trmins, trmaxs, back, pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
if (tr.fraction != 1.0 && tr.entityNum >= 0 && tr.entityNum < ENTITYNUM_NONE)
|
|
{
|
|
bgEntity_t *bgEnt = PM_BGEntForNum(tr.entityNum);
|
|
|
|
if (bgEnt && (bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
saberMoveName_t PM_SaberFlipOverAttackMove(void)
|
|
{
|
|
vec3_t fwdAngles, jumpFwd;
|
|
// float zDiff = 0;
|
|
// playerState_t *psData;
|
|
// bgEntity_t *bgEnt;
|
|
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
//see if we have an overridden (or cancelled) lunge move
|
|
if ( saber1
|
|
&& saber1->jumpAtkFwdMove != LS_INVALID )
|
|
{
|
|
if ( saber1->jumpAtkFwdMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber1->jumpAtkFwdMove;
|
|
}
|
|
}
|
|
if ( saber2
|
|
&& saber2->jumpAtkFwdMove != LS_INVALID )
|
|
{
|
|
if ( saber2->jumpAtkFwdMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber2->jumpAtkFwdMove;
|
|
}
|
|
}
|
|
//no overrides, cancelled?
|
|
if ( saber1
|
|
&& saber1->jumpAtkFwdMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
if ( saber2
|
|
&& saber2->jumpAtkFwdMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
//just do it
|
|
VectorCopy( pm->ps->viewangles, fwdAngles );
|
|
fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
|
|
AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
|
|
VectorScale( jumpFwd, 150, pm->ps->velocity );//was 50
|
|
pm->ps->velocity[2] = 400;
|
|
|
|
/*
|
|
bgEnt = PM_BGEntForNum(tr->entityNum);
|
|
|
|
if (!bgEnt)
|
|
{
|
|
return LS_A_FLIP_STAB;
|
|
}
|
|
|
|
psData = bgEnt->playerState;
|
|
|
|
//go higher for enemies higher than you, lower for those lower than you
|
|
if (psData)
|
|
{
|
|
zDiff = psData->origin[2] - pm->ps->origin[2];
|
|
}
|
|
else
|
|
{
|
|
zDiff = 0;
|
|
}
|
|
pm->ps->velocity[2] += (zDiff)*1.5f;
|
|
|
|
//clamp to decent-looking values
|
|
if ( zDiff <= 0 && pm->ps->velocity[2] < 200 )
|
|
{//if we're on same level, don't let me jump so low, I clip into the ground
|
|
pm->ps->velocity[2] = 200;
|
|
}
|
|
else if ( pm->ps->velocity[2] < 100 )
|
|
{
|
|
pm->ps->velocity[2] = 100;
|
|
}
|
|
else if ( pm->ps->velocity[2] > 400 )
|
|
{
|
|
pm->ps->velocity[2] = 400;
|
|
}
|
|
*/
|
|
|
|
PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height
|
|
|
|
PM_AddEvent( EV_JUMP );
|
|
pm->ps->fd.forceJumpSound = 1;
|
|
pm->cmd.upmove = 0;
|
|
|
|
/*
|
|
if ( PM_irand_timesync( 0, 1 ) )
|
|
{
|
|
return LS_A_FLIP_STAB;
|
|
}
|
|
else
|
|
*/
|
|
{
|
|
return LS_A_FLIP_SLASH;
|
|
}
|
|
}
|
|
|
|
int PM_SaberBackflipAttackMove( void )
|
|
{
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
//see if we have an overridden (or cancelled) lunge move
|
|
if ( saber1
|
|
&& saber1->jumpAtkBackMove != LS_INVALID )
|
|
{
|
|
if ( saber1->jumpAtkBackMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber1->jumpAtkBackMove;
|
|
}
|
|
}
|
|
if ( saber2
|
|
&& saber2->jumpAtkBackMove != LS_INVALID )
|
|
{
|
|
if ( saber2->jumpAtkBackMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber2->jumpAtkBackMove;
|
|
}
|
|
}
|
|
//no overrides, cancelled?
|
|
if ( saber1
|
|
&& saber1->jumpAtkBackMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
if ( saber2
|
|
&& saber2->jumpAtkBackMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
//just do it
|
|
pm->cmd.upmove = 127;
|
|
pm->ps->velocity[2] = 500;
|
|
return LS_A_BACKFLIP_ATK;
|
|
}
|
|
|
|
int PM_SaberDualJumpAttackMove( void )
|
|
{
|
|
//FIXME: to make this move easier to execute, should be allowed to do it
|
|
// after you've already started your jump... but jump is delayed in
|
|
// this anim, so how do we undo the jump?
|
|
pm->cmd.upmove = 0;//no jump just yet
|
|
return LS_JUMPATTACK_DUAL;
|
|
}
|
|
|
|
#define FLIPHACK_DISTANCE 200
|
|
|
|
qboolean PM_SomeoneInFront(trace_t *tr)
|
|
{ //Also a very simplified version of the sp counterpart
|
|
vec3_t flatAng;
|
|
vec3_t fwd, back;
|
|
vec3_t trmins = {-15, -15, -8};
|
|
vec3_t trmaxs = {15, 15, 8};
|
|
|
|
VectorCopy(pm->ps->viewangles, flatAng);
|
|
flatAng[PITCH] = 0;
|
|
|
|
AngleVectors(flatAng, fwd, 0, 0);
|
|
|
|
back[0] = pm->ps->origin[0] + fwd[0]*FLIPHACK_DISTANCE;
|
|
back[1] = pm->ps->origin[1] + fwd[1]*FLIPHACK_DISTANCE;
|
|
back[2] = pm->ps->origin[2] + fwd[2]*FLIPHACK_DISTANCE;
|
|
|
|
pm->trace(tr, pm->ps->origin, trmins, trmaxs, back, pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
if (tr->fraction != 1.0 && tr->entityNum >= 0 && tr->entityNum < ENTITYNUM_NONE)
|
|
{
|
|
bgEntity_t *bgEnt = PM_BGEntForNum(tr->entityNum);
|
|
|
|
if (bgEnt && (bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
saberMoveName_t PM_SaberLungeAttackMove( qboolean noSpecials )
|
|
{
|
|
vec3_t fwdAngles, jumpFwd;
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
//see if we have an overridden (or cancelled) lunge move
|
|
if ( saber1
|
|
&& saber1->lungeAtkMove != LS_INVALID )
|
|
{
|
|
if ( saber1->lungeAtkMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber1->lungeAtkMove;
|
|
}
|
|
}
|
|
if ( saber2
|
|
&& saber2->lungeAtkMove != LS_INVALID )
|
|
{
|
|
if ( saber2->lungeAtkMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber2->lungeAtkMove;
|
|
}
|
|
}
|
|
//no overrides, cancelled?
|
|
if ( saber1
|
|
&& saber1->lungeAtkMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
if ( saber2
|
|
&& saber2->lungeAtkMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
//just do it
|
|
if (pm->ps->fd.saberAnimLevel == SS_FAST)
|
|
{
|
|
VectorCopy( pm->ps->viewangles, fwdAngles );
|
|
fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
|
|
//do the lunge
|
|
AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
|
|
VectorScale( jumpFwd, 150, pm->ps->velocity );
|
|
PM_AddEvent( EV_JUMP );
|
|
|
|
return LS_A_LUNGE;
|
|
}
|
|
else if ( !noSpecials && pm->ps->fd.saberAnimLevel == SS_STAFF)
|
|
{
|
|
return LS_SPINATTACK;
|
|
}
|
|
else if ( !noSpecials )
|
|
{
|
|
return LS_SPINATTACK_DUAL;
|
|
}
|
|
return LS_A_T2B;
|
|
}
|
|
|
|
saberMoveName_t PM_SaberJumpAttackMove2( void )
|
|
{
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
//see if we have an overridden (or cancelled) lunge move
|
|
if ( saber1
|
|
&& saber1->jumpAtkFwdMove != LS_INVALID )
|
|
{
|
|
if ( saber1->jumpAtkFwdMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber1->jumpAtkFwdMove;
|
|
}
|
|
}
|
|
if ( saber2
|
|
&& saber2->jumpAtkFwdMove != LS_INVALID )
|
|
{
|
|
if ( saber2->jumpAtkFwdMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber2->jumpAtkFwdMove;
|
|
}
|
|
}
|
|
//no overrides, cancelled?
|
|
if ( saber1
|
|
&& saber1->jumpAtkFwdMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
if ( saber2
|
|
&& saber2->jumpAtkFwdMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
//just do it
|
|
if (pm->ps->fd.saberAnimLevel == SS_DUAL)
|
|
{
|
|
return PM_SaberDualJumpAttackMove();
|
|
}
|
|
else
|
|
{
|
|
//rwwFIXMEFIXME I don't like randomness for this sort of thing, gives people reason to
|
|
//complain combat is unpredictable. Maybe do something more clever to determine
|
|
//if we should do a left or right?
|
|
/*
|
|
if (PM_irand_timesync(0, 1))
|
|
{
|
|
newmove = LS_JUMPATTACK_STAFF_LEFT;
|
|
}
|
|
else
|
|
*/
|
|
{
|
|
return LS_JUMPATTACK_STAFF_RIGHT;
|
|
}
|
|
}
|
|
return LS_A_T2B;
|
|
}
|
|
|
|
saberMoveName_t PM_SaberJumpAttackMove( void )
|
|
{
|
|
vec3_t fwdAngles, jumpFwd;
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
//see if we have an overridden (or cancelled) lunge move
|
|
if ( saber1
|
|
&& saber1->jumpAtkFwdMove != LS_INVALID )
|
|
{
|
|
if ( saber1->jumpAtkFwdMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber1->jumpAtkFwdMove;
|
|
}
|
|
}
|
|
if ( saber2
|
|
&& saber2->jumpAtkFwdMove != LS_INVALID )
|
|
{
|
|
if ( saber2->jumpAtkFwdMove != LS_NONE )
|
|
{
|
|
return (saberMoveName_t)saber2->jumpAtkFwdMove;
|
|
}
|
|
}
|
|
//no overrides, cancelled?
|
|
if ( saber1
|
|
&& saber1->jumpAtkFwdMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
if ( saber2
|
|
&& saber2->jumpAtkFwdMove == LS_NONE )
|
|
{
|
|
return LS_A_T2B;//LS_NONE;
|
|
}
|
|
//just do it
|
|
VectorCopy( pm->ps->viewangles, fwdAngles );
|
|
fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
|
|
AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
|
|
VectorScale( jumpFwd, 300, pm->ps->velocity );
|
|
pm->ps->velocity[2] = 280;
|
|
PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height
|
|
|
|
PM_AddEvent( EV_JUMP );
|
|
pm->ps->fd.forceJumpSound = 1;
|
|
pm->cmd.upmove = 0;
|
|
|
|
return LS_A_JUMP_T__B_;
|
|
}
|
|
|
|
float PM_GroundDistance(void)
|
|
{
|
|
trace_t tr;
|
|
vec3_t down;
|
|
|
|
VectorCopy(pm->ps->origin, down);
|
|
|
|
down[2] -= 4096;
|
|
|
|
pm->trace(&tr, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, MASK_SOLID);
|
|
|
|
VectorSubtract(pm->ps->origin, tr.endpos, down);
|
|
|
|
return VectorLength(down);
|
|
}
|
|
|
|
float PM_WalkableGroundDistance(void)
|
|
{
|
|
trace_t tr;
|
|
vec3_t down;
|
|
|
|
VectorCopy(pm->ps->origin, down);
|
|
|
|
down[2] -= 4096;
|
|
|
|
pm->trace(&tr, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, MASK_SOLID);
|
|
|
|
if ( tr.plane.normal[2] < MIN_WALK_NORMAL )
|
|
{//can't stand on this plane
|
|
return 4096;
|
|
}
|
|
|
|
VectorSubtract(pm->ps->origin, tr.endpos, down);
|
|
|
|
return VectorLength(down);
|
|
}
|
|
|
|
qboolean BG_SaberInTransitionAny( int move );
|
|
static qboolean PM_CanDoDualDoubleAttacks(void)
|
|
{
|
|
if ( pm->ps->weapon == WP_SABER )
|
|
{
|
|
saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
|
|
if ( saber
|
|
&& (saber->saberFlags&SFL_NO_MIRROR_ATTACKS) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
saber = BG_MySaber( pm->ps->clientNum, 1 );
|
|
if ( saber
|
|
&& (saber->saberFlags&SFL_NO_MIRROR_ATTACKS) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
if (BG_SaberInSpecialAttack(pm->ps->torsoAnim) ||
|
|
BG_SaberInSpecialAttack(pm->ps->legsAnim))
|
|
{
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
|
|
static qboolean PM_CheckEnemyPresence( int dir, float radius )
|
|
{ //anyone in this dir?
|
|
vec3_t angles;
|
|
vec3_t checkDir;
|
|
vec3_t tTo;
|
|
vec3_t tMins, tMaxs;
|
|
trace_t tr;
|
|
const float tSize = 12.0f;
|
|
//sp uses a bbox ent list check, but.. that's not so easy/fast to
|
|
//do in predicted code. So I'll just do a single box trace in the proper direction,
|
|
//and take whatever is first hit.
|
|
|
|
VectorSet(tMins, -tSize, -tSize, -tSize);
|
|
VectorSet(tMaxs, tSize, tSize, tSize);
|
|
|
|
VectorCopy(pm->ps->viewangles, angles);
|
|
angles[PITCH] = 0.0f;
|
|
|
|
switch( dir )
|
|
{
|
|
case DIR_RIGHT:
|
|
AngleVectors( angles, NULL, checkDir, NULL );
|
|
break;
|
|
case DIR_LEFT:
|
|
AngleVectors( angles, NULL, checkDir, NULL );
|
|
VectorScale( checkDir, -1, checkDir );
|
|
break;
|
|
case DIR_FRONT:
|
|
AngleVectors( angles, checkDir, NULL, NULL );
|
|
break;
|
|
case DIR_BACK:
|
|
AngleVectors( angles, checkDir, NULL, NULL );
|
|
VectorScale( checkDir, -1, checkDir );
|
|
break;
|
|
}
|
|
|
|
VectorMA(pm->ps->origin, radius, checkDir, tTo);
|
|
pm->trace(&tr, pm->ps->origin, tMins, tMaxs, tTo, pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
if (tr.fraction != 1.0f && tr.entityNum < ENTITYNUM_WORLD)
|
|
{ //let's see who we hit
|
|
bgEntity_t *bgEnt = PM_BGEntForNum(tr.entityNum);
|
|
|
|
if (bgEnt &&
|
|
(bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
|
|
{ //this guy can be considered an "enemy"... if he is on the same team, oh well. can't bg-check that (without a whole lot of hassle).
|
|
return qtrue;
|
|
}
|
|
}
|
|
|
|
//no one in the trace
|
|
return qfalse;
|
|
}
|
|
|
|
#define SABER_ALT_ATTACK_POWER 50//75?
|
|
#define SABER_ALT_ATTACK_POWER_LR 10//30?
|
|
#define SABER_ALT_ATTACK_POWER_FB 25//30/50?
|
|
|
|
extern qboolean PM_SaberInReturn( int move ); //bg_panimate.c
|
|
saberMoveName_t PM_CheckPullAttack( void )
|
|
{
|
|
#if 0 //disabling these for MP, they aren't useful
|
|
if (!(pm->cmd.buttons & BUTTON_ATTACK))
|
|
{
|
|
return LS_NONE;
|
|
}
|
|
|
|
if ( (pm->ps->saberMove == LS_READY||PM_SaberInReturn(pm->ps->saberMove)||PM_SaberInReflect(pm->ps->saberMove))//ready
|
|
//&& (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer())//PLAYER ONLY
|
|
&& pm->ps->fd.saberAnimLevel >= SS_FAST//single saber styles - FIXME: Tavion?
|
|
&& pm->ps->fd.saberAnimLevel <= SS_STRONG//single saber styles - FIXME: Tavion?
|
|
//&& G_TryingPullAttack( pm->gent, &pm->cmd, qfalse )
|
|
//&& pm->ps->fd.forcePowerLevel[FP_PULL]
|
|
//rwwFIXMEFIXME: rick has the damn msg.cpp file checked out exclusively so I can't update the bloody psf to send this for prediction
|
|
&& pm->ps->powerups[PW_DISINT_4] > pm->cmd.serverTime
|
|
&& !(pm->ps->fd.forcePowersActive & (1<<FP_GRIP))
|
|
&& pm->ps->powerups[PW_PULL] > pm->cmd.serverTime
|
|
//&& pm->cmd.forwardmove<0//pulling back
|
|
&& (pm->cmd.buttons&BUTTON_ATTACK)//attacking
|
|
&& BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_FB ) )//pm->ps->forcePower >= SABER_ALT_ATTACK_POWER_FB//have enough power
|
|
{//FIXME: some NPC logic to do this?
|
|
qboolean doMove = qtrue;
|
|
// if ( g_saberNewControlScheme->integer
|
|
// || g_crosshairEntNum < ENTITYNUM_WORLD )//in old control scheme, there has to be someone there
|
|
{
|
|
saberMoveName_t pullAttackMove = LS_NONE;
|
|
if ( pm->ps->fd.saberAnimLevel == SS_FAST )
|
|
{
|
|
pullAttackMove = LS_PULL_ATTACK_STAB;
|
|
}
|
|
else
|
|
{
|
|
pullAttackMove = LS_PULL_ATTACK_SWING;
|
|
}
|
|
|
|
/*
|
|
if ( g_crosshairEntNum < ENTITYNUM_WORLD
|
|
&& pm->gent && pm->gent->client )
|
|
{
|
|
gentity_t *targEnt = &g_entities[g_crosshairEntNum];
|
|
if ( targEnt->client
|
|
&& targEnt->health > 0
|
|
//FIXME: check other things like in knockdown, saberlock, uninterruptable anims, etc.
|
|
&& !PM_InOnGroundAnim( &targEnt->client->ps )
|
|
&& !PM_LockedAnim( targEnt->client->ps.legsAnim )
|
|
&& !PM_SuperBreakLoseAnim( targEnt->client->ps.legsAnim )
|
|
&& !PM_SuperBreakWinAnim( targEnt->client->ps.legsAnim )
|
|
&& targEnt->client->ps.saberLockTime <= 0
|
|
&& WP_ForceThrowable( targEnt, targEnt, pm->gent, qtrue, 1.0f, 0.0f, NULL ) )
|
|
{
|
|
if ( !g_saberNewControlScheme->integer )
|
|
{//in old control scheme, make sure they're close or far enough away for the move we'll be doing
|
|
float targDist = Distance( targEnt->currentOrigin, pm->ps->origin );
|
|
if ( pullAttackMove == LS_PULL_ATTACK_STAB )
|
|
{//must be closer than 512
|
|
if ( targDist > 384.0f )
|
|
{
|
|
return LS_NONE;
|
|
}
|
|
}
|
|
else//if ( pullAttackMove == LS_PULL_ATTACK_SWING )
|
|
{//must be farther than 256
|
|
if ( targDist > 512.0f )
|
|
{
|
|
return LS_NONE;
|
|
}
|
|
if ( targDist < 192.0f )
|
|
{
|
|
return LS_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
vec3_t targAngles = {0,targEnt->client->ps.viewangles[YAW],0};
|
|
if ( InFront( pm->ps->origin, targEnt->currentOrigin, targAngles ) )
|
|
{
|
|
NPC_SetAnim( targEnt, SETANIM_BOTH, BOTH_PULLED_INAIR_F, SETANIM_FLAG_OVERRIDE, SETANIM_FLAG_HOLD );
|
|
}
|
|
else
|
|
{
|
|
NPC_SetAnim( targEnt, SETANIM_BOTH, BOTH_PULLED_INAIR_B, SETANIM_FLAG_OVERRIDE, SETANIM_FLAG_HOLD );
|
|
}
|
|
//hold the anim until I'm with done pull anim
|
|
targEnt->client->ps.legsAnimTimer = targEnt->client->ps.torsoAnimTimer = PM_AnimLength( pm->gent->client->clientInfo.animFileIndex, (animNumber_t)saberMoveData[pullAttackMove].animToUse );
|
|
//set pullAttackTime
|
|
pm->gent->client->ps.pullAttackTime = targEnt->client->ps.pullAttackTime = level.time+targEnt->client->ps.legsAnimTimer;
|
|
//make us know about each other
|
|
pm->gent->client->ps.pullAttackEntNum = g_crosshairEntNum;
|
|
targEnt->client->ps.pullAttackEntNum = pm->ps->clientNum;
|
|
//do effect and sound on me
|
|
pm->ps->powerups[PW_FORCE_PUSH] = level.time + 1000;
|
|
if ( pm->gent )
|
|
{
|
|
G_Sound( pm->gent, G_SoundIndex( "sound/weapons/force/pull.wav" ) );
|
|
}
|
|
doMove = qtrue;
|
|
}
|
|
}
|
|
*/
|
|
if ( doMove )
|
|
{
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB );
|
|
return pullAttackMove;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
return LS_NONE;
|
|
}
|
|
|
|
qboolean PM_InSecondaryStyle( void )
|
|
{
|
|
if ( pm->ps->fd.saberAnimLevelBase == SS_STAFF
|
|
|| pm->ps->fd.saberAnimLevelBase == SS_DUAL )
|
|
{
|
|
if ( pm->ps->fd.saberAnimLevel != pm->ps->fd.saberAnimLevelBase )
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove)
|
|
{
|
|
saberMoveName_t newmove = LS_NONE;
|
|
qboolean noSpecials = PM_InSecondaryStyle();
|
|
qboolean allowCartwheels = qtrue;
|
|
saberMoveName_t overrideJumpRightAttackMove = LS_INVALID;
|
|
saberMoveName_t overrideJumpLeftAttackMove = LS_INVALID;
|
|
|
|
if ( pm->ps->weapon == WP_SABER )
|
|
{
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
|
|
if ( saber1
|
|
&& saber1->jumpAtkRightMove != LS_INVALID )
|
|
{
|
|
if ( saber1->jumpAtkRightMove != LS_NONE )
|
|
{//actually overriding
|
|
overrideJumpRightAttackMove = (saberMoveName_t)saber1->jumpAtkRightMove;
|
|
}
|
|
else if ( saber2
|
|
&& saber2->jumpAtkRightMove > LS_NONE )
|
|
{//would be cancelling it, but check the second saber, too
|
|
overrideJumpRightAttackMove = (saberMoveName_t)saber2->jumpAtkRightMove;
|
|
}
|
|
else
|
|
{//nope, just cancel it
|
|
overrideJumpRightAttackMove = LS_NONE;
|
|
}
|
|
}
|
|
else if ( saber2
|
|
&& saber2->jumpAtkRightMove != LS_INVALID )
|
|
{//first saber not overridden, check second
|
|
overrideJumpRightAttackMove = (saberMoveName_t)saber2->jumpAtkRightMove;
|
|
}
|
|
|
|
if ( saber1
|
|
&& saber1->jumpAtkLeftMove != LS_INVALID )
|
|
{
|
|
if ( saber1->jumpAtkLeftMove != LS_NONE )
|
|
{//actually overriding
|
|
overrideJumpLeftAttackMove = (saberMoveName_t)saber1->jumpAtkLeftMove;
|
|
}
|
|
else if ( saber2
|
|
&& saber2->jumpAtkLeftMove > LS_NONE )
|
|
{//would be cancelling it, but check the second saber, too
|
|
overrideJumpLeftAttackMove = (saberMoveName_t)saber2->jumpAtkLeftMove;
|
|
}
|
|
else
|
|
{//nope, just cancel it
|
|
overrideJumpLeftAttackMove = LS_NONE;
|
|
}
|
|
}
|
|
else if ( saber2
|
|
&& saber2->jumpAtkLeftMove != LS_INVALID )
|
|
{//first saber not overridden, check second
|
|
overrideJumpLeftAttackMove = (saberMoveName_t)saber1->jumpAtkLeftMove;
|
|
}
|
|
|
|
if ( saber1
|
|
&& (saber1->saberFlags&SFL_NO_CARTWHEELS) )
|
|
{
|
|
allowCartwheels = qfalse;
|
|
}
|
|
if ( saber2
|
|
&& (saber2->saberFlags&SFL_NO_CARTWHEELS) )
|
|
{
|
|
allowCartwheels = qfalse;
|
|
}
|
|
}
|
|
|
|
if ( pm->cmd.rightmove > 0 )
|
|
{//moving right
|
|
if ( !noSpecials
|
|
&& overrideJumpRightAttackMove != LS_NONE
|
|
&& pm->ps->velocity[2] > 20.0f //pm->ps->groundEntityNum != ENTITYNUM_NONE//on ground
|
|
&& (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack
|
|
&& PM_GroundDistance() < 70.0f //not too high above ground
|
|
&& ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player
|
|
&& BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power
|
|
{//cartwheel right
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR);
|
|
if ( overrideJumpRightAttackMove != LS_INVALID )
|
|
{//overridden with another move
|
|
return overrideJumpRightAttackMove;
|
|
}
|
|
else
|
|
{
|
|
vec3_t right, fwdAngles;
|
|
|
|
VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f);
|
|
|
|
AngleVectors( fwdAngles, NULL, right, NULL );
|
|
pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f;
|
|
VectorMA( pm->ps->velocity, 190.0f, right, pm->ps->velocity );
|
|
if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
|
|
{
|
|
newmove = LS_BUTTERFLY_RIGHT;
|
|
pm->ps->velocity[2] = 350.0f;
|
|
}
|
|
else if ( allowCartwheels )
|
|
{
|
|
//PM_SetJumped( JUMP_VELOCITY, qtrue );
|
|
PM_AddEvent( EV_JUMP );
|
|
pm->ps->velocity[2] = 300.0f;
|
|
|
|
//if ( !Q_irand( 0, 1 ) )
|
|
//if (PM_GroundDistance() >= 25.0f)
|
|
if (1)
|
|
{
|
|
newmove = LS_JUMPATTACK_ARIAL_RIGHT;
|
|
}
|
|
else
|
|
{
|
|
newmove = LS_JUMPATTACK_CART_RIGHT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( pm->cmd.forwardmove > 0 )
|
|
{//forward right = TL2BR slash
|
|
newmove = LS_A_TL2BR;
|
|
}
|
|
else if ( pm->cmd.forwardmove < 0 )
|
|
{//backward right = BL2TR uppercut
|
|
newmove = LS_A_BL2TR;
|
|
}
|
|
else
|
|
{//just right is a left slice
|
|
newmove = LS_A_L2R;
|
|
}
|
|
}
|
|
else if ( pm->cmd.rightmove < 0 )
|
|
{//moving left
|
|
if ( !noSpecials
|
|
&& overrideJumpLeftAttackMove != LS_NONE
|
|
&& pm->ps->velocity[2] > 20.0f //pm->ps->groundEntityNum != ENTITYNUM_NONE//on ground
|
|
&& (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack
|
|
&& PM_GroundDistance() < 70.0f //not too high above ground
|
|
&& ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player
|
|
&& BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power
|
|
{//cartwheel left
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR);
|
|
|
|
if ( overrideJumpLeftAttackMove != LS_INVALID )
|
|
{//overridden with another move
|
|
return overrideJumpLeftAttackMove;
|
|
}
|
|
else
|
|
{
|
|
vec3_t right, fwdAngles;
|
|
|
|
VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f);
|
|
AngleVectors( fwdAngles, NULL, right, NULL );
|
|
pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f;
|
|
VectorMA( pm->ps->velocity, -190.0f, right, pm->ps->velocity );
|
|
if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
|
|
{
|
|
newmove = LS_BUTTERFLY_LEFT;
|
|
pm->ps->velocity[2] = 250.0f;
|
|
}
|
|
else if ( allowCartwheels )
|
|
{
|
|
//PM_SetJumped( JUMP_VELOCITY, qtrue );
|
|
PM_AddEvent( EV_JUMP );
|
|
pm->ps->velocity[2] = 350.0f;
|
|
|
|
//if ( !Q_irand( 0, 1 ) )
|
|
//if (PM_GroundDistance() >= 25.0f)
|
|
if (1)
|
|
{
|
|
newmove = LS_JUMPATTACK_ARIAL_LEFT;
|
|
}
|
|
else
|
|
{
|
|
newmove = LS_JUMPATTACK_CART_LEFT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( pm->cmd.forwardmove > 0 )
|
|
{//forward left = TR2BL slash
|
|
newmove = LS_A_TR2BL;
|
|
}
|
|
else if ( pm->cmd.forwardmove < 0 )
|
|
{//backward left = BR2TL uppercut
|
|
newmove = LS_A_BR2TL;
|
|
}
|
|
else
|
|
{//just left is a right slice
|
|
newmove = LS_A_R2L;
|
|
}
|
|
}
|
|
else
|
|
{//not moving left or right
|
|
if ( pm->cmd.forwardmove > 0 )
|
|
{//forward= T2B slash
|
|
if (!noSpecials&&
|
|
(pm->ps->fd.saberAnimLevel == SS_DUAL || pm->ps->fd.saberAnimLevel == SS_STAFF) &&
|
|
pm->ps->fd.forceRageRecoveryTime < pm->cmd.serverTime &&
|
|
//pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 &&
|
|
(pm->ps->groundEntityNum != ENTITYNUM_NONE || PM_GroundDistance() <= 40) &&
|
|
pm->ps->velocity[2] >= 0 &&
|
|
(pm->cmd.upmove > 0 || pm->ps->pm_flags & PMF_JUMP_HELD) &&
|
|
!BG_SaberInTransitionAny(pm->ps->saberMove) &&
|
|
!BG_SaberInAttack(pm->ps->saberMove) &&
|
|
pm->ps->weaponTime <= 0 &&
|
|
pm->ps->forceHandExtend == HANDEXTEND_NONE &&
|
|
(pm->cmd.buttons & BUTTON_ATTACK)&&
|
|
BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) )
|
|
{ //DUAL/STAFF JUMP ATTACK
|
|
newmove = PM_SaberJumpAttackMove2();
|
|
if ( newmove != LS_A_T2B
|
|
&& newmove != LS_NONE )
|
|
{
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
|
|
}
|
|
}
|
|
else if (!noSpecials&&
|
|
pm->ps->fd.saberAnimLevel == SS_MEDIUM &&
|
|
pm->ps->velocity[2] > 100 &&
|
|
PM_GroundDistance() < 32 &&
|
|
!BG_InSpecialJump(pm->ps->legsAnim) &&
|
|
!BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
|
|
BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB))
|
|
{ //FLIP AND DOWNWARD ATTACK
|
|
//trace_t tr;
|
|
|
|
//if (PM_SomeoneInFront(&tr))
|
|
{
|
|
newmove = PM_SaberFlipOverAttackMove();
|
|
if ( newmove != LS_A_T2B
|
|
&& newmove != LS_NONE )
|
|
{
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
|
|
}
|
|
}
|
|
}
|
|
else if (!noSpecials&&
|
|
pm->ps->fd.saberAnimLevel == SS_STRONG &&
|
|
pm->ps->velocity[2] > 100 &&
|
|
PM_GroundDistance() < 32 &&
|
|
!BG_InSpecialJump(pm->ps->legsAnim) &&
|
|
!BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
|
|
BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_FB ))
|
|
{ //DFA
|
|
//trace_t tr;
|
|
|
|
//if (PM_SomeoneInFront(&tr))
|
|
{
|
|
newmove = PM_SaberJumpAttackMove();
|
|
if ( newmove != LS_A_T2B
|
|
&& newmove != LS_NONE )
|
|
{
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
|
|
}
|
|
}
|
|
}
|
|
else if ((pm->ps->fd.saberAnimLevel == SS_FAST || pm->ps->fd.saberAnimLevel == SS_DUAL || pm->ps->fd.saberAnimLevel == SS_STAFF) &&
|
|
pm->ps->groundEntityNum != ENTITYNUM_NONE &&
|
|
(pm->ps->pm_flags & PMF_DUCKED) &&
|
|
pm->ps->weaponTime <= 0 &&
|
|
!BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
|
|
BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB))
|
|
{ //LUNGE (weak)
|
|
newmove = PM_SaberLungeAttackMove( noSpecials );
|
|
if ( newmove != LS_A_T2B
|
|
&& newmove != LS_NONE )
|
|
{
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
|
|
}
|
|
}
|
|
else if ( !noSpecials )
|
|
{
|
|
saberMoveName_t stabDownMove = PM_CheckStabDown();
|
|
if (stabDownMove != LS_NONE
|
|
&& BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) )
|
|
{
|
|
newmove = stabDownMove;
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
|
|
}
|
|
else
|
|
{
|
|
newmove = LS_A_T2B;
|
|
}
|
|
}
|
|
}
|
|
else if ( pm->cmd.forwardmove < 0 )
|
|
{//backward= T2B slash//B2T uppercut?
|
|
if (!noSpecials&&
|
|
pm->ps->fd.saberAnimLevel == SS_STAFF &&
|
|
pm->ps->fd.forceRageRecoveryTime < pm->cmd.serverTime &&
|
|
pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 &&
|
|
(pm->ps->groundEntityNum != ENTITYNUM_NONE || PM_GroundDistance() <= 40) &&
|
|
pm->ps->velocity[2] >= 0 &&
|
|
(pm->cmd.upmove > 0 || pm->ps->pm_flags & PMF_JUMP_HELD) &&
|
|
!BG_SaberInTransitionAny(pm->ps->saberMove) &&
|
|
!BG_SaberInAttack(pm->ps->saberMove) &&
|
|
pm->ps->weaponTime <= 0 &&
|
|
pm->ps->forceHandExtend == HANDEXTEND_NONE &&
|
|
(pm->cmd.buttons & BUTTON_ATTACK))
|
|
{ //BACKFLIP ATTACK
|
|
newmove = PM_SaberBackflipAttackMove();
|
|
}
|
|
else if (PM_CanBackstab() && !BG_SaberInSpecialAttack(pm->ps->torsoAnim))
|
|
{ //BACKSTAB (attack varies by level)
|
|
if (pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_2 && pm->ps->fd.saberAnimLevel != SS_STAFF)
|
|
{//medium and higher attacks
|
|
if ( (pm->ps->pm_flags&PMF_DUCKED) || pm->cmd.upmove < 0 )
|
|
{
|
|
newmove = LS_A_BACK_CR;
|
|
}
|
|
else
|
|
{
|
|
newmove = LS_A_BACK;
|
|
}
|
|
}
|
|
else
|
|
{ //weak attack
|
|
newmove = LS_A_BACKSTAB;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
newmove = LS_A_T2B;
|
|
}
|
|
}
|
|
else if ( PM_SaberInBounce( curmove ) )
|
|
{//bounces should go to their default attack if you don't specify a direction but are attacking
|
|
newmove = saberMoveData[curmove].chain_attack;
|
|
|
|
if ( PM_SaberKataDone(curmove, newmove) )
|
|
{
|
|
newmove = saberMoveData[curmove].chain_idle;
|
|
}
|
|
else
|
|
{
|
|
newmove = saberMoveData[curmove].chain_attack;
|
|
}
|
|
}
|
|
else if ( curmove == LS_READY )
|
|
{//Not moving at all, shouldn't have gotten here...?
|
|
//for now, just pick a random attack
|
|
//newmove = Q_irand( LS_A_TL2BR, LS_A_T2B );
|
|
//rww - If we don't seed with a "common" value, the client and server will get mismatched
|
|
//prediction values. Under laggy conditions this will cause the appearance of rapid swing
|
|
//sequence changes.
|
|
|
|
newmove = LS_A_T2B; //decided we don't like random attacks when idle, use an overhead instead.
|
|
}
|
|
}
|
|
|
|
if (pm->ps->fd.saberAnimLevel == SS_DUAL)
|
|
{
|
|
if ( ( newmove == LS_A_R2L || newmove == LS_S_R2L
|
|
|| newmove == LS_A_L2R || newmove == LS_S_L2R )
|
|
&& PM_CanDoDualDoubleAttacks()
|
|
&& PM_CheckEnemyPresence( DIR_RIGHT, 100.0f )
|
|
&& PM_CheckEnemyPresence( DIR_LEFT, 100.0f ) )
|
|
{//enemy both on left and right
|
|
newmove = LS_DUAL_LR;
|
|
//probably already moved, but...
|
|
pm->cmd.rightmove = 0;
|
|
}
|
|
else if ( (newmove == LS_A_T2B || newmove == LS_S_T2B
|
|
|| newmove == LS_A_BACK || newmove == LS_A_BACK_CR )
|
|
&& PM_CanDoDualDoubleAttacks()
|
|
&& PM_CheckEnemyPresence( DIR_FRONT, 100.0f )
|
|
&& PM_CheckEnemyPresence( DIR_BACK, 100.0f ) )
|
|
{//enemy both in front and back
|
|
newmove = LS_DUAL_FB;
|
|
//probably already moved, but...
|
|
pm->cmd.forwardmove = 0;
|
|
}
|
|
}
|
|
|
|
return newmove;
|
|
}
|
|
|
|
int PM_KickMoveForConditions(void)
|
|
{
|
|
int kickMove = -1;
|
|
|
|
//FIXME: only if FP_SABER_OFFENSE >= 3
|
|
if ( pm->cmd.rightmove )
|
|
{//kick to side
|
|
if ( pm->cmd.rightmove > 0 )
|
|
{//kick right
|
|
kickMove = LS_KICK_R;
|
|
}
|
|
else
|
|
{//kick left
|
|
kickMove = LS_KICK_L;
|
|
}
|
|
pm->cmd.rightmove = 0;
|
|
}
|
|
else if ( pm->cmd.forwardmove )
|
|
{//kick front/back
|
|
if ( pm->cmd.forwardmove > 0 )
|
|
{//kick fwd
|
|
/*
|
|
if (pm->ps->groundEntityNum != ENTITYNUM_NONE &&
|
|
PM_CheckEnemyPresence( DIR_FRONT, 64.0f ))
|
|
{
|
|
kickMove = LS_HILT_BASH;
|
|
}
|
|
else
|
|
*/
|
|
{
|
|
kickMove = LS_KICK_F;
|
|
}
|
|
}
|
|
else
|
|
{//kick back
|
|
kickMove = LS_KICK_B;
|
|
}
|
|
pm->cmd.forwardmove = 0;
|
|
}
|
|
else
|
|
{
|
|
//if (pm->cmd.buttons & BUTTON_ATTACK)
|
|
//if (pm->ps->pm_flags & PMF_JUMP_HELD)
|
|
if (0)
|
|
{ //ok, let's try some fancy kicks
|
|
//qboolean is actually of type int anyway, but just for safeness.
|
|
int front = (int)PM_CheckEnemyPresence( DIR_FRONT, 100.0f );
|
|
int back = (int)PM_CheckEnemyPresence( DIR_BACK, 100.0f );
|
|
int right = (int)PM_CheckEnemyPresence( DIR_RIGHT, 100.0f );
|
|
int left = (int)PM_CheckEnemyPresence( DIR_LEFT, 100.0f );
|
|
int numEnemy = front+back+right+left;
|
|
|
|
if (numEnemy >= 3 ||
|
|
((!right || !left) && numEnemy >= 2))
|
|
{ //> 2 enemies near, or, >= 2 enemies near and they are not to the right and left.
|
|
kickMove = LS_KICK_S;
|
|
}
|
|
else if (right && left)
|
|
{ //enemies on both sides
|
|
kickMove = LS_KICK_RL;
|
|
}
|
|
else
|
|
{ //oh well, just do a forward kick
|
|
kickMove = LS_KICK_F;
|
|
}
|
|
|
|
pm->cmd.upmove = 0;
|
|
}
|
|
}
|
|
|
|
return kickMove;
|
|
}
|
|
|
|
qboolean BG_InSlopeAnim( int anim );
|
|
qboolean PM_RunningAnim( int anim );
|
|
|
|
qboolean PM_SaberMoveOkayForKata( void )
|
|
{
|
|
if ( pm->ps->saberMove == LS_READY
|
|
|| PM_SaberInStart( pm->ps->saberMove ) )
|
|
{
|
|
return qtrue;
|
|
}
|
|
else
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
|
|
qboolean PM_CanDoKata( void )
|
|
{
|
|
if ( PM_InSecondaryStyle() )
|
|
{
|
|
return qfalse;
|
|
}
|
|
|
|
if ( !pm->ps->saberInFlight//not throwing saber
|
|
&& PM_SaberMoveOkayForKata()
|
|
&& !BG_SaberInKata(pm->ps->saberMove)
|
|
&& !BG_InKataAnim(pm->ps->legsAnim)
|
|
&& !BG_InKataAnim(pm->ps->torsoAnim)
|
|
/*
|
|
&& pm->ps->saberAnimLevel >= SS_FAST//fast, med or strong style
|
|
&& pm->ps->saberAnimLevel <= SS_STRONG//FIXME: Tavion, too?
|
|
*/
|
|
&& pm->ps->groundEntityNum != ENTITYNUM_NONE//not in the air
|
|
&& (pm->cmd.buttons&BUTTON_ATTACK)//pressing attack
|
|
&& (pm->cmd.buttons&BUTTON_ALT_ATTACK)//pressing alt attack
|
|
&& !pm->cmd.forwardmove//not moving f/b
|
|
&& !pm->cmd.rightmove//not moving r/l
|
|
&& pm->cmd.upmove <= 0//not jumping...?
|
|
&& BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER) )// have enough power
|
|
{//FIXME: check rage, etc...
|
|
saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
|
|
if ( saber
|
|
&& saber->kataMove == LS_NONE )
|
|
{//kata move has been overridden in a way that should stop you from doing it at all
|
|
return qfalse;
|
|
}
|
|
saber = BG_MySaber( pm->ps->clientNum, 1 );
|
|
if ( saber
|
|
&& saber->kataMove == LS_NONE )
|
|
{//kata move has been overridden in a way that should stop you from doing it at all
|
|
return qfalse;
|
|
}
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_CheckAltKickAttack( void )
|
|
{
|
|
if ( pm->ps->weapon == WP_SABER )
|
|
{
|
|
saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
|
|
if ( saber
|
|
&& (saber->saberFlags&SFL_NO_KICKS) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
saber = BG_MySaber( pm->ps->clientNum, 1 );
|
|
if ( saber
|
|
&& (saber->saberFlags&SFL_NO_KICKS) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
if ( (pm->cmd.buttons&BUTTON_ALT_ATTACK)
|
|
//&& (!(pm->ps->pm_flags&PMF_ALT_ATTACK_HELD)||PM_SaberInReturn(pm->ps->saberMove))
|
|
&& (!BG_FlippingAnim(pm->ps->legsAnim)||pm->ps->legsTimer<=250)
|
|
&& (pm->ps->fd.saberAnimLevel == SS_STAFF/*||!pm->ps->saber[0].throwable*/) && !pm->ps->saberHolstered )
|
|
{
|
|
return qtrue;
|
|
}
|
|
return qfalse;
|
|
}
|
|
|
|
int bg_parryDebounce[NUM_FORCE_POWER_LEVELS] =
|
|
{
|
|
500,//if don't even have defense, can't use defense!
|
|
300,
|
|
150,
|
|
50
|
|
};
|
|
|
|
qboolean PM_SaberPowerCheck(void)
|
|
{
|
|
if (pm->ps->saberInFlight)
|
|
{ //so we don't keep doing stupid force out thing while guiding saber.
|
|
if (pm->ps->fd.forcePower > forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW])
|
|
{
|
|
return qtrue;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return BG_EnoughForcePowerForMove(forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW]);
|
|
}
|
|
|
|
return qfalse;
|
|
}
|
|
|
|
qboolean PM_CanDoRollStab( void )
|
|
{
|
|
if ( pm->ps->weapon == WP_SABER )
|
|
{
|
|
saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
|
|
if ( saber
|
|
&& (saber->saberFlags&SFL_NO_ROLL_STAB) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
saber = BG_MySaber( pm->ps->clientNum, 1 );
|
|
if ( saber
|
|
&& (saber->saberFlags&SFL_NO_ROLL_STAB) )
|
|
{
|
|
return qfalse;
|
|
}
|
|
}
|
|
return qtrue;
|
|
}
|
|
/*
|
|
=================
|
|
PM_WeaponLightsaber
|
|
|
|
Consults a chart to choose what to do with the lightsaber.
|
|
While this is a little different than the Quake 3 code, there is no clean way of using the Q3 code for this kind of thing.
|
|
=================
|
|
*/
|
|
// Ultimate goal is to set the sabermove to the proper next location
|
|
// Note that if the resultant animation is NONE, then the animation is essentially "idle", and is set in WP_TorsoAnim
|
|
qboolean PM_WalkingAnim( int anim );
|
|
qboolean PM_SwimmingAnim( int anim );
|
|
int PM_SaberBounceForAttack( int move );
|
|
qboolean BG_SuperBreakLoseAnim( int anim );
|
|
qboolean BG_SuperBreakWinAnim( int anim );
|
|
void PM_WeaponLightsaber(void)
|
|
{
|
|
int addTime,amount;
|
|
qboolean delayed_fire = qfalse;
|
|
int anim=-1, curmove, newmove=LS_NONE;
|
|
|
|
qboolean checkOnlyWeap = qfalse;
|
|
|
|
if ( PM_InKnockDown( pm->ps ) || BG_InRoll( pm->ps, pm->ps->legsAnim ))
|
|
{//in knockdown
|
|
// make weapon function
|
|
if ( pm->ps->weaponTime > 0 ) {
|
|
pm->ps->weaponTime -= pml.msec;
|
|
if ( pm->ps->weaponTime <= 0 )
|
|
{
|
|
pm->ps->weaponTime = 0;
|
|
}
|
|
}
|
|
if ( pm->ps->legsAnim == BOTH_ROLL_F
|
|
&& pm->ps->legsTimer <= 250 )
|
|
{
|
|
if ( (pm->cmd.buttons&BUTTON_ATTACK) )
|
|
{
|
|
if ( BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) && !pm->ps->saberInFlight )
|
|
{
|
|
if ( PM_CanDoRollStab() )
|
|
{
|
|
//make sure the saber is on for this move!
|
|
if ( pm->ps->saberHolstered == 2 )
|
|
{//all the way off
|
|
pm->ps->saberHolstered = 0;
|
|
PM_AddEvent(EV_SABER_UNHOLSTER);
|
|
}
|
|
PM_SetSaberMove( LS_ROLL_STAB );
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
if ( pm->ps->saberLockTime > pm->cmd.serverTime )
|
|
{
|
|
pm->ps->saberMove = LS_NONE;
|
|
PM_SaberLocked();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
if ( /*( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_BF1LOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||*/
|
|
pm->ps->saberLockFrame
|
|
)
|
|
{
|
|
if (pm->ps->saberLockEnemy < ENTITYNUM_NONE &&
|
|
pm->ps->saberLockEnemy >= 0)
|
|
{
|
|
bgEntity_t *bgEnt;
|
|
playerState_t *en;
|
|
|
|
bgEnt = PM_BGEntForNum(pm->ps->saberLockEnemy);
|
|
|
|
if (bgEnt)
|
|
{
|
|
en = bgEnt->playerState;
|
|
|
|
if (en)
|
|
{
|
|
PM_SaberLockBreak(en, qfalse, 0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (/* ( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_BF1LOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
|
|
(pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||*/
|
|
pm->ps->saberLockFrame
|
|
)
|
|
{
|
|
pm->ps->torsoTimer = 0;
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_STAND1,SETANIM_FLAG_OVERRIDE, 100);
|
|
pm->ps->saberLockFrame = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( BG_KickingAnim( pm->ps->legsAnim ) ||
|
|
BG_KickingAnim( pm->ps->torsoAnim ))
|
|
{
|
|
if ( pm->ps->legsTimer > 0 )
|
|
{//you're kicking, no interruptions
|
|
return;
|
|
}
|
|
//done? be immeditately ready to do an attack
|
|
pm->ps->saberMove = LS_READY;
|
|
pm->ps->weaponTime = 0;
|
|
}
|
|
|
|
if ( BG_SuperBreakLoseAnim( pm->ps->torsoAnim )
|
|
|| BG_SuperBreakWinAnim( pm->ps->torsoAnim ) )
|
|
{
|
|
if ( pm->ps->torsoTimer > 0 )
|
|
{//never interrupt these
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (BG_SabersOff( pm->ps ))
|
|
{
|
|
if (pm->ps->saberMove != LS_READY)
|
|
{
|
|
PM_SetSaberMove( LS_READY );
|
|
}
|
|
|
|
if ((pm->ps->legsAnim) != (pm->ps->torsoAnim) && !BG_InSlopeAnim(pm->ps->legsAnim) &&
|
|
pm->ps->torsoTimer <= 0)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE, 100);
|
|
}
|
|
else if (BG_InSlopeAnim(pm->ps->legsAnim) && pm->ps->torsoTimer <= 0)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,PM_GetSaberStance(),SETANIM_FLAG_OVERRIDE, 100);
|
|
}
|
|
|
|
if (pm->ps->weaponTime < 1 && ((pm->cmd.buttons & BUTTON_ALT_ATTACK) || (pm->cmd.buttons & BUTTON_ATTACK)))
|
|
{
|
|
if (pm->ps->duelTime < pm->cmd.serverTime)
|
|
{
|
|
if (!pm->ps->m_iVehicleNum)
|
|
{ //don't let em unholster the saber by attacking while on vehicle
|
|
pm->ps->saberHolstered = 0;
|
|
PM_AddEvent(EV_SABER_UNHOLSTER);
|
|
}
|
|
else
|
|
{
|
|
pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
|
|
pm->cmd.buttons &= ~BUTTON_ATTACK;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pm->ps->weaponTime > 0 )
|
|
{
|
|
pm->ps->weaponTime -= pml.msec;
|
|
}
|
|
|
|
checkOnlyWeap = qtrue;
|
|
goto weapChecks;
|
|
}
|
|
|
|
if (!pm->ps->saberEntityNum && pm->ps->saberInFlight)
|
|
{ //this means our saber has been knocked away
|
|
/*
|
|
if (pm->ps->saberMove != LS_READY)
|
|
{
|
|
PM_SetSaberMove( LS_READY );
|
|
}
|
|
|
|
if ((pm->ps->legsAnim) != (pm->ps->torsoAnim) && !BG_InSlopeAnim(pm->ps->legsAnim))
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE, 100);
|
|
}
|
|
|
|
if (BG_InSaberStandAnim(pm->ps->torsoAnim) || pm->ps->torsoAnim == BOTH_SABERPULL)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_STAND1,SETANIM_FLAG_OVERRIDE, 100);
|
|
}
|
|
|
|
return;
|
|
*/
|
|
//Old method, don't want to do this now because we want to finish up reflected attacks and things
|
|
//if our saber is pried out of our hands from one.
|
|
if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
|
|
{
|
|
if ( pm->ps->saberHolstered > 1 )
|
|
{
|
|
pm->ps->saberHolstered = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pm->cmd.buttons &= ~BUTTON_ATTACK;
|
|
}
|
|
pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
|
|
}
|
|
|
|
if ( (pm->cmd.buttons & BUTTON_ALT_ATTACK) )
|
|
{ //might as well just check for a saber throw right here
|
|
if (pm->ps->fd.saberAnimLevel == SS_STAFF)
|
|
{ //kick instead of doing a throw
|
|
//if in a saber attack return anim, can interrupt it with a kick
|
|
if ( pm->ps->weaponTime > 0//can't fire yet
|
|
&& PM_SaberInReturn( pm->ps->saberMove )//in a saber return move - FIXME: what about transitions?
|
|
//&& pm->ps->weaponTime <= 250//should be able to fire soon
|
|
//&& pm->ps->torsoTimer <= 250//torso almost done
|
|
&& pm->ps->saberBlocked == BLOCKED_NONE//not interacting with any other saber
|
|
&& !(pm->cmd.buttons&BUTTON_ATTACK) )//not trying to swing the saber
|
|
{
|
|
if ( (pm->cmd.forwardmove||pm->cmd.rightmove)//trying to kick in a specific direction
|
|
&& PM_CheckAltKickAttack() )//trying to do a kick
|
|
{//allow them to do the kick now!
|
|
int kickMove = PM_KickMoveForConditions();
|
|
if (kickMove != -1)
|
|
{
|
|
pm->ps->weaponTime = 0;
|
|
PM_SetSaberMove( kickMove );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if ( pm->ps->weaponTime < 1&&
|
|
pm->ps->saberCanThrow &&
|
|
//pm->ps->fd.forcePower >= forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW] &&
|
|
!BG_HasYsalamiri(pm->gametype, pm->ps) &&
|
|
BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_SABERTHROW) &&
|
|
pm->ps->fd.forcePowerLevel[FP_SABERTHROW] > 0 &&
|
|
PM_SaberPowerCheck() )
|
|
{
|
|
trace_t sabTr;
|
|
vec3_t fwd, minFwd, sabMins, sabMaxs;
|
|
|
|
VectorSet( sabMins, SABERMINS_X, SABERMINS_Y, SABERMINS_Z );
|
|
VectorSet( sabMaxs, SABERMAXS_X, SABERMAXS_Y, SABERMAXS_Z );
|
|
|
|
AngleVectors( pm->ps->viewangles, fwd, NULL, NULL );
|
|
VectorMA( pm->ps->origin, SABER_MIN_THROW_DIST, fwd, minFwd );
|
|
|
|
pm->trace(&sabTr, pm->ps->origin, sabMins, sabMaxs, minFwd, pm->ps->clientNum, MASK_PLAYERSOLID);
|
|
|
|
if ( sabTr.allsolid || sabTr.startsolid || sabTr.fraction < 1.0f )
|
|
{//not enough room to throw
|
|
}
|
|
else
|
|
{//throw it
|
|
//This will get set to false again once the saber makes it back to its owner game-side
|
|
if (!pm->ps->saberInFlight)
|
|
{
|
|
pm->ps->fd.forcePower -= forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW];
|
|
}
|
|
|
|
pm->ps->saberInFlight = qtrue;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( pm->ps->saberInFlight && pm->ps->saberEntityNum )
|
|
{//guiding saber
|
|
if ( (pm->ps->fd.saberAnimLevel != SS_DUAL //not using 2 sabers
|
|
|| pm->ps->saberHolstered //left one off - FIXME: saberHolstered 1 should be left one off, 0 should be both on, 2 should be both off
|
|
|| (!(pm->cmd.buttons&BUTTON_ATTACK)//not trying to start an attack AND...
|
|
&& (pm->ps->torsoAnim == BOTH_SABERDUAL_STANCE//not already attacking
|
|
|| pm->ps->torsoAnim == BOTH_SABERPULL//not already attacking
|
|
|| pm->ps->torsoAnim == BOTH_STAND1//not already attacking
|
|
|| PM_RunningAnim( pm->ps->torsoAnim ) //not already attacking
|
|
|| PM_WalkingAnim( pm->ps->torsoAnim ) //not already attacking
|
|
|| PM_JumpingAnim( pm->ps->torsoAnim )//not already attacking
|
|
|| PM_SwimmingAnim( pm->ps->torsoAnim ))//not already attacking
|
|
)
|
|
)
|
|
)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO, BOTH_SABERPULL, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100);
|
|
pm->ps->torsoTimer = 1;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// don't allow attack until all buttons are up
|
|
//This is bad. It freezes the attack state and the animations if you hold the button after respawning, and it looks strange.
|
|
/*
|
|
if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
|
|
return;
|
|
}
|
|
*/
|
|
|
|
// check for dead player
|
|
if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
|
|
return;
|
|
}
|
|
|
|
/*
|
|
|
|
if (pm->ps->weaponstate == WEAPON_READY ||
|
|
pm->ps->weaponstate == WEAPON_IDLE)
|
|
{
|
|
if (pm->ps->saberMove != LS_READY && pm->ps->weaponTime <= 0 && !pm->ps->saberBlocked)
|
|
{
|
|
PM_SetSaberMove( LS_READY );
|
|
}
|
|
}
|
|
|
|
if(PM_RunningAnim(pm->ps->torsoAnim))
|
|
{
|
|
if ((pm->ps->torsoAnim) != (pm->ps->legsAnim))
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE, 100);
|
|
}
|
|
}
|
|
*/
|
|
|
|
// make weapon function
|
|
if ( pm->ps->weaponTime > 0 )
|
|
{
|
|
//check for special pull move while busy
|
|
saberMoveName_t pullmove = PM_CheckPullAttack();
|
|
if (pullmove != LS_NONE)
|
|
{
|
|
pm->ps->weaponTime = 0;
|
|
pm->ps->torsoTimer = 0;
|
|
pm->ps->legsTimer = 0;
|
|
pm->ps->forceHandExtend = HANDEXTEND_NONE;
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
PM_SetSaberMove(pullmove);
|
|
return;
|
|
}
|
|
|
|
pm->ps->weaponTime -= pml.msec;
|
|
|
|
//This was stupid and didn't work right. Looks like things are fine without it.
|
|
// if (pm->ps->saberBlocked && pm->ps->torsoAnim != saberMoveData[pm->ps->saberMove].animToUse)
|
|
// { //rww - keep him in the blocking pose until he can attack again
|
|
// PM_SetAnim(SETANIM_TORSO,saberMoveData[pm->ps->saberMove].animToUse,saberMoveData[pm->ps->saberMove].animSetFlags|SETANIM_FLAG_HOLD, saberMoveData[pm->ps->saberMove].blendTime);
|
|
// return;
|
|
// }
|
|
}
|
|
else
|
|
{
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
}
|
|
|
|
// Now we react to a block action by the player's lightsaber.
|
|
if ( pm->ps->saberBlocked )
|
|
{
|
|
if ( pm->ps->saberBlocked >= BLOCKED_UPPER_RIGHT
|
|
&& pm->ps->saberBlocked < BLOCKED_UPPER_RIGHT_PROJ)
|
|
{//hold the parry for a bit
|
|
pm->ps->weaponTime = bg_parryDebounce[pm->ps->fd.forcePowerLevel[FP_SABER_DEFENSE]]+200;
|
|
}
|
|
switch ( pm->ps->saberBlocked )
|
|
{
|
|
case BLOCKED_BOUNCE_MOVE:
|
|
{ //act as a bounceMove and reset the saberMove instead of using a seperate value for it
|
|
pm->ps->torsoTimer = 0;
|
|
PM_SetSaberMove( pm->ps->saberMove );
|
|
pm->ps->weaponTime = pm->ps->torsoTimer;
|
|
pm->ps->saberBlocked = 0;
|
|
}
|
|
break;
|
|
case BLOCKED_PARRY_BROKEN:
|
|
//whatever parry we were is in now broken, play the appropriate knocked-away anim
|
|
{
|
|
int nextMove;
|
|
|
|
if ( PM_SaberInBrokenParry( pm->ps->saberMove ) )
|
|
{//already have one...?
|
|
nextMove = pm->ps->saberMove;
|
|
}
|
|
else
|
|
{
|
|
nextMove = PM_BrokenParryForParry( pm->ps->saberMove );
|
|
}
|
|
if ( nextMove != LS_NONE )
|
|
{
|
|
PM_SetSaberMove( nextMove );
|
|
pm->ps->weaponTime = pm->ps->torsoTimer;
|
|
}
|
|
else
|
|
{//Maybe in a knockaway?
|
|
}
|
|
}
|
|
break;
|
|
case BLOCKED_ATK_BOUNCE:
|
|
// If there is absolutely no blocked move in the chart, don't even mess with the animation.
|
|
// OR if we are already in a block or parry.
|
|
if (pm->ps->saberMove >= LS_T1_BR__R)
|
|
{//an actual bounce? Other bounces before this are actually transitions?
|
|
pm->ps->saberBlocked = BLOCKED_NONE;
|
|
}
|
|
else
|
|
{
|
|
int bounceMove;
|
|
|
|
if ( PM_SaberInBounce( pm->ps->saberMove ) || !BG_SaberInAttack( pm->ps->saberMove ) )
|
|
{
|
|
if ( pm->cmd.buttons & BUTTON_ATTACK )
|
|
{//transition to a new attack
|
|
int newQuad = PM_SaberMoveQuadrantForMovement( &pm->cmd );
|
|
while ( newQuad == saberMoveData[pm->ps->saberMove].startQuad )
|
|
{//player is still in same attack quad, don't repeat that attack because it looks bad,
|
|
//FIXME: try to pick one that might look cool?
|
|
//newQuad = Q_irand( Q_BR, Q_BL );
|
|
newQuad = PM_irand_timesync( Q_BR, Q_BL );
|
|
//FIXME: sanity check, just in case?
|
|
}//else player is switching up anyway, take the new attack dir
|
|
bounceMove = transitionMove[saberMoveData[pm->ps->saberMove].startQuad][newQuad];
|
|
}
|
|
else
|
|
{//return to ready
|
|
if ( saberMoveData[pm->ps->saberMove].startQuad == Q_T )
|
|
{
|
|
bounceMove = LS_R_BL2TR;
|
|
}
|
|
else if ( saberMoveData[pm->ps->saberMove].startQuad < Q_T )
|
|
{
|
|
bounceMove = LS_R_TL2BR+saberMoveData[pm->ps->saberMove].startQuad-Q_BR;
|
|
}
|
|
else// if ( saberMoveData[pm->ps->saberMove].startQuad > Q_T )
|
|
{
|
|
bounceMove = LS_R_BR2TL+saberMoveData[pm->ps->saberMove].startQuad-Q_TL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{//start the bounce
|
|
bounceMove = PM_SaberBounceForAttack( (saberMoveName_t)pm->ps->saberMove );
|
|
}
|
|
|
|
PM_SetSaberMove( bounceMove );
|
|
|
|
pm->ps->weaponTime = pm->ps->torsoTimer;//+saberMoveData[bounceMove].blendTime+SABER_BLOCK_DUR;
|
|
|
|
}
|
|
break;
|
|
case BLOCKED_UPPER_RIGHT:
|
|
PM_SetSaberMove( LS_PARRY_UR );
|
|
break;
|
|
case BLOCKED_UPPER_RIGHT_PROJ:
|
|
PM_SetSaberMove( LS_REFLECT_UR );
|
|
break;
|
|
case BLOCKED_UPPER_LEFT:
|
|
PM_SetSaberMove( LS_PARRY_UL );
|
|
break;
|
|
case BLOCKED_UPPER_LEFT_PROJ:
|
|
PM_SetSaberMove( LS_REFLECT_UL );
|
|
break;
|
|
case BLOCKED_LOWER_RIGHT:
|
|
PM_SetSaberMove( LS_PARRY_LR );
|
|
break;
|
|
case BLOCKED_LOWER_RIGHT_PROJ:
|
|
PM_SetSaberMove( LS_REFLECT_LR );
|
|
break;
|
|
case BLOCKED_LOWER_LEFT:
|
|
PM_SetSaberMove( LS_PARRY_LL );
|
|
break;
|
|
case BLOCKED_LOWER_LEFT_PROJ:
|
|
PM_SetSaberMove( LS_REFLECT_LL);
|
|
break;
|
|
case BLOCKED_TOP:
|
|
PM_SetSaberMove( LS_PARRY_UP );
|
|
break;
|
|
case BLOCKED_TOP_PROJ:
|
|
PM_SetSaberMove( LS_REFLECT_UP );
|
|
break;
|
|
default:
|
|
pm->ps->saberBlocked = BLOCKED_NONE;
|
|
break;
|
|
}
|
|
if ( pm->ps->saberBlocked >= BLOCKED_UPPER_RIGHT
|
|
&& pm->ps->saberBlocked < BLOCKED_UPPER_RIGHT_PROJ)
|
|
{//hold the parry for a bit
|
|
if ( pm->ps->torsoTimer < pm->ps->weaponTime )
|
|
{
|
|
pm->ps->torsoTimer = pm->ps->weaponTime;
|
|
}
|
|
}
|
|
|
|
//what the? I don't know why I was doing this.
|
|
/*
|
|
if (pm->ps->saberBlocked != BLOCKED_ATK_BOUNCE && pm->ps->saberBlocked != BLOCKED_PARRY_BROKEN && pm->ps->weaponTime < 1)
|
|
{
|
|
pm->ps->torsoTimer = SABER_BLOCK_DUR;
|
|
pm->ps->weaponTime = pm->ps->torsoTimer;
|
|
}
|
|
*/
|
|
|
|
//clear block
|
|
pm->ps->saberBlocked = 0;
|
|
|
|
// Charging is like a lead-up before attacking again. This is an appropriate use, or we can create a new weaponstate for blocking
|
|
pm->ps->weaponstate = WEAPON_READY;
|
|
|
|
// Done with block, so stop these active weapon branches.
|
|
return;
|
|
}
|
|
|
|
weapChecks:
|
|
if (pm->ps->saberEntityNum)
|
|
{ //only check if we have our saber with us
|
|
// check for weapon change
|
|
// can't change if weapon is firing, but can change again if lowering or raising
|
|
//if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
|
|
if (pm->ps->weaponTime <= 0 && pm->ps->torsoTimer <= 0)
|
|
{
|
|
if ( pm->ps->weapon != pm->cmd.weapon ) {
|
|
PM_BeginWeaponChange( pm->cmd.weapon );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( PM_CanDoKata() )
|
|
{
|
|
saberMoveName_t overrideMove = LS_INVALID;
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
//see if we have an overridden (or cancelled) kata move
|
|
if ( saber1 && saber1->kataMove != LS_INVALID )
|
|
{
|
|
if ( saber1->kataMove != LS_NONE )
|
|
{
|
|
overrideMove = (saberMoveName_t)saber1->kataMove;
|
|
}
|
|
}
|
|
if ( overrideMove == LS_INVALID )
|
|
{//not overridden by first saber, check second
|
|
if ( saber2
|
|
&& saber2->kataMove != LS_INVALID )
|
|
{
|
|
if ( saber2->kataMove != LS_NONE )
|
|
{
|
|
overrideMove = (saberMoveName_t)saber2->kataMove;
|
|
}
|
|
}
|
|
}
|
|
//no overrides, cancelled?
|
|
if ( overrideMove == LS_INVALID )
|
|
{
|
|
if ( saber2
|
|
&& saber2->kataMove == LS_NONE )
|
|
{
|
|
overrideMove = LS_NONE;
|
|
}
|
|
else if ( saber2
|
|
&& saber2->kataMove == LS_NONE )
|
|
{
|
|
overrideMove = LS_NONE;
|
|
}
|
|
}
|
|
if ( overrideMove == LS_INVALID )
|
|
{//not overridden
|
|
//FIXME: make sure to turn on saber(s)!
|
|
switch ( pm->ps->fd.saberAnimLevel )
|
|
{
|
|
case SS_FAST:
|
|
case SS_TAVION:
|
|
PM_SetSaberMove( LS_A1_SPECIAL );
|
|
break;
|
|
case SS_MEDIUM:
|
|
PM_SetSaberMove( LS_A2_SPECIAL );
|
|
break;
|
|
case SS_STRONG:
|
|
case SS_DESANN:
|
|
PM_SetSaberMove( LS_A3_SPECIAL );
|
|
break;
|
|
case SS_DUAL:
|
|
PM_SetSaberMove( LS_DUAL_SPIN_PROTECT );//PM_CheckDualSpinProtect();
|
|
break;
|
|
case SS_STAFF:
|
|
PM_SetSaberMove( LS_STAFF_SOULCAL );
|
|
break;
|
|
}
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
//G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER );//FP_SPEED, SINGLE_SPECIAL_POWER );
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER);
|
|
}
|
|
else if ( overrideMove != LS_NONE )
|
|
{
|
|
PM_SetSaberMove( overrideMove );
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER);
|
|
}
|
|
if ( overrideMove != LS_NONE )
|
|
{//not cancelled
|
|
return;
|
|
}
|
|
}
|
|
|
|
if ( pm->ps->weaponTime > 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// *********************************************************
|
|
// WEAPON_DROPPING
|
|
// *********************************************************
|
|
|
|
// change weapon if time
|
|
if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
|
|
PM_FinishWeaponChange();
|
|
return;
|
|
}
|
|
|
|
// *********************************************************
|
|
// WEAPON_RAISING
|
|
// *********************************************************
|
|
|
|
if ( pm->ps->weaponstate == WEAPON_RAISING )
|
|
{//Just selected the weapon
|
|
pm->ps->weaponstate = WEAPON_IDLE;
|
|
if((pm->ps->legsAnim) == BOTH_WALK1 )
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_WALK1,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else if((pm->ps->legsAnim) == BOTH_RUN1 )
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_RUN1,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else if((pm->ps->legsAnim) == BOTH_RUN2 )
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_RUN2,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else if( pm->ps->legsAnim == BOTH_RUN_STAFF)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_RUN_STAFF,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else if( pm->ps->legsAnim == BOTH_RUN_DUAL)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_RUN_DUAL,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else if((pm->ps->legsAnim) == BOTH_WALK1 )
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_WALK1,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else if( pm->ps->legsAnim == BOTH_WALK2)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_WALK2,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else if( pm->ps->legsAnim == BOTH_WALK_STAFF)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_WALK_STAFF,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else if( pm->ps->legsAnim == BOTH_WALK_DUAL)
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,BOTH_WALK_DUAL,SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
else
|
|
{
|
|
PM_SetAnim(SETANIM_TORSO,PM_GetSaberStance(),SETANIM_FLAG_NORMAL, 100);
|
|
}
|
|
|
|
if (pm->ps->weaponstate == WEAPON_RAISING)
|
|
{
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
if (checkOnlyWeap)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// *********************************************************
|
|
// Check for WEAPON ATTACK
|
|
// *********************************************************
|
|
if (pm->ps->fd.saberAnimLevel == SS_STAFF &&
|
|
(pm->cmd.buttons & BUTTON_ALT_ATTACK))
|
|
{ //ok, try a kick I guess.
|
|
int kickMove = -1;
|
|
|
|
if ( !BG_KickingAnim(pm->ps->torsoAnim) &&
|
|
!BG_KickingAnim(pm->ps->legsAnim) &&
|
|
!BG_InRoll(pm->ps, pm->ps->legsAnim) &&
|
|
// !BG_KickMove( pm->ps->saberMove )//not already in a kick
|
|
pm->ps->saberMove == LS_READY
|
|
&& !(pm->ps->pm_flags&PMF_DUCKED)//not ducked
|
|
&& (pm->cmd.upmove >= 0 ) //not trying to duck
|
|
)//&& pm->ps->groundEntityNum != ENTITYNUM_NONE)
|
|
{//player kicks
|
|
kickMove = PM_KickMoveForConditions();
|
|
}
|
|
|
|
if (kickMove != -1)
|
|
{
|
|
if ( pm->ps->groundEntityNum == ENTITYNUM_NONE )
|
|
{//if in air, convert kick to an in-air kick
|
|
float gDist = PM_GroundDistance();
|
|
//let's only allow air kicks if a certain distance from the ground
|
|
//it's silly to be able to do them right as you land.
|
|
//also looks wrong to transition from a non-complete flip anim...
|
|
if ((!BG_FlippingAnim( pm->ps->legsAnim ) || pm->ps->legsTimer <= 0) &&
|
|
gDist > 64.0f && //strict minimum
|
|
gDist > (-pm->ps->velocity[2])-64.0f //make sure we are high to ground relative to downward velocity as well
|
|
)
|
|
{
|
|
switch ( kickMove )
|
|
{
|
|
case LS_KICK_F:
|
|
kickMove = LS_KICK_F_AIR;
|
|
break;
|
|
case LS_KICK_B:
|
|
kickMove = LS_KICK_B_AIR;
|
|
break;
|
|
case LS_KICK_R:
|
|
kickMove = LS_KICK_R_AIR;
|
|
break;
|
|
case LS_KICK_L:
|
|
kickMove = LS_KICK_L_AIR;
|
|
break;
|
|
default: //oh well, can't do any other kick move while in-air
|
|
kickMove = -1;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{//leave it as a normal kick unless we're too high up
|
|
if ( gDist > 128.0f || pm->ps->velocity[2] >= 0 )
|
|
{ //off ground, but too close to ground
|
|
kickMove = -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (kickMove != -1)
|
|
{
|
|
PM_SetSaberMove( kickMove );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
//this is never a valid regular saber attack button
|
|
pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
|
|
|
|
if(!delayed_fire)
|
|
{
|
|
// Start with the current move, and cross index it with the current control states.
|
|
if ( pm->ps->saberMove > LS_NONE && pm->ps->saberMove < LS_MOVE_MAX )
|
|
{
|
|
curmove = pm->ps->saberMove;
|
|
}
|
|
else
|
|
{
|
|
curmove = LS_READY;
|
|
}
|
|
|
|
if ( curmove == LS_A_JUMP_T__B_ || pm->ps->torsoAnim == BOTH_FORCELEAP2_T__B_ )
|
|
{//must transition back to ready from this anim
|
|
newmove = LS_R_T2B;
|
|
}
|
|
// check for fire
|
|
else if ( !(pm->cmd.buttons & (BUTTON_ATTACK|BUTTON_ALT_ATTACK)) )
|
|
{//not attacking
|
|
pm->ps->weaponTime = 0;
|
|
|
|
if ( pm->ps->weaponTime > 0 )
|
|
{//Still firing
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
}
|
|
else if ( pm->ps->weaponstate != WEAPON_READY )
|
|
{
|
|
pm->ps->weaponstate = WEAPON_IDLE;
|
|
}
|
|
//Check for finishing an anim if necc.
|
|
if ( curmove >= LS_S_TL2BR && curmove <= LS_S_T2B )
|
|
{//started a swing, must continue from here
|
|
newmove = LS_A_TL2BR + (curmove-LS_S_TL2BR);
|
|
}
|
|
else if ( curmove >= LS_A_TL2BR && curmove <= LS_A_T2B )
|
|
{//finished an attack, must continue from here
|
|
newmove = LS_R_TL2BR + (curmove-LS_A_TL2BR);
|
|
}
|
|
else if ( PM_SaberInTransition( curmove ) )
|
|
{//in a transition, must play sequential attack
|
|
newmove = saberMoveData[curmove].chain_attack;
|
|
}
|
|
else if ( PM_SaberInBounce( curmove ) )
|
|
{//in a bounce
|
|
newmove = saberMoveData[curmove].chain_idle;//oops, not attacking, so don't chain
|
|
}
|
|
else
|
|
{//FIXME: what about returning from a parry?
|
|
//PM_SetSaberMove( LS_READY );
|
|
//if ( pm->ps->saberBlockingTime > pm->cmd.serverTime )
|
|
{
|
|
PM_SetSaberMove( LS_READY );
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// ***************************************************
|
|
// Pressing attack, so we must look up the proper attack move.
|
|
|
|
if ( pm->ps->weaponTime > 0 )
|
|
{ // Last attack is not yet complete.
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
int both = qfalse;
|
|
if ( pm->ps->torsoAnim == BOTH_FORCELONGLEAP_ATTACK
|
|
|| pm->ps->torsoAnim == BOTH_FORCELONGLEAP_LAND )
|
|
{//can't attack in these anims
|
|
return;
|
|
}
|
|
else if ( pm->ps->torsoAnim == BOTH_FORCELONGLEAP_START )
|
|
{//only 1 attack you can do from this anim
|
|
if ( pm->ps->torsoTimer >= 200 )
|
|
{//hit it early enough to do the attack
|
|
PM_SetSaberMove( LS_LEAP_ATTACK );
|
|
}
|
|
return;
|
|
}
|
|
if ( curmove >= LS_PARRY_UP && curmove <= LS_REFLECT_LL )
|
|
{//from a parry or reflection, can go directly into an attack
|
|
switch ( saberMoveData[curmove].endQuad )
|
|
{
|
|
case Q_T:
|
|
newmove = LS_A_T2B;
|
|
break;
|
|
case Q_TR:
|
|
newmove = LS_A_TR2BL;
|
|
break;
|
|
case Q_TL:
|
|
newmove = LS_A_TL2BR;
|
|
break;
|
|
case Q_BR:
|
|
newmove = LS_A_BR2TL;
|
|
break;
|
|
case Q_BL:
|
|
newmove = LS_A_BL2TR;
|
|
break;
|
|
//shouldn't be a parry that ends at L, R or B
|
|
}
|
|
}
|
|
|
|
if ( newmove != LS_NONE )
|
|
{//have a valid, final LS_ move picked, so skip findingt he transition move and just get the anim
|
|
anim = saberMoveData[newmove].animToUse;
|
|
}
|
|
|
|
//FIXME: diagonal dirs use the figure-eight attacks from ready pose?
|
|
if ( anim == -1 )
|
|
{
|
|
//FIXME: take FP_SABER_OFFENSE into account here somehow?
|
|
if ( PM_SaberInTransition( curmove ) )
|
|
{//in a transition, must play sequential attack
|
|
newmove = saberMoveData[curmove].chain_attack;
|
|
}
|
|
else if ( curmove >= LS_S_TL2BR && curmove <= LS_S_T2B )
|
|
{//started a swing, must continue from here
|
|
newmove = LS_A_TL2BR + (curmove-LS_S_TL2BR);
|
|
}
|
|
else if ( PM_SaberInBrokenParry( curmove ) )
|
|
{//broken parries must always return to ready
|
|
newmove = LS_READY;
|
|
}
|
|
else//if ( pm->cmd.buttons&BUTTON_ATTACK && !(pm->ps->pm_flags&PMF_ATTACK_HELD) )//only do this if just pressed attack button?
|
|
{//get attack move from movement command
|
|
/*
|
|
if ( PM_SaberKataDone() )
|
|
{//we came from a bounce and cannot chain to another attack because our kata is done
|
|
newmove = saberMoveData[curmove].chain_idle;
|
|
}
|
|
else */
|
|
newmove = PM_SaberAttackForMovement( curmove );
|
|
if ( (PM_SaberInBounce( curmove )||PM_SaberInBrokenParry( curmove ))
|
|
&& saberMoveData[newmove].startQuad == saberMoveData[curmove].endQuad )
|
|
{//this attack would be a repeat of the last (which was blocked), so don't actually use it, use the default chain attack for this bounce
|
|
newmove = saberMoveData[curmove].chain_attack;
|
|
}
|
|
|
|
if ( PM_SaberKataDone( curmove, newmove ) )
|
|
{//cannot chain this time
|
|
newmove = saberMoveData[curmove].chain_idle;
|
|
}
|
|
}
|
|
/*
|
|
if ( newmove == LS_NONE )
|
|
{//FIXME: should we allow this? Are there some anims that you should never be able to chain into an attack?
|
|
//only curmove that might get in here is LS_NONE, LS_DRAW, LS_PUTAWAY and the LS_R_ returns... all of which are in Q_R
|
|
newmove = PM_AttackMoveForQuad( saberMoveData[curmove].endQuad );
|
|
}
|
|
*/
|
|
if ( newmove != LS_NONE )
|
|
{
|
|
//Now get the proper transition move
|
|
newmove = PM_SaberAnimTransitionAnim( curmove, newmove );
|
|
anim = saberMoveData[newmove].animToUse;
|
|
}
|
|
}
|
|
|
|
if (anim == -1)
|
|
{//not side-stepping, pick neutral anim
|
|
// Add randomness for prototype?
|
|
newmove = saberMoveData[curmove].chain_attack;
|
|
|
|
anim= saberMoveData[newmove].animToUse;
|
|
|
|
if ( !pm->cmd.forwardmove && !pm->cmd.rightmove && pm->cmd.upmove >= 0 && pm->ps->groundEntityNum != ENTITYNUM_NONE )
|
|
{//not moving at all, so set the anim on entire body
|
|
both = qtrue;
|
|
}
|
|
|
|
}
|
|
|
|
if ( anim == -1)
|
|
{
|
|
switch ( pm->ps->legsAnim )
|
|
{
|
|
case BOTH_WALK1:
|
|
case BOTH_WALK2:
|
|
case BOTH_WALK_STAFF:
|
|
case BOTH_WALK_DUAL:
|
|
case BOTH_WALKBACK1:
|
|
case BOTH_WALKBACK2:
|
|
case BOTH_WALKBACK_STAFF:
|
|
case BOTH_WALKBACK_DUAL:
|
|
case BOTH_RUN1:
|
|
case BOTH_RUN2:
|
|
case BOTH_RUN_STAFF:
|
|
case BOTH_RUN_DUAL:
|
|
case BOTH_RUNBACK1:
|
|
case BOTH_RUNBACK2:
|
|
case BOTH_RUNBACK_STAFF:
|
|
anim = pm->ps->legsAnim;
|
|
break;
|
|
default:
|
|
anim = PM_GetSaberStance();
|
|
break;
|
|
}
|
|
|
|
// if (PM_RunningAnim(anim) && !pm->cmd.forwardmove && !pm->cmd.rightmove)
|
|
// { //semi-hacky (if not moving on x-y and still playing the running anim, force the player out of it)
|
|
// anim = PM_GetSaberStance();
|
|
// }
|
|
newmove = LS_READY;
|
|
}
|
|
|
|
PM_SetSaberMove( newmove );
|
|
|
|
if ( both && pm->ps->torsoAnim == anim )
|
|
{
|
|
PM_SetAnim(SETANIM_LEGS,anim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100);
|
|
}
|
|
|
|
//don't fire again until anim is done
|
|
pm->ps->weaponTime = pm->ps->torsoTimer;
|
|
}
|
|
}
|
|
|
|
// *********************************************************
|
|
// WEAPON_FIRING
|
|
// *********************************************************
|
|
|
|
pm->ps->weaponstate = WEAPON_FIRING;
|
|
|
|
amount = weaponData[pm->ps->weapon].energyPerShot;
|
|
|
|
addTime = pm->ps->weaponTime;
|
|
|
|
pm->ps->saberAttackSequence = pm->ps->torsoAnim;
|
|
if ( !addTime )
|
|
{
|
|
addTime = weaponData[pm->ps->weapon].fireTime;
|
|
}
|
|
pm->ps->weaponTime = addTime;
|
|
}
|
|
|
|
void PM_SetSaberMove(short newMove)
|
|
{
|
|
unsigned int setflags = saberMoveData[newMove].animSetFlags;
|
|
int anim = saberMoveData[newMove].animToUse;
|
|
int parts = SETANIM_TORSO;
|
|
|
|
if ( newMove == LS_READY || newMove == LS_A_FLIP_STAB || newMove == LS_A_FLIP_SLASH )
|
|
{//finished with a kata (or in a special move) reset attack counter
|
|
pm->ps->saberAttackChainCount = 0;
|
|
}
|
|
else if ( BG_SaberInAttack( newMove ) )
|
|
{//continuing with a kata, increment attack counter
|
|
pm->ps->saberAttackChainCount++;
|
|
}
|
|
|
|
if (pm->ps->saberAttackChainCount > 16)
|
|
{ //for the sake of being able to send the value over the net within a reasonable bit count
|
|
pm->ps->saberAttackChainCount = 16;
|
|
}
|
|
|
|
if ( newMove == LS_DRAW )
|
|
{
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
if ( saber1
|
|
&& saber1->drawAnim != -1 )
|
|
{
|
|
anim = saber1->drawAnim;
|
|
}
|
|
else if ( saber2
|
|
&& saber2->drawAnim != -1 )
|
|
{
|
|
anim = saber2->drawAnim;
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
|
|
{
|
|
anim = BOTH_S1_S7;
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
|
|
{
|
|
anim = BOTH_S1_S6;
|
|
}
|
|
}
|
|
else if ( newMove == LS_PUTAWAY )
|
|
{
|
|
saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
|
|
saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
|
|
if ( saber1
|
|
&& saber1->putawayAnim != -1 )
|
|
{
|
|
anim = saber1->putawayAnim;
|
|
}
|
|
else if ( saber2
|
|
&& saber2->putawayAnim != -1 )
|
|
{
|
|
anim = saber2->putawayAnim;
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
|
|
{
|
|
anim = BOTH_S7_S1;
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
|
|
{
|
|
anim = BOTH_S6_S1;
|
|
}
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == SS_STAFF && newMove >= LS_S_TL2BR && newMove < LS_REFLECT_LL )
|
|
{//staff has an entirely new set of anims, besides special attacks
|
|
//FIXME: include ready and draw/putaway?
|
|
//FIXME: get hand-made bounces and deflections?
|
|
if ( newMove >= LS_V1_BR && newMove <= LS_REFLECT_LL )
|
|
{//there aren't 1-7, just 1, 6 and 7, so just set it
|
|
anim = BOTH_P7_S7_T_ + (anim-BOTH_P1_S1_T_);//shift it up to the proper set
|
|
}
|
|
else
|
|
{//add the appropriate animLevel
|
|
anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
|
|
}
|
|
}
|
|
else if ( pm->ps->fd.saberAnimLevel == SS_DUAL && newMove >= LS_S_TL2BR && newMove < LS_REFLECT_LL )
|
|
{ //akimbo has an entirely new set of anims, besides special attacks
|
|
//FIXME: include ready and draw/putaway?
|
|
//FIXME: get hand-made bounces and deflections?
|
|
if ( newMove >= LS_V1_BR && newMove <= LS_REFLECT_LL )
|
|
{//there aren't 1-7, just 1, 6 and 7, so just set it
|
|
anim = BOTH_P6_S6_T_ + (anim-BOTH_P1_S1_T_);//shift it up to the proper set
|
|
}
|
|
else
|
|
{//add the appropriate animLevel
|
|
anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
|
|
}
|
|
}
|
|
/*
|
|
else if ( newMove == LS_DRAW && pm->ps->SaberStaff() )
|
|
{//hold saber out front as we turn it on
|
|
//FIXME: need a real "draw" anim for this (and put-away)
|
|
anim = BOTH_SABERSTAFF_STANCE;
|
|
}
|
|
*/
|
|
else if ( pm->ps->fd.saberAnimLevel > FORCE_LEVEL_1 &&
|
|
!BG_SaberInIdle( newMove ) && !PM_SaberInParry( newMove ) && !PM_SaberInKnockaway( newMove ) && !PM_SaberInBrokenParry( newMove ) && !PM_SaberInReflect( newMove ) && !BG_SaberInSpecial(newMove))
|
|
{//readies, parries and reflections have only 1 level
|
|
anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
|
|
}
|
|
|
|
// If the move does the same animation as the last one, we need to force a restart...
|
|
if ( saberMoveData[pm->ps->saberMove].animToUse == anim && newMove > LS_PUTAWAY)
|
|
{
|
|
setflags |= SETANIM_FLAG_RESTART;
|
|
}
|
|
|
|
//saber torso anims should always be highest priority (4/12/02 - for special anims only)
|
|
if (!pm->ps->m_iVehicleNum)
|
|
{ //if not riding a vehicle
|
|
if (BG_SaberInSpecial(newMove))
|
|
{
|
|
setflags |= SETANIM_FLAG_OVERRIDE;
|
|
}
|
|
/*
|
|
if ( newMove == LS_A_LUNGE
|
|
|| newMove == LS_A_JUMP_T__B_
|
|
|| newMove == LS_A_BACKSTAB
|
|
|| newMove == LS_A_BACK
|
|
|| newMove == LS_A_BACK_CR
|
|
|| newMove == LS_A_FLIP_STAB
|
|
|| newMove == LS_A_FLIP_SLASH
|
|
|| newMove == LS_JUMPATTACK_DUAL
|
|
|| newMove == LS_A_BACKFLIP_ATK)
|
|
{
|
|
setflags |= SETANIM_FLAG_OVERRIDE;
|
|
}
|
|
*/
|
|
}
|
|
if ( BG_InSaberStandAnim(anim) || anim == BOTH_STAND1 )
|
|
{
|
|
anim = (pm->ps->legsAnim);
|
|
|
|
if ((anim >= BOTH_STAND1 && anim <= BOTH_STAND4TOATTACK2) ||
|
|
(anim >= TORSO_DROPWEAP1 && anim <= TORSO_WEAPONIDLE10))
|
|
{ //If standing then use the special saber stand anim
|
|
anim = PM_GetSaberStance();
|
|
}
|
|
|
|
if (pm->ps->pm_flags & PMF_DUCKED)
|
|
{ //Playing torso walk anims while crouched makes you look like a monkey
|
|
anim = PM_GetSaberStance();
|
|
}
|
|
|
|
if (anim == BOTH_WALKBACK1 || anim == BOTH_WALKBACK2 || anim == BOTH_WALK1)
|
|
{ //normal stance when walking backward so saber doesn't look like it's cutting through leg
|
|
anim = PM_GetSaberStance();
|
|
}
|
|
|
|
if (BG_InSlopeAnim( anim ))
|
|
{
|
|
anim = PM_GetSaberStance();
|
|
}
|
|
|
|
parts = SETANIM_TORSO;
|
|
}
|
|
|
|
if (!pm->ps->m_iVehicleNum)
|
|
{ //if not riding a vehicle
|
|
if (newMove == LS_JUMPATTACK_ARIAL_RIGHT ||
|
|
newMove == LS_JUMPATTACK_ARIAL_LEFT)
|
|
{ //force only on legs
|
|
parts = SETANIM_LEGS;
|
|
}
|
|
else if ( newMove == LS_A_LUNGE
|
|
|| newMove == LS_A_JUMP_T__B_
|
|
|| newMove == LS_A_BACKSTAB
|
|
|| newMove == LS_A_BACK
|
|
|| newMove == LS_A_BACK_CR
|
|
|| newMove == LS_ROLL_STAB
|
|
|| newMove == LS_A_FLIP_STAB
|
|
|| newMove == LS_A_FLIP_SLASH
|
|
|| newMove == LS_JUMPATTACK_DUAL
|
|
|| newMove == LS_JUMPATTACK_ARIAL_LEFT
|
|
|| newMove == LS_JUMPATTACK_ARIAL_RIGHT
|
|
|| newMove == LS_JUMPATTACK_CART_LEFT
|
|
|| newMove == LS_JUMPATTACK_CART_RIGHT
|
|
|| newMove == LS_JUMPATTACK_STAFF_LEFT
|
|
|| newMove == LS_JUMPATTACK_STAFF_RIGHT
|
|
|| newMove == LS_A_BACKFLIP_ATK
|
|
|| newMove == LS_STABDOWN
|
|
|| newMove == LS_STABDOWN_STAFF
|
|
|| newMove == LS_STABDOWN_DUAL
|
|
|| newMove == LS_DUAL_SPIN_PROTECT
|
|
|| newMove == LS_STAFF_SOULCAL
|
|
|| newMove == LS_A1_SPECIAL
|
|
|| newMove == LS_A2_SPECIAL
|
|
|| newMove == LS_A3_SPECIAL
|
|
|| newMove == LS_UPSIDE_DOWN_ATTACK
|
|
|| newMove == LS_PULL_ATTACK_STAB
|
|
|| newMove == LS_PULL_ATTACK_SWING
|
|
|| BG_KickMove( newMove ) )
|
|
{
|
|
parts = SETANIM_BOTH;
|
|
}
|
|
else if ( BG_SpinningSaberAnim( anim ) )
|
|
{//spins must be played on entire body
|
|
parts = SETANIM_BOTH;
|
|
}
|
|
else if ( (!pm->cmd.forwardmove&&!pm->cmd.rightmove&&!pm->cmd.upmove))
|
|
{//not trying to run, duck or jump
|
|
if ( !BG_FlippingAnim( pm->ps->legsAnim ) &&
|
|
!BG_InRoll( pm->ps, pm->ps->legsAnim ) &&
|
|
!PM_InKnockDown( pm->ps ) &&
|
|
!PM_JumpingAnim( pm->ps->legsAnim ) &&
|
|
!BG_InSpecialJump( pm->ps->legsAnim ) &&
|
|
anim != PM_GetSaberStance() &&
|
|
pm->ps->groundEntityNum != ENTITYNUM_NONE &&
|
|
!(pm->ps->pm_flags & PMF_DUCKED))
|
|
{
|
|
parts = SETANIM_BOTH;
|
|
}
|
|
else if ( !(pm->ps->pm_flags & PMF_DUCKED)
|
|
&& ( newMove == LS_SPINATTACK_DUAL || newMove == LS_SPINATTACK ) )
|
|
{
|
|
parts = SETANIM_BOTH;
|
|
}
|
|
}
|
|
|
|
PM_SetAnim(parts, anim, setflags, saberMoveData[newMove].blendTime);
|
|
if (parts != SETANIM_LEGS &&
|
|
(pm->ps->legsAnim == BOTH_ARIAL_LEFT ||
|
|
pm->ps->legsAnim == BOTH_ARIAL_RIGHT))
|
|
{
|
|
if (pm->ps->legsTimer > pm->ps->torsoTimer)
|
|
{
|
|
pm->ps->legsTimer = pm->ps->torsoTimer;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ( (pm->ps->torsoAnim) == anim )
|
|
{//successfully changed anims
|
|
//special check for *starting* a saber swing
|
|
//playing at attack
|
|
if ( BG_SaberInAttack( newMove ) || BG_SaberInSpecialAttack( anim ) )
|
|
{
|
|
if ( pm->ps->saberMove != newMove )
|
|
{//wasn't playing that attack before
|
|
if ( newMove != LS_KICK_F
|
|
&& newMove != LS_KICK_B
|
|
&& newMove != LS_KICK_R
|
|
&& newMove != LS_KICK_L
|
|
&& newMove != LS_KICK_F_AIR
|
|
&& newMove != LS_KICK_B_AIR
|
|
&& newMove != LS_KICK_R_AIR
|
|
&& newMove != LS_KICK_L_AIR )
|
|
{
|
|
PM_AddEvent(EV_SABER_ATTACK);
|
|
}
|
|
|
|
if (pm->ps->brokenLimbs)
|
|
{ //randomly make pain sounds with a broken arm because we are suffering.
|
|
int iFactor = -1;
|
|
|
|
if (pm->ps->brokenLimbs & (1<<BROKENLIMB_RARM))
|
|
{ //You're using it more. So it hurts more.
|
|
iFactor = 5;
|
|
}
|
|
else if (pm->ps->brokenLimbs & (1<<BROKENLIMB_LARM))
|
|
{
|
|
iFactor = 10;
|
|
}
|
|
|
|
if (iFactor != -1)
|
|
{
|
|
if ( !PM_irand_timesync( 0, iFactor ) )
|
|
{
|
|
BG_AddPredictableEventToPlayerstate(EV_PAIN, PM_irand_timesync( 1, 100 ), pm->ps);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (BG_SaberInSpecial(newMove) &&
|
|
pm->ps->weaponTime < pm->ps->torsoTimer)
|
|
{ //rww 01-02-03 - I think this will solve the issue of special attacks being interruptable, hopefully without side effects
|
|
pm->ps->weaponTime = pm->ps->torsoTimer;
|
|
}
|
|
|
|
pm->ps->saberMove = newMove;
|
|
pm->ps->saberBlocking = saberMoveData[newMove].blocking;
|
|
|
|
pm->ps->torsoAnim = anim;
|
|
|
|
if (pm->ps->weaponTime <= 0)
|
|
{
|
|
pm->ps->saberBlocked = BLOCKED_NONE;
|
|
}
|
|
}
|
|
}
|
|
|
|
saberInfo_t *BG_MySaber( int clientNum, int saberNum )
|
|
{
|
|
//returns a pointer to the requested saberNum
|
|
#ifdef QAGAME
|
|
gentity_t *ent = &g_entities[clientNum];
|
|
if ( ent->inuse && ent->client )
|
|
{
|
|
if ( !ent->client->saber[saberNum].model
|
|
|| !ent->client->saber[saberNum].model[0] )
|
|
{ //don't have saber anymore!
|
|
return NULL;
|
|
}
|
|
return &ent->client->saber[saberNum];
|
|
}
|
|
#elif defined CGAME
|
|
clientInfo_t *ci = NULL;
|
|
if (clientNum < MAX_CLIENTS)
|
|
{
|
|
ci = &cgs.clientinfo[clientNum];
|
|
}
|
|
else
|
|
{
|
|
centity_t *cent = &cg_entities[clientNum];
|
|
if (cent->npcClient)
|
|
{
|
|
ci = cent->npcClient;
|
|
}
|
|
}
|
|
if ( ci
|
|
&& ci->infoValid )
|
|
{
|
|
if ( !ci->saber[saberNum].model
|
|
|| !ci->saber[saberNum].model[0] )
|
|
{ //don't have sabers anymore!
|
|
return NULL;
|
|
}
|
|
return &ci->saber[saberNum];
|
|
}
|
|
#endif
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#include "../namespace_end.h"
|