codemp/game/bg_saber.c

Go to the documentation of this file.
00001 #include "q_shared.h"
00002 #include "bg_public.h"
00003 #include "bg_local.h"
00004 #include "w_saber.h"
00005 
00006 #include "../namespace_begin.h"
00007 extern qboolean BG_SabersOff( playerState_t *ps );
00008 saberInfo_t *BG_MySaber( int clientNum, int saberNum );
00009 
00010 int PM_irand_timesync(int val1, int val2)
00011 {
00012         int i;
00013 
00014         i = (val1-1) + (Q_random( &pm->cmd.serverTime )*(val2 - val1)) + 1;
00015         if (i < val1)
00016         {
00017                 i = val1;
00018         }
00019         if (i > val2)
00020         {
00021                 i = val2;
00022         }
00023 
00024         return i;
00025 }
00026 
00027 void BG_ForcePowerDrain( playerState_t *ps, forcePowers_t forcePower, int overrideAmt )
00028 {
00029         //take away the power
00030         int     drain = overrideAmt;
00031 
00032         /*
00033         if (ps->powerups[PW_FORCE_BOON])
00034         {
00035                 return;
00036         }
00037         */
00038         //No longer grant infinite force with boon.
00039 
00040         if ( !drain )
00041         {
00042                 drain = forcePowerNeeded[ps->fd.forcePowerLevel[forcePower]][forcePower];
00043         }
00044         if ( !drain )
00045         {
00046                 return;
00047         }
00048 
00049         if (forcePower == FP_LEVITATION)
00050         { //special case
00051                 int jumpDrain = 0;
00052 
00053                 if (ps->velocity[2] > 250)
00054                 {
00055                         jumpDrain = 20;
00056                 }
00057                 else if (ps->velocity[2] > 200)
00058                 {
00059                         jumpDrain = 16;
00060                 }
00061                 else if (ps->velocity[2] > 150)
00062                 {
00063                         jumpDrain = 12;
00064                 }
00065                 else if (ps->velocity[2] > 100)
00066                 {
00067                         jumpDrain = 8;
00068                 }
00069                 else if (ps->velocity[2] > 50)
00070                 {
00071                         jumpDrain = 6;
00072                 }
00073                 else if (ps->velocity[2] > 0)
00074                 {
00075                         jumpDrain = 4;
00076                 }
00077 
00078                 if (jumpDrain)
00079                 {
00080                         if (ps->fd.forcePowerLevel[FP_LEVITATION])
00081                         { //don't divide by 0!
00082                                 jumpDrain /= ps->fd.forcePowerLevel[FP_LEVITATION];
00083                         }
00084                 }
00085 
00086                 ps->fd.forcePower -= jumpDrain;
00087                 if ( ps->fd.forcePower < 0 )
00088                 {
00089                         ps->fd.forcePower = 0;
00090                 }
00091 
00092                 return;
00093         }
00094 
00095         ps->fd.forcePower -= drain;
00096         if ( ps->fd.forcePower < 0 )
00097         {
00098                 ps->fd.forcePower = 0;
00099         }
00100 }
00101 
00102 qboolean BG_EnoughForcePowerForMove( int cost )
00103 {
00104         if ( pm->ps->fd.forcePower < cost )
00105         {
00106                 PM_AddEvent( EV_NOAMMO );
00107                 return qfalse;
00108         }
00109 
00110         return qtrue;
00111 }
00112 
00113 // Silly, but I'm replacing these macros so they are shorter!
00114 #define AFLAG_IDLE      (SETANIM_FLAG_NORMAL)
00115 #define AFLAG_ACTIVE (SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS)
00116 #define AFLAG_WAIT (SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS)
00117 #define AFLAG_FINISH (SETANIM_FLAG_HOLD)
00118 
00119 //FIXME: add the alternate anims for each style?
00120 saberMoveData_t saberMoveData[LS_MOVE_MAX] = {//                                                        NB:randomized
00121         // name                 anim(do all styles?)startQ      endQ    setanimflag             blend,  blocking        chain_idle              chain_attack    trailLen
00122         {"None",                BOTH_STAND1,            Q_R,    Q_R,    AFLAG_IDLE,             350,    BLK_NO,         LS_NONE,                LS_NONE,                0       },      // LS_NONE              = 0,
00123 
00124         // General movements with saber
00125         {"Ready",               BOTH_STAND2,            Q_R,    Q_R,    AFLAG_IDLE,             350,    BLK_WIDE,       LS_READY,               LS_S_R2L,               0       },      // LS_READY,
00126         {"Draw",                BOTH_STAND1TO2,         Q_R,    Q_R,    AFLAG_FINISH,   350,    BLK_NO,         LS_READY,               LS_S_R2L,               0       },      // LS_DRAW,
00127         {"Putaway",             BOTH_STAND2TO1,         Q_R,    Q_R,    AFLAG_FINISH,   350,    BLK_NO,         LS_READY,               LS_S_R2L,               0       },      // LS_PUTAWAY,
00128 
00129         // Attacks
00130         //UL2LR
00131         {"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
00132         //SLASH LEFT
00133         {"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
00134         //LL2UR
00135         {"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
00136         //LR2UL
00137         {"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
00138         //SLASH RIGHT
00139         {"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
00140         //UR2LL
00141         {"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
00142         //SLASH DOWN
00143         {"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
00144         //special attacks
00145         {"Back Stab",   BOTH_A2_STABBACK1,      Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_A_BACKSTAB
00146         {"Back Att",    BOTH_ATTACK_BACK,       Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_A_BACK
00147         {"CR Back Att", BOTH_CROUCHATTACKBACK1,Q_R,     Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_A_BACK_CR
00148         {"RollStab",    BOTH_ROLL_STAB,         Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_ROLL_STAB
00149         {"Lunge Att",   BOTH_LUNGE2_B__T_,      Q_B,    Q_T,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_A_LUNGE
00150         {"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_
00151         {"Flip Stab",   BOTH_JUMPFLIPSTABDOWN,Q_R,      Q_T,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_T1_T___R,    200     },      // LS_A_FLIP_STAB
00152         {"Flip Slash",  BOTH_JUMPFLIPSLASHDOWN1,Q_L,Q_R,        AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_T1__R_T_,    200     },      // LS_A_FLIP_SLASH
00153         {"DualJump Atk",BOTH_JUMPATTACK6,       Q_R,    Q_BL,   AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_T1_BL_TR,    200     },      // LS_JUMPATTACK_DUAL
00154 
00155         {"DualJumpAtkL_A",BOTH_ARIAL_LEFT,      Q_R,    Q_TL,   AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_A_TL2BR,             200     },      // LS_JUMPATTACK_ARIAL_LEFT
00156         {"DualJumpAtkR_A",BOTH_ARIAL_RIGHT,     Q_R,    Q_TR,   AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_A_TR2BL,             200     },      // LS_JUMPATTACK_ARIAL_RIGHT
00157 
00158         {"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
00159         {"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
00160         
00161         {"DualJumpAtkLStaff", BOTH_BUTTERFLY_FL1,Q_R,Q_L,       AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_T1__L__R,    200     },      // LS_JUMPATTACK_STAFF_LEFT
00162         {"DualJumpAtkRStaff", BOTH_BUTTERFLY_FR1,Q_R,Q_R,       AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_T1__R__L,    200     },      // LS_JUMPATTACK_STAFF_RIGHT
00163 
00164         {"ButterflyLeft", BOTH_BUTTERFLY_LEFT,Q_R,Q_L,          AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_T1__L__R,    200     },      // LS_BUTTERFLY_LEFT
00165         {"ButterflyRight", BOTH_BUTTERFLY_RIGHT,Q_R,Q_R,        AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_T1__R__L,    200     },      // LS_BUTTERFLY_RIGHT
00166         
00167         {"BkFlip Atk",  BOTH_JUMPATTACK7,       Q_B,    Q_T,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_T1_T___R,    200     },      // LS_A_BACKFLIP_ATK
00168         {"DualSpinAtk", BOTH_SPINATTACK6,       Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_SPINATTACK_DUAL
00169         {"StfSpinAtk",  BOTH_SPINATTACK7,       Q_L,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_SPINATTACK
00170         {"LngLeapAtk",  BOTH_FORCELONGLEAP_ATTACK,Q_R,Q_L,      AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_LEAP_ATTACK
00171         {"SwoopAtkR",   BOTH_VS_ATR_S,          Q_R,    Q_T,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_SWOOP_ATTACK_RIGHT
00172         {"SwoopAtkL",   BOTH_VS_ATL_S,          Q_L,    Q_T,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_SWOOP_ATTACK_LEFT
00173         {"TauntaunAtkR",BOTH_VT_ATR_S,          Q_R,    Q_T,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_TAUNTAUN_ATTACK_RIGHT
00174         {"TauntaunAtkL",BOTH_VT_ATL_S,          Q_L,    Q_T,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_TAUNTAUN_ATTACK_LEFT
00175         {"StfKickFwd",  BOTH_A7_KICK_F,         Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_S_R2L,               200     },      // LS_KICK_F
00176         {"StfKickBack", BOTH_A7_KICK_B,         Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_S_R2L,               200     },      // LS_KICK_B
00177         {"StfKickRight",BOTH_A7_KICK_R,         Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_S_R2L,               200     },      // LS_KICK_R
00178         {"StfKickLeft", BOTH_A7_KICK_L,         Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_S_R2L,               200     },      // LS_KICK_L
00179         {"StfKickSpin", BOTH_A7_KICK_S,         Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_NO,         LS_READY,               LS_S_R2L,               200     },      // LS_KICK_S
00180         {"StfKickBkFwd",BOTH_A7_KICK_BF,        Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_NO,         LS_READY,               LS_S_R2L,               200     },      // LS_KICK_BF
00181         {"StfKickSplit",BOTH_A7_KICK_RL,        Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_NO,         LS_READY,               LS_S_R2L,               200     },      // LS_KICK_RL
00182         {"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
00183         {"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
00184         {"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
00185         {"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
00186         {"StabDown",    BOTH_STABDOWN,          Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_S_R2L,               200     },      // LS_STABDOWN
00187         {"StabDownStf", BOTH_STABDOWN_STAFF,Q_R,        Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_S_R2L,               200     },      // LS_STABDOWN_STAFF
00188         {"StabDownDual",BOTH_STABDOWN_DUAL,     Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_S_R2L,               200     },      // LS_STABDOWN_DUAL
00189         {"dualspinprot",BOTH_A6_SABERPROTECT,Q_R,       Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               500     },      // LS_DUAL_SPIN_PROTECT
00190         {"StfSoulCal",  BOTH_A7_SOULCAL,        Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               500     },      // LS_STAFF_SOULCAL
00191         {"specialfast", BOTH_A1_SPECIAL,        Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               2000},  // LS_A1_SPECIAL
00192         {"specialmed",  BOTH_A2_SPECIAL,        Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               2000},  // LS_A2_SPECIAL
00193         {"specialstr",  BOTH_A3_SPECIAL,        Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               2000},  // LS_A3_SPECIAL
00194         {"upsidedwnatk",BOTH_FLIP_ATTACK7,      Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200},   // LS_UPSIDE_DOWN_ATTACK
00195         {"pullatkstab", BOTH_PULL_IMPALE_STAB,Q_R,      Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200},   // LS_PULL_ATTACK_STAB
00196         {"pullatkswing",BOTH_PULL_IMPALE_SWING,Q_R,     Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200},   // LS_PULL_ATTACK_SWING
00197         {"AloraSpinAtk",BOTH_ALORA_SPIN_SLASH,Q_R,      Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_SPINATTACK_ALORA
00198         {"Dual FB Atk", BOTH_A6_FB,                     Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_DUAL_FB
00199         {"Dual LR Atk", BOTH_A6_LR,                     Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200 },  // LS_DUAL_LR
00200         {"StfHiltBash", BOTH_A7_HILT,           Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_HILT_BASH
00201 
00202         //starts
00203         {"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
00204         {"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
00205         {"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
00206         {"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
00207         {"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
00208         {"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
00209         {"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
00210         
00211         //returns
00212         {"TL2BR Ret",   BOTH_R1_BR_S1,          Q_BR,   Q_R,    AFLAG_FINISH,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_R_TL2BR
00213         {"L2R Ret",             BOTH_R1__R_S1,          Q_R,    Q_R,    AFLAG_FINISH,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_R_L2R
00214         {"BL2TR Ret",   BOTH_R1_TR_S1,          Q_TR,   Q_R,    AFLAG_FINISH,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_R_BL2TR
00215         {"BR2TL Ret",   BOTH_R1_TL_S1,          Q_TL,   Q_R,    AFLAG_FINISH,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_R_BR2TL
00216         {"R2L Ret",             BOTH_R1__L_S1,          Q_L,    Q_R,    AFLAG_FINISH,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_R_R2L
00217         {"TR2BL Ret",   BOTH_R1_BL_S1,          Q_BL,   Q_R,    AFLAG_FINISH,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_R_TR2BL
00218         {"T2B Ret",             BOTH_R1_B__S1,          Q_B,    Q_R,    AFLAG_FINISH,   100,    BLK_TIGHT,      LS_READY,               LS_READY,               200     },      // LS_R_T2B
00219 
00220         //Transitions
00221         {"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
00222         {"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)
00223         {"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)
00224         {"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
00225         {"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
00226         {"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
00227         {"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)
00228         {"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
00229         {"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)
00230         {"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
00231         {"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
00232         {"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
00233         {"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
00234         {"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)
00235         {"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)
00236         {"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
00237         {"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
00238         {"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
00239         {"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
00240         {"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
00241         {"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
00242         {"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
00243         {"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
00244         {"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
00245         {"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
00246         {"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)
00247         {"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)
00248         {"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)
00249         {"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)
00250         {"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
00251         {"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
00252         {"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
00253         {"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)
00254         {"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)
00255         {"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
00256         {"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)
00257         {"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
00258         {"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
00259         {"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
00260         {"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)
00261         {"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)
00262         {"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
00263 
00264         //Bounces
00265         {"Bounce BR",   BOTH_B1_BR___,          Q_BR,   Q_BR,   AFLAG_ACTIVE,   100,    BLK_NO, LS_R_TL2BR,             LS_T1_BR_TR,    150     },      
00266         {"Bounce R",    BOTH_B1__R___,          Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_NO, LS_R_L2R,               LS_T1__R__L,    150     },      
00267         {"Bounce TR",   BOTH_B1_TR___,          Q_TR,   Q_TR,   AFLAG_ACTIVE,   100,    BLK_NO, LS_R_BL2TR,             LS_T1_TR_TL,    150     },      
00268         {"Bounce T",    BOTH_B1_T____,          Q_T,    Q_T,    AFLAG_ACTIVE,   100,    BLK_NO, LS_R_BL2TR,             LS_T1_T__BL,    150     },      
00269         {"Bounce TL",   BOTH_B1_TL___,          Q_TL,   Q_TL,   AFLAG_ACTIVE,   100,    BLK_NO, LS_R_BR2TL,             LS_T1_TL_TR,    150     },      
00270         {"Bounce L",    BOTH_B1__L___,          Q_L,    Q_L,    AFLAG_ACTIVE,   100,    BLK_NO, LS_R_R2L,               LS_T1__L__R,    150     },      
00271         {"Bounce BL",   BOTH_B1_BL___,          Q_BL,   Q_BL,   AFLAG_ACTIVE,   100,    BLK_NO, LS_R_TR2BL,             LS_T1_BL_TR,    150     },      
00272 
00273         //Deflected attacks (like bounces, but slide off enemy saber, not straight back)
00274         {"Deflect BR",  BOTH_D1_BR___,          Q_BR,   Q_BR,   AFLAG_ACTIVE,   100,    BLK_NO, LS_R_TL2BR,             LS_T1_BR_TR,    150     },      
00275         {"Deflect R",   BOTH_D1__R___,          Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_NO, LS_R_L2R,               LS_T1__R__L,    150     },      
00276         {"Deflect TR",  BOTH_D1_TR___,          Q_TR,   Q_TR,   AFLAG_ACTIVE,   100,    BLK_NO, LS_R_BL2TR,             LS_T1_TR_TL,    150     },      
00277         {"Deflect T",   BOTH_B1_T____,          Q_T,    Q_T,    AFLAG_ACTIVE,   100,    BLK_NO, LS_R_BL2TR,             LS_T1_T__BL,    150     },      
00278         {"Deflect TL",  BOTH_D1_TL___,          Q_TL,   Q_TL,   AFLAG_ACTIVE,   100,    BLK_NO, LS_R_BR2TL,             LS_T1_TL_TR,    150     },      
00279         {"Deflect L",   BOTH_D1__L___,          Q_L,    Q_L,    AFLAG_ACTIVE,   100,    BLK_NO, LS_R_R2L,               LS_T1__L__R,    150     },      
00280         {"Deflect BL",  BOTH_D1_BL___,          Q_BL,   Q_BL,   AFLAG_ACTIVE,   100,    BLK_NO, LS_R_TR2BL,             LS_T1_BL_TR,    150     },      
00281         {"Deflect B",   BOTH_D1_B____,          Q_B,    Q_B,    AFLAG_ACTIVE,   100,    BLK_NO, LS_R_BL2TR,             LS_T1_T__BL,    150     },      
00282 
00283         //Reflected attacks
00284         {"Reflected BR",BOTH_V1_BR_S1,          Q_BR,   Q_BR,   AFLAG_ACTIVE,   100,    BLK_NO, LS_READY,               LS_READY,       150     },//    LS_V1_BR
00285         {"Reflected R", BOTH_V1__R_S1,          Q_R,    Q_R,    AFLAG_ACTIVE,   100,    BLK_NO, LS_READY,               LS_READY,       150     },//    LS_V1__R
00286         {"Reflected TR",BOTH_V1_TR_S1,          Q_TR,   Q_TR,   AFLAG_ACTIVE,   100,    BLK_NO, LS_READY,               LS_READY,       150     },//    LS_V1_TR
00287         {"Reflected T", BOTH_V1_T__S1,          Q_T,    Q_T,    AFLAG_ACTIVE,   100,    BLK_NO, LS_READY,               LS_READY,       150     },//    LS_V1_T_
00288         {"Reflected TL",BOTH_V1_TL_S1,          Q_TL,   Q_TL,   AFLAG_ACTIVE,   100,    BLK_NO, LS_READY,               LS_READY,       150     },//    LS_V1_TL
00289         {"Reflected L", BOTH_V1__L_S1,          Q_L,    Q_L,    AFLAG_ACTIVE,   100,    BLK_NO, LS_READY,               LS_READY,       150     },//    LS_V1__L
00290         {"Reflected BL",BOTH_V1_BL_S1,          Q_BL,   Q_BL,   AFLAG_ACTIVE,   100,    BLK_NO, LS_READY,               LS_READY,       150     },//    LS_V1_BL
00291         {"Reflected B", BOTH_V1_B__S1,          Q_B,    Q_B,    AFLAG_ACTIVE,   100,    BLK_NO, LS_READY,               LS_READY,       150     },//    LS_V1_B_
00292 
00293         // Broken parries
00294         {"BParry Top",  BOTH_H1_S1_T_,          Q_T,    Q_B,    AFLAG_ACTIVE,   50,             BLK_NO, LS_READY,               LS_READY,               150     },      // LS_PARRY_UP,
00295         {"BParry UR",   BOTH_H1_S1_TR,          Q_TR,   Q_BL,   AFLAG_ACTIVE,   50,             BLK_NO, LS_READY,               LS_READY,               150     },      // LS_PARRY_UR,
00296         {"BParry UL",   BOTH_H1_S1_TL,          Q_TL,   Q_BR,   AFLAG_ACTIVE,   50,             BLK_NO, LS_READY,               LS_READY,               150     },      // LS_PARRY_UL,
00297         {"BParry LR",   BOTH_H1_S1_BL,          Q_BL,   Q_TR,   AFLAG_ACTIVE,   50,             BLK_NO, LS_READY,               LS_READY,               150     },      // LS_PARRY_LR,
00298         {"BParry Bot",  BOTH_H1_S1_B_,          Q_B,    Q_T,    AFLAG_ACTIVE,   50,             BLK_NO, LS_READY,               LS_READY,               150     },      // LS_PARRY_LL
00299         {"BParry LL",   BOTH_H1_S1_BR,          Q_BR,   Q_TL,   AFLAG_ACTIVE,   50,             BLK_NO, LS_READY,               LS_READY,               150     },      // LS_PARRY_LL
00300 
00301         // Knockaways
00302         {"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,
00303         {"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,
00304         {"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,
00305         {"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,
00306         {"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
00307 
00308         // Parry
00309         {"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,
00310         {"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,
00311         {"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,
00312         {"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,
00313         {"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
00314 
00315         // Reflecting a missile
00316         {"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,
00317         {"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,
00318         {"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,
00319         {"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
00320         {"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,
00321 };
00322 
00323 
00324 int transitionMove[Q_NUM_QUADS][Q_NUM_QUADS] = 
00325 {
00326         LS_NONE,        //Can't transition to same pos!
00327         LS_T1_BR__R,//40
00328         LS_T1_BR_TR,
00329         LS_T1_BR_T_,
00330         LS_T1_BR_TL,
00331         LS_T1_BR__L,
00332         LS_T1_BR_BL,
00333         LS_NONE,        //No transitions to bottom, and no anims start there, so shouldn't need any
00334         LS_T1__R_BR,//46
00335         LS_NONE,        //Can't transition to same pos!
00336         LS_T1__R_TR,
00337         LS_T1__R_T_,
00338         LS_T1__R_TL,
00339         LS_T1__R__L,
00340         LS_T1__R_BL,
00341         LS_NONE,        //No transitions to bottom, and no anims start there, so shouldn't need any
00342         LS_T1_TR_BR,//52
00343         LS_T1_TR__R,
00344         LS_NONE,        //Can't transition to same pos!
00345         LS_T1_TR_T_,
00346         LS_T1_TR_TL,
00347         LS_T1_TR__L,
00348         LS_T1_TR_BL,
00349         LS_NONE,        //No transitions to bottom, and no anims start there, so shouldn't need any
00350         LS_T1_T__BR,//58
00351         LS_T1_T___R,
00352         LS_T1_T__TR,
00353         LS_NONE,        //Can't transition to same pos!
00354         LS_T1_T__TL,
00355         LS_T1_T___L,
00356         LS_T1_T__BL,
00357         LS_NONE,        //No transitions to bottom, and no anims start there, so shouldn't need any
00358         LS_T1_TL_BR,//64
00359         LS_T1_TL__R,
00360         LS_T1_TL_TR,
00361         LS_T1_TL_T_,
00362         LS_NONE,        //Can't transition to same pos!
00363         LS_T1_TL__L,
00364         LS_T1_TL_BL,
00365         LS_NONE,        //No transitions to bottom, and no anims start there, so shouldn't need any
00366         LS_T1__L_BR,//70
00367         LS_T1__L__R,
00368         LS_T1__L_TR,
00369         LS_T1__L_T_,
00370         LS_T1__L_TL,
00371         LS_NONE,        //Can't transition to same pos!
00372         LS_T1__L_BL,
00373         LS_NONE,        //No transitions to bottom, and no anims start there, so shouldn't need any
00374         LS_T1_BL_BR,//76
00375         LS_T1_BL__R,
00376         LS_T1_BL_TR,
00377         LS_T1_BL_T_,
00378         LS_T1_BL_TL,
00379         LS_T1_BL__L,
00380         LS_NONE,        //Can't transition to same pos!
00381         LS_NONE,        //No transitions to bottom, and no anims start there, so shouldn't need any
00382         LS_T1_BL_BR,//NOTE: there are no transitions from bottom, so re-use the bottom right transitions
00383         LS_T1_BR__R,
00384         LS_T1_BR_TR,
00385         LS_T1_BR_T_,
00386         LS_T1_BR_TL,
00387         LS_T1_BR__L,
00388         LS_T1_BR_BL,
00389         LS_NONE         //No transitions to bottom, and no anims start there, so shouldn't need any
00390 };
00391 
00392 saberMoveName_t PM_AttackMoveForQuad( int quad )
00393 {
00394         switch ( quad )
00395         {
00396         case Q_B:
00397         case Q_BR:
00398                 return LS_A_BR2TL;
00399                 break;
00400         case Q_R:
00401                 return LS_A_R2L;
00402                 break;
00403         case Q_TR:
00404                 return LS_A_TR2BL;
00405                 break;
00406         case Q_T:
00407                 return LS_A_T2B;
00408                 break;
00409         case Q_TL:
00410                 return LS_A_TL2BR;
00411                 break;
00412         case Q_L:
00413                 return LS_A_L2R;
00414                 break;
00415         case Q_BL:
00416                 return LS_A_BL2TR;
00417                 break;
00418         }
00419         return LS_NONE;
00420 }
00421 
00422 qboolean PM_SaberKataDone(int curmove, int newmove);
00423 
00424 int PM_SaberAnimTransitionAnim( int curmove, int newmove )
00425 {
00426         int retmove = newmove;
00427         if ( curmove == LS_READY )
00428         {//just standing there
00429                 switch ( newmove )
00430                 {
00431                 case LS_A_TL2BR:
00432                 case LS_A_L2R:
00433                 case LS_A_BL2TR:
00434                 case LS_A_BR2TL:
00435                 case LS_A_R2L:
00436                 case LS_A_TR2BL:
00437                 case LS_A_T2B:
00438                         //transition is the start
00439                         retmove = LS_S_TL2BR + (newmove-LS_A_TL2BR);
00440                         break;
00441                 }
00442         }
00443         else
00444         {
00445                 switch ( newmove )
00446                 {
00447                 //transitioning to ready pose
00448                 case LS_READY:
00449                         switch ( curmove )
00450                         {
00451                         //transitioning from an attack
00452                         case LS_A_TL2BR:
00453                         case LS_A_L2R:
00454                         case LS_A_BL2TR:
00455                         case LS_A_BR2TL:
00456                         case LS_A_R2L:
00457                         case LS_A_TR2BL:
00458                         case LS_A_T2B:
00459                                 //transition is the return
00460                                 retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR);
00461                                 break;
00462                         }
00463                         break;
00464                 //transitioning to an attack
00465                 case LS_A_TL2BR:
00466                 case LS_A_L2R:
00467                 case LS_A_BL2TR:
00468                 case LS_A_BR2TL:
00469                 case LS_A_R2L:
00470                 case LS_A_TR2BL:
00471                 case LS_A_T2B:
00472                         if ( newmove == curmove )
00473                         {
00474                                 //going into an attack
00475                                 if ( PM_SaberKataDone( curmove, newmove ) )
00476                                 {//done with this kata, must return to ready before attack again
00477                                         retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR);
00478                                 }
00479                                 else
00480                                 {//okay to chain to another attack
00481                                         retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
00482                                 }
00483                         }
00484                         else if ( saberMoveData[curmove].endQuad == saberMoveData[newmove].startQuad )
00485                         {//new move starts from same quadrant
00486                                 retmove = newmove;
00487                         }
00488                         else
00489                         {
00490                                 switch ( curmove )
00491                                 {
00492                                 //transitioning from an attack
00493                                 case LS_A_TL2BR:
00494                                 case LS_A_L2R:
00495                                 case LS_A_BL2TR:
00496                                 case LS_A_BR2TL:
00497                                 case LS_A_R2L:
00498                                 case LS_A_TR2BL:
00499                                 case LS_A_T2B:
00500                                 case LS_D1_BR:
00501                                 case LS_D1__R:
00502                                 case LS_D1_TR:
00503                                 case LS_D1_T_:
00504                                 case LS_D1_TL:
00505                                 case LS_D1__L:
00506                                 case LS_D1_BL:
00507                                 case LS_D1_B_:
00508                                         retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
00509                                         break;
00510                                 //transitioning from a return
00511                                 case LS_R_TL2BR:
00512                                 case LS_R_L2R:
00513                                 case LS_R_BL2TR:
00514                                 case LS_R_BR2TL:
00515                                 case LS_R_R2L:
00516                                 case LS_R_TR2BL:
00517                                 case LS_R_T2B:
00518                                 //transitioning from a bounce
00519                                 /*
00520                                 case LS_BOUNCE_UL2LL:
00521                                 case LS_BOUNCE_LL2UL:
00522                                 case LS_BOUNCE_L2LL:
00523                                 case LS_BOUNCE_L2UL:
00524                                 case LS_BOUNCE_UR2LR:
00525                                 case LS_BOUNCE_LR2UR:
00526                                 case LS_BOUNCE_R2LR:
00527                                 case LS_BOUNCE_R2UR:
00528                                 case LS_BOUNCE_TOP:
00529                                 case LS_OVER_UR2UL:
00530                                 case LS_OVER_UL2UR:
00531                                 case LS_BOUNCE_UR:
00532                                 case LS_BOUNCE_UL:
00533                                 case LS_BOUNCE_LR:
00534                                 case LS_BOUNCE_LL:
00535                                 */
00536                                 //transitioning from a parry/reflection/knockaway/broken parry
00537                                 case LS_PARRY_UP:
00538                                 case LS_PARRY_UR:
00539                                 case LS_PARRY_UL:
00540                                 case LS_PARRY_LR:
00541                                 case LS_PARRY_LL:
00542                                 case LS_REFLECT_UP:
00543                                 case LS_REFLECT_UR:
00544                                 case LS_REFLECT_UL:
00545                                 case LS_REFLECT_LR:
00546                                 case LS_REFLECT_LL:
00547                                 case LS_K1_T_:
00548                                 case LS_K1_TR:
00549                                 case LS_K1_TL:
00550                                 case LS_K1_BR:
00551                                 case LS_K1_BL:
00552                                 case LS_V1_BR:
00553                                 case LS_V1__R:
00554                                 case LS_V1_TR:
00555                                 case LS_V1_T_:
00556                                 case LS_V1_TL:
00557                                 case LS_V1__L:
00558                                 case LS_V1_BL:
00559                                 case LS_V1_B_:
00560                                 case LS_H1_T_:
00561                                 case LS_H1_TR:
00562                                 case LS_H1_TL:
00563                                 case LS_H1_BR:
00564                                 case LS_H1_BL:
00565                                         retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
00566                                         break;
00567                                 //NB: transitioning from transitions is fine
00568                                 }
00569                         }
00570                         break;
00571                 //transitioning to any other anim is not supported
00572                 }
00573         }
00574 
00575         if ( retmove == LS_NONE )
00576         {
00577                 return newmove;
00578         }
00579 
00580         return retmove;
00581 }
00582 
00583 extern qboolean BG_InKnockDown( int anim );
00584 saberMoveName_t PM_CheckStabDown( void )
00585 {
00586         vec3_t faceFwd, facingAngles;
00587         vec3_t fwd;
00588         bgEntity_t *ent = NULL;
00589         trace_t tr;
00590         //yeah, vm's may complain, but.. who cares!
00591         vec3_t trmins = {-15, -15, -15};
00592         vec3_t trmaxs = {15, 15, 15};
00593 
00594         saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
00595         saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
00596         if ( saber1
00597                 && (saber1->saberFlags&SFL_NO_STABDOWN) )
00598         {
00599                 return LS_NONE;
00600         }
00601         if ( saber2
00602                 && (saber2->saberFlags&SFL_NO_STABDOWN) )
00603         {
00604                 return LS_NONE;
00605         }
00606 
00607         if ( pm->ps->groundEntityNum == ENTITYNUM_NONE )
00608         {//sorry must be on ground!
00609                 return LS_NONE;
00610         }
00611         if ( pm->ps->clientNum < MAX_CLIENTS )
00612         {//player
00613                 pm->ps->velocity[2] = 0;
00614                 pm->cmd.upmove = 0;
00615         }
00616 
00617         VectorSet(facingAngles, 0, pm->ps->viewangles[YAW], 0);
00618         AngleVectors( facingAngles, faceFwd, NULL, NULL );
00619 
00620         //FIXME: need to only move forward until we bump into our target...?
00621         VectorMA(pm->ps->origin, 164.0f, faceFwd, fwd);
00622 
00623         pm->trace(&tr, pm->ps->origin, trmins, trmaxs, fwd, pm->ps->clientNum, MASK_PLAYERSOLID);
00624 
00625         if (tr.entityNum < ENTITYNUM_WORLD)
00626         {
00627                 ent = PM_BGEntForNum(tr.entityNum);
00628         }
00629 
00630         if ( ent &&
00631                 (ent->s.eType == ET_PLAYER || ent->s.eType == ET_NPC) &&
00632                 BG_InKnockDown( ent->s.legsAnim ) )
00633         {//guy is on the ground below me, do a top-down attack
00634                 if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
00635                 {
00636                         return LS_STABDOWN_DUAL;
00637                 }
00638                 else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
00639                 {
00640                         return LS_STABDOWN_STAFF;
00641                 }
00642                 else
00643                 {
00644                         return LS_STABDOWN;
00645                 }
00646         }
00647         return LS_NONE;
00648 }
00649 
00650 int PM_SaberMoveQuadrantForMovement( usercmd_t *ucmd )
00651 {
00652         if ( ucmd->rightmove > 0 )
00653         {//moving right
00654                 if ( ucmd->forwardmove > 0 )
00655                 {//forward right = TL2BR slash
00656                         return Q_TL;
00657                 }
00658                 else if ( ucmd->forwardmove < 0 )
00659                 {//backward right = BL2TR uppercut
00660                         return Q_BL;
00661                 }
00662                 else
00663                 {//just right is a left slice
00664                         return Q_L;
00665                 }
00666         }
00667         else if ( ucmd->rightmove < 0 )
00668         {//moving left
00669                 if ( ucmd->forwardmove > 0 )
00670                 {//forward left = TR2BL slash
00671                         return Q_TR;
00672                 }
00673                 else if ( ucmd->forwardmove < 0 )
00674                 {//backward left = BR2TL uppercut
00675                         return Q_BR;
00676                 }
00677                 else
00678                 {//just left is a right slice
00679                         return Q_R;
00680                 }
00681         }
00682         else
00683         {//not moving left or right
00684                 if ( ucmd->forwardmove > 0 )
00685                 {//forward= T2B slash
00686                         return Q_T;
00687                 }
00688                 else if ( ucmd->forwardmove < 0 )
00689                 {//backward= T2B slash  //or B2T uppercut?
00690                         return Q_T;
00691                 }
00692                 else
00693                 {//Not moving at all
00694                         return Q_R;
00695                 }
00696         }
00697 }
00698 
00699 //===================================================================
00700 qboolean PM_SaberInBounce( int move )
00701 {
00702         if ( move >= LS_B1_BR && move <= LS_B1_BL )
00703         {
00704                 return qtrue;
00705         }
00706         if ( move >= LS_D1_BR && move <= LS_D1_BL )
00707         {
00708                 return qtrue;
00709         }
00710         return qfalse;
00711 }
00712 
00713 qboolean PM_SaberInTransition( int move );
00714 
00715 int saberMoveTransitionAngle[Q_NUM_QUADS][Q_NUM_QUADS] = 
00716 {
00717         0,//Q_BR,Q_BR,
00718         45,//Q_BR,Q_R,
00719         90,//Q_BR,Q_TR,
00720         135,//Q_BR,Q_T,
00721         180,//Q_BR,Q_TL,
00722         215,//Q_BR,Q_L,
00723         270,//Q_BR,Q_BL,
00724         45,//Q_BR,Q_B,
00725         45,//Q_R,Q_BR,
00726         0,//Q_R,Q_R,
00727         45,//Q_R,Q_TR,
00728         90,//Q_R,Q_T,
00729         135,//Q_R,Q_TL,
00730         180,//Q_R,Q_L,
00731         215,//Q_R,Q_BL,
00732         90,//Q_R,Q_B,
00733         90,//Q_TR,Q_BR,
00734         45,//Q_TR,Q_R,
00735         0,//Q_TR,Q_TR,
00736         45,//Q_TR,Q_T,
00737         90,//Q_TR,Q_TL,
00738         135,//Q_TR,Q_L,
00739         180,//Q_TR,Q_BL,
00740         135,//Q_TR,Q_B,
00741         135,//Q_T,Q_BR,
00742         90,//Q_T,Q_R,
00743         45,//Q_T,Q_TR,
00744         0,//Q_T,Q_T,
00745         45,//Q_T,Q_TL,
00746         90,//Q_T,Q_L,
00747         135,//Q_T,Q_BL,
00748         180,//Q_T,Q_B,
00749         180,//Q_TL,Q_BR,
00750         135,//Q_TL,Q_R,
00751         90,//Q_TL,Q_TR,
00752         45,//Q_TL,Q_T,
00753         0,//Q_TL,Q_TL,
00754         45,//Q_TL,Q_L,
00755         90,//Q_TL,Q_BL,
00756         135,//Q_TL,Q_B,
00757         215,//Q_L,Q_BR,
00758         180,//Q_L,Q_R,
00759         135,//Q_L,Q_TR,
00760         90,//Q_L,Q_T,
00761         45,//Q_L,Q_TL,
00762         0,//Q_L,Q_L,
00763         45,//Q_L,Q_BL,
00764         90,//Q_L,Q_B,
00765         270,//Q_BL,Q_BR,
00766         215,//Q_BL,Q_R,
00767         180,//Q_BL,Q_TR,
00768         135,//Q_BL,Q_T,
00769         90,//Q_BL,Q_TL,
00770         45,//Q_BL,Q_L,
00771         0,//Q_BL,Q_BL,
00772         45,//Q_BL,Q_B,
00773         45,//Q_B,Q_BR,
00774         90,//Q_B,Q_R,
00775         135,//Q_B,Q_TR,
00776         180,//Q_B,Q_T,
00777         135,//Q_B,Q_TL,
00778         90,//Q_B,Q_L,
00779         45,//Q_B,Q_BL,
00780         0//Q_B,Q_B,
00781 };
00782 
00783 int PM_SaberAttackChainAngle( int move1, int move2 )
00784 {
00785         if ( move1 == -1 || move2 == -1 )
00786         {
00787                 return -1;
00788         }
00789         return saberMoveTransitionAngle[saberMoveData[move1].endQuad][saberMoveData[move2].startQuad];
00790 }
00791 
00792 qboolean PM_SaberKataDone(int curmove, int newmove)
00793 {
00794         if (pm->ps->m_iVehicleNum)
00795         { //never continue kata on vehicle
00796                 if (pm->ps->saberAttackChainCount > 0)
00797                 {
00798                         return qtrue;
00799                 }
00800         }
00801 
00802         if ( pm->ps->fd.saberAnimLevel == SS_DESANN || pm->ps->fd.saberAnimLevel == SS_TAVION )
00803         {//desann and tavion can link up as many attacks as they want
00804                 return qfalse;
00805         }
00806 
00807         if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
00808         {
00809                 //TEMP: for now, let staff attacks infinitely chain
00810                 return qfalse;
00811         }
00812         else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
00813         {
00814                 //TEMP: for now, let staff attacks infinitely chain
00815                 return qfalse;
00816         }
00817         else if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_3 )
00818         {
00819                 if ( curmove == LS_NONE || newmove == LS_NONE )
00820                 {
00821                         if ( pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_3 && pm->ps->saberAttackChainCount > PM_irand_timesync( 0, 1 ) )
00822                         {
00823                                 return qtrue;
00824                         }
00825                 }
00826                 else if ( pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 3 ) )
00827                 {
00828                         return qtrue;
00829                 }
00830                 else if ( pm->ps->saberAttackChainCount > 0 )
00831                 {
00832                         int chainAngle = PM_SaberAttackChainAngle( curmove, newmove );
00833                         if ( chainAngle < 135 || chainAngle > 215 )
00834                         {//if trying to chain to a move that doesn't continue the momentum
00835                                 return qtrue;
00836                         }
00837                         else if ( chainAngle == 180 )
00838                         {//continues the momentum perfectly, allow it to chain 66% of the time
00839                                 if ( pm->ps->saberAttackChainCount > 1 )
00840                                 {
00841                                         return qtrue;
00842                                 }
00843                         }
00844                         else
00845                         {//would continue the movement somewhat, 50% chance of continuing
00846                                 if ( pm->ps->saberAttackChainCount > 2 )
00847                                 {
00848                                         return qtrue;
00849                                 }
00850                         }
00851                 }
00852         }
00853         else 
00854         {//Perhaps have chainAngle influence fast and medium chains as well? For now, just do level 3.
00855                 if (newmove == LS_A_TL2BR ||
00856                         newmove == LS_A_L2R ||
00857                         newmove == LS_A_BL2TR ||
00858                         newmove == LS_A_BR2TL ||
00859                         newmove == LS_A_R2L ||
00860                         newmove == LS_A_TR2BL )
00861                 { //lower chaining tolerance for spinning saber anims
00862                         int chainTolerance;
00863 
00864                         if (pm->ps->fd.saberAnimLevel == FORCE_LEVEL_1)
00865                         {
00866                                 chainTolerance = 5;
00867                         }
00868                         else
00869                         {
00870                                 chainTolerance = 3;
00871                         }
00872 
00873                         if (pm->ps->saberAttackChainCount >= chainTolerance && PM_irand_timesync(1, pm->ps->saberAttackChainCount) > chainTolerance)
00874                         {
00875                                 return qtrue;
00876                         }
00877                 }
00878                 if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_2 && pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 5 ) )
00879                 {
00880                         return qtrue;
00881                 }
00882         }
00883         return qfalse;
00884 }
00885 
00886 void PM_SetAnimFrame( playerState_t *gent, int frame, qboolean torso, qboolean legs )
00887 {
00888         gent->saberLockFrame = frame;
00889 }
00890 
00891 int PM_SaberLockWinAnim( qboolean victory, qboolean superBreak )
00892 {
00893         int winAnim = -1;
00894         switch ( pm->ps->torsoAnim )
00895         {
00896 /*
00897         default:
00898 #ifndef FINAL_BUILD
00899                 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 );
00900 #endif
00901 */
00902         case BOTH_BF2LOCK:
00903                 if ( superBreak )
00904                 {
00905                         winAnim = BOTH_LK_S_S_T_SB_1_W;
00906                 }
00907                 else if ( !victory )
00908                 {
00909                         winAnim = BOTH_BF1BREAK;
00910                 }
00911                 else
00912                 {
00913                         pm->ps->saberMove = LS_A_T2B;
00914                         winAnim = BOTH_A3_T__B_;
00915                 }
00916                 break;
00917         case BOTH_BF1LOCK:
00918                 if ( superBreak )
00919                 {
00920                         winAnim = BOTH_LK_S_S_T_SB_1_W;
00921                 }
00922                 else if ( !victory )
00923                 {
00924                         winAnim = BOTH_KNOCKDOWN4;
00925                 }
00926                 else
00927                 {
00928                         pm->ps->saberMove = LS_K1_T_;
00929                         winAnim = BOTH_K1_S1_T_;
00930                 }
00931                 break;
00932         case BOTH_CWCIRCLELOCK:
00933                 if ( superBreak )
00934                 {
00935                         winAnim = BOTH_LK_S_S_S_SB_1_W;
00936                 }
00937                 else if ( !victory )
00938                 {
00939                         pm->ps->saberMove = LS_V1_BL;//pm->ps->saberBounceMove = 
00940                         pm->ps->saberBlocked = BLOCKED_PARRY_BROKEN;
00941                         winAnim = BOTH_V1_BL_S1;
00942                 }
00943                 else
00944                 {
00945                         winAnim = BOTH_CWCIRCLEBREAK;
00946                 }
00947                 break;
00948         case BOTH_CCWCIRCLELOCK:
00949                 if ( superBreak )
00950                 {
00951                         winAnim = BOTH_LK_S_S_S_SB_1_W;
00952                 }
00953                 else if ( !victory )
00954                 {
00955                         pm->ps->saberMove = LS_V1_BR;//pm->ps->saberBounceMove = 
00956                         pm->ps->saberBlocked = BLOCKED_PARRY_BROKEN;
00957                         winAnim = BOTH_V1_BR_S1;
00958                 }
00959                 else
00960                 {
00961                         winAnim = BOTH_CCWCIRCLEBREAK;
00962                 }
00963                 break;
00964         default:
00965                 //must be using new system:
00966                 break;
00967         }
00968         if ( winAnim != -1 )
00969         {
00970                 PM_SetAnim( SETANIM_BOTH, winAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 );
00971                 pm->ps->weaponTime = pm->ps->torsoTimer;
00972                 pm->ps->saberBlocked = BLOCKED_NONE;
00973                 pm->ps->weaponstate = WEAPON_FIRING;
00974                 /*
00975                 if ( superBreak 
00976                         && winAnim != BOTH_LK_ST_DL_T_SB_1_W )
00977                 {//going to attack with saber, do a saber trail
00978                         pm->ps->SaberActivateTrail( 200 );
00979                 }
00980                 */
00981         }
00982         return winAnim;
00983 }
00984 
00985 // Need to avoid nesting namespaces!
00986 #include "../namespace_end.h"
00987 #ifdef QAGAME //including game headers on cgame is FORBIDDEN ^_^
00988 
00989 #include "g_local.h"
00990 extern void NPC_SetAnim(gentity_t *ent, int setAnimParts, int anim, int setAnimFlags);
00991 extern gentity_t g_entities[];
00992 
00993 #elif defined CGAME
00994 
00995 #include "..\cgame\cg_local.h" //ahahahahhahahaha@$!$!
00996 
00997 #endif
00998 #include "../namespace_begin.h"
00999 
01000 int PM_SaberLockLoseAnim( playerState_t *genemy, qboolean victory, qboolean superBreak )
01001 { 
01002         int loseAnim = -1;
01003         switch ( genemy->torsoAnim )
01004         {
01005 /*
01006         default:
01007 #ifndef FINAL_BUILD
01008                 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 );
01009 #endif
01010 */
01011         case BOTH_BF2LOCK:
01012                 if ( superBreak )
01013                 {
01014                         loseAnim = BOTH_LK_S_S_T_SB_1_L;
01015                 }
01016                 else if ( !victory )
01017                 {
01018                         loseAnim = BOTH_BF1BREAK;
01019                 }
01020                 else
01021                 {
01022                         if ( !victory )
01023                         {//no-one won
01024                                 genemy->saberMove = LS_K1_T_;
01025                                 loseAnim = BOTH_K1_S1_T_;
01026                         }
01027                         else
01028                         {//FIXME: this anim needs to transition back to ready when done
01029                                 loseAnim = BOTH_BF1BREAK;
01030                         }
01031                 }
01032                 break;
01033         case BOTH_BF1LOCK:
01034                 if ( superBreak )
01035                 {
01036                         loseAnim = BOTH_LK_S_S_T_SB_1_L;
01037                 }
01038                 else if ( !victory )
01039                 {
01040                         loseAnim = BOTH_KNOCKDOWN4;
01041                 }
01042                 else
01043                 {
01044                         if ( !victory )
01045                         {//no-one won
01046                                 genemy->saberMove = LS_A_T2B;
01047                                 loseAnim = BOTH_A3_T__B_;
01048                         }
01049                         else
01050                         {
01051                                 loseAnim = BOTH_KNOCKDOWN4;
01052                         }
01053                 }
01054                 break;
01055         case BOTH_CWCIRCLELOCK:
01056                 if ( superBreak )
01057                 {
01058                         loseAnim = BOTH_LK_S_S_S_SB_1_L;
01059                 }
01060                 else if ( !victory )
01061                 {
01062                         genemy->saberMove = LS_V1_BL;//genemy->saberBounceMove = 
01063                         genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
01064                         loseAnim = BOTH_V1_BL_S1;
01065                 }
01066                 else
01067                 {
01068                         if ( !victory )
01069                         {//no-one won
01070                                 loseAnim = BOTH_CCWCIRCLEBREAK;
01071                         }
01072                         else
01073                         {
01074                                 genemy->saberMove = LS_V1_BL;//genemy->saberBounceMove = 
01075                                 genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
01076                                 loseAnim = BOTH_V1_BL_S1;
01077                                 /*
01078                                 genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_H1_BR;
01079                                 genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN;
01080                                 loseAnim = BOTH_H1_S1_BL;
01081                                 */
01082                         }
01083                 }
01084                 break;
01085         case BOTH_CCWCIRCLELOCK:
01086                 if ( superBreak )
01087                 {
01088                         loseAnim = BOTH_LK_S_S_S_SB_1_L;
01089                 }
01090                 else if ( !victory )
01091                 {
01092                         genemy->saberMove = LS_V1_BR;//genemy->saberBounceMove = 
01093                         genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
01094                         loseAnim = BOTH_V1_BR_S1;
01095                 }
01096                 else
01097                 {
01098                         if ( !victory )
01099                         {//no-one won
01100                                 loseAnim = BOTH_CWCIRCLEBREAK;
01101                         }
01102                         else
01103                         {
01104                                 genemy->saberMove = LS_V1_BR;//genemy->saberBounceMove = 
01105                                 genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
01106                                 loseAnim = BOTH_V1_BR_S1;
01107                                 /*
01108                                 genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_H1_BL;
01109                                 genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN;
01110                                 loseAnim = BOTH_H1_S1_BR;
01111                                 */
01112                         }
01113                 }
01114                 break;
01115         }
01116         if ( loseAnim != -1 )
01117         {
01118 #ifdef QAGAME
01119                 NPC_SetAnim( &g_entities[genemy->clientNum], SETANIM_BOTH, loseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
01120                 genemy->weaponTime = genemy->torsoTimer;// + 250;
01121 #endif
01122                 genemy->saberBlocked = BLOCKED_NONE;
01123                 genemy->weaponstate = WEAPON_READY;
01124         }
01125         return loseAnim;
01126 }
01127 
01128 int PM_SaberLockResultAnim( playerState_t *duelist, qboolean superBreak, qboolean won )
01129 {
01130         int baseAnim = duelist->torsoAnim;
01131         switch ( baseAnim )
01132         {
01133         case BOTH_LK_S_S_S_L_2:         //lock if I'm using single vs. a single and other intitiated
01134                 baseAnim = BOTH_LK_S_S_S_L_1;
01135                 break;
01136         case BOTH_LK_S_S_T_L_2:         //lock if I'm using single vs. a single and other initiated
01137                 baseAnim = BOTH_LK_S_S_T_L_1;
01138                 break;
01139         case BOTH_LK_DL_DL_S_L_2:       //lock if I'm using dual vs. dual and other initiated
01140                 baseAnim = BOTH_LK_DL_DL_S_L_1;
01141                 break;
01142         case BOTH_LK_DL_DL_T_L_2:       //lock if I'm using dual vs. dual and other initiated
01143                 baseAnim = BOTH_LK_DL_DL_T_L_1;
01144                 break;
01145         case BOTH_LK_ST_ST_S_L_2:       //lock if I'm using staff vs. a staff and other initiated
01146                 baseAnim = BOTH_LK_ST_ST_S_L_1;
01147                 break;
01148         case BOTH_LK_ST_ST_T_L_2:       //lock if I'm using staff vs. a staff and other initiated
01149                 baseAnim = BOTH_LK_ST_ST_T_L_1;
01150                 break;
01151         }
01152         //what kind of break?
01153         if ( !superBreak )
01154         { 
01155                 baseAnim -= 2;
01156         }
01157         else if ( superBreak )
01158         {
01159                 baseAnim += 1;
01160         }
01161         else
01162         {//WTF?  Not a valid result
01163                 return -1;
01164         }
01165         //win or lose?
01166         if ( won )
01167         {
01168                 baseAnim += 1;
01169         }
01170 
01171         //play the anim and hold it
01172 #ifdef QAGAME
01173         //server-side: set it on the other guy, too
01174         if ( duelist->clientNum == pm->ps->clientNum )
01175         {//me
01176                 PM_SetAnim( SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 );
01177         }
01178         else
01179         {//other guy
01180                 NPC_SetAnim( &g_entities[duelist->clientNum], SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
01181         }
01182 #else
01183         PM_SetAnim( SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 0 );
01184 #endif
01185 
01186         if ( superBreak
01187                 && !won )
01188         {//if you lose a superbreak, you're defenseless
01189                 /*
01190                 //Taken care of in SetSaberBoxSize()
01191                 //make saberent not block
01192                 gentity_t *saberent = &g_entities[duelist->client->ps.saberEntityNum];
01193                 if ( saberent )
01194                 {
01195                         VectorClear(saberent->mins);
01196                         VectorClear(saberent->maxs);
01197                         G_SetOrigin(saberent, duelist->currentOrigin);
01198                 }
01199                 */
01200 #ifdef QAGAME
01201                 if ( 1 )
01202 #else
01203                 if ( duelist->clientNum == pm->ps->clientNum )
01204 #endif
01205                 {
01206                         //set sabermove to none
01207                         duelist->saberMove = LS_NONE;
01208                         //Hold the anim a little longer than it is
01209                         duelist->torsoTimer += 250;
01210                 }
01211         }
01212 
01213 #ifdef QAGAME
01214         if ( 1 )
01215 #else
01216         if ( duelist->clientNum == pm->ps->clientNum )
01217 #endif
01218         {
01219                 //no attacking during this anim
01220                 duelist->weaponTime = duelist->torsoTimer;
01221                 duelist->saberBlocked = BLOCKED_NONE;
01222                 /*
01223                 if ( superBreak
01224                         && won
01225                         && baseAnim != BOTH_LK_ST_DL_T_SB_1_W )
01226                 {//going to attack with saber, do a saber trail
01227                         duelist->client->ps.SaberActivateTrail( 200 );
01228                 }
01229                 */
01230         }
01231         return baseAnim;
01232 }
01233 
01234 void PM_SaberLockBreak( playerState_t *genemy, qboolean victory, int strength )
01235 {
01236         int     winAnim = BOTH_STAND1, loseAnim = BOTH_STAND1;
01237         //qboolean punishLoser = qfalse;
01238         qboolean noKnockdown = qfalse;
01239         qboolean singleVsSingle = qtrue;
01240         qboolean superBreak = (strength+pm->ps->saberLockHits > Q_irand(2,4));
01241 
01242         winAnim = PM_SaberLockWinAnim( victory, superBreak );
01243         if ( winAnim != -1 )
01244         {//a single vs. single break
01245                 loseAnim = PM_SaberLockLoseAnim( genemy, victory, superBreak );
01246         }
01247         else
01248         {//must be a saberlock that's not between single and single...
01249                 singleVsSingle = qfalse;
01250                 winAnim = PM_SaberLockResultAnim( pm->ps, superBreak, qtrue );
01251                 pm->ps->weaponstate = WEAPON_FIRING;
01252                 loseAnim = PM_SaberLockResultAnim( genemy, superBreak, qfalse );
01253                 genemy->weaponstate = WEAPON_READY;
01254         }
01255 
01256         if ( victory )
01257         { //someone lost the lock, so punish them by knocking them down
01258                 if ( pm->ps->saberLockHits && !superBreak )
01259                 {//there was some over-power in the win, but not enough to superbreak
01260                         vec3_t oppDir;
01261 
01262                         int strength = 8;
01263 
01264                         VectorSubtract(genemy->origin, pm->ps->origin, oppDir);
01265                         VectorNormalize(oppDir);
01266 
01267                         if (noKnockdown)
01268                         {
01269                                 if (!genemy->saberEntityNum)
01270                                 { //if he has already lost his saber then just knock him down
01271                                         noKnockdown = qfalse;
01272                                 }
01273                         }
01274 
01275                         if (!noKnockdown && BG_KnockDownable(genemy))
01276                         {
01277                                 genemy->forceHandExtend = HANDEXTEND_KNOCKDOWN;
01278                                 genemy->forceHandExtendTime = pm->cmd.serverTime + 1100;
01279                                 genemy->forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
01280 
01281                                 genemy->otherKiller = pm->ps->clientNum;
01282                                 genemy->otherKillerTime = pm->cmd.serverTime + 5000;
01283                                 genemy->otherKillerDebounceTime = pm->cmd.serverTime + 100;
01284 
01285                                 genemy->velocity[0] = oppDir[0]*(strength*40);
01286                                 genemy->velocity[1] = oppDir[1]*(strength*40);
01287                                 genemy->velocity[2] = 100;
01288                         }
01289 
01290                         pm->checkDuelLoss = genemy->clientNum+1;
01291 
01292                         pm->ps->saberEventFlags |= SEF_LOCK_WON;
01293                 }
01294         }
01295         else
01296         { //If no one lost, then shove each player away from the other
01297                 vec3_t oppDir;
01298 
01299                 int strength = 4;
01300 
01301                 VectorSubtract(genemy->origin, pm->ps->origin, oppDir);
01302                 VectorNormalize(oppDir);
01303                 genemy->velocity[0] = oppDir[0]*(strength*40);
01304                 genemy->velocity[1] = oppDir[1]*(strength*40);
01305                 genemy->velocity[2] = 150;
01306 
01307                 VectorSubtract(pm->ps->origin, genemy->origin, oppDir);
01308                 VectorNormalize(oppDir);
01309                 pm->ps->velocity[0] = oppDir[0]*(strength*40);
01310                 pm->ps->velocity[1] = oppDir[1]*(strength*40);
01311                 pm->ps->velocity[2] = 150;
01312 
01313                 genemy->forceHandExtend = HANDEXTEND_WEAPONREADY;
01314         }
01315 
01316         pm->ps->weaponTime = 0;
01317         genemy->weaponTime = 0;
01318 
01319         pm->ps->saberLockTime = genemy->saberLockTime = 0;
01320         pm->ps->saberLockFrame = genemy->saberLockFrame = 0;
01321         pm->ps->saberLockEnemy = genemy->saberLockEnemy = 0;
01322 
01323         pm->ps->forceHandExtend = HANDEXTEND_WEAPONREADY;
01324 
01325         PM_AddEvent( EV_JUMP );
01326         if ( !victory )
01327         {//no-one won
01328                 BG_AddPredictableEventToPlayerstate(EV_JUMP, 0, genemy);
01329         }
01330         else
01331         {
01332                 if ( PM_irand_timesync( 0, 1 ) )
01333                 {
01334                         BG_AddPredictableEventToPlayerstate(EV_JUMP, PM_irand_timesync( 0, 75 ), genemy);
01335                 }
01336         }
01337 }
01338 
01339 qboolean BG_CheckIncrementLockAnim( int anim, int winOrLose )
01340 {
01341         qboolean increment = qfalse;//???
01342         //RULE: if you are the first style in the lock anim, you advance from LOSING position to WINNING position
01343         //              if you are the second style in the lock anim, you advance from WINNING position to LOSING position
01344         switch ( anim )
01345         {
01346         //increment to win:
01347         case BOTH_LK_DL_DL_S_L_1:       //lock if I'm using dual vs. dual and I initiated
01348         case BOTH_LK_DL_DL_S_L_2:       //lock if I'm using dual vs. dual and other initiated
01349         case BOTH_LK_DL_DL_T_L_1:       //lock if I'm using dual vs. dual and I initiated
01350         case BOTH_LK_DL_DL_T_L_2:       //lock if I'm using dual vs. dual and other initiated
01351         case BOTH_LK_DL_S_S_L_1:                //lock if I'm using dual vs. a single
01352         case BOTH_LK_DL_S_T_L_1:                //lock if I'm using dual vs. a single
01353         case BOTH_LK_DL_ST_S_L_1:       //lock if I'm using dual vs. a staff
01354         case BOTH_LK_DL_ST_T_L_1:       //lock if I'm using dual vs. a staff
01355         case BOTH_LK_S_S_S_L_1:         //lock if I'm using single vs. a single and I initiated
01356         case BOTH_LK_S_S_T_L_2:         //lock if I'm using single vs. a single and other initiated
01357         case BOTH_LK_ST_S_S_L_1:                //lock if I'm using staff vs. a single
01358         case BOTH_LK_ST_S_T_L_1:                //lock if I'm using staff vs. a single
01359         case BOTH_LK_ST_ST_T_L_1:       //lock if I'm using staff vs. a staff and I initiated
01360         case BOTH_LK_ST_ST_T_L_2:       //lock if I'm using staff vs. a staff and other initiated
01361                 if ( winOrLose == SABERLOCK_WIN )
01362                 {
01363                         increment = qtrue;
01364                 }
01365                 else
01366                 {
01367                         increment = qfalse;
01368                 }
01369                 break;
01370 
01371         //decrement to win:
01372         case BOTH_LK_S_DL_S_L_1:                //lock if I'm using single vs. a dual
01373         case BOTH_LK_S_DL_T_L_1:                //lock if I'm using single vs. a dual
01374         case BOTH_LK_S_S_S_L_2:         //lock if I'm using single vs. a single and other intitiated
01375         case BOTH_LK_S_S_T_L_1:         //lock if I'm using single vs. a single and I initiated
01376         case BOTH_LK_S_ST_S_L_1:                //lock if I'm using single vs. a staff
01377         case BOTH_LK_S_ST_T_L_1:                //lock if I'm using single vs. a staff
01378         case BOTH_LK_ST_DL_S_L_1:       //lock if I'm using staff vs. dual
01379         case BOTH_LK_ST_DL_T_L_1:       //lock if I'm using staff vs. dual
01380         case BOTH_LK_ST_ST_S_L_1:       //lock if I'm using staff vs. a staff and I initiated
01381         case BOTH_LK_ST_ST_S_L_2:       //lock if I'm using staff vs. a staff and other initiated
01382                 if ( winOrLose == SABERLOCK_WIN )
01383                 {
01384                         increment = qfalse;
01385                 }
01386                 else
01387                 {
01388                         increment = qtrue;
01389                 }
01390                 break;
01391         default:
01392                 break;
01393         }
01394         return increment;
01395 }
01396 
01397 extern qboolean ValidAnimFileIndex ( int index );
01398 void PM_SaberLocked( void )
01399 {
01400         int     remaining = 0;
01401         playerState_t *genemy;
01402         bgEntity_t *eGenemy = PM_BGEntForNum(pm->ps->saberLockEnemy);
01403 
01404         if (!eGenemy)
01405         {
01406                 return;
01407         }
01408 
01409         genemy = eGenemy->playerState;
01410 
01411         if ( !genemy )
01412         {
01413                 return;
01414         }
01415         /*if ( ( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
01416                         (pm->ps->torsoAnim) == BOTH_BF1LOCK ||
01417                         (pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
01418                         (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK )
01419                 && ( (genemy->torsoAnim) == BOTH_BF2LOCK ||
01420                         (genemy->torsoAnim) == BOTH_BF1LOCK ||
01421                         (genemy->torsoAnim) == BOTH_CWCIRCLELOCK ||
01422                         (genemy->torsoAnim) == BOTH_CCWCIRCLELOCK )
01423                 )
01424                 */ //yeah..
01425         if (pm->ps->saberLockFrame &&
01426                 genemy->saberLockFrame &&
01427                 BG_InSaberLock(pm->ps->torsoAnim) &&
01428                 BG_InSaberLock(genemy->torsoAnim))
01429         {
01430                 float dist = 0;
01431 
01432                 pm->ps->torsoTimer = 0;
01433                 pm->ps->weaponTime = 0;
01434                 genemy->torsoTimer = 0;
01435                 genemy->weaponTime = 0;
01436 
01437                 dist = DistanceSquared(pm->ps->origin,genemy->origin);
01438                 if ( dist < 64 || dist > 6400 )
01439                 {//between 8 and 80 from each other
01440                         PM_SaberLockBreak( genemy, qfalse, 0 );
01441                         return;
01442                 }
01443                 /*
01444                 //NOTE: time-out is handled around where PM_SaberLocked is called
01445                 if ( pm->ps->saberLockTime <= pm->cmd.serverTime + 500 )
01446                 {//lock just ended
01447                         PM_SaberLockBreak( genemy, qfalse, 0 );
01448                         return;
01449                 }
01450                 */
01451                 if ( pm->ps->saberLockAdvance )
01452                 {//holding attack
01453                         animation_t *anim;
01454                         float           currentFrame;
01455                         int                     curFrame;
01456                         int                     strength = 1;
01457 
01458                         pm->ps->saberLockAdvance = qfalse;
01459 
01460                         anim = &pm->animations[pm->ps->torsoAnim];
01461 
01462                         currentFrame = pm->ps->saberLockFrame;
01463 
01464                         strength = pm->ps->fd.forcePowerLevel[FP_SABER_OFFENSE]+1;
01465 
01466                         //advance/decrement my frame number
01467                         if ( BG_InSaberLockOld( pm->ps->torsoAnim ) )
01468                         { //old locks
01469                                 if ( (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||
01470                                         (pm->ps->torsoAnim) == BOTH_BF2LOCK )
01471                                 {
01472                                         curFrame = floor( currentFrame )-strength;
01473                                         //drop my frame one
01474                                         if ( curFrame <= anim->firstFrame )
01475                                         {//I won!  Break out
01476                                                 PM_SaberLockBreak( genemy, qtrue, strength );
01477                                                 return;
01478                                         }
01479                                         else
01480                                         {
01481                                                 PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
01482                                                 remaining = curFrame-anim->firstFrame;
01483                                         }
01484                                 }
01485                                 else
01486                                 {
01487                                         curFrame = ceil( currentFrame )+strength;
01488                                         //advance my frame one
01489                                         if ( curFrame >= anim->firstFrame+anim->numFrames )
01490                                         {//I won!  Break out
01491                                                 PM_SaberLockBreak( genemy, qtrue, strength );
01492                                                 return;
01493                                         }
01494                                         else
01495                                         {
01496                                                 PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
01497                                                 remaining = anim->firstFrame+anim->numFrames-curFrame;
01498                                         }
01499                                 }
01500                         }
01501                         else
01502                         { //new locks
01503                                 if ( BG_CheckIncrementLockAnim( pm->ps->torsoAnim, SABERLOCK_WIN ) )
01504                                 {
01505                                         curFrame = ceil( currentFrame )+strength;
01506                                         //advance my frame one
01507                                         if ( curFrame >= anim->firstFrame+anim->numFrames )
01508                                         {//I won!  Break out
01509                                                 PM_SaberLockBreak( genemy, qtrue, strength );
01510                                                 return;
01511                                         }
01512                                         else
01513                                         {
01514                                                 PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
01515                                                 remaining = anim->firstFrame+anim->numFrames-curFrame;
01516                                         }
01517                                 }
01518                                 else
01519                                 {
01520                                         curFrame = floor( currentFrame )-strength;
01521                                         //drop my frame one
01522                                         if ( curFrame <= anim->firstFrame )
01523                                         {//I won!  Break out
01524                                                 PM_SaberLockBreak( genemy, qtrue, strength );
01525                                                 return;
01526                                         }
01527                                         else
01528                                         {
01529                                                 PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
01530                                                 remaining = curFrame-anim->firstFrame;
01531                                         }
01532                                 }
01533                         }
01534                         if ( !PM_irand_timesync( 0, 2 ) )
01535                         {
01536                                 PM_AddEvent( EV_JUMP );
01537                         }
01538                         //advance/decrement enemy frame number
01539                         anim = &pm->animations[(genemy->torsoAnim)];
01540 
01541                         if ( BG_InSaberLockOld( genemy->torsoAnim ) )
01542                         {
01543                                 if ( (genemy->torsoAnim) == BOTH_CWCIRCLELOCK ||
01544                                         (genemy->torsoAnim) == BOTH_BF1LOCK )
01545                                 {
01546                                         if ( !PM_irand_timesync( 0, 2 ) )
01547                                         {
01548                                                 BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy);
01549                                         }
01550                                         PM_SetAnimFrame( genemy, anim->firstFrame+remaining, qtrue, qtrue );
01551                                 }
01552                                 else
01553                                 {
01554                                         PM_SetAnimFrame( genemy, anim->firstFrame+anim->numFrames-remaining, qtrue, qtrue );
01555                                 }
01556                         }
01557                         else
01558                         {//new locks
01559                                 if ( BG_CheckIncrementLockAnim( genemy->torsoAnim, SABERLOCK_LOSE ) )
01560                                 {
01561                                         if ( !PM_irand_timesync( 0, 2 ) )
01562                                         {
01563                                                 BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy);
01564                                         }
01565                                         PM_SetAnimFrame( genemy, anim->firstFrame+anim->numFrames-remaining, qtrue, qtrue );
01566                                 }
01567                                 else
01568                                 {
01569                                         PM_SetAnimFrame( genemy, anim->firstFrame+remaining, qtrue, qtrue );
01570                                 }
01571                         }
01572                 }
01573         }
01574         else
01575         {//something broke us out of it
01576                 PM_SaberLockBreak( genemy, qfalse, 0 );
01577         }
01578 }
01579 
01580 qboolean PM_SaberInBrokenParry( int move )
01581 {
01582         if ( move >= LS_V1_BR && move <= LS_V1_B_ )
01583         {
01584                 return qtrue;
01585         }
01586         if ( move >= LS_H1_T_ && move <= LS_H1_BL )
01587         {
01588                 return qtrue;
01589         }
01590         return qfalse;
01591 }
01592 
01593 
01594 int PM_BrokenParryForParry( int move )
01595 {
01596         switch ( move )
01597         {
01598         case LS_PARRY_UP:
01599                 return LS_H1_T_;
01600                 break;
01601         case LS_PARRY_UR:
01602                 return LS_H1_TR;
01603                 break;
01604         case LS_PARRY_UL:
01605                 return LS_H1_TL;
01606                 break;
01607         case LS_PARRY_LR:
01608                 return LS_H1_BL;
01609                 break;
01610         case LS_PARRY_LL:
01611                 return LS_H1_BR;
01612                 break;
01613         case LS_READY:
01614                 return LS_H1_B_;
01615                 break;
01616         }
01617         return LS_NONE;
01618 }
01619 
01620 #define BACK_STAB_DISTANCE 128
01621 
01622 qboolean PM_CanBackstab(void)
01623 {
01624         trace_t tr;
01625         vec3_t flatAng;
01626         vec3_t fwd, back;
01627         vec3_t trmins = {-15, -15, -8};
01628         vec3_t trmaxs = {15, 15, 8};
01629 
01630         VectorCopy(pm->ps->viewangles, flatAng);
01631         flatAng[PITCH] = 0;
01632 
01633         AngleVectors(flatAng, fwd, 0, 0);
01634 
01635         back[0] = pm->ps->origin[0] - fwd[0]*BACK_STAB_DISTANCE;
01636         back[1] = pm->ps->origin[1] - fwd[1]*BACK_STAB_DISTANCE;
01637         back[2] = pm->ps->origin[2] - fwd[2]*BACK_STAB_DISTANCE;
01638 
01639         pm->trace(&tr, pm->ps->origin, trmins, trmaxs, back, pm->ps->clientNum, MASK_PLAYERSOLID);
01640 
01641         if (tr.fraction != 1.0 && tr.entityNum >= 0 && tr.entityNum < ENTITYNUM_NONE)
01642         {
01643                 bgEntity_t *bgEnt = PM_BGEntForNum(tr.entityNum);
01644 
01645                 if (bgEnt && (bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
01646                 {
01647                         return qtrue;
01648                 }
01649         }
01650 
01651         return qfalse;
01652 }
01653 
01654 saberMoveName_t PM_SaberFlipOverAttackMove(void)
01655 { 
01656         vec3_t fwdAngles, jumpFwd;
01657 //      float zDiff = 0;
01658 //      playerState_t *psData;
01659 //      bgEntity_t *bgEnt;
01660 
01661         saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
01662         saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
01663         //see if we have an overridden (or cancelled) lunge move
01664         if ( saber1
01665                 && saber1->jumpAtkFwdMove != LS_INVALID )
01666         {
01667                 if ( saber1->jumpAtkFwdMove != LS_NONE )
01668                 {
01669                         return (saberMoveName_t)saber1->jumpAtkFwdMove;
01670                 }
01671         }
01672         if ( saber2
01673                 && saber2->jumpAtkFwdMove != LS_INVALID )
01674         {
01675                 if ( saber2->jumpAtkFwdMove != LS_NONE )
01676                 {
01677                         return (saberMoveName_t)saber2->jumpAtkFwdMove;
01678                 }
01679         }
01680         //no overrides, cancelled?
01681         if ( saber1
01682                 && saber1->jumpAtkFwdMove == LS_NONE )
01683         {
01684                 return LS_A_T2B;//LS_NONE;
01685         }
01686         if ( saber2 
01687                 && saber2->jumpAtkFwdMove == LS_NONE )
01688         {
01689                 return LS_A_T2B;//LS_NONE;
01690         }
01691         //just do it
01692         VectorCopy( pm->ps->viewangles, fwdAngles );
01693         fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
01694         AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
01695         VectorScale( jumpFwd, 150, pm->ps->velocity );//was 50
01696         pm->ps->velocity[2] = 400;
01697 
01698         /*
01699         bgEnt = PM_BGEntForNum(tr->entityNum);
01700 
01701         if (!bgEnt)
01702         {
01703                 return LS_A_FLIP_STAB;
01704         }
01705 
01706     psData = bgEnt->playerState;
01707 
01708         //go higher for enemies higher than you, lower for those lower than you
01709         if (psData)
01710         {
01711                 zDiff = psData->origin[2] - pm->ps->origin[2];
01712         }
01713         else
01714         {
01715                 zDiff = 0;
01716         }
01717         pm->ps->velocity[2] += (zDiff)*1.5f;
01718 
01719         //clamp to decent-looking values
01720         if ( zDiff <= 0 && pm->ps->velocity[2] < 200 )
01721         {//if we're on same level, don't let me jump so low, I clip into the ground
01722                 pm->ps->velocity[2] = 200;
01723         }
01724         else if ( pm->ps->velocity[2] < 100 )
01725         {
01726                 pm->ps->velocity[2] = 100;
01727         }
01728         else if ( pm->ps->velocity[2] > 400 )
01729         {
01730                 pm->ps->velocity[2] = 400;
01731         }
01732         */
01733 
01734         PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height
01735 
01736         PM_AddEvent( EV_JUMP );
01737         pm->ps->fd.forceJumpSound = 1;
01738         pm->cmd.upmove = 0;
01739 
01740         /*
01741         if ( PM_irand_timesync( 0, 1 ) )
01742         {
01743                 return LS_A_FLIP_STAB;
01744         }
01745         else
01746         */
01747         {
01748                 return LS_A_FLIP_SLASH;
01749         }
01750 }
01751 
01752 int PM_SaberBackflipAttackMove( void )
01753 {
01754         saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
01755         saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
01756         //see if we have an overridden (or cancelled) lunge move
01757         if ( saber1
01758                 && saber1->jumpAtkBackMove != LS_INVALID )
01759         {
01760                 if ( saber1->jumpAtkBackMove != LS_NONE )
01761                 {
01762                         return (saberMoveName_t)saber1->jumpAtkBackMove;
01763                 }
01764         }
01765         if ( saber2
01766                 && saber2->jumpAtkBackMove != LS_INVALID )
01767         {
01768                 if ( saber2->jumpAtkBackMove != LS_NONE )
01769                 {
01770                         return (saberMoveName_t)saber2->jumpAtkBackMove;
01771                 }
01772         }
01773         //no overrides, cancelled?
01774         if ( saber1
01775                 && saber1->jumpAtkBackMove == LS_NONE )
01776         {
01777                 return LS_A_T2B;//LS_NONE;
01778         }
01779         if ( saber2
01780                 && saber2->jumpAtkBackMove == LS_NONE )
01781         {
01782                 return LS_A_T2B;//LS_NONE;
01783         }
01784         //just do it
01785         pm->cmd.upmove = 127;
01786         pm->ps->velocity[2] = 500;
01787         return LS_A_BACKFLIP_ATK;
01788 }
01789 
01790 int PM_SaberDualJumpAttackMove( void )
01791 {
01792         //FIXME: to make this move easier to execute, should be allowed to do it 
01793         //              after you've already started your jump... but jump is delayed in
01794         //              this anim, so how do we undo the jump?
01795         pm->cmd.upmove = 0;//no jump just yet
01796         return LS_JUMPATTACK_DUAL;
01797 }
01798 
01799 #define FLIPHACK_DISTANCE 200
01800 
01801 qboolean PM_SomeoneInFront(trace_t *tr)
01802 { //Also a very simplified version of the sp counterpart
01803         vec3_t flatAng;
01804         vec3_t fwd, back;
01805         vec3_t trmins = {-15, -15, -8};
01806         vec3_t trmaxs = {15, 15, 8};
01807 
01808         VectorCopy(pm->ps->viewangles, flatAng);
01809         flatAng[PITCH] = 0;
01810 
01811         AngleVectors(flatAng, fwd, 0, 0);
01812 
01813         back[0] = pm->ps->origin[0] + fwd[0]*FLIPHACK_DISTANCE;
01814         back[1] = pm->ps->origin[1] + fwd[1]*FLIPHACK_DISTANCE;
01815         back[2] = pm->ps->origin[2] + fwd[2]*FLIPHACK_DISTANCE;
01816 
01817         pm->trace(tr, pm->ps->origin, trmins, trmaxs, back, pm->ps->clientNum, MASK_PLAYERSOLID);
01818 
01819         if (tr->fraction != 1.0 && tr->entityNum >= 0 && tr->entityNum < ENTITYNUM_NONE)
01820         {
01821                 bgEntity_t *bgEnt = PM_BGEntForNum(tr->entityNum);
01822 
01823                 if (bgEnt && (bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
01824                 {
01825                         return qtrue;
01826                 }
01827         }
01828 
01829         return qfalse;
01830 }
01831 
01832 saberMoveName_t PM_SaberLungeAttackMove( qboolean noSpecials )
01833 {
01834         vec3_t fwdAngles, jumpFwd;
01835         saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
01836         saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
01837         //see if we have an overridden (or cancelled) lunge move
01838         if ( saber1
01839                 && saber1->lungeAtkMove != LS_INVALID )
01840         {
01841                 if ( saber1->lungeAtkMove != LS_NONE )
01842                 {
01843                         return (saberMoveName_t)saber1->lungeAtkMove;
01844                 }
01845         }
01846         if ( saber2
01847                 && saber2->lungeAtkMove != LS_INVALID )
01848         {
01849                 if ( saber2->lungeAtkMove != LS_NONE )
01850                 {
01851                         return (saberMoveName_t)saber2->lungeAtkMove;
01852                 }
01853         }
01854         //no overrides, cancelled?
01855         if ( saber1
01856                 && saber1->lungeAtkMove == LS_NONE )
01857         {
01858                 return LS_A_T2B;//LS_NONE;
01859         }
01860         if ( saber2
01861         && saber2->lungeAtkMove == LS_NONE )
01862         {
01863                 return LS_A_T2B;//LS_NONE;
01864         }
01865         //just do it
01866         if (pm->ps->fd.saberAnimLevel == SS_FAST)
01867         {
01868                 VectorCopy( pm->ps->viewangles, fwdAngles );
01869                 fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
01870                 //do the lunge
01871                 AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
01872                 VectorScale( jumpFwd, 150, pm->ps->velocity );
01873                 PM_AddEvent( EV_JUMP );
01874 
01875                 return LS_A_LUNGE;
01876         }
01877         else if ( !noSpecials && pm->ps->fd.saberAnimLevel == SS_STAFF)
01878         {
01879                 return LS_SPINATTACK;
01880         }
01881         else if ( !noSpecials )
01882         {
01883                 return LS_SPINATTACK_DUAL;
01884         }
01885         return LS_A_T2B;
01886 }
01887 
01888 saberMoveName_t PM_SaberJumpAttackMove2( void )
01889 {
01890         saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
01891         saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
01892         //see if we have an overridden (or cancelled) lunge move
01893         if ( saber1
01894                 && saber1->jumpAtkFwdMove != LS_INVALID )
01895         {
01896                 if ( saber1->jumpAtkFwdMove != LS_NONE )
01897                 {
01898                         return (saberMoveName_t)saber1->jumpAtkFwdMove;
01899                 }
01900         }
01901         if ( saber2
01902         && saber2->jumpAtkFwdMove != LS_INVALID )
01903         {
01904                 if ( saber2->jumpAtkFwdMove != LS_NONE )
01905                 {
01906                         return (saberMoveName_t)saber2->jumpAtkFwdMove;
01907                 }
01908         }
01909         //no overrides, cancelled?
01910         if ( saber1
01911                 && saber1->jumpAtkFwdMove == LS_NONE )
01912         {
01913                 return LS_A_T2B;//LS_NONE;
01914         }
01915         if ( saber2
01916                 && saber2->jumpAtkFwdMove == LS_NONE )
01917         {
01918                 return LS_A_T2B;//LS_NONE;
01919         }
01920         //just do it
01921         if (pm->ps->fd.saberAnimLevel == SS_DUAL)
01922         {
01923                 return PM_SaberDualJumpAttackMove();
01924         }
01925         else
01926         {
01927                 //rwwFIXMEFIXME I don't like randomness for this sort of thing, gives people reason to
01928                 //complain combat is unpredictable. Maybe do something more clever to determine
01929                 //if we should do a left or right?
01930                 /*
01931                 if (PM_irand_timesync(0, 1))
01932                 {
01933                         newmove = LS_JUMPATTACK_STAFF_LEFT;
01934                 }
01935                 else
01936                 */
01937                 {
01938                         return LS_JUMPATTACK_STAFF_RIGHT;
01939                 }
01940         }
01941         return LS_A_T2B;
01942 }
01943 
01944 saberMoveName_t PM_SaberJumpAttackMove( void )
01945 {
01946         vec3_t fwdAngles, jumpFwd;
01947         saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
01948         saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
01949         //see if we have an overridden (or cancelled) lunge move
01950         if ( saber1
01951                 && saber1->jumpAtkFwdMove != LS_INVALID )
01952         {
01953                 if ( saber1->jumpAtkFwdMove != LS_NONE )
01954                 {
01955                         return (saberMoveName_t)saber1->jumpAtkFwdMove;
01956                 }
01957         }
01958         if ( saber2
01959                 && saber2->jumpAtkFwdMove != LS_INVALID )
01960         {
01961                 if ( saber2->jumpAtkFwdMove != LS_NONE )
01962                 {
01963                         return (saberMoveName_t)saber2->jumpAtkFwdMove;
01964                 }
01965         }
01966         //no overrides, cancelled?
01967         if ( saber1
01968                 && saber1->jumpAtkFwdMove == LS_NONE )
01969         {
01970                 return LS_A_T2B;//LS_NONE;
01971         }
01972         if ( saber2
01973                 && saber2->jumpAtkFwdMove == LS_NONE )
01974         {
01975                 return LS_A_T2B;//LS_NONE;
01976         }
01977         //just do it
01978         VectorCopy( pm->ps->viewangles, fwdAngles );
01979         fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
01980         AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
01981         VectorScale( jumpFwd, 300, pm->ps->velocity );
01982         pm->ps->velocity[2] = 280;
01983         PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height
01984 
01985         PM_AddEvent( EV_JUMP );
01986         pm->ps->fd.forceJumpSound = 1;
01987         pm->cmd.upmove = 0;
01988 
01989         return LS_A_JUMP_T__B_;
01990 }
01991 
01992 float PM_GroundDistance(void)
01993 {
01994         trace_t tr;
01995         vec3_t down;
01996 
01997         VectorCopy(pm->ps->origin, down);
01998 
01999         down[2] -= 4096;
02000 
02001         pm->trace(&tr, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, MASK_SOLID);
02002 
02003         VectorSubtract(pm->ps->origin, tr.endpos, down);
02004 
02005         return VectorLength(down);
02006 }
02007 
02008 float PM_WalkableGroundDistance(void)
02009 {
02010         trace_t tr;
02011         vec3_t down;
02012 
02013         VectorCopy(pm->ps->origin, down);
02014 
02015         down[2] -= 4096;
02016 
02017         pm->trace(&tr, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, MASK_SOLID);
02018 
02019         if ( tr.plane.normal[2] < MIN_WALK_NORMAL )
02020         {//can't stand on this plane
02021                 return 4096;
02022         }
02023 
02024         VectorSubtract(pm->ps->origin, tr.endpos, down);
02025 
02026         return VectorLength(down);
02027 }
02028 
02029 qboolean BG_SaberInTransitionAny( int move );
02030 static qboolean PM_CanDoDualDoubleAttacks(void)
02031 {
02032         if ( pm->ps->weapon == WP_SABER )
02033         {
02034                 saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
02035                 if ( saber
02036                         && (saber->saberFlags&SFL_NO_MIRROR_ATTACKS) )
02037                 {
02038                         return qfalse;
02039                 }
02040                 saber = BG_MySaber( pm->ps->clientNum, 1 );
02041                 if ( saber
02042                         && (saber->saberFlags&SFL_NO_MIRROR_ATTACKS) )
02043                 {
02044                         return qfalse;
02045                 }
02046         }
02047         if (BG_SaberInSpecialAttack(pm->ps->torsoAnim) ||
02048                 BG_SaberInSpecialAttack(pm->ps->legsAnim))
02049         {
02050                 return qfalse;
02051         }
02052         return qtrue;
02053 }
02054 
02055 static qboolean PM_CheckEnemyPresence( int dir, float radius )
02056 { //anyone in this dir?
02057         vec3_t angles;
02058         vec3_t checkDir;
02059         vec3_t tTo;
02060         vec3_t tMins, tMaxs;
02061         trace_t tr;
02062         const float tSize = 12.0f;
02063         //sp uses a bbox ent list check, but.. that's not so easy/fast to
02064         //do in predicted code. So I'll just do a single box trace in the proper direction,
02065         //and take whatever is first hit.
02066 
02067         VectorSet(tMins, -tSize, -tSize, -tSize);
02068         VectorSet(tMaxs, tSize, tSize, tSize);
02069 
02070         VectorCopy(pm->ps->viewangles, angles);
02071         angles[PITCH] = 0.0f;
02072 
02073         switch( dir )
02074         {
02075         case DIR_RIGHT:
02076                 AngleVectors( angles, NULL, checkDir, NULL );
02077                 break;
02078         case DIR_LEFT:
02079                 AngleVectors( angles, NULL, checkDir, NULL );
02080                 VectorScale( checkDir, -1, checkDir );
02081                 break;
02082         case DIR_FRONT:
02083                 AngleVectors( angles, checkDir, NULL, NULL );
02084                 break;
02085         case DIR_BACK:
02086                 AngleVectors( angles, checkDir, NULL, NULL );
02087                 VectorScale( checkDir, -1, checkDir );
02088                 break;
02089         }
02090 
02091         VectorMA(pm->ps->origin, radius, checkDir, tTo);
02092         pm->trace(&tr, pm->ps->origin, tMins, tMaxs, tTo, pm->ps->clientNum, MASK_PLAYERSOLID);
02093 
02094         if (tr.fraction != 1.0f && tr.entityNum < ENTITYNUM_WORLD)
02095         { //let's see who we hit
02096                 bgEntity_t *bgEnt = PM_BGEntForNum(tr.entityNum);
02097 
02098                 if (bgEnt &&
02099                         (bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
02100                 { //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).
02101                         return qtrue;
02102                 }
02103         }
02104 
02105         //no one in the trace
02106         return qfalse;
02107 }
02108 
02109 #define SABER_ALT_ATTACK_POWER          50//75?
02110 #define SABER_ALT_ATTACK_POWER_LR       10//30?
02111 #define SABER_ALT_ATTACK_POWER_FB       25//30/50?
02112 
02113 extern qboolean PM_SaberInReturn( int move ); //bg_panimate.c
02114 saberMoveName_t PM_CheckPullAttack( void )
02115 {
02116 #if 0 //disabling these for MP, they aren't useful
02117         if (!(pm->cmd.buttons & BUTTON_ATTACK))
02118         {
02119                 return LS_NONE;
02120         }
02121 
02122         if ( (pm->ps->saberMove == LS_READY||PM_SaberInReturn(pm->ps->saberMove)||PM_SaberInReflect(pm->ps->saberMove))//ready
02123                 //&& (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer())//PLAYER ONLY
02124                 && pm->ps->fd.saberAnimLevel >= SS_FAST//single saber styles - FIXME: Tavion?
02125                 && pm->ps->fd.saberAnimLevel <= SS_STRONG//single saber styles - FIXME: Tavion?
02126                 //&& G_TryingPullAttack( pm->gent, &pm->cmd, qfalse )
02127                 //&& pm->ps->fd.forcePowerLevel[FP_PULL] 
02128                 //rwwFIXMEFIXME: rick has the damn msg.cpp file checked out exclusively so I can't update the bloody psf to send this for prediction
02129                 && pm->ps->powerups[PW_DISINT_4] > pm->cmd.serverTime
02130                 && !(pm->ps->fd.forcePowersActive & (1<<FP_GRIP))
02131                 && pm->ps->powerups[PW_PULL] > pm->cmd.serverTime
02132                 //&& pm->cmd.forwardmove<0//pulling back
02133                 && (pm->cmd.buttons&BUTTON_ATTACK)//attacking
02134                 && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_FB ) )//pm->ps->forcePower >= SABER_ALT_ATTACK_POWER_FB//have enough power
02135         {//FIXME: some NPC logic to do this?
02136                 qboolean doMove = qtrue;
02137 //              if ( g_saberNewControlScheme->integer
02138 //                      || g_crosshairEntNum < ENTITYNUM_WORLD )//in old control scheme, there has to be someone there
02139                 {       
02140                         saberMoveName_t pullAttackMove = LS_NONE;
02141                         if ( pm->ps->fd.saberAnimLevel == SS_FAST )
02142                         {
02143                                 pullAttackMove = LS_PULL_ATTACK_STAB;
02144                         }
02145                         else
02146                         {
02147                                 pullAttackMove = LS_PULL_ATTACK_SWING;
02148                         }
02149 
02150                         /*
02151                         if ( g_crosshairEntNum < ENTITYNUM_WORLD 
02152                                 && pm->gent && pm->gent->client )
02153                         {
02154                                 gentity_t *targEnt = &g_entities[g_crosshairEntNum];
02155                                 if ( targEnt->client
02156                                         && targEnt->health > 0
02157                                         //FIXME: check other things like in knockdown, saberlock, uninterruptable anims, etc.
02158                                         && !PM_InOnGroundAnim( &targEnt->client->ps )
02159                                         && !PM_LockedAnim( targEnt->client->ps.legsAnim ) 
02160                                         && !PM_SuperBreakLoseAnim( targEnt->client->ps.legsAnim )
02161                                         && !PM_SuperBreakWinAnim( targEnt->client->ps.legsAnim )
02162                                         && targEnt->client->ps.saberLockTime <= 0
02163                                         && WP_ForceThrowable( targEnt, targEnt, pm->gent, qtrue, 1.0f, 0.0f, NULL ) )
02164                                 {
02165                                         if ( !g_saberNewControlScheme->integer )
02166                                         {//in old control scheme, make sure they're close or far enough away for the move we'll be doing
02167                                                 float targDist = Distance( targEnt->currentOrigin, pm->ps->origin );
02168                                                 if ( pullAttackMove == LS_PULL_ATTACK_STAB )
02169                                                 {//must be closer than 512
02170                                                         if ( targDist > 384.0f )
02171                                                         {
02172                                                                 return LS_NONE;
02173                                                         }
02174                                                 }
02175                                                 else//if ( pullAttackMove == LS_PULL_ATTACK_SWING )
02176                                                 {//must be farther than 256
02177                                                         if ( targDist > 512.0f )
02178                                                         {
02179                                                                 return LS_NONE;
02180                                                         }
02181                                                         if ( targDist < 192.0f )
02182                                                         {
02183                                                                 return LS_NONE;
02184                                                         }
02185                                                 }
02186                                         }
02187 
02188                                         vec3_t targAngles = {0,targEnt->client->ps.viewangles[YAW],0};
02189                                         if ( InFront( pm->ps->origin, targEnt->currentOrigin, targAngles ) )
02190                                         {
02191                                                 NPC_SetAnim( targEnt, SETANIM_BOTH, BOTH_PULLED_INAIR_F, SETANIM_FLAG_OVERRIDE, SETANIM_FLAG_HOLD );
02192                                         }
02193                                         else
02194                                         {
02195                                                 NPC_SetAnim( targEnt, SETANIM_BOTH, BOTH_PULLED_INAIR_B, SETANIM_FLAG_OVERRIDE, SETANIM_FLAG_HOLD );
02196                                         }
02197                                         //hold the anim until I'm with done pull anim
02198                                         targEnt->client->ps.legsAnimTimer = targEnt->client->ps.torsoAnimTimer = PM_AnimLength( pm->gent->client->clientInfo.animFileIndex, (animNumber_t)saberMoveData[pullAttackMove].animToUse );
02199                                         //set pullAttackTime
02200                                         pm->gent->client->ps.pullAttackTime = targEnt->client->ps.pullAttackTime = level.time+targEnt->client->ps.legsAnimTimer;
02201                                         //make us know about each other
02202                                         pm->gent->client->ps.pullAttackEntNum = g_crosshairEntNum;
02203                                         targEnt->client->ps.pullAttackEntNum = pm->ps->clientNum;
02204                                         //do effect and sound on me
02205                                         pm->ps->powerups[PW_FORCE_PUSH] = level.time + 1000;
02206                                         if ( pm->gent )
02207                                         {
02208                                                 G_Sound( pm->gent, G_SoundIndex( "sound/weapons/force/pull.wav" ) );
02209                                         }
02210                                         doMove = qtrue;
02211                                 }
02212                         }
02213                         */
02214                         if ( doMove )
02215                         {
02216                                 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB );
02217                                 return pullAttackMove;
02218                         }
02219                 }
02220         }
02221 #endif
02222         return LS_NONE;
02223 }
02224 
02225 qboolean PM_InSecondaryStyle( void )
02226 {
02227         if ( pm->ps->fd.saberAnimLevelBase == SS_STAFF 
02228                 || pm->ps->fd.saberAnimLevelBase == SS_DUAL )
02229         {
02230                 if ( pm->ps->fd.saberAnimLevel != pm->ps->fd.saberAnimLevelBase )
02231                 {
02232                         return qtrue;
02233                 }
02234         }
02235         return qfalse;
02236 }
02237 
02238 saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove)
02239 {
02240         saberMoveName_t newmove = LS_NONE;
02241         qboolean noSpecials = PM_InSecondaryStyle();
02242         qboolean allowCartwheels = qtrue;
02243         saberMoveName_t overrideJumpRightAttackMove = LS_INVALID;
02244         saberMoveName_t overrideJumpLeftAttackMove = LS_INVALID;
02245 
02246         if ( pm->ps->weapon == WP_SABER )
02247         {
02248                 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
02249                 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
02250 
02251                 if ( saber1
02252                         && saber1->jumpAtkRightMove != LS_INVALID )
02253                 {
02254                         if ( saber1->jumpAtkRightMove != LS_NONE )
02255                         {//actually overriding
02256                                 overrideJumpRightAttackMove = (saberMoveName_t)saber1->jumpAtkRightMove;
02257                         }
02258                         else if ( saber2
02259                                 && saber2->jumpAtkRightMove > LS_NONE )
02260                         {//would be cancelling it, but check the second saber, too
02261                                 overrideJumpRightAttackMove = (saberMoveName_t)saber2->jumpAtkRightMove;
02262                         }
02263                         else
02264                         {//nope, just cancel it
02265                                 overrideJumpRightAttackMove = LS_NONE;
02266                         }
02267                 }
02268                 else if ( saber2
02269                         && saber2->jumpAtkRightMove != LS_INVALID )
02270                 {//first saber not overridden, check second
02271                         overrideJumpRightAttackMove = (saberMoveName_t)saber2->jumpAtkRightMove;
02272                 }
02273 
02274                 if ( saber1
02275                         && saber1->jumpAtkLeftMove != LS_INVALID )
02276                 {
02277                         if ( saber1->jumpAtkLeftMove != LS_NONE )
02278                         {//actually overriding
02279                                 overrideJumpLeftAttackMove = (saberMoveName_t)saber1->jumpAtkLeftMove;
02280                         }
02281                         else if ( saber2
02282                                 && saber2->jumpAtkLeftMove > LS_NONE )
02283                         {//would be cancelling it, but check the second saber, too
02284                                 overrideJumpLeftAttackMove = (saberMoveName_t)saber2->jumpAtkLeftMove;
02285                         }
02286                         else
02287                         {//nope, just cancel it
02288                                 overrideJumpLeftAttackMove = LS_NONE;
02289                         }
02290                 }
02291                 else if ( saber2
02292                         && saber2->jumpAtkLeftMove != LS_INVALID )
02293                 {//first saber not overridden, check second
02294                         overrideJumpLeftAttackMove = (saberMoveName_t)saber1->jumpAtkLeftMove;
02295                 }
02296 
02297                 if ( saber1
02298                         && (saber1->saberFlags&SFL_NO_CARTWHEELS) )
02299                 {
02300                         allowCartwheels = qfalse;
02301                 }
02302                 if ( saber2
02303                         && (saber2->saberFlags&SFL_NO_CARTWHEELS) )
02304                 {
02305                         allowCartwheels = qfalse;
02306                 }
02307         }
02308 
02309         if ( pm->cmd.rightmove > 0 )
02310         {//moving right
02311                 if ( !noSpecials
02312                         && overrideJumpRightAttackMove != LS_NONE
02313                         && pm->ps->velocity[2] > 20.0f //pm->ps->groundEntityNum != ENTITYNUM_NONE//on ground
02314                         && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack
02315                         && PM_GroundDistance() < 70.0f //not too high above ground
02316                         && ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player
02317                         && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power
02318                 {//cartwheel right
02319                         BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR);
02320                         if ( overrideJumpRightAttackMove != LS_INVALID )
02321                         {//overridden with another move
02322                                 return overrideJumpRightAttackMove;
02323                         }
02324                         else
02325                         {
02326                                 vec3_t right, fwdAngles;
02327 
02328                                 VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f);
02329 
02330                                 AngleVectors( fwdAngles, NULL, right, NULL );
02331                                 pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f; 
02332                                 VectorMA( pm->ps->velocity, 190.0f, right, pm->ps->velocity );
02333                                 if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
02334                                 {
02335                                         newmove = LS_BUTTERFLY_RIGHT;
02336                                         pm->ps->velocity[2] = 350.0f;
02337                                 }
02338                                 else if ( allowCartwheels )
02339                                 {
02340                                         //PM_SetJumped( JUMP_VELOCITY, qtrue );
02341                                         PM_AddEvent( EV_JUMP );
02342                                         pm->ps->velocity[2] = 300.0f;
02343 
02344                                         //if ( !Q_irand( 0, 1 ) )
02345                                         //if (PM_GroundDistance() >= 25.0f)
02346                                         if (1)
02347                                         {
02348                                                 newmove = LS_JUMPATTACK_ARIAL_RIGHT;
02349                                         }
02350                                         else
02351                                         {
02352                                                 newmove = LS_JUMPATTACK_CART_RIGHT;
02353                                         }
02354                                 }
02355                         }
02356                 }
02357                 else if ( pm->cmd.forwardmove > 0 )
02358                 {//forward right = TL2BR slash
02359                         newmove = LS_A_TL2BR;
02360                 }
02361                 else if ( pm->cmd.forwardmove < 0 )
02362                 {//backward right = BL2TR uppercut
02363                         newmove = LS_A_BL2TR;
02364                 }
02365                 else
02366                 {//just right is a left slice
02367                         newmove = LS_A_L2R;
02368                 }
02369         }
02370         else if ( pm->cmd.rightmove < 0 )
02371         {//moving left
02372                 if ( !noSpecials
02373                         && overrideJumpLeftAttackMove != LS_NONE
02374                         && pm->ps->velocity[2] > 20.0f //pm->ps->groundEntityNum != ENTITYNUM_NONE//on ground
02375                         && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack
02376                         && PM_GroundDistance() < 70.0f //not too high above ground
02377                         && ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player
02378                         && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power
02379                 {//cartwheel left
02380                         BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR);
02381 
02382                         if ( overrideJumpLeftAttackMove != LS_INVALID )
02383                         {//overridden with another move
02384                                 return overrideJumpLeftAttackMove;
02385                         }
02386                         else
02387                         {
02388                                 vec3_t right, fwdAngles;
02389 
02390                                 VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f);
02391                                 AngleVectors( fwdAngles, NULL, right, NULL );
02392                                 pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f; 
02393                                 VectorMA( pm->ps->velocity, -190.0f, right, pm->ps->velocity );
02394                                 if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
02395                                 {
02396                                         newmove = LS_BUTTERFLY_LEFT;
02397                                         pm->ps->velocity[2] = 250.0f;
02398                                 }
02399                                 else if ( allowCartwheels )
02400                                 {
02401                                         //PM_SetJumped( JUMP_VELOCITY, qtrue );
02402                                         PM_AddEvent( EV_JUMP );
02403                                         pm->ps->velocity[2] = 350.0f;
02404 
02405                                         //if ( !Q_irand( 0, 1 ) )
02406                                         //if (PM_GroundDistance() >= 25.0f)
02407                                         if (1)
02408                                         {
02409                                                 newmove = LS_JUMPATTACK_ARIAL_LEFT;
02410                                         }
02411                                         else
02412                                         {
02413                                                 newmove = LS_JUMPATTACK_CART_LEFT;
02414                                         }
02415                                 }
02416                         }
02417                 }
02418                 else if ( pm->cmd.forwardmove > 0 )
02419                 {//forward left = TR2BL slash
02420                         newmove = LS_A_TR2BL;
02421                 }
02422                 else if ( pm->cmd.forwardmove < 0 )
02423                 {//backward left = BR2TL uppercut
02424                         newmove = LS_A_BR2TL;
02425                 }
02426                 else
02427                 {//just left is a right slice
02428                         newmove = LS_A_R2L;
02429                 }
02430         }
02431         else
02432         {//not moving left or right
02433                 if ( pm->cmd.forwardmove > 0 )
02434                 {//forward= T2B slash
02435                         if (!noSpecials&&
02436                                 (pm->ps->fd.saberAnimLevel == SS_DUAL || pm->ps->fd.saberAnimLevel == SS_STAFF) &&
02437                                 pm->ps->fd.forceRageRecoveryTime < pm->cmd.serverTime &&
02438                                 //pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 &&
02439                                 (pm->ps->groundEntityNum != ENTITYNUM_NONE || PM_GroundDistance() <= 40) &&
02440                                 pm->ps->velocity[2] >= 0 &&
02441                                 (pm->cmd.upmove > 0 || pm->ps->pm_flags & PMF_JUMP_HELD) &&
02442                                 !BG_SaberInTransitionAny(pm->ps->saberMove) &&
02443                                 !BG_SaberInAttack(pm->ps->saberMove) &&
02444                                 pm->ps->weaponTime <= 0 &&
02445                                 pm->ps->forceHandExtend == HANDEXTEND_NONE &&
02446                                 (pm->cmd.buttons & BUTTON_ATTACK)&&
02447                                 BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) )
02448                         { //DUAL/STAFF JUMP ATTACK
02449                                 newmove = PM_SaberJumpAttackMove2();
02450                                 if ( newmove != LS_A_T2B 
02451                                         && newmove != LS_NONE )
02452                                 {
02453                                         BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
02454                                 }
02455                         }
02456                         else if (!noSpecials&&
02457                                 pm->ps->fd.saberAnimLevel == SS_MEDIUM &&
02458                                 pm->ps->velocity[2] > 100 &&
02459                                 PM_GroundDistance() < 32 &&
02460                                 !BG_InSpecialJump(pm->ps->legsAnim) &&
02461                                 !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
02462                                 BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB))
02463                         { //FLIP AND DOWNWARD ATTACK
02464                                 //trace_t tr;
02465 
02466                                 //if (PM_SomeoneInFront(&tr))
02467                                 {
02468                                         newmove = PM_SaberFlipOverAttackMove();
02469                                         if ( newmove != LS_A_T2B
02470                                                 && newmove != LS_NONE )
02471                                         {
02472                                                 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
02473                                         }
02474                                 }
02475                         }
02476                         else if (!noSpecials&&
02477                                 pm->ps->fd.saberAnimLevel == SS_STRONG &&
02478                                 pm->ps->velocity[2] > 100 &&
02479                                 PM_GroundDistance() < 32 &&
02480                                 !BG_InSpecialJump(pm->ps->legsAnim) &&
02481                                 !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
02482                                 BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_FB ))
02483                         { //DFA
02484                                 //trace_t tr;
02485 
02486                                 //if (PM_SomeoneInFront(&tr))
02487                                 {
02488                                         newmove = PM_SaberJumpAttackMove();
02489                                         if ( newmove != LS_A_T2B
02490                                                 && newmove != LS_NONE )
02491                                         {
02492                                                 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
02493                                         }
02494                                 }
02495                         }
02496                         else if ((pm->ps->fd.saberAnimLevel == SS_FAST || pm->ps->fd.saberAnimLevel == SS_DUAL || pm->ps->fd.saberAnimLevel == SS_STAFF) &&
02497                                 pm->ps->groundEntityNum != ENTITYNUM_NONE &&
02498                                 (pm->ps->pm_flags & PMF_DUCKED) &&
02499                                 pm->ps->weaponTime <= 0 &&
02500                                 !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
02501                                 BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB))
02502                         { //LUNGE (weak)
02503                                 newmove = PM_SaberLungeAttackMove( noSpecials );
02504                                 if ( newmove != LS_A_T2B
02505                                         && newmove != LS_NONE )
02506                                 {
02507                                         BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
02508                                 }
02509                         }
02510                         else if ( !noSpecials )
02511                         {
02512                                 saberMoveName_t stabDownMove = PM_CheckStabDown();
02513                                 if (stabDownMove != LS_NONE 
02514                                         && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) )
02515                                 {
02516                                         newmove = stabDownMove;
02517                                         BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
02518                                 }
02519                                 else
02520                                 {
02521                                         newmove = LS_A_T2B;
02522                                 }
02523                         }
02524                 }
02525                 else if ( pm->cmd.forwardmove < 0 )
02526                 {//backward= T2B slash//B2T uppercut?
02527                         if (!noSpecials&&
02528                                 pm->ps->fd.saberAnimLevel == SS_STAFF &&
02529                                 pm->ps->fd.forceRageRecoveryTime < pm->cmd.serverTime &&
02530                                 pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 &&
02531                                 (pm->ps->groundEntityNum != ENTITYNUM_NONE || PM_GroundDistance() <= 40) &&
02532                                 pm->ps->velocity[2] >= 0 &&
02533                                 (pm->cmd.upmove > 0 || pm->ps->pm_flags & PMF_JUMP_HELD) &&
02534                                 !BG_SaberInTransitionAny(pm->ps->saberMove) &&
02535                                 !BG_SaberInAttack(pm->ps->saberMove) &&
02536                                 pm->ps->weaponTime <= 0 &&
02537                                 pm->ps->forceHandExtend == HANDEXTEND_NONE &&
02538                                 (pm->cmd.buttons & BUTTON_ATTACK))
02539                         { //BACKFLIP ATTACK
02540                                 newmove = PM_SaberBackflipAttackMove();
02541                         }
02542                         else if (PM_CanBackstab() && !BG_SaberInSpecialAttack(pm->ps->torsoAnim))
02543                         { //BACKSTAB (attack varies by level)
02544                                 if (pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_2 && pm->ps->fd.saberAnimLevel != SS_STAFF)
02545                                 {//medium and higher attacks
02546                                         if ( (pm->ps->pm_flags&PMF_DUCKED) || pm->cmd.upmove < 0 )
02547                                         {
02548                                                 newmove = LS_A_BACK_CR;
02549                                         }
02550                                         else
02551                                         {
02552                                                 newmove = LS_A_BACK;
02553                                         }
02554                                 }
02555                                 else
02556                                 { //weak attack
02557                                         newmove = LS_A_BACKSTAB;
02558                                 }
02559                         }
02560                         else
02561                         {
02562                                 newmove = LS_A_T2B;
02563                         }
02564                 }
02565                 else if ( PM_SaberInBounce( curmove ) )
02566                 {//bounces should go to their default attack if you don't specify a direction but are attacking
02567                         newmove = saberMoveData[curmove].chain_attack;
02568 
02569                         if ( PM_SaberKataDone(curmove, newmove) )
02570                         {
02571                                 newmove = saberMoveData[curmove].chain_idle;
02572                         }
02573                         else
02574                         {
02575                                 newmove = saberMoveData[curmove].chain_attack;
02576                         }
02577                 }
02578                 else if ( curmove == LS_READY )
02579                 {//Not moving at all, shouldn't have gotten here...?
02580                         //for now, just pick a random attack
02581                         //newmove = Q_irand( LS_A_TL2BR, LS_A_T2B );
02582                         //rww - If we don't seed with a "common" value, the client and server will get mismatched
02583                         //prediction values. Under laggy conditions this will cause the appearance of rapid swing
02584                         //sequence changes.
02585 
02586                         newmove = LS_A_T2B; //decided we don't like random attacks when idle, use an overhead instead.
02587                 }
02588         }
02589 
02590         if (pm->ps->fd.saberAnimLevel == SS_DUAL)
02591         {
02592                 if ( ( newmove == LS_A_R2L || newmove == LS_S_R2L
02593                                         || newmove == LS_A_L2R  || newmove == LS_S_L2R )
02594                         && PM_CanDoDualDoubleAttacks()
02595                         && PM_CheckEnemyPresence( DIR_RIGHT, 100.0f )
02596                         && PM_CheckEnemyPresence( DIR_LEFT, 100.0f ) )
02597                 {//enemy both on left and right
02598                         newmove = LS_DUAL_LR;
02599                         //probably already moved, but...
02600                         pm->cmd.rightmove = 0;
02601                 }
02602                 else if ( (newmove == LS_A_T2B || newmove == LS_S_T2B
02603                                         || newmove == LS_A_BACK || newmove == LS_A_BACK_CR )
02604                         && PM_CanDoDualDoubleAttacks()
02605                         && PM_CheckEnemyPresence( DIR_FRONT, 100.0f )
02606                         && PM_CheckEnemyPresence( DIR_BACK, 100.0f ) )
02607                 {//enemy both in front and back
02608                         newmove = LS_DUAL_FB;
02609                         //probably already moved, but...
02610                         pm->cmd.forwardmove = 0;
02611                 }
02612         }
02613 
02614         return newmove;
02615 }
02616 
02617 int PM_KickMoveForConditions(void)
02618 {
02619         int kickMove = -1;
02620 
02621         //FIXME: only if FP_SABER_OFFENSE >= 3
02622         if ( pm->cmd.rightmove )
02623         {//kick to side
02624                 if ( pm->cmd.rightmove > 0 )
02625                 {//kick right
02626                         kickMove = LS_KICK_R;
02627                 }
02628                 else
02629                 {//kick left
02630                         kickMove = LS_KICK_L;
02631                 }
02632                 pm->cmd.rightmove = 0;
02633         }
02634         else if ( pm->cmd.forwardmove )
02635         {//kick front/back
02636                 if ( pm->cmd.forwardmove > 0 )
02637                 {//kick fwd
02638                         /*
02639                         if (pm->ps->groundEntityNum != ENTITYNUM_NONE &&
02640                                 PM_CheckEnemyPresence( DIR_FRONT, 64.0f ))
02641                         {
02642                                 kickMove = LS_HILT_BASH;
02643                         }
02644                         else
02645                         */
02646                         {
02647                                 kickMove = LS_KICK_F;
02648                         }
02649                 }
02650                 else
02651                 {//kick back
02652                         kickMove = LS_KICK_B;
02653                 }
02654                 pm->cmd.forwardmove = 0;
02655         }
02656         else
02657         {
02658                 //if (pm->cmd.buttons & BUTTON_ATTACK)
02659                 //if (pm->ps->pm_flags & PMF_JUMP_HELD)
02660                 if (0)
02661                 { //ok, let's try some fancy kicks
02662                         //qboolean is actually of type int anyway, but just for safeness.
02663                         int front = (int)PM_CheckEnemyPresence( DIR_FRONT, 100.0f );
02664                         int back = (int)PM_CheckEnemyPresence( DIR_BACK, 100.0f );
02665                         int right = (int)PM_CheckEnemyPresence( DIR_RIGHT, 100.0f );
02666                         int left = (int)PM_CheckEnemyPresence( DIR_LEFT, 100.0f );
02667                         int numEnemy = front+back+right+left;
02668 
02669                         if (numEnemy >= 3 ||
02670                                 ((!right || !left) && numEnemy >= 2))
02671                         { //> 2 enemies near, or, >= 2 enemies near and they are not to the right and left.
02672                 kickMove = LS_KICK_S;
02673                         }
02674                         else if (right && left)
02675                         { //enemies on both sides
02676                                 kickMove = LS_KICK_RL;
02677                         }
02678                         else
02679                         { //oh well, just do a forward kick
02680                                 kickMove = LS_KICK_F;
02681                         }
02682 
02683                         pm->cmd.upmove = 0;
02684                 }
02685         }
02686 
02687         return kickMove;
02688 }
02689 
02690 qboolean BG_InSlopeAnim( int anim );
02691 qboolean PM_RunningAnim( int anim );
02692 
02693 qboolean PM_SaberMoveOkayForKata( void )
02694 {
02695         if ( pm->ps->saberMove == LS_READY
02696                 || PM_SaberInStart( pm->ps->saberMove ) )
02697         {
02698                 return qtrue;
02699         }
02700         else
02701         {
02702                 return qfalse;
02703         }
02704 }
02705 
02706 qboolean PM_CanDoKata( void )
02707 {
02708         if ( PM_InSecondaryStyle() )
02709         {
02710                 return qfalse;
02711         }
02712 
02713         if ( !pm->ps->saberInFlight//not throwing saber
02714                 && PM_SaberMoveOkayForKata()
02715                 && !BG_SaberInKata(pm->ps->saberMove)
02716                 && !BG_InKataAnim(pm->ps->legsAnim)
02717                 && !BG_InKataAnim(pm->ps->torsoAnim)
02718                 /*
02719                 && pm->ps->saberAnimLevel >= SS_FAST//fast, med or strong style
02720                 && pm->ps->saberAnimLevel <= SS_STRONG//FIXME: Tavion, too?
02721                 */
02722                 && pm->ps->groundEntityNum != ENTITYNUM_NONE//not in the air
02723                 && (pm->cmd.buttons&BUTTON_ATTACK)//pressing attack
02724                 && (pm->cmd.buttons&BUTTON_ALT_ATTACK)//pressing alt attack
02725                 && !pm->cmd.forwardmove//not moving f/b
02726                 && !pm->cmd.rightmove//not moving r/l
02727                 && pm->cmd.upmove <= 0//not jumping...?
02728                 && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER) )// have enough power
02729         {//FIXME: check rage, etc...
02730                 saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
02731                 if ( saber
02732                         && saber->kataMove == LS_NONE )
02733                 {//kata move has been overridden in a way that should stop you from doing it at all
02734                         return qfalse;
02735                 }
02736                 saber = BG_MySaber( pm->ps->clientNum, 1 );
02737                 if ( saber
02738                         && saber->kataMove == LS_NONE )
02739                 {//kata move has been overridden in a way that should stop you from doing it at all
02740                         return qfalse;
02741                 }
02742                 return qtrue;
02743         }
02744         return qfalse;
02745 }
02746 
02747 qboolean PM_CheckAltKickAttack( void )
02748 {
02749         if ( pm->ps->weapon == WP_SABER )
02750         {
02751                 saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
02752                 if ( saber
02753                         && (saber->saberFlags&SFL_NO_KICKS) )
02754                 {
02755                         return qfalse;
02756                 }
02757                 saber = BG_MySaber( pm->ps->clientNum, 1 );
02758                 if ( saber
02759                         && (saber->saberFlags&SFL_NO_KICKS) )
02760                 {
02761                         return qfalse;
02762                 }
02763         }
02764         if ( (pm->cmd.buttons&BUTTON_ALT_ATTACK) 
02765                 //&& (!(pm->ps->pm_flags&PMF_ALT_ATTACK_HELD)||PM_SaberInReturn(pm->ps->saberMove))
02766                 && (!BG_FlippingAnim(pm->ps->legsAnim)||pm->ps->legsTimer<=250)
02767                 && (pm->ps->fd.saberAnimLevel == SS_STAFF/*||!pm->ps->saber[0].throwable*/) && !pm->ps->saberHolstered )
02768         {
02769                 return qtrue;
02770         }
02771         return qfalse;
02772 }
02773 
02774 int bg_parryDebounce[NUM_FORCE_POWER_LEVELS] =
02775 {
02776         500,//if don't even have defense, can't use defense!
02777         300,
02778         150,
02779         50
02780 };
02781 
02782 qboolean PM_SaberPowerCheck(void)
02783 {
02784         if (pm->ps->saberInFlight)
02785         { //so we don't keep doing stupid force out thing while guiding saber.
02786                 if (pm->ps->fd.forcePower > forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW])
02787                 {
02788                         return qtrue;
02789                 }
02790         }
02791         else
02792         {
02793                 return BG_EnoughForcePowerForMove(forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW]);
02794         }
02795 
02796         return qfalse;
02797 }
02798 
02799 qboolean PM_CanDoRollStab( void )
02800 {
02801         if ( pm->ps->weapon == WP_SABER )
02802         {
02803                 saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
02804                 if ( saber
02805                         && (saber->saberFlags&SFL_NO_ROLL_STAB) )
02806                 {
02807                         return qfalse;
02808                 }
02809                 saber = BG_MySaber( pm->ps->clientNum, 1 );
02810                 if ( saber
02811                         && (saber->saberFlags&SFL_NO_ROLL_STAB) )
02812                 {
02813                         return qfalse;
02814                 }
02815         }
02816         return qtrue;
02817 }
02818 /*
02819 =================
02820 PM_WeaponLightsaber
02821 
02822 Consults a chart to choose what to do with the lightsaber.
02823 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.
02824 =================
02825 */
02826 // Ultimate goal is to set the sabermove to the proper next location
02827 // Note that if the resultant animation is NONE, then the animation is essentially "idle", and is set in WP_TorsoAnim
02828 qboolean PM_WalkingAnim( int anim );
02829 qboolean PM_SwimmingAnim( int anim );
02830 int PM_SaberBounceForAttack( int move );
02831 qboolean BG_SuperBreakLoseAnim( int anim );
02832 qboolean BG_SuperBreakWinAnim( int anim );
02833 void PM_WeaponLightsaber(void)
02834 {
02835         int                     addTime,amount;
02836         qboolean        delayed_fire = qfalse;
02837         int                     anim=-1, curmove, newmove=LS_NONE;
02838 
02839         qboolean checkOnlyWeap = qfalse;
02840 
02841         if ( PM_InKnockDown( pm->ps ) || BG_InRoll( pm->ps, pm->ps->legsAnim ))
02842         {//in knockdown
02843                 // make weapon function
02844                 if ( pm->ps->weaponTime > 0 ) {
02845                         pm->ps->weaponTime -= pml.msec;
02846                         if ( pm->ps->weaponTime <= 0 )
02847                         {
02848                                 pm->ps->weaponTime = 0;
02849                         }
02850                 }
02851                 if ( pm->ps->legsAnim == BOTH_ROLL_F 
02852                         && pm->ps->legsTimer <= 250 )
02853                 {
02854                         if ( (pm->cmd.buttons&BUTTON_ATTACK) )
02855                         {
02856                                 if ( BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) && !pm->ps->saberInFlight )
02857                                 {
02858                                         if ( PM_CanDoRollStab() )
02859                                         {
02860                                                 //make sure the saber is on for this move!
02861                                                 if ( pm->ps->saberHolstered == 2 )
02862                                                 {//all the way off
02863                                                         pm->ps->saberHolstered = 0;
02864                                                         PM_AddEvent(EV_SABER_UNHOLSTER);
02865                                                 }
02866                                                 PM_SetSaberMove( LS_ROLL_STAB );
02867                                                 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
02868                                         }
02869                                 }
02870                         }
02871                 }
02872                 return;
02873         }
02874 
02875         if ( pm->ps->saberLockTime > pm->cmd.serverTime )
02876         {
02877                 pm->ps->saberMove = LS_NONE;
02878                 PM_SaberLocked();
02879                 return;
02880         }
02881         else
02882         {
02883                 if ( /*( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
02884                                 (pm->ps->torsoAnim) == BOTH_BF1LOCK ||
02885                                 (pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
02886                                 (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||*/
02887                                 pm->ps->saberLockFrame
02888                         )
02889                 {
02890                         if (pm->ps->saberLockEnemy < ENTITYNUM_NONE &&
02891                                 pm->ps->saberLockEnemy >= 0)
02892                         {
02893                                 bgEntity_t *bgEnt;
02894                                 playerState_t *en;
02895 
02896                                 bgEnt = PM_BGEntForNum(pm->ps->saberLockEnemy);
02897 
02898                                 if (bgEnt)
02899                                 {
02900                                         en = bgEnt->playerState;
02901 
02902                                         if (en)
02903                                         {
02904                                                 PM_SaberLockBreak(en, qfalse, 0);
02905                                                 return;
02906                                         }
02907                                 }
02908                         }
02909 
02910                         if (/* ( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
02911                                         (pm->ps->torsoAnim) == BOTH_BF1LOCK ||
02912                                         (pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
02913                                         (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||*/
02914                                         pm->ps->saberLockFrame
02915                                 )
02916                         {
02917                                 pm->ps->torsoTimer = 0;
02918                                 PM_SetAnim(SETANIM_TORSO,BOTH_STAND1,SETANIM_FLAG_OVERRIDE, 100);
02919                                 pm->ps->saberLockFrame = 0;
02920                         }
02921                 }
02922         }
02923 
02924         if ( BG_KickingAnim( pm->ps->legsAnim ) ||
02925                 BG_KickingAnim( pm->ps->torsoAnim ))
02926         {
02927                 if ( pm->ps->legsTimer > 0 )
02928                 {//you're kicking, no interruptions
02929                         return;
02930                 }
02931                 //done?  be immeditately ready to do an attack
02932                 pm->ps->saberMove = LS_READY;
02933                 pm->ps->weaponTime = 0;
02934         }
02935 
02936         if ( BG_SuperBreakLoseAnim( pm->ps->torsoAnim )
02937                 || BG_SuperBreakWinAnim( pm->ps->torsoAnim ) )
02938         {
02939                 if ( pm->ps->torsoTimer > 0 )
02940                 {//never interrupt these
02941                         return;
02942                 }
02943         }
02944 
02945         if (BG_SabersOff( pm->ps ))
02946         {
02947                 if (pm->ps->saberMove != LS_READY)
02948                 {
02949                         PM_SetSaberMove( LS_READY );
02950                 }
02951 
02952                 if ((pm->ps->legsAnim) != (pm->ps->torsoAnim) && !BG_InSlopeAnim(pm->ps->legsAnim) &&
02953                         pm->ps->torsoTimer <= 0)
02954                 {
02955                         PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE, 100);
02956                 }
02957                 else if (BG_InSlopeAnim(pm->ps->legsAnim) && pm->ps->torsoTimer <= 0)
02958                 {
02959                         PM_SetAnim(SETANIM_TORSO,PM_GetSaberStance(),SETANIM_FLAG_OVERRIDE, 100);
02960                 }
02961 
02962                 if (pm->ps->weaponTime < 1 && ((pm->cmd.buttons & BUTTON_ALT_ATTACK) || (pm->cmd.buttons & BUTTON_ATTACK)))
02963                 {
02964                         if (pm->ps->duelTime < pm->cmd.serverTime)
02965                         {
02966                                 if (!pm->ps->m_iVehicleNum)
02967                                 { //don't let em unholster the saber by attacking while on vehicle
02968                                         pm->ps->saberHolstered = 0;
02969                                         PM_AddEvent(EV_SABER_UNHOLSTER);
02970                                 }
02971                                 else
02972                                 {
02973                                         pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
02974                                         pm->cmd.buttons &= ~BUTTON_ATTACK;
02975                                 }
02976                         }
02977                 }
02978 
02979                 if ( pm->ps->weaponTime > 0 )
02980                 {
02981                         pm->ps->weaponTime -= pml.msec;
02982                 }
02983 
02984                 checkOnlyWeap = qtrue;
02985                 goto weapChecks;
02986         }
02987 
02988         if (!pm->ps->saberEntityNum && pm->ps->saberInFlight)
02989         { //this means our saber has been knocked away
02990                 /*
02991                 if (pm->ps->saberMove != LS_READY)
02992                 {
02993                         PM_SetSaberMove( LS_READY );
02994                 }
02995 
02996                 if ((pm->ps->legsAnim) != (pm->ps->torsoAnim) && !BG_InSlopeAnim(pm->ps->legsAnim))
02997                 {
02998                         PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE, 100);
02999                 }
03000 
03001                 if (BG_InSaberStandAnim(pm->ps->torsoAnim) || pm->ps->torsoAnim == BOTH_SABERPULL)
03002                 {
03003                         PM_SetAnim(SETANIM_TORSO,BOTH_STAND1,SETANIM_FLAG_OVERRIDE, 100);
03004                 }
03005 
03006                 return;
03007                 */
03008                 //Old method, don't want to do this now because we want to finish up reflected attacks and things
03009                 //if our saber is pried out of our hands from one.
03010                 if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
03011                 {
03012                         if ( pm->ps->saberHolstered > 1 )
03013                         {
03014                                 pm->ps->saberHolstered = 1;
03015                         }
03016                 }
03017                 else
03018                 {
03019                         pm->cmd.buttons &= ~BUTTON_ATTACK;
03020                 }
03021                 pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
03022         }
03023 
03024         if ( (pm->cmd.buttons & BUTTON_ALT_ATTACK) )
03025         { //might as well just check for a saber throw right here
03026                 if (pm->ps->fd.saberAnimLevel == SS_STAFF)
03027                 { //kick instead of doing a throw 
03028                         //if in a saber attack return anim, can interrupt it with a kick
03029                         if ( pm->ps->weaponTime > 0//can't fire yet
03030                                 && PM_SaberInReturn( pm->ps->saberMove )//in a saber return move - FIXME: what about transitions?
03031                                 //&& pm->ps->weaponTime <= 250//should be able to fire soon
03032                                 //&& pm->ps->torsoTimer <= 250//torso almost done
03033                                 && pm->ps->saberBlocked == BLOCKED_NONE//not interacting with any other saber
03034                                 && !(pm->cmd.buttons&BUTTON_ATTACK) )//not trying to swing the saber
03035                         {
03036                                 if ( (pm->cmd.forwardmove||pm->cmd.rightmove)//trying to kick in a specific direction
03037                                         && PM_CheckAltKickAttack() )//trying to do a kick
03038                                 {//allow them to do the kick now!
03039                                         int kickMove = PM_KickMoveForConditions();
03040                                         if (kickMove != -1)
03041                                         {
03042                                                 pm->ps->weaponTime = 0;
03043                                                 PM_SetSaberMove( kickMove );
03044                                                 return;
03045                                         }
03046                                 }
03047                         }
03048                 }
03049                 else if ( pm->ps->weaponTime < 1&&
03050                                 pm->ps->saberCanThrow &&
03051                                 //pm->ps->fd.forcePower >= forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW] &&
03052                                 !BG_HasYsalamiri(pm->gametype, pm->ps) &&
03053                                 BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_SABERTHROW) &&
03054                                 pm->ps->fd.forcePowerLevel[FP_SABERTHROW] > 0 &&
03055                                 PM_SaberPowerCheck() )
03056                 {
03057                         trace_t sabTr;
03058                         vec3_t  fwd, minFwd, sabMins, sabMaxs;
03059 
03060                         VectorSet( sabMins, SABERMINS_X, SABERMINS_Y, SABERMINS_Z );
03061                         VectorSet( sabMaxs, SABERMAXS_X, SABERMAXS_Y, SABERMAXS_Z );
03062 
03063                         AngleVectors( pm->ps->viewangles, fwd, NULL, NULL );
03064                         VectorMA( pm->ps->origin, SABER_MIN_THROW_DIST, fwd, minFwd );
03065 
03066                         pm->trace(&sabTr, pm->ps->origin, sabMins, sabMaxs, minFwd, pm->ps->clientNum, MASK_PLAYERSOLID);
03067 
03068                         if ( sabTr.allsolid || sabTr.startsolid || sabTr.fraction < 1.0f )
03069                         {//not enough room to throw
03070                         }
03071                         else
03072                         {//throw it
03073                                 //This will get set to false again once the saber makes it back to its owner game-side
03074                                 if (!pm->ps->saberInFlight)
03075                                 {
03076                                         pm->ps->fd.forcePower -= forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW];
03077                                 }
03078 
03079                                 pm->ps->saberInFlight = qtrue;
03080                         }
03081                 }
03082         }
03083         
03084         if ( pm->ps->saberInFlight && pm->ps->saberEntityNum )
03085         {//guiding saber
03086                 if ( (pm->ps->fd.saberAnimLevel != SS_DUAL //not using 2 sabers
03087                           || pm->ps->saberHolstered //left one off - FIXME: saberHolstered 1 should be left one off, 0 should be both on, 2 should be both off
03088                           || (!(pm->cmd.buttons&BUTTON_ATTACK)//not trying to start an attack AND...
03089                                   && (pm->ps->torsoAnim == BOTH_SABERDUAL_STANCE//not already attacking
03090                                           || pm->ps->torsoAnim == BOTH_SABERPULL//not already attacking
03091                                           || pm->ps->torsoAnim == BOTH_STAND1//not already attacking
03092                                           || PM_RunningAnim( pm->ps->torsoAnim ) //not already attacking
03093                                           || PM_WalkingAnim( pm->ps->torsoAnim ) //not already attacking
03094                                           || PM_JumpingAnim( pm->ps->torsoAnim )//not already attacking
03095                                           || PM_SwimmingAnim( pm->ps->torsoAnim ))//not already attacking
03096                                 )
03097                           )
03098                         )
03099                 {
03100                         PM_SetAnim(SETANIM_TORSO, BOTH_SABERPULL, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100);
03101                         pm->ps->torsoTimer = 1;
03102                         return;
03103                 }
03104         }
03105 
03106    // don't allow attack until all buttons are up
03107         //This is bad. It freezes the attack state and the animations if you hold the button after respawning, and it looks strange.
03108         /*
03109         if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
03110                 return;
03111         }
03112         */
03113 
03114         // check for dead player
03115         if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
03116                 return;
03117         }
03118 
03119         /*
03120 
03121         if (pm->ps->weaponstate == WEAPON_READY ||
03122                 pm->ps->weaponstate == WEAPON_IDLE)
03123         {
03124                 if (pm->ps->saberMove != LS_READY && pm->ps->weaponTime <= 0 && !pm->ps->saberBlocked)
03125                 {
03126                         PM_SetSaberMove( LS_READY );
03127                 }
03128         }
03129 
03130         if(PM_RunningAnim(pm->ps->torsoAnim))
03131         {
03132                 if ((pm->ps->torsoAnim) != (pm->ps->legsAnim))
03133                 {
03134                         PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE, 100);
03135                 }
03136         }
03137         */
03138 
03139         // make weapon function
03140         if ( pm->ps->weaponTime > 0 )
03141         {
03142                 //check for special pull move while busy
03143                 saberMoveName_t pullmove = PM_CheckPullAttack();
03144                 if (pullmove != LS_NONE)
03145                 {
03146                         pm->ps->weaponTime = 0;
03147                         pm->ps->torsoTimer = 0;
03148                         pm->ps->legsTimer = 0;
03149                         pm->ps->forceHandExtend = HANDEXTEND_NONE;
03150                         pm->ps->weaponstate = WEAPON_READY;
03151                         PM_SetSaberMove(pullmove);
03152                         return;
03153                 }
03154 
03155                 pm->ps->weaponTime -= pml.msec;
03156 
03157                 //This was stupid and didn't work right. Looks like things are fine without it.
03158         //      if (pm->ps->saberBlocked && pm->ps->torsoAnim != saberMoveData[pm->ps->saberMove].animToUse)
03159         //      { //rww - keep him in the blocking pose until he can attack again
03160         //              PM_SetAnim(SETANIM_TORSO,saberMoveData[pm->ps->saberMove].animToUse,saberMoveData[pm->ps->saberMove].animSetFlags|SETANIM_FLAG_HOLD, saberMoveData[pm->ps->saberMove].blendTime);
03161         //              return;
03162         //      }
03163         }
03164         else
03165         {
03166                 pm->ps->weaponstate = WEAPON_READY;
03167         }
03168 
03169         // Now we react to a block action by the player's lightsaber.
03170         if ( pm->ps->saberBlocked )
03171         {
03172                 if ( pm->ps->saberBlocked >= BLOCKED_UPPER_RIGHT 
03173                         && pm->ps->saberBlocked < BLOCKED_UPPER_RIGHT_PROJ)
03174                 {//hold the parry for a bit
03175                         pm->ps->weaponTime = bg_parryDebounce[pm->ps->fd.forcePowerLevel[FP_SABER_DEFENSE]]+200;
03176                 }
03177                 switch ( pm->ps->saberBlocked )
03178                 {
03179                         case BLOCKED_BOUNCE_MOVE:
03180                                 { //act as a bounceMove and reset the saberMove instead of using a seperate value for it
03181                                         pm->ps->torsoTimer = 0;
03182                                         PM_SetSaberMove( pm->ps->saberMove );
03183                                         pm->ps->weaponTime = pm->ps->torsoTimer;
03184                                         pm->ps->saberBlocked = 0;
03185                                 }
03186                                 break;
03187                         case BLOCKED_PARRY_BROKEN:
03188                                 //whatever parry we were is in now broken, play the appropriate knocked-away anim
03189                                 {
03190                                         int nextMove;
03191 
03192                                         if ( PM_SaberInBrokenParry( pm->ps->saberMove ) )
03193                                         {//already have one...?
03194                                                 nextMove = pm->ps->saberMove;
03195                                         }
03196                                         else
03197                                         {
03198                                                 nextMove = PM_BrokenParryForParry( pm->ps->saberMove );
03199                                         }
03200                                         if ( nextMove != LS_NONE )
03201                                         {
03202                                                 PM_SetSaberMove( nextMove );
03203                                                 pm->ps->weaponTime = pm->ps->torsoTimer;
03204                                         }
03205                                         else
03206                                         {//Maybe in a knockaway?
03207                                         }
03208                                 }
03209                                 break;
03210                         case BLOCKED_ATK_BOUNCE:
03211                                 // If there is absolutely no blocked move in the chart, don't even mess with the animation.
03212                                 // OR if we are already in a block or parry.
03213                                 if (pm->ps->saberMove >= LS_T1_BR__R)
03214                                 {//an actual bounce?  Other bounces before this are actually transitions?
03215                                         pm->ps->saberBlocked = BLOCKED_NONE;
03216                                 }
03217                                 else
03218                                 {
03219                                         int bounceMove;
03220 
03221                                         if ( PM_SaberInBounce( pm->ps->saberMove ) || !BG_SaberInAttack( pm->ps->saberMove ) )
03222                                         {
03223                                                 if ( pm->cmd.buttons & BUTTON_ATTACK )
03224                                                 {//transition to a new attack
03225                                                         int newQuad = PM_SaberMoveQuadrantForMovement( &pm->cmd );
03226                                                         while ( newQuad == saberMoveData[pm->ps->saberMove].startQuad )
03227                                                         {//player is still in same attack quad, don't repeat that attack because it looks bad, 
03228                                                                 //FIXME: try to pick one that might look cool?
03229                                                                 //newQuad = Q_irand( Q_BR, Q_BL );
03230                                                                 newQuad = PM_irand_timesync( Q_BR, Q_BL );
03231                                                                 //FIXME: sanity check, just in case?
03232                                                         }//else player is switching up anyway, take the new attack dir
03233                                                         bounceMove = transitionMove[saberMoveData[pm->ps->saberMove].startQuad][newQuad];
03234                                                 }
03235                                                 else
03236                                                 {//return to ready
03237                                                         if ( saberMoveData[pm->ps->saberMove].startQuad == Q_T )
03238                                                         {
03239                                                                 bounceMove = LS_R_BL2TR;
03240                                                         }
03241                                                         else if ( saberMoveData[pm->ps->saberMove].startQuad < Q_T )
03242                                                         {
03243                                                                 bounceMove = LS_R_TL2BR+saberMoveData[pm->ps->saberMove].startQuad-Q_BR;
03244                                                         }
03245                                                         else// if ( saberMoveData[pm->ps->saberMove].startQuad > Q_T )
03246                                                         {
03247                                                                 bounceMove = LS_R_BR2TL+saberMoveData[pm->ps->saberMove].startQuad-Q_TL;
03248                                                         }
03249                                                 }
03250                                         }
03251                                         else
03252                                         {//start the bounce
03253                                                 bounceMove = PM_SaberBounceForAttack( (saberMoveName_t)pm->ps->saberMove );
03254                                         }
03255 
03256                                         PM_SetSaberMove( bounceMove );
03257 
03258                                         pm->ps->weaponTime = pm->ps->torsoTimer;//+saberMoveData[bounceMove].blendTime+SABER_BLOCK_DUR;
03259 
03260                                 }
03261                                 break;
03262                         case BLOCKED_UPPER_RIGHT:
03263                                 PM_SetSaberMove( LS_PARRY_UR );
03264                                 break;
03265                         case BLOCKED_UPPER_RIGHT_PROJ:
03266                                 PM_SetSaberMove( LS_REFLECT_UR );
03267                                 break;
03268                         case BLOCKED_UPPER_LEFT:
03269                                 PM_SetSaberMove( LS_PARRY_UL );
03270                                 break;
03271                         case BLOCKED_UPPER_LEFT_PROJ:
03272                                 PM_SetSaberMove( LS_REFLECT_UL );
03273                                 break;
03274                         case BLOCKED_LOWER_RIGHT:
03275                                 PM_SetSaberMove( LS_PARRY_LR );
03276                                 break;
03277                         case BLOCKED_LOWER_RIGHT_PROJ:
03278                                 PM_SetSaberMove( LS_REFLECT_LR );
03279                                 break;
03280                         case BLOCKED_LOWER_LEFT:
03281                                 PM_SetSaberMove( LS_PARRY_LL );
03282                                 break;
03283                         case BLOCKED_LOWER_LEFT_PROJ:
03284                                 PM_SetSaberMove( LS_REFLECT_LL);
03285                                 break;
03286                         case BLOCKED_TOP:
03287                                 PM_SetSaberMove( LS_PARRY_UP );
03288                                 break;
03289                         case BLOCKED_TOP_PROJ:
03290                                 PM_SetSaberMove( LS_REFLECT_UP );
03291                                 break;
03292                         default:
03293                                 pm->ps->saberBlocked = BLOCKED_NONE;
03294                                 break;
03295                 }
03296                 if ( pm->ps->saberBlocked >= BLOCKED_UPPER_RIGHT 
03297                         && pm->ps->saberBlocked < BLOCKED_UPPER_RIGHT_PROJ)
03298                 {//hold the parry for a bit
03299                         if ( pm->ps->torsoTimer < pm->ps->weaponTime )
03300                         {
03301                                 pm->ps->torsoTimer = pm->ps->weaponTime;
03302                         }
03303                 }
03304 
03305                 //what the? I don't know why I was doing this.
03306                 /*
03307                 if (pm->ps->saberBlocked != BLOCKED_ATK_BOUNCE && pm->ps->saberBlocked != BLOCKED_PARRY_BROKEN && pm->ps->weaponTime < 1)
03308                 {
03309                         pm->ps->torsoTimer = SABER_BLOCK_DUR;
03310                         pm->ps->weaponTime = pm->ps->torsoTimer;
03311                 }
03312                 */
03313 
03314                 //clear block
03315                 pm->ps->saberBlocked = 0;
03316 
03317                 // Charging is like a lead-up before attacking again.  This is an appropriate use, or we can create a new weaponstate for blocking
03318                 pm->ps->weaponstate = WEAPON_READY;
03319 
03320                 // Done with block, so stop these active weapon branches.
03321                 return;
03322         }
03323 
03324 weapChecks:
03325         if (pm->ps->saberEntityNum)
03326         { //only check if we have our saber with us
03327                 // check for weapon change
03328                 // can't change if weapon is firing, but can change again if lowering or raising
03329                 //if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
03330                 if (pm->ps->weaponTime <= 0 && pm->ps->torsoTimer <= 0)
03331                 {
03332                         if ( pm->ps->weapon != pm->cmd.weapon ) {
03333                                 PM_BeginWeaponChange( pm->cmd.weapon );
03334                         }
03335                 }
03336         }
03337 
03338         if ( PM_CanDoKata() )
03339         {
03340                 saberMoveName_t overrideMove = LS_INVALID;
03341                 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
03342                 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
03343                 //see if we have an overridden (or cancelled) kata move
03344                 if ( saber1 && saber1->kataMove != LS_INVALID )
03345                 {
03346                         if ( saber1->kataMove != LS_NONE )
03347                         {
03348                                 overrideMove = (saberMoveName_t)saber1->kataMove;
03349                         }
03350                 }
03351                 if ( overrideMove == LS_INVALID )
03352                 {//not overridden by first saber, check second
03353                         if ( saber2
03354                                 && saber2->kataMove != LS_INVALID )
03355                         {
03356                                 if ( saber2->kataMove != LS_NONE )
03357                                 {
03358                                         overrideMove = (saberMoveName_t)saber2->kataMove;
03359                                 }
03360                         }
03361                 }
03362                 //no overrides, cancelled?
03363                 if ( overrideMove == LS_INVALID )
03364                 {
03365                         if ( saber2
03366                                 && saber2->kataMove == LS_NONE )
03367                         {
03368                                 overrideMove = LS_NONE;
03369                         }
03370                         else if ( saber2
03371                                 && saber2->kataMove == LS_NONE )
03372                         {
03373                                 overrideMove = LS_NONE;
03374                         }
03375                 }
03376                 if ( overrideMove == LS_INVALID )
03377                 {//not overridden
03378                         //FIXME: make sure to turn on saber(s)!
03379                         switch ( pm->ps->fd.saberAnimLevel )
03380                         {
03381                         case SS_FAST:
03382                         case SS_TAVION:
03383                                 PM_SetSaberMove( LS_A1_SPECIAL );
03384                                 break;
03385                         case SS_MEDIUM:
03386                                 PM_SetSaberMove( LS_A2_SPECIAL );
03387                                 break;
03388                         case SS_STRONG:
03389                         case SS_DESANN:
03390                                 PM_SetSaberMove( LS_A3_SPECIAL );
03391                                 break;
03392                         case SS_DUAL:
03393                                 PM_SetSaberMove( LS_DUAL_SPIN_PROTECT );//PM_CheckDualSpinProtect();
03394                                 break;
03395                         case SS_STAFF:
03396                                 PM_SetSaberMove( LS_STAFF_SOULCAL );
03397                                 break;
03398                         }
03399                         pm->ps->weaponstate = WEAPON_FIRING;
03400                         //G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER );//FP_SPEED, SINGLE_SPECIAL_POWER );
03401                         BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER);
03402                 }
03403                 else if ( overrideMove != LS_NONE )
03404                 {
03405                         PM_SetSaberMove( overrideMove );
03406                         pm->ps->weaponstate = WEAPON_FIRING;
03407                         BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER);
03408                 }
03409                 if ( overrideMove != LS_NONE )
03410                 {//not cancelled
03411                         return;
03412                 }
03413         }
03414 
03415         if ( pm->ps->weaponTime > 0 ) 
03416         {
03417                 return;
03418         }
03419 
03420         // *********************************************************
03421         // WEAPON_DROPPING
03422         // *********************************************************
03423 
03424         // change weapon if time
03425         if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
03426                 PM_FinishWeaponChange();
03427                 return;
03428         }
03429 
03430         // *********************************************************
03431         // WEAPON_RAISING
03432         // *********************************************************
03433 
03434         if ( pm->ps->weaponstate == WEAPON_RAISING ) 
03435         {//Just selected the weapon
03436                 pm->ps->weaponstate = WEAPON_IDLE;
03437                 if((pm->ps->legsAnim) == BOTH_WALK1 )
03438                 {
03439                         PM_SetAnim(SETANIM_TORSO,BOTH_WALK1,SETANIM_FLAG_NORMAL, 100);
03440                 }
03441                 else if((pm->ps->legsAnim) == BOTH_RUN1 )
03442                 {
03443                         PM_SetAnim(SETANIM_TORSO,BOTH_RUN1,SETANIM_FLAG_NORMAL, 100);
03444                 }
03445                 else if((pm->ps->legsAnim) == BOTH_RUN2 )
03446                 {
03447                         PM_SetAnim(SETANIM_TORSO,BOTH_RUN2,SETANIM_FLAG_NORMAL, 100);
03448                 }
03449                 else if( pm->ps->legsAnim == BOTH_RUN_STAFF)
03450                 {
03451                         PM_SetAnim(SETANIM_TORSO,BOTH_RUN_STAFF,SETANIM_FLAG_NORMAL, 100);
03452                 }
03453                 else if( pm->ps->legsAnim == BOTH_RUN_DUAL)
03454                 {
03455                         PM_SetAnim(SETANIM_TORSO,BOTH_RUN_DUAL,SETANIM_FLAG_NORMAL, 100);
03456                 }
03457                 else if((pm->ps->legsAnim) == BOTH_WALK1 )
03458                 {
03459                         PM_SetAnim(SETANIM_TORSO,BOTH_WALK1,SETANIM_FLAG_NORMAL, 100);
03460                 }
03461                 else if( pm->ps->legsAnim == BOTH_WALK2)
03462                 {
03463                         PM_SetAnim(SETANIM_TORSO,BOTH_WALK2,SETANIM_FLAG_NORMAL, 100);
03464                 }
03465                 else if( pm->ps->legsAnim == BOTH_WALK_STAFF)
03466                 {
03467                         PM_SetAnim(SETANIM_TORSO,BOTH_WALK_STAFF,SETANIM_FLAG_NORMAL, 100);
03468                 }
03469                 else if( pm->ps->legsAnim == BOTH_WALK_DUAL)
03470                 {
03471                         PM_SetAnim(SETANIM_TORSO,BOTH_WALK_DUAL,SETANIM_FLAG_NORMAL, 100);
03472                 }
03473                 else
03474                 {
03475                         PM_SetAnim(SETANIM_TORSO,PM_GetSaberStance(),SETANIM_FLAG_NORMAL, 100);
03476                 }
03477 
03478                 if (pm->ps->weaponstate == WEAPON_RAISING)
03479                 {
03480                         return;
03481                 }
03482 
03483         }
03484 
03485         if (checkOnlyWeap)
03486         {
03487                 return;
03488         }
03489 
03490         // *********************************************************
03491         // Check for WEAPON ATTACK
03492         // *********************************************************
03493         if (pm->ps->fd.saberAnimLevel == SS_STAFF &&
03494                 (pm->cmd.buttons & BUTTON_ALT_ATTACK))
03495         { //ok, try a kick I guess.
03496                 int kickMove = -1;
03497 
03498                 if ( !BG_KickingAnim(pm->ps->torsoAnim) &&
03499                         !BG_KickingAnim(pm->ps->legsAnim) &&
03500                         !BG_InRoll(pm->ps, pm->ps->legsAnim) &&
03501 //                      !BG_KickMove( pm->ps->saberMove )//not already in a kick
03502                         pm->ps->saberMove == LS_READY
03503                         && !(pm->ps->pm_flags&PMF_DUCKED)//not ducked
03504                         && (pm->cmd.upmove >= 0 ) //not trying to duck
03505                         )//&& pm->ps->groundEntityNum != ENTITYNUM_NONE)
03506                 {//player kicks
03507                         kickMove = PM_KickMoveForConditions();
03508                 }
03509 
03510                 if (kickMove != -1)
03511                 {
03512                         if ( pm->ps->groundEntityNum == ENTITYNUM_NONE )
03513                         {//if in air, convert kick to an in-air kick
03514                                 float gDist = PM_GroundDistance();
03515                                 //let's only allow air kicks if a certain distance from the ground
03516                                 //it's silly to be able to do them right as you land.
03517                                 //also looks wrong to transition from a non-complete flip anim...
03518                                 if ((!BG_FlippingAnim( pm->ps->legsAnim ) || pm->ps->legsTimer <= 0) &&
03519                                         gDist > 64.0f && //strict minimum
03520                                         gDist > (-pm->ps->velocity[2])-64.0f //make sure we are high to ground relative to downward velocity as well
03521                                         )
03522                                 {
03523                                         switch ( kickMove )
03524                                         {
03525                                         case LS_KICK_F:
03526                                                 kickMove = LS_KICK_F_AIR;
03527                                                 break;
03528                                         case LS_KICK_B:
03529                                                 kickMove = LS_KICK_B_AIR;
03530                                                 break;
03531                                         case LS_KICK_R:
03532                                                 kickMove = LS_KICK_R_AIR;
03533                                                 break;
03534                                         case LS_KICK_L:
03535                                                 kickMove = LS_KICK_L_AIR;
03536                                                 break;
03537                                         default: //oh well, can't do any other kick move while in-air
03538                                                 kickMove = -1;
03539                                                 break;
03540                                         }
03541                                 }
03542                                 else
03543                                 {//leave it as a normal kick unless we're too high up
03544                                         if ( gDist > 128.0f || pm->ps->velocity[2] >= 0 )
03545                                         { //off ground, but too close to ground
03546                                                 kickMove = -1;
03547                                         }
03548                                 }
03549                         }
03550 
03551                         if (kickMove != -1)
03552                         {
03553                                 PM_SetSaberMove( kickMove );
03554                                 return;
03555                         }
03556                 }
03557         }
03558 
03559         //this is never a valid regular saber attack button
03560         pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
03561 
03562         if(!delayed_fire)
03563         {
03564                 // Start with the current move, and cross index it with the current control states.
03565                 if ( pm->ps->saberMove > LS_NONE && pm->ps->saberMove < LS_MOVE_MAX )
03566                 {
03567                         curmove = pm->ps->saberMove;
03568                 }
03569                 else
03570                 {
03571                         curmove = LS_READY;
03572                 }
03573 
03574                 if ( curmove == LS_A_JUMP_T__B_ || pm->ps->torsoAnim == BOTH_FORCELEAP2_T__B_ )
03575                 {//must transition back to ready from this anim
03576                         newmove = LS_R_T2B;
03577                 }
03578                 // check for fire
03579                 else if ( !(pm->cmd.buttons & (BUTTON_ATTACK|BUTTON_ALT_ATTACK)) )
03580                 {//not attacking
03581                         pm->ps->weaponTime = 0;
03582                         
03583                         if ( pm->ps->weaponTime > 0 )
03584                         {//Still firing
03585                                 pm->ps->weaponstate = WEAPON_FIRING;
03586                         }
03587                         else if ( pm->ps->weaponstate != WEAPON_READY )
03588                         {
03589                                 pm->ps->weaponstate = WEAPON_IDLE;
03590                         }
03591                         //Check for finishing an anim if necc.
03592                         if ( curmove >= LS_S_TL2BR && curmove <= LS_S_T2B )
03593                         {//started a swing, must continue from here
03594                                 newmove = LS_A_TL2BR + (curmove-LS_S_TL2BR);
03595                         }
03596                         else if ( curmove >= LS_A_TL2BR && curmove <= LS_A_T2B )
03597                         {//finished an attack, must continue from here
03598                                 newmove = LS_R_TL2BR + (curmove-LS_A_TL2BR);
03599                         }
03600                         else if ( PM_SaberInTransition( curmove ) )
03601                         {//in a transition, must play sequential attack
03602                                 newmove = saberMoveData[curmove].chain_attack;
03603                         }
03604                         else if ( PM_SaberInBounce( curmove ) )
03605                         {//in a bounce
03606                                 newmove = saberMoveData[curmove].chain_idle;//oops, not attacking, so don't chain
03607                         }
03608                         else
03609                         {//FIXME: what about returning from a parry?
03610                                 //PM_SetSaberMove( LS_READY );
03611                                 //if ( pm->ps->saberBlockingTime > pm->cmd.serverTime )
03612                                 {
03613                                         PM_SetSaberMove( LS_READY );
03614                                 }
03615                                 return;
03616                         }
03617                 }
03618 
03619                 // ***************************************************
03620                 // Pressing attack, so we must look up the proper attack move.
03621 
03622                 if ( pm->ps->weaponTime > 0 )
03623                 {       // Last attack is not yet complete.
03624                         pm->ps->weaponstate = WEAPON_FIRING;
03625                         return;
03626                 }
03627                 else
03628                 {
03629                         int     both = qfalse;
03630                         if ( pm->ps->torsoAnim == BOTH_FORCELONGLEAP_ATTACK
03631                                 || pm->ps->torsoAnim == BOTH_FORCELONGLEAP_LAND )
03632                         {//can't attack in these anims
03633                                 return;
03634                         }
03635                         else if ( pm->ps->torsoAnim == BOTH_FORCELONGLEAP_START )
03636                         {//only 1 attack you can do from this anim
03637                                 if ( pm->ps->torsoTimer >= 200 )
03638                                 {//hit it early enough to do the attack
03639                                         PM_SetSaberMove( LS_LEAP_ATTACK );
03640                                 }
03641                                 return;
03642                         }
03643                         if ( curmove >= LS_PARRY_UP && curmove <= LS_REFLECT_LL )
03644                         {//from a parry or reflection, can go directly into an attack
03645                                 switch ( saberMoveData[curmove].endQuad )
03646                                 {
03647                                 case Q_T:
03648                                         newmove = LS_A_T2B;
03649                                         break;
03650                                 case Q_TR:
03651                                         newmove = LS_A_TR2BL;
03652                                         break;
03653                                 case Q_TL:
03654                                         newmove = LS_A_TL2BR;
03655                                         break;
03656                                 case Q_BR:
03657                                         newmove = LS_A_BR2TL;
03658                                         break;
03659                                 case Q_BL:
03660                                         newmove = LS_A_BL2TR;
03661                                         break;
03662                                 //shouldn't be a parry that ends at L, R or B
03663                                 }
03664                         }
03665 
03666                         if ( newmove != LS_NONE )
03667                         {//have a valid, final LS_ move picked, so skip findingt he transition move and just get the anim
03668                                 anim = saberMoveData[newmove].animToUse;
03669                         }
03670 
03671                         //FIXME: diagonal dirs use the figure-eight attacks from ready pose?
03672                         if ( anim == -1 )
03673                         {
03674                                 //FIXME: take FP_SABER_OFFENSE into account here somehow?
03675                                 if ( PM_SaberInTransition( curmove ) )
03676                                 {//in a transition, must play sequential attack
03677                                         newmove = saberMoveData[curmove].chain_attack;
03678                                 }
03679                                 else if ( curmove >= LS_S_TL2BR && curmove <= LS_S_T2B )
03680                                 {//started a swing, must continue from here
03681                                         newmove = LS_A_TL2BR + (curmove-LS_S_TL2BR);
03682                                 }
03683                                 else if ( PM_SaberInBrokenParry( curmove ) )
03684                                 {//broken parries must always return to ready
03685                                         newmove = LS_READY;
03686                                 }
03687                                 else//if ( pm->cmd.buttons&BUTTON_ATTACK && !(pm->ps->pm_flags&PMF_ATTACK_HELD) )//only do this if just pressed attack button?
03688                                 {//get attack move from movement command
03689                                         /*
03690                                         if ( PM_SaberKataDone() )
03691                                         {//we came from a bounce and cannot chain to another attack because our kata is done
03692                                                 newmove = saberMoveData[curmove].chain_idle;
03693                                         }
03694                                         else */
03695                                         newmove = PM_SaberAttackForMovement( curmove );
03696                                         if ( (PM_SaberInBounce( curmove )||PM_SaberInBrokenParry( curmove ))
03697                                                 && saberMoveData[newmove].startQuad == saberMoveData[curmove].endQuad )
03698                                         {//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
03699                                                 newmove = saberMoveData[curmove].chain_attack;
03700                                         }
03701 
03702                                         if ( PM_SaberKataDone( curmove, newmove ) )
03703                                         {//cannot chain this time
03704                                                 newmove = saberMoveData[curmove].chain_idle;
03705                                         }
03706                                 }
03707                                 /*
03708                                 if ( newmove == LS_NONE )
03709                                 {//FIXME: should we allow this?  Are there some anims that you should never be able to chain into an attack?
03710                                         //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
03711                                         newmove = PM_AttackMoveForQuad( saberMoveData[curmove].endQuad );
03712                                 }
03713                                 */
03714                                 if ( newmove != LS_NONE )
03715                                 {
03716                                         //Now get the proper transition move
03717                                         newmove = PM_SaberAnimTransitionAnim( curmove, newmove );
03718                                         anim = saberMoveData[newmove].animToUse;
03719                                 }
03720                         }
03721 
03722                         if (anim == -1)
03723                         {//not side-stepping, pick neutral anim
03724                                 // Add randomness for prototype?
03725                                 newmove = saberMoveData[curmove].chain_attack;
03726 
03727                                 anim= saberMoveData[newmove].animToUse;
03728 
03729                                 if ( !pm->cmd.forwardmove && !pm->cmd.rightmove && pm->cmd.upmove >= 0 && pm->ps->groundEntityNum != ENTITYNUM_NONE )
03730                                 {//not moving at all, so set the anim on entire body
03731                                         both = qtrue;
03732                                 }
03733                         
03734                         }
03735 
03736                         if ( anim == -1)
03737                         {
03738                                 switch ( pm->ps->legsAnim )
03739                                 {
03740                                 case BOTH_WALK1:
03741                                 case BOTH_WALK2:
03742                                 case BOTH_WALK_STAFF:
03743                                 case BOTH_WALK_DUAL:
03744                                 case BOTH_WALKBACK1:
03745                                 case BOTH_WALKBACK2:
03746                                 case BOTH_WALKBACK_STAFF:
03747                                 case BOTH_WALKBACK_DUAL:
03748                                 case BOTH_RUN1:
03749                                 case BOTH_RUN2:
03750                                 case BOTH_RUN_STAFF:
03751                                 case BOTH_RUN_DUAL:
03752                                 case BOTH_RUNBACK1:
03753                                 case BOTH_RUNBACK2:
03754                                 case BOTH_RUNBACK_STAFF:
03755                                         anim = pm->ps->legsAnim;
03756                                         break;
03757                                 default:
03758                                         anim = PM_GetSaberStance();
03759                                         break;
03760                                 }
03761 
03762 //                              if (PM_RunningAnim(anim) && !pm->cmd.forwardmove && !pm->cmd.rightmove)
03763 //                              { //semi-hacky (if not moving on x-y and still playing the running anim, force the player out of it)
03764 //                                      anim = PM_GetSaberStance();
03765 //                              }
03766                                 newmove = LS_READY;
03767                         }
03768 
03769                         PM_SetSaberMove( newmove );
03770 
03771                         if ( both && pm->ps->torsoAnim == anim )
03772                         {
03773                                 PM_SetAnim(SETANIM_LEGS,anim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD, 100);
03774                         }
03775 
03776                         //don't fire again until anim is done
03777                         pm->ps->weaponTime = pm->ps->torsoTimer;
03778                 }
03779         }
03780 
03781         // *********************************************************
03782         // WEAPON_FIRING
03783         // *********************************************************
03784 
03785         pm->ps->weaponstate = WEAPON_FIRING;
03786 
03787         amount = weaponData[pm->ps->weapon].energyPerShot;
03788 
03789         addTime = pm->ps->weaponTime;
03790 
03791         pm->ps->saberAttackSequence = pm->ps->torsoAnim;
03792         if ( !addTime )
03793         {
03794                 addTime = weaponData[pm->ps->weapon].fireTime;
03795         }
03796         pm->ps->weaponTime = addTime;
03797 }
03798 
03799 void PM_SetSaberMove(short newMove)
03800 {
03801         unsigned int setflags = saberMoveData[newMove].animSetFlags;
03802         int     anim = saberMoveData[newMove].animToUse;
03803         int parts = SETANIM_TORSO;
03804 
03805         if ( newMove == LS_READY || newMove == LS_A_FLIP_STAB || newMove == LS_A_FLIP_SLASH )
03806         {//finished with a kata (or in a special move) reset attack counter
03807                 pm->ps->saberAttackChainCount = 0;
03808         }
03809         else if ( BG_SaberInAttack( newMove ) )
03810         {//continuing with a kata, increment attack counter
03811                 pm->ps->saberAttackChainCount++;
03812         }
03813 
03814         if (pm->ps->saberAttackChainCount > 16)
03815         { //for the sake of being able to send the value over the net within a reasonable bit count
03816                 pm->ps->saberAttackChainCount = 16;
03817         }
03818 
03819         if ( newMove == LS_DRAW )
03820         {
03821                 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
03822                 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
03823                 if ( saber1 
03824                         && saber1->drawAnim != -1 )
03825                 {
03826                         anim = saber1->drawAnim;
03827                 }
03828                 else if ( saber2 
03829                         && saber2->drawAnim != -1 )
03830                 {
03831                         anim = saber2->drawAnim;
03832                 }
03833                 else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
03834                 {
03835                         anim = BOTH_S1_S7;
03836                 }
03837                 else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
03838                 {
03839                         anim = BOTH_S1_S6;
03840                 }
03841         }
03842         else if ( newMove == LS_PUTAWAY )
03843         {
03844                 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
03845                 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
03846                 if ( saber1 
03847                         && saber1->putawayAnim != -1 )
03848                 {
03849                         anim = saber1->putawayAnim;
03850                 }
03851                 else if ( saber2 
03852                         && saber2->putawayAnim != -1 )
03853                 {
03854                         anim = saber2->putawayAnim;
03855                 }
03856                 else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
03857                 {
03858                         anim = BOTH_S7_S1;
03859                 }
03860                 else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
03861                 {
03862                         anim = BOTH_S6_S1;
03863                 }
03864         }
03865         else if ( pm->ps->fd.saberAnimLevel == SS_STAFF && newMove >= LS_S_TL2BR && newMove < LS_REFLECT_LL )
03866         {//staff has an entirely new set of anims, besides special attacks
03867                 //FIXME: include ready and draw/putaway?
03868                 //FIXME: get hand-made bounces and deflections?
03869                 if ( newMove >= LS_V1_BR && newMove <= LS_REFLECT_LL )
03870                 {//there aren't 1-7, just 1, 6 and 7, so just set it
03871                         anim = BOTH_P7_S7_T_ + (anim-BOTH_P1_S1_T_);//shift it up to the proper set
03872                 }
03873                 else
03874                 {//add the appropriate animLevel
03875                         anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
03876                 }
03877         }
03878         else if ( pm->ps->fd.saberAnimLevel == SS_DUAL && newMove >= LS_S_TL2BR && newMove < LS_REFLECT_LL )
03879         { //akimbo has an entirely new set of anims, besides special attacks
03880                 //FIXME: include ready and draw/putaway?
03881                 //FIXME: get hand-made bounces and deflections?
03882                 if ( newMove >= LS_V1_BR && newMove <= LS_REFLECT_LL )
03883                 {//there aren't 1-7, just 1, 6 and 7, so just set it
03884                         anim = BOTH_P6_S6_T_ + (anim-BOTH_P1_S1_T_);//shift it up to the proper set
03885                 }
03886                 else
03887                 {//add the appropriate animLevel
03888                         anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
03889                 }
03890         }
03891         /*
03892         else if ( newMove == LS_DRAW && pm->ps->SaberStaff() )
03893         {//hold saber out front as we turn it on
03894                 //FIXME: need a real "draw" anim for this (and put-away)
03895                 anim = BOTH_SABERSTAFF_STANCE;
03896         }
03897         */
03898         else if ( pm->ps->fd.saberAnimLevel > FORCE_LEVEL_1 &&
03899                  !BG_SaberInIdle( newMove ) && !PM_SaberInParry( newMove ) && !PM_SaberInKnockaway( newMove ) && !PM_SaberInBrokenParry( newMove ) && !PM_SaberInReflect( newMove ) && !BG_SaberInSpecial(newMove))
03900         {//readies, parries and reflections have only 1 level 
03901                 anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
03902         }
03903 
03904         // If the move does the same animation as the last one, we need to force a restart...
03905         if ( saberMoveData[pm->ps->saberMove].animToUse == anim && newMove > LS_PUTAWAY)
03906         {
03907                 setflags |= SETANIM_FLAG_RESTART;
03908         }
03909 
03910         //saber torso anims should always be highest priority (4/12/02 - for special anims only)
03911         if (!pm->ps->m_iVehicleNum)
03912         { //if not riding a vehicle
03913                 if (BG_SaberInSpecial(newMove))
03914                 {
03915                         setflags |= SETANIM_FLAG_OVERRIDE;
03916                 }
03917                 /*
03918                 if ( newMove == LS_A_LUNGE 
03919                         || newMove == LS_A_JUMP_T__B_ 
03920                         || newMove == LS_A_BACKSTAB
03921                         || newMove == LS_A_BACK
03922                         || newMove == LS_A_BACK_CR
03923                         || newMove == LS_A_FLIP_STAB
03924                         || newMove == LS_A_FLIP_SLASH
03925                         || newMove == LS_JUMPATTACK_DUAL
03926                         || newMove == LS_A_BACKFLIP_ATK)
03927                 {
03928                         setflags |= SETANIM_FLAG_OVERRIDE;
03929                 }
03930                 */
03931         }
03932         if ( BG_InSaberStandAnim(anim) || anim == BOTH_STAND1 )
03933         {
03934                 anim = (pm->ps->legsAnim);
03935 
03936                 if ((anim >= BOTH_STAND1 && anim <= BOTH_STAND4TOATTACK2) ||
03937                         (anim >= TORSO_DROPWEAP1 && anim <= TORSO_WEAPONIDLE10))
03938                 { //If standing then use the special saber stand anim
03939                         anim = PM_GetSaberStance();
03940                 }
03941 
03942                 if (pm->ps->pm_flags & PMF_DUCKED)
03943                 { //Playing torso walk anims while crouched makes you look like a monkey
03944                         anim = PM_GetSaberStance();
03945                 }
03946 
03947                 if (anim == BOTH_WALKBACK1 || anim == BOTH_WALKBACK2 || anim == BOTH_WALK1)
03948                 { //normal stance when walking backward so saber doesn't look like it's cutting through leg
03949                         anim = PM_GetSaberStance();
03950                 }
03951 
03952                 if (BG_InSlopeAnim( anim ))
03953                 {
03954                         anim = PM_GetSaberStance();
03955                 }
03956 
03957                 parts = SETANIM_TORSO;
03958         }
03959 
03960         if (!pm->ps->m_iVehicleNum)
03961         { //if not riding a vehicle
03962                 if (newMove == LS_JUMPATTACK_ARIAL_RIGHT ||
03963                                 newMove == LS_JUMPATTACK_ARIAL_LEFT)
03964                 { //force only on legs
03965                         parts = SETANIM_LEGS;
03966                 }
03967                 else if ( newMove == LS_A_LUNGE 
03968                                 || newMove == LS_A_JUMP_T__B_ 
03969                                 || newMove == LS_A_BACKSTAB
03970                                 || newMove == LS_A_BACK
03971                                 || newMove == LS_A_BACK_CR
03972                                 || newMove == LS_ROLL_STAB
03973                                 || newMove == LS_A_FLIP_STAB
03974                                 || newMove == LS_A_FLIP_SLASH
03975                                 || newMove == LS_JUMPATTACK_DUAL
03976                                 || newMove == LS_JUMPATTACK_ARIAL_LEFT
03977                                 || newMove == LS_JUMPATTACK_ARIAL_RIGHT
03978                                 || newMove == LS_JUMPATTACK_CART_LEFT
03979                                 || newMove == LS_JUMPATTACK_CART_RIGHT
03980                                 || newMove == LS_JUMPATTACK_STAFF_LEFT
03981                                 || newMove == LS_JUMPATTACK_STAFF_RIGHT
03982                                 || newMove == LS_A_BACKFLIP_ATK
03983                                 || newMove == LS_STABDOWN
03984                                 || newMove == LS_STABDOWN_STAFF
03985                                 || newMove == LS_STABDOWN_DUAL
03986                                 || newMove == LS_DUAL_SPIN_PROTECT
03987                                 || newMove == LS_STAFF_SOULCAL
03988                                 || newMove == LS_A1_SPECIAL
03989                                 || newMove == LS_A2_SPECIAL
03990                                 || newMove == LS_A3_SPECIAL
03991                                 || newMove == LS_UPSIDE_DOWN_ATTACK
03992                                 || newMove == LS_PULL_ATTACK_STAB
03993                                 || newMove == LS_PULL_ATTACK_SWING
03994                                 || BG_KickMove( newMove ) )
03995                 {
03996                         parts = SETANIM_BOTH;
03997                 }
03998                 else if ( BG_SpinningSaberAnim( anim ) )
03999                 {//spins must be played on entire body
04000                         parts = SETANIM_BOTH;
04001                 }
04002                 else if ( (!pm->cmd.forwardmove&&!pm->cmd.rightmove&&!pm->cmd.upmove))
04003                 {//not trying to run, duck or jump
04004                         if ( !BG_FlippingAnim( pm->ps->legsAnim ) && 
04005                                 !BG_InRoll( pm->ps, pm->ps->legsAnim ) && 
04006                                 !PM_InKnockDown( pm->ps ) && 
04007                                 !PM_JumpingAnim( pm->ps->legsAnim ) &&
04008                                 !BG_InSpecialJump( pm->ps->legsAnim ) &&
04009                                 anim != PM_GetSaberStance() &&
04010                                 pm->ps->groundEntityNum != ENTITYNUM_NONE &&
04011                                 !(pm->ps->pm_flags & PMF_DUCKED))
04012                         {
04013                                 parts = SETANIM_BOTH;
04014                         }
04015                         else if ( !(pm->ps->pm_flags & PMF_DUCKED) 
04016                                 && ( newMove == LS_SPINATTACK_DUAL || newMove == LS_SPINATTACK ) )
04017                         {
04018                                 parts = SETANIM_BOTH;
04019                         }
04020                 }
04021 
04022                 PM_SetAnim(parts, anim, setflags, saberMoveData[newMove].blendTime);
04023                 if (parts != SETANIM_LEGS &&
04024                         (pm->ps->legsAnim == BOTH_ARIAL_LEFT ||
04025                         pm->ps->legsAnim == BOTH_ARIAL_RIGHT))
04026                 {
04027                         if (pm->ps->legsTimer > pm->ps->torsoTimer)
04028                         {
04029                                 pm->ps->legsTimer = pm->ps->torsoTimer;
04030                         }
04031                 }
04032 
04033         }
04034 
04035         if ( (pm->ps->torsoAnim) == anim )
04036         {//successfully changed anims
04037         //special check for *starting* a saber swing
04038                 //playing at attack
04039                 if ( BG_SaberInAttack( newMove ) || BG_SaberInSpecialAttack( anim ) )
04040                 {
04041                         if ( pm->ps->saberMove != newMove )
04042                         {//wasn't playing that attack before
04043                                 if ( newMove != LS_KICK_F
04044                                         && newMove != LS_KICK_B
04045                                         && newMove != LS_KICK_R
04046                                         && newMove != LS_KICK_L
04047                                         && newMove != LS_KICK_F_AIR
04048                                         && newMove != LS_KICK_B_AIR
04049                                         && newMove != LS_KICK_R_AIR
04050                                         && newMove != LS_KICK_L_AIR )
04051                                 {
04052                     PM_AddEvent(EV_SABER_ATTACK);
04053                                 }
04054 
04055                                 if (pm->ps->brokenLimbs)
04056                                 { //randomly make pain sounds with a broken arm because we are suffering.
04057                                         int iFactor = -1;
04058 
04059                                         if (pm->ps->brokenLimbs & (1<<BROKENLIMB_RARM))
04060                                         { //You're using it more. So it hurts more.
04061                                                 iFactor = 5;
04062                                         }
04063                                         else if (pm->ps->brokenLimbs & (1<<BROKENLIMB_LARM))
04064                                         {
04065                                                 iFactor = 10;
04066                                         }
04067 
04068                                         if (iFactor != -1)
04069                                         {
04070                                                 if ( !PM_irand_timesync( 0, iFactor ) )
04071                                                 {
04072                                                         BG_AddPredictableEventToPlayerstate(EV_PAIN, PM_irand_timesync( 1, 100 ), pm->ps);
04073                                                 }
04074                                         }
04075                                 }
04076                         }
04077                 }
04078 
04079                 if (BG_SaberInSpecial(newMove) &&
04080                         pm->ps->weaponTime < pm->ps->torsoTimer)
04081                 { //rww 01-02-03 - I think this will solve the issue of special attacks being interruptable, hopefully without side effects
04082                         pm->ps->weaponTime = pm->ps->torsoTimer;
04083                 }
04084 
04085                 pm->ps->saberMove = newMove;
04086                 pm->ps->saberBlocking = saberMoveData[newMove].blocking;
04087 
04088                 pm->ps->torsoAnim = anim;
04089 
04090                 if (pm->ps->weaponTime <= 0)
04091                 {
04092                         pm->ps->saberBlocked = BLOCKED_NONE;
04093                 }
04094         }
04095 }
04096 
04097 saberInfo_t *BG_MySaber( int clientNum, int saberNum )
04098 {
04099         //returns a pointer to the requested saberNum
04100 #ifdef QAGAME
04101         gentity_t *ent = &g_entities[clientNum];
04102         if ( ent->inuse && ent->client )
04103         {
04104                 if ( !ent->client->saber[saberNum].model 
04105                         || !ent->client->saber[saberNum].model[0] )
04106                 { //don't have saber anymore!
04107                         return NULL;
04108                 }
04109                 return &ent->client->saber[saberNum];
04110         }
04111 #elif defined CGAME
04112         clientInfo_t *ci = NULL;
04113         if (clientNum < MAX_CLIENTS)
04114         {
04115                 ci = &cgs.clientinfo[clientNum];
04116         }
04117         else
04118         {
04119                 centity_t *cent = &cg_entities[clientNum];
04120                 if (cent->npcClient)
04121                 {
04122                         ci = cent->npcClient;
04123                 }
04124         }
04125         if ( ci 
04126                 && ci->infoValid )
04127         {
04128                 if ( !ci->saber[saberNum].model 
04129                         || !ci->saber[saberNum].model[0] )
04130                 { //don't have sabers anymore!
04131                         return NULL;
04132                 }
04133                 return &ci->saber[saberNum];
04134         }
04135 #endif
04136 
04137         return NULL;
04138 }
04139 
04140 #include "../namespace_end.h"