1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2013 - 2015, OpenJK contributors
7
8 This file is part of the OpenJK source code.
9
10 OpenJK is free software; you can redistribute it and/or modify it
11 under the terms of the GNU General Public License version 2 as
12 published by the Free Software Foundation.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, see <http://www.gnu.org/licenses/>.
21 ===========================================================================
22 */
23
24 #include "qcommon/q_shared.h"
25 #include "bg_public.h"
26 #include "bg_local.h"
27 #include "w_saber.h"
28
29 extern qboolean BG_SabersOff( playerState_t *ps );
30 saberInfo_t *BG_MySaber( int clientNum, int saberNum );
31
PM_irand_timesync(int val1,int val2)32 int PM_irand_timesync(int val1, int val2)
33 {
34 int i;
35
36 i = (val1-1) + (Q_random( &pm->cmd.serverTime )*(val2 - val1)) + 1;
37 if (i < val1)
38 {
39 i = val1;
40 }
41 if (i > val2)
42 {
43 i = val2;
44 }
45
46 return i;
47 }
48
BG_ForcePowerDrain(playerState_t * ps,forcePowers_t forcePower,int overrideAmt)49 void BG_ForcePowerDrain( playerState_t *ps, forcePowers_t forcePower, int overrideAmt )
50 {
51 //take away the power
52 int drain = overrideAmt;
53
54 /*
55 if (ps->powerups[PW_FORCE_BOON])
56 {
57 return;
58 }
59 */
60 //No longer grant infinite force with boon.
61
62 if ( !drain )
63 {
64 drain = forcePowerNeeded[ps->fd.forcePowerLevel[forcePower]][forcePower];
65 }
66 if ( !drain )
67 {
68 return;
69 }
70
71 if (forcePower == FP_LEVITATION)
72 { //special case
73 int jumpDrain = 0;
74
75 if (ps->velocity[2] > 250)
76 {
77 jumpDrain = 20;
78 }
79 else if (ps->velocity[2] > 200)
80 {
81 jumpDrain = 16;
82 }
83 else if (ps->velocity[2] > 150)
84 {
85 jumpDrain = 12;
86 }
87 else if (ps->velocity[2] > 100)
88 {
89 jumpDrain = 8;
90 }
91 else if (ps->velocity[2] > 50)
92 {
93 jumpDrain = 6;
94 }
95 else if (ps->velocity[2] > 0)
96 {
97 jumpDrain = 4;
98 }
99
100 if (jumpDrain)
101 {
102 if (ps->fd.forcePowerLevel[FP_LEVITATION])
103 { //don't divide by 0!
104 jumpDrain /= ps->fd.forcePowerLevel[FP_LEVITATION];
105 }
106 }
107
108 ps->fd.forcePower -= jumpDrain;
109 if ( ps->fd.forcePower < 0 )
110 {
111 ps->fd.forcePower = 0;
112 }
113
114 return;
115 }
116
117 ps->fd.forcePower -= drain;
118 if ( ps->fd.forcePower < 0 )
119 {
120 ps->fd.forcePower = 0;
121 }
122 }
123
BG_EnoughForcePowerForMove(int cost)124 qboolean BG_EnoughForcePowerForMove( int cost )
125 {
126 if ( pm->ps->fd.forcePower < cost )
127 {
128 PM_AddEvent( EV_NOAMMO );
129 return qfalse;
130 }
131
132 return qtrue;
133 }
134
135 // Silly, but I'm replacing these macros so they are shorter!
136 #define AFLAG_IDLE (SETANIM_FLAG_NORMAL)
137 #define AFLAG_ACTIVE (SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS)
138 #define AFLAG_WAIT (SETANIM_FLAG_HOLD | SETANIM_FLAG_HOLDLESS)
139 #define AFLAG_FINISH (SETANIM_FLAG_HOLD)
140
141 //FIXME: add the alternate anims for each style?
142 saberMoveData_t saberMoveData[LS_MOVE_MAX] = {// NB:randomized
143 // name anim(do all styles?)startQ endQ setanimflag blend, blocking chain_idle chain_attack trailLen
144 {"None", BOTH_STAND1, Q_R, Q_R, AFLAG_IDLE, 350, BLK_NO, LS_NONE, LS_NONE, 0 }, // LS_NONE = 0,
145
146 // General movements with saber
147 {"Ready", BOTH_STAND2, Q_R, Q_R, AFLAG_IDLE, 350, BLK_WIDE, LS_READY, LS_S_R2L, 0 }, // LS_READY,
148 {"Draw", BOTH_STAND1TO2, Q_R, Q_R, AFLAG_FINISH, 350, BLK_NO, LS_READY, LS_S_R2L, 0 }, // LS_DRAW,
149 {"Putaway", BOTH_STAND2TO1, Q_R, Q_R, AFLAG_FINISH, 350, BLK_NO, LS_READY, LS_S_R2L, 0 }, // LS_PUTAWAY,
150
151 // Attacks
152 //UL2LR
153 {"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
154 //SLASH LEFT
155 {"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
156 //LL2UR
157 {"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
158 //LR2UL
159 {"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
160 //SLASH RIGHT
161 {"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
162 //UR2LL
163 {"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
164 //SLASH DOWN
165 {"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
166 //special attacks
167 {"Back Stab", BOTH_A2_STABBACK1, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_BACKSTAB
168 {"Back Att", BOTH_ATTACK_BACK, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_BACK
169 {"CR Back Att", BOTH_CROUCHATTACKBACK1,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_BACK_CR
170 {"RollStab", BOTH_ROLL_STAB, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_ROLL_STAB
171 {"Lunge Att", BOTH_LUNGE2_B__T_, Q_B, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_A_LUNGE
172 {"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_
173 {"Flip Stab", BOTH_JUMPFLIPSTABDOWN,Q_R, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1_T___R, 200 }, // LS_A_FLIP_STAB
174 {"Flip Slash", BOTH_JUMPFLIPSLASHDOWN1,Q_L,Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__R_T_, 200 }, // LS_A_FLIP_SLASH
175 {"DualJump Atk",BOTH_JUMPATTACK6, Q_R, Q_BL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1_BL_TR, 200 }, // LS_JUMPATTACK_DUAL
176
177 {"DualJumpAtkL_A",BOTH_ARIAL_LEFT, Q_R, Q_TL, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_A_TL2BR, 200 }, // LS_JUMPATTACK_ARIAL_LEFT
178 {"DualJumpAtkR_A",BOTH_ARIAL_RIGHT, Q_R, Q_TR, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_A_TR2BL, 200 }, // LS_JUMPATTACK_ARIAL_RIGHT
179
180 {"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
181 {"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
182
183 {"DualJumpAtkLStaff", BOTH_BUTTERFLY_FL1,Q_R,Q_L, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__L__R, 200 }, // LS_JUMPATTACK_STAFF_LEFT
184 {"DualJumpAtkRStaff", BOTH_BUTTERFLY_FR1,Q_R,Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__R__L, 200 }, // LS_JUMPATTACK_STAFF_RIGHT
185
186 {"ButterflyLeft", BOTH_BUTTERFLY_LEFT,Q_R,Q_L, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__L__R, 200 }, // LS_BUTTERFLY_LEFT
187 {"ButterflyRight", BOTH_BUTTERFLY_RIGHT,Q_R,Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1__R__L, 200 }, // LS_BUTTERFLY_RIGHT
188
189 {"BkFlip Atk", BOTH_JUMPATTACK7, Q_B, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_T1_T___R, 200 }, // LS_A_BACKFLIP_ATK
190 {"DualSpinAtk", BOTH_SPINATTACK6, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SPINATTACK_DUAL
191 {"StfSpinAtk", BOTH_SPINATTACK7, Q_L, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SPINATTACK
192 {"LngLeapAtk", BOTH_FORCELONGLEAP_ATTACK,Q_R,Q_L, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_LEAP_ATTACK
193 {"SwoopAtkR", BOTH_VS_ATR_S, Q_R, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SWOOP_ATTACK_RIGHT
194 {"SwoopAtkL", BOTH_VS_ATL_S, Q_L, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SWOOP_ATTACK_LEFT
195 {"TauntaunAtkR",BOTH_VT_ATR_S, Q_R, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_TAUNTAUN_ATTACK_RIGHT
196 {"TauntaunAtkL",BOTH_VT_ATL_S, Q_L, Q_T, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_TAUNTAUN_ATTACK_LEFT
197 {"StfKickFwd", BOTH_A7_KICK_F, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_F
198 {"StfKickBack", BOTH_A7_KICK_B, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_B
199 {"StfKickRight",BOTH_A7_KICK_R, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_R
200 {"StfKickLeft", BOTH_A7_KICK_L, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_KICK_L
201 {"StfKickSpin", BOTH_A7_KICK_S, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_S_R2L, 200 }, // LS_KICK_S
202 {"StfKickBkFwd",BOTH_A7_KICK_BF, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_S_R2L, 200 }, // LS_KICK_BF
203 {"StfKickSplit",BOTH_A7_KICK_RL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_S_R2L, 200 }, // LS_KICK_RL
204 {"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
205 {"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
206 {"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
207 {"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
208 {"StabDown", BOTH_STABDOWN, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_STABDOWN
209 {"StabDownStf", BOTH_STABDOWN_STAFF,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_STABDOWN_STAFF
210 {"StabDownDual",BOTH_STABDOWN_DUAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_S_R2L, 200 }, // LS_STABDOWN_DUAL
211 {"dualspinprot",BOTH_A6_SABERPROTECT,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 500 }, // LS_DUAL_SPIN_PROTECT
212 {"StfSoulCal", BOTH_A7_SOULCAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 500 }, // LS_STAFF_SOULCAL
213 {"specialfast", BOTH_A1_SPECIAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 2000}, // LS_A1_SPECIAL
214 {"specialmed", BOTH_A2_SPECIAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 2000}, // LS_A2_SPECIAL
215 {"specialstr", BOTH_A3_SPECIAL, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 2000}, // LS_A3_SPECIAL
216 {"upsidedwnatk",BOTH_FLIP_ATTACK7, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200}, // LS_UPSIDE_DOWN_ATTACK
217 {"pullatkstab", BOTH_PULL_IMPALE_STAB,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200}, // LS_PULL_ATTACK_STAB
218 {"pullatkswing",BOTH_PULL_IMPALE_SWING,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200}, // LS_PULL_ATTACK_SWING
219 {"AloraSpinAtk",BOTH_ALORA_SPIN_SLASH,Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_SPINATTACK_ALORA
220 {"Dual FB Atk", BOTH_A6_FB, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_DUAL_FB
221 {"Dual LR Atk", BOTH_A6_LR, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_DUAL_LR
222 {"StfHiltBash", BOTH_A7_HILT, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_HILT_BASH
223
224 //starts
225 {"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
226 {"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
227 {"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
228 {"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
229 {"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
230 {"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
231 {"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
232
233 //returns
234 {"TL2BR Ret", BOTH_R1_BR_S1, Q_BR, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_TL2BR
235 {"L2R Ret", BOTH_R1__R_S1, Q_R, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_L2R
236 {"BL2TR Ret", BOTH_R1_TR_S1, Q_TR, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_BL2TR
237 {"BR2TL Ret", BOTH_R1_TL_S1, Q_TL, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_BR2TL
238 {"R2L Ret", BOTH_R1__L_S1, Q_L, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_R2L
239 {"TR2BL Ret", BOTH_R1_BL_S1, Q_BL, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_TR2BL
240 {"T2B Ret", BOTH_R1_B__S1, Q_B, Q_R, AFLAG_FINISH, 100, BLK_TIGHT, LS_READY, LS_READY, 200 }, // LS_R_T2B
241
242 //Transitions
243 {"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
244 {"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)
245 {"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)
246 {"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
247 {"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
248 {"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
249 {"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)
250 {"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
251 {"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)
252 {"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
253 {"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
254 {"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
255 {"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
256 {"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)
257 {"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)
258 {"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
259 {"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
260 {"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
261 {"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
262 {"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
263 {"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
264 {"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
265 {"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
266 {"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
267 {"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
268 {"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)
269 {"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)
270 {"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)
271 {"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)
272 {"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
273 {"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
274 {"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
275 {"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)
276 {"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)
277 {"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
278 {"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)
279 {"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
280 {"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
281 {"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
282 {"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)
283 {"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)
284 {"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
285
286 //Bounces
287 {"Bounce BR", BOTH_B1_BR___, Q_BR, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_T1_BR_TR, 150 },
288 {"Bounce R", BOTH_B1__R___, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_T1__R__L, 150 },
289 {"Bounce TR", BOTH_B1_TR___, Q_TR, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_TR_TL, 150 },
290 {"Bounce T", BOTH_B1_T____, Q_T, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_T__BL, 150 },
291 {"Bounce TL", BOTH_B1_TL___, Q_TL, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_T1_TL_TR, 150 },
292 {"Bounce L", BOTH_B1__L___, Q_L, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_T1__L__R, 150 },
293 {"Bounce BL", BOTH_B1_BL___, Q_BL, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_T1_BL_TR, 150 },
294
295 //Deflected attacks (like bounces, but slide off enemy saber, not straight back)
296 {"Deflect BR", BOTH_D1_BR___, Q_BR, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TL2BR, LS_T1_BR_TR, 150 },
297 {"Deflect R", BOTH_D1__R___, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_R_L2R, LS_T1__R__L, 150 },
298 {"Deflect TR", BOTH_D1_TR___, Q_TR, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_TR_TL, 150 },
299 {"Deflect T", BOTH_B1_T____, Q_T, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_T__BL, 150 },
300 {"Deflect TL", BOTH_D1_TL___, Q_TL, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BR2TL, LS_T1_TL_TR, 150 },
301 {"Deflect L", BOTH_D1__L___, Q_L, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_R_R2L, LS_T1__L__R, 150 },
302 {"Deflect BL", BOTH_D1_BL___, Q_BL, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_R_TR2BL, LS_T1_BL_TR, 150 },
303 {"Deflect B", BOTH_D1_B____, Q_B, Q_B, AFLAG_ACTIVE, 100, BLK_NO, LS_R_BL2TR, LS_T1_T__BL, 150 },
304
305 //Reflected attacks
306 {"Reflected BR",BOTH_V1_BR_S1, Q_BR, Q_BR, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_BR
307 {"Reflected R", BOTH_V1__R_S1, Q_R, Q_R, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1__R
308 {"Reflected TR",BOTH_V1_TR_S1, Q_TR, Q_TR, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_TR
309 {"Reflected T", BOTH_V1_T__S1, Q_T, Q_T, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_T_
310 {"Reflected TL",BOTH_V1_TL_S1, Q_TL, Q_TL, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_TL
311 {"Reflected L", BOTH_V1__L_S1, Q_L, Q_L, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1__L
312 {"Reflected BL",BOTH_V1_BL_S1, Q_BL, Q_BL, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_BL
313 {"Reflected B", BOTH_V1_B__S1, Q_B, Q_B, AFLAG_ACTIVE, 100, BLK_NO, LS_READY, LS_READY, 150 },// LS_V1_B_
314
315 // Broken parries
316 {"BParry Top", BOTH_H1_S1_T_, Q_T, Q_B, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UP,
317 {"BParry UR", BOTH_H1_S1_TR, Q_TR, Q_BL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UR,
318 {"BParry UL", BOTH_H1_S1_TL, Q_TL, Q_BR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_UL,
319 {"BParry LR", BOTH_H1_S1_BR, Q_BL, Q_TR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LR,
320 {"BParry Bot", BOTH_H1_S1_B_, Q_B, Q_T, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LR
321 {"BParry LL", BOTH_H1_S1_BL, Q_BR, Q_TL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LL
322 //{"BParry LR", BOTH_H1_S1_BL, Q_BL, Q_TR, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LR,
323 //{"BParry Bot", BOTH_H1_S1_B_, Q_B, Q_T, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LL
324 //{"BParry LL", BOTH_H1_S1_BR, Q_BR, Q_TL, AFLAG_ACTIVE, 50, BLK_NO, LS_READY, LS_READY, 150 }, // LS_PARRY_LL
325
326 // Knockaways
327 {"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,
328 {"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,
329 {"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,
330 {"Knock LR", BOTH_K1_S1_BR, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_T1_BL_TL, 150 }, // LS_PARRY_LR,
331 {"Knock LL", BOTH_K1_S1_BL, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_T1_BR_TR, 150 }, // LS_PARRY_LL
332 //{"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,
333 //{"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
334
335 // Parry
336 {"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,
337 {"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,
338 {"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,
339 {"Parry LR", BOTH_P1_S1_BR, Q_R, Q_BR, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TL2BR, LS_A_BR2TL, 150 }, // LS_PARRY_LR,
340 {"Parry LL", BOTH_P1_S1_BL, Q_R, Q_BL, AFLAG_ACTIVE, 50, BLK_WIDE, LS_R_TR2BL, LS_A_BL2TR, 150 }, // LS_PARRY_LL
341 //{"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,
342 //{"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
343
344 // Reflecting a missile
345 {"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,
346 {"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,
347 {"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,
348 {"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
349 {"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,
350 };
351
352 int transitionMove[Q_NUM_QUADS][Q_NUM_QUADS] =
353 {
354 { LS_NONE, LS_T1_BR__R, LS_T1_BR_TR, LS_T1_BR_T_, LS_T1_BR_TL, LS_T1_BR__L, LS_T1_BR_BL, LS_NONE },
355 { LS_T1__R_BR, LS_NONE, LS_T1__R_TR, LS_T1__R_T_, LS_T1__R_TL, LS_T1__R__L, LS_T1__R_BL, LS_NONE },
356 { LS_T1_TR_BR, LS_T1_TR__R, LS_NONE, LS_T1_TR_T_, LS_T1_TR_TL, LS_T1_TR__L, LS_T1_TR_BL, LS_NONE },
357 { LS_T1_T__BR, LS_T1_T___R, LS_T1_T__TR, LS_NONE, LS_T1_T__TL, LS_T1_T___L, LS_T1_T__BL, LS_NONE },
358 { LS_T1_TL_BR, LS_T1_TL__R, LS_T1_TL_TR, LS_T1_TL_T_, LS_NONE, LS_T1_TL__L, LS_T1_TL_BL, LS_NONE },
359 { LS_T1__L_BR, LS_T1__L__R, LS_T1__L_TR, LS_T1__L_T_, LS_T1__L_TL, LS_NONE, LS_T1__L_BL, LS_NONE },
360 { LS_T1_BL_BR, LS_T1_BL__R, LS_T1_BL_TR, LS_T1_BL_T_, LS_T1_BL_TL, LS_T1_BL__L, LS_NONE, LS_NONE },
361 { LS_T1_BL_BR, LS_T1_BR__R, LS_T1_BR_TR, LS_T1_BR_T_, LS_T1_BR_TL, LS_T1_BR__L, LS_T1_BR_BL, LS_NONE },
362 };
363
PM_AttackMoveForQuad(int quad)364 saberMoveName_t PM_AttackMoveForQuad( int quad )
365 {
366 switch ( quad )
367 {
368 case Q_B:
369 case Q_BR:
370 return LS_A_BR2TL;
371 break;
372 case Q_R:
373 return LS_A_R2L;
374 break;
375 case Q_TR:
376 return LS_A_TR2BL;
377 break;
378 case Q_T:
379 return LS_A_T2B;
380 break;
381 case Q_TL:
382 return LS_A_TL2BR;
383 break;
384 case Q_L:
385 return LS_A_L2R;
386 break;
387 case Q_BL:
388 return LS_A_BL2TR;
389 break;
390 }
391 return LS_NONE;
392 }
393
394 qboolean PM_SaberKataDone(int curmove, int newmove);
395
PM_SaberAnimTransitionAnim(int curmove,int newmove)396 int PM_SaberAnimTransitionAnim( int curmove, int newmove )
397 {
398 int retmove = newmove;
399 if ( curmove == LS_READY )
400 {//just standing there
401 switch ( newmove )
402 {
403 case LS_A_TL2BR:
404 case LS_A_L2R:
405 case LS_A_BL2TR:
406 case LS_A_BR2TL:
407 case LS_A_R2L:
408 case LS_A_TR2BL:
409 case LS_A_T2B:
410 //transition is the start
411 retmove = LS_S_TL2BR + (newmove-LS_A_TL2BR);
412 break;
413 }
414 }
415 else
416 {
417 switch ( newmove )
418 {
419 //transitioning to ready pose
420 case LS_READY:
421 switch ( curmove )
422 {
423 //transitioning from an attack
424 case LS_A_TL2BR:
425 case LS_A_L2R:
426 case LS_A_BL2TR:
427 case LS_A_BR2TL:
428 case LS_A_R2L:
429 case LS_A_TR2BL:
430 case LS_A_T2B:
431 //transition is the return
432 retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR);
433 break;
434 }
435 break;
436 //transitioning to an attack
437 case LS_A_TL2BR:
438 case LS_A_L2R:
439 case LS_A_BL2TR:
440 case LS_A_BR2TL:
441 case LS_A_R2L:
442 case LS_A_TR2BL:
443 case LS_A_T2B:
444 if ( newmove == curmove )
445 {
446 //going into an attack
447 if ( PM_SaberKataDone( curmove, newmove ) )
448 {//done with this kata, must return to ready before attack again
449 retmove = LS_R_TL2BR + (newmove-LS_A_TL2BR);
450 }
451 else
452 {//okay to chain to another attack
453 retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
454 }
455 }
456 else if ( saberMoveData[curmove].endQuad == saberMoveData[newmove].startQuad )
457 {//new move starts from same quadrant
458 retmove = newmove;
459 }
460 else
461 {
462 switch ( curmove )
463 {
464 //transitioning from an attack
465 case LS_A_TL2BR:
466 case LS_A_L2R:
467 case LS_A_BL2TR:
468 case LS_A_BR2TL:
469 case LS_A_R2L:
470 case LS_A_TR2BL:
471 case LS_A_T2B:
472 case LS_D1_BR:
473 case LS_D1__R:
474 case LS_D1_TR:
475 case LS_D1_T_:
476 case LS_D1_TL:
477 case LS_D1__L:
478 case LS_D1_BL:
479 case LS_D1_B_:
480 retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
481 break;
482 //transitioning from a return
483 case LS_R_TL2BR:
484 case LS_R_L2R:
485 case LS_R_BL2TR:
486 case LS_R_BR2TL:
487 case LS_R_R2L:
488 case LS_R_TR2BL:
489 case LS_R_T2B:
490 //transitioning from a bounce
491 /*
492 case LS_BOUNCE_UL2LL:
493 case LS_BOUNCE_LL2UL:
494 case LS_BOUNCE_L2LL:
495 case LS_BOUNCE_L2UL:
496 case LS_BOUNCE_UR2LR:
497 case LS_BOUNCE_LR2UR:
498 case LS_BOUNCE_R2LR:
499 case LS_BOUNCE_R2UR:
500 case LS_BOUNCE_TOP:
501 case LS_OVER_UR2UL:
502 case LS_OVER_UL2UR:
503 case LS_BOUNCE_UR:
504 case LS_BOUNCE_UL:
505 case LS_BOUNCE_LR:
506 case LS_BOUNCE_LL:
507 */
508 //transitioning from a parry/reflection/knockaway/broken parry
509 case LS_PARRY_UP:
510 case LS_PARRY_UR:
511 case LS_PARRY_UL:
512 case LS_PARRY_LR:
513 case LS_PARRY_LL:
514 case LS_REFLECT_UP:
515 case LS_REFLECT_UR:
516 case LS_REFLECT_UL:
517 case LS_REFLECT_LR:
518 case LS_REFLECT_LL:
519 case LS_K1_T_:
520 case LS_K1_TR:
521 case LS_K1_TL:
522 case LS_K1_BR:
523 case LS_K1_BL:
524 case LS_V1_BR:
525 case LS_V1__R:
526 case LS_V1_TR:
527 case LS_V1_T_:
528 case LS_V1_TL:
529 case LS_V1__L:
530 case LS_V1_BL:
531 case LS_V1_B_:
532 case LS_H1_T_:
533 case LS_H1_TR:
534 case LS_H1_TL:
535 case LS_H1_BR:
536 case LS_H1_BL:
537 retmove = transitionMove[saberMoveData[curmove].endQuad][saberMoveData[newmove].startQuad];
538 break;
539 //NB: transitioning from transitions is fine
540 }
541 }
542 break;
543 //transitioning to any other anim is not supported
544 }
545 }
546
547 if ( retmove == LS_NONE )
548 {
549 return newmove;
550 }
551
552 return retmove;
553 }
554
555 extern qboolean BG_InKnockDown( int anim );
PM_CheckStabDown(void)556 saberMoveName_t PM_CheckStabDown( void )
557 {
558 vec3_t faceFwd, facingAngles;
559 vec3_t fwd;
560 bgEntity_t *ent = NULL;
561 trace_t tr;
562 //yeah, vm's may complain, but.. who cares!
563 vec3_t trmins = {-15, -15, -15};
564 vec3_t trmaxs = {15, 15, 15};
565
566 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
567 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
568 if ( saber1
569 && (saber1->saberFlags&SFL_NO_STABDOWN) )
570 {
571 return LS_NONE;
572 }
573 if ( saber2
574 && (saber2->saberFlags&SFL_NO_STABDOWN) )
575 {
576 return LS_NONE;
577 }
578
579 if ( pm->ps->groundEntityNum == ENTITYNUM_NONE )
580 {//sorry must be on ground!
581 return LS_NONE;
582 }
583 if ( pm->ps->clientNum < MAX_CLIENTS )
584 {//player
585 pm->ps->velocity[2] = 0;
586 pm->cmd.upmove = 0;
587 }
588
589 VectorSet(facingAngles, 0, pm->ps->viewangles[YAW], 0);
590 AngleVectors( facingAngles, faceFwd, NULL, NULL );
591
592 //FIXME: need to only move forward until we bump into our target...?
593 VectorMA(pm->ps->origin, 164.0f, faceFwd, fwd);
594
595 pm->trace(&tr, pm->ps->origin, trmins, trmaxs, fwd, pm->ps->clientNum, MASK_PLAYERSOLID);
596
597 if (tr.entityNum < ENTITYNUM_WORLD)
598 {
599 ent = PM_BGEntForNum(tr.entityNum);
600 }
601
602 if ( ent &&
603 (ent->s.eType == ET_PLAYER || ent->s.eType == ET_NPC) &&
604 BG_InKnockDown( ent->s.legsAnim ) )
605 {//guy is on the ground below me, do a top-down attack
606 if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
607 {
608 return LS_STABDOWN_DUAL;
609 }
610 else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
611 {
612 return LS_STABDOWN_STAFF;
613 }
614 else
615 {
616 return LS_STABDOWN;
617 }
618 }
619 return LS_NONE;
620 }
621
PM_SaberMoveQuadrantForMovement(usercmd_t * ucmd)622 int PM_SaberMoveQuadrantForMovement( usercmd_t *ucmd )
623 {
624 if ( ucmd->rightmove > 0 )
625 {//moving right
626 if ( ucmd->forwardmove > 0 )
627 {//forward right = TL2BR slash
628 return Q_TL;
629 }
630 else if ( ucmd->forwardmove < 0 )
631 {//backward right = BL2TR uppercut
632 return Q_BL;
633 }
634 else
635 {//just right is a left slice
636 return Q_L;
637 }
638 }
639 else if ( ucmd->rightmove < 0 )
640 {//moving left
641 if ( ucmd->forwardmove > 0 )
642 {//forward left = TR2BL slash
643 return Q_TR;
644 }
645 else if ( ucmd->forwardmove < 0 )
646 {//backward left = BR2TL uppercut
647 return Q_BR;
648 }
649 else
650 {//just left is a right slice
651 return Q_R;
652 }
653 }
654 else
655 {//not moving left or right
656 if ( ucmd->forwardmove > 0 )
657 {//forward= T2B slash
658 return Q_T;
659 }
660 else if ( ucmd->forwardmove < 0 )
661 {//backward= T2B slash //or B2T uppercut?
662 return Q_T;
663 }
664 else
665 {//Not moving at all
666 return Q_R;
667 }
668 }
669 }
670
671 //===================================================================
PM_SaberInBounce(int move)672 qboolean PM_SaberInBounce( int move )
673 {
674 if ( move >= LS_B1_BR && move <= LS_B1_BL )
675 {
676 return qtrue;
677 }
678 if ( move >= LS_D1_BR && move <= LS_D1_BL )
679 {
680 return qtrue;
681 }
682 return qfalse;
683 }
684
685 qboolean PM_SaberInTransition( int move );
686
687 int saberMoveTransitionAngle[Q_NUM_QUADS][Q_NUM_QUADS] =
688 {
689 // Q_BR,Q_BR, Q_BR,Q_R, Q_BR,Q_TR, Q_BR,Q_T, Q_BR,Q_TL, Q_BR,Q_L, Q_BR,Q_BL, Q_BR,Q_B,
690 { 0, 45, 90, 135, 180, 215, 270, 45 },
691 // Q_R,Q_BR, Q_R,Q_R, Q_R,Q_TR, Q_R,Q_T, Q_R,Q_TL, Q_R,Q_L, Q_R,Q_BL, Q_R,Q_B,
692 { 45, 0, 45, 90, 135, 180, 215, 90 },
693 // Q_TR,Q_BR, Q_TR,Q_R, Q_TR,Q_TR, Q_TR,Q_T, Q_TR,Q_TL, Q_TR,Q_L, Q_TR,Q_BL, Q_TR,Q_B,
694 { 90, 45, 0, 45, 90, 135, 180, 135 },
695 // Q_T,Q_BR, Q_T,Q_R, Q_T,Q_TR, Q_T,Q_T, Q_T,Q_TL, Q_T,Q_L, Q_T,Q_BL, Q_T,Q_B,
696 { 135, 90, 45, 0, 45, 90, 135, 180 },
697 // Q_TL,Q_BR, Q_TL,Q_R, Q_TL,Q_TR, Q_TL,Q_T, Q_TL,Q_TL, Q_TL,Q_L, Q_TL,Q_BL, Q_TL,Q_B,
698 { 180, 135, 90, 45, 0, 45, 90, 135 },
699 // Q_L,Q_BR, Q_L,Q_R, Q_L,Q_TR, Q_L,Q_T, Q_L,Q_TL, Q_L,Q_L, Q_L,Q_BL, Q_L,Q_B,
700 { 215, 180, 135, 90, 45, 0, 45, 90 },
701 // Q_BL,Q_BR, Q_BL,Q_R, Q_BL,Q_TR, Q_BL,Q_T, Q_BL,Q_TL, Q_BL,Q_L, Q_BL,Q_BL, Q_BL,Q_B,
702 { 270, 215, 180, 135, 90, 45, 0, 45 },
703 // Q_B,Q_BR, Q_B,Q_R, Q_B,Q_TR, Q_B,Q_T, Q_B,Q_TL, Q_B,Q_L, Q_B,Q_BL, Q_B,Q_B,
704 { 45, 90, 135, 180, 135, 90, 45, 0 },
705 };
706
PM_SaberAttackChainAngle(int move1,int move2)707 int PM_SaberAttackChainAngle( int move1, int move2 )
708 {
709 if ( move1 == -1 || move2 == -1 )
710 {
711 return -1;
712 }
713 return saberMoveTransitionAngle[saberMoveData[move1].endQuad][saberMoveData[move2].startQuad];
714 }
715
PM_SaberKataDone(int curmove,int newmove)716 qboolean PM_SaberKataDone(int curmove, int newmove)
717 {
718 if (pm->ps->m_iVehicleNum)
719 { //never continue kata on vehicle
720 if (pm->ps->saberAttackChainCount > 0)
721 {
722 return qtrue;
723 }
724 }
725
726 if ( pm->ps->fd.saberAnimLevel == SS_DESANN || pm->ps->fd.saberAnimLevel == SS_TAVION )
727 {//desann and tavion can link up as many attacks as they want
728 return qfalse;
729 }
730
731 if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
732 {
733 //TEMP: for now, let staff attacks infinitely chain
734 return qfalse;
735 }
736 else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
737 {
738 //TEMP: for now, let staff attacks infinitely chain
739 return qfalse;
740 }
741 else if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_3 )
742 {
743 if ( curmove == LS_NONE || newmove == LS_NONE )
744 {
745 if ( pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_3 && pm->ps->saberAttackChainCount > PM_irand_timesync( 0, 1 ) )
746 {
747 return qtrue;
748 }
749 }
750 else if ( pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 3 ) )
751 {
752 return qtrue;
753 }
754 else if ( pm->ps->saberAttackChainCount > 0 )
755 {
756 int chainAngle = PM_SaberAttackChainAngle( curmove, newmove );
757 if ( chainAngle < 135 || chainAngle > 215 )
758 {//if trying to chain to a move that doesn't continue the momentum
759 return qtrue;
760 }
761 else if ( chainAngle == 180 )
762 {//continues the momentum perfectly, allow it to chain 66% of the time
763 if ( pm->ps->saberAttackChainCount > 1 )
764 {
765 return qtrue;
766 }
767 }
768 else
769 {//would continue the movement somewhat, 50% chance of continuing
770 if ( pm->ps->saberAttackChainCount > 2 )
771 {
772 return qtrue;
773 }
774 }
775 }
776 }
777 else
778 {//Perhaps have chainAngle influence fast and medium chains as well? For now, just do level 3.
779 if (newmove == LS_A_TL2BR ||
780 newmove == LS_A_L2R ||
781 newmove == LS_A_BL2TR ||
782 newmove == LS_A_BR2TL ||
783 newmove == LS_A_R2L ||
784 newmove == LS_A_TR2BL )
785 { //lower chaining tolerance for spinning saber anims
786 int chainTolerance;
787
788 if (pm->ps->fd.saberAnimLevel == FORCE_LEVEL_1)
789 {
790 chainTolerance = 5;
791 }
792 else
793 {
794 chainTolerance = 3;
795 }
796
797 if (pm->ps->saberAttackChainCount >= chainTolerance && PM_irand_timesync(1, pm->ps->saberAttackChainCount) > chainTolerance)
798 {
799 return qtrue;
800 }
801 }
802 if ( pm->ps->fd.saberAnimLevel == FORCE_LEVEL_2 && pm->ps->saberAttackChainCount > PM_irand_timesync( 2, 5 ) )
803 {
804 return qtrue;
805 }
806 }
807 return qfalse;
808 }
809
PM_SetAnimFrame(playerState_t * gent,int frame,qboolean torso,qboolean legs)810 void PM_SetAnimFrame( playerState_t *gent, int frame, qboolean torso, qboolean legs )
811 {
812 gent->saberLockFrame = frame;
813 }
814
PM_SaberLockWinAnim(qboolean victory,qboolean superBreak)815 int PM_SaberLockWinAnim( qboolean victory, qboolean superBreak )
816 {
817 int winAnim = -1;
818 switch ( pm->ps->torsoAnim )
819 {
820 /*
821 default:
822 #ifndef FINAL_BUILD
823 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 );
824 #endif
825 */
826 case BOTH_BF2LOCK:
827 if ( superBreak )
828 {
829 winAnim = BOTH_LK_S_S_T_SB_1_W;
830 }
831 else if ( !victory )
832 {
833 winAnim = BOTH_BF1BREAK;
834 }
835 else
836 {
837 pm->ps->saberMove = LS_A_T2B;
838 winAnim = BOTH_A3_T__B_;
839 }
840 break;
841 case BOTH_BF1LOCK:
842 if ( superBreak )
843 {
844 winAnim = BOTH_LK_S_S_T_SB_1_W;
845 }
846 else if ( !victory )
847 {
848 winAnim = BOTH_KNOCKDOWN4;
849 }
850 else
851 {
852 pm->ps->saberMove = LS_K1_T_;
853 winAnim = BOTH_K1_S1_T_;
854 }
855 break;
856 case BOTH_CWCIRCLELOCK:
857 if ( superBreak )
858 {
859 winAnim = BOTH_LK_S_S_S_SB_1_W;
860 }
861 else if ( !victory )
862 {
863 pm->ps->saberMove = LS_V1_BL;//pm->ps->saberBounceMove =
864 pm->ps->saberBlocked = BLOCKED_PARRY_BROKEN;
865 winAnim = BOTH_V1_BL_S1;
866 }
867 else
868 {
869 winAnim = BOTH_CWCIRCLEBREAK;
870 }
871 break;
872 case BOTH_CCWCIRCLELOCK:
873 if ( superBreak )
874 {
875 winAnim = BOTH_LK_S_S_S_SB_1_W;
876 }
877 else if ( !victory )
878 {
879 pm->ps->saberMove = LS_V1_BR;//pm->ps->saberBounceMove =
880 pm->ps->saberBlocked = BLOCKED_PARRY_BROKEN;
881 winAnim = BOTH_V1_BR_S1;
882 }
883 else
884 {
885 winAnim = BOTH_CCWCIRCLEBREAK;
886 }
887 break;
888 default:
889 //must be using new system:
890 break;
891 }
892 if ( winAnim != -1 )
893 {
894 PM_SetAnim( SETANIM_BOTH, winAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
895 pm->ps->weaponTime = pm->ps->torsoTimer;
896 pm->ps->saberBlocked = BLOCKED_NONE;
897 pm->ps->weaponstate = WEAPON_FIRING;
898 /*
899 if ( superBreak
900 && winAnim != BOTH_LK_ST_DL_T_SB_1_W )
901 {//going to attack with saber, do a saber trail
902 pm->ps->SaberActivateTrail( 200 );
903 }
904 */
905 }
906 return winAnim;
907 }
908
909 // Need to avoid nesting namespaces!
910 #ifdef _GAME //including game headers on cgame is FORBIDDEN ^_^
911 #include "g_local.h"
912 extern void NPC_SetAnim(gentity_t *ent, int setAnimParts, int anim, int setAnimFlags);
913 extern gentity_t g_entities[];
914 #elif defined(_CGAME)
915 #include "cgame/cg_local.h" //ahahahahhahahaha@$!$!
916 #endif
917
PM_SaberLockLoseAnim(playerState_t * genemy,qboolean victory,qboolean superBreak)918 int PM_SaberLockLoseAnim( playerState_t *genemy, qboolean victory, qboolean superBreak )
919 {
920 int loseAnim = -1;
921 switch ( genemy->torsoAnim )
922 {
923 /*
924 default:
925 #ifndef FINAL_BUILD
926 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 );
927 #endif
928 */
929 case BOTH_BF2LOCK:
930 if ( superBreak )
931 {
932 loseAnim = BOTH_LK_S_S_T_SB_1_L;
933 }
934 else if ( !victory )
935 {
936 loseAnim = BOTH_BF1BREAK;
937 }
938 else
939 {
940 if ( !victory )
941 {//no-one won
942 genemy->saberMove = LS_K1_T_;
943 loseAnim = BOTH_K1_S1_T_;
944 }
945 else
946 {//FIXME: this anim needs to transition back to ready when done
947 loseAnim = BOTH_BF1BREAK;
948 }
949 }
950 break;
951 case BOTH_BF1LOCK:
952 if ( superBreak )
953 {
954 loseAnim = BOTH_LK_S_S_T_SB_1_L;
955 }
956 else if ( !victory )
957 {
958 loseAnim = BOTH_KNOCKDOWN4;
959 }
960 else
961 {
962 if ( !victory )
963 {//no-one won
964 genemy->saberMove = LS_A_T2B;
965 loseAnim = BOTH_A3_T__B_;
966 }
967 else
968 {
969 loseAnim = BOTH_KNOCKDOWN4;
970 }
971 }
972 break;
973 case BOTH_CWCIRCLELOCK:
974 if ( superBreak )
975 {
976 loseAnim = BOTH_LK_S_S_S_SB_1_L;
977 }
978 else if ( !victory )
979 {
980 genemy->saberMove = LS_V1_BL;//genemy->saberBounceMove =
981 genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
982 loseAnim = BOTH_V1_BL_S1;
983 }
984 else
985 {
986 if ( !victory )
987 {//no-one won
988 loseAnim = BOTH_CCWCIRCLEBREAK;
989 }
990 else
991 {
992 genemy->saberMove = LS_V1_BL;//genemy->saberBounceMove =
993 genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
994 loseAnim = BOTH_V1_BL_S1;
995 /*
996 genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_H1_BR;
997 genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN;
998 loseAnim = BOTH_H1_S1_BL;
999 */
1000 }
1001 }
1002 break;
1003 case BOTH_CCWCIRCLELOCK:
1004 if ( superBreak )
1005 {
1006 loseAnim = BOTH_LK_S_S_S_SB_1_L;
1007 }
1008 else if ( !victory )
1009 {
1010 genemy->saberMove = LS_V1_BR;//genemy->saberBounceMove =
1011 genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
1012 loseAnim = BOTH_V1_BR_S1;
1013 }
1014 else
1015 {
1016 if ( !victory )
1017 {//no-one won
1018 loseAnim = BOTH_CWCIRCLEBREAK;
1019 }
1020 else
1021 {
1022 genemy->saberMove = LS_V1_BR;//genemy->saberBounceMove =
1023 genemy->saberBlocked = BLOCKED_PARRY_BROKEN;
1024 loseAnim = BOTH_V1_BR_S1;
1025 /*
1026 genemy->client->ps.saberMove = genemy->client->ps.saberBounceMove = LS_H1_BL;
1027 genemy->client->ps.saberBlocked = BLOCKED_PARRY_BROKEN;
1028 loseAnim = BOTH_H1_S1_BR;
1029 */
1030 }
1031 }
1032 break;
1033 }
1034 if ( loseAnim != -1 )
1035 {
1036 #ifdef _GAME
1037 NPC_SetAnim( &g_entities[genemy->clientNum], SETANIM_BOTH, loseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
1038 genemy->weaponTime = genemy->torsoTimer;// + 250;
1039 #endif
1040 genemy->saberBlocked = BLOCKED_NONE;
1041 genemy->weaponstate = WEAPON_READY;
1042 }
1043 return loseAnim;
1044 }
1045
PM_SaberLockResultAnim(playerState_t * duelist,qboolean superBreak,qboolean won)1046 int PM_SaberLockResultAnim( playerState_t *duelist, qboolean superBreak, qboolean won )
1047 {
1048 int baseAnim = duelist->torsoAnim;
1049 switch ( baseAnim )
1050 {
1051 case BOTH_LK_S_S_S_L_2: //lock if I'm using single vs. a single and other intitiated
1052 baseAnim = BOTH_LK_S_S_S_L_1;
1053 break;
1054 case BOTH_LK_S_S_T_L_2: //lock if I'm using single vs. a single and other initiated
1055 baseAnim = BOTH_LK_S_S_T_L_1;
1056 break;
1057 case BOTH_LK_DL_DL_S_L_2: //lock if I'm using dual vs. dual and other initiated
1058 baseAnim = BOTH_LK_DL_DL_S_L_1;
1059 break;
1060 case BOTH_LK_DL_DL_T_L_2: //lock if I'm using dual vs. dual and other initiated
1061 baseAnim = BOTH_LK_DL_DL_T_L_1;
1062 break;
1063 case BOTH_LK_ST_ST_S_L_2: //lock if I'm using staff vs. a staff and other initiated
1064 baseAnim = BOTH_LK_ST_ST_S_L_1;
1065 break;
1066 case BOTH_LK_ST_ST_T_L_2: //lock if I'm using staff vs. a staff and other initiated
1067 baseAnim = BOTH_LK_ST_ST_T_L_1;
1068 break;
1069 }
1070 //what kind of break?
1071 if ( !superBreak )
1072 {
1073 baseAnim -= 2;
1074 }
1075 else if ( superBreak )
1076 {
1077 baseAnim += 1;
1078 }
1079 else
1080 {//WTF? Not a valid result
1081 return -1;
1082 }
1083 //win or lose?
1084 if ( won )
1085 {
1086 baseAnim += 1;
1087 }
1088
1089 //play the anim and hold it
1090 #ifdef _GAME
1091 //server-side: set it on the other guy, too
1092 if ( duelist->clientNum == pm->ps->clientNum )
1093 {//me
1094 PM_SetAnim( SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
1095 }
1096 else
1097 {//other guy
1098 NPC_SetAnim( &g_entities[duelist->clientNum], SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
1099 }
1100 #else
1101 PM_SetAnim( SETANIM_BOTH, baseAnim, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD );
1102 #endif
1103
1104 if ( superBreak
1105 && !won )
1106 {//if you lose a superbreak, you're defenseless
1107 /*
1108 //Taken care of in SetSaberBoxSize()
1109 //make saberent not block
1110 gentity_t *saberent = &g_entities[duelist->client->ps.saberEntityNum];
1111 if ( saberent )
1112 {
1113 VectorClear(saberent->mins);
1114 VectorClear(saberent->maxs);
1115 G_SetOrigin(saberent, duelist->currentOrigin);
1116 }
1117 */
1118 #ifdef _GAME
1119 if ( 1 )
1120 #else
1121 if ( duelist->clientNum == pm->ps->clientNum )
1122 #endif
1123 {
1124 //set sabermove to none
1125 duelist->saberMove = LS_NONE;
1126 //Hold the anim a little longer than it is
1127 duelist->torsoTimer += 250;
1128 }
1129 }
1130
1131 #ifdef _GAME
1132 if ( 1 )
1133 #else
1134 if ( duelist->clientNum == pm->ps->clientNum )
1135 #endif
1136 {
1137 //no attacking during this anim
1138 duelist->weaponTime = duelist->torsoTimer;
1139 duelist->saberBlocked = BLOCKED_NONE;
1140 /*
1141 if ( superBreak
1142 && won
1143 && baseAnim != BOTH_LK_ST_DL_T_SB_1_W )
1144 {//going to attack with saber, do a saber trail
1145 duelist->client->ps.SaberActivateTrail( 200 );
1146 }
1147 */
1148 }
1149 return baseAnim;
1150 }
1151
PM_SaberLockBreak(playerState_t * genemy,qboolean victory,int strength)1152 void PM_SaberLockBreak( playerState_t *genemy, qboolean victory, int strength )
1153 {
1154 //qboolean punishLoser = qfalse;
1155 qboolean noKnockdown = qfalse;
1156 qboolean superBreak = (strength+pm->ps->saberLockHits > Q_irand(2,4));
1157
1158 //a single vs. single break
1159 if ( PM_SaberLockWinAnim( victory, superBreak ) != -1 )
1160 PM_SaberLockLoseAnim( genemy, victory, superBreak );
1161
1162 //must be a saberlock that's not between single and single...
1163 else {
1164 PM_SaberLockResultAnim( pm->ps, superBreak, qtrue );
1165 pm->ps->weaponstate = WEAPON_FIRING;
1166 PM_SaberLockResultAnim( genemy, superBreak, qfalse );
1167 genemy->weaponstate = WEAPON_READY;
1168 }
1169
1170 if ( victory )
1171 { //someone lost the lock, so punish them by knocking them down
1172 if ( pm->ps->saberLockHits && !superBreak )
1173 {//there was some over-power in the win, but not enough to superbreak
1174 vec3_t oppDir;
1175
1176 int newstrength = 8;
1177
1178 VectorSubtract(genemy->origin, pm->ps->origin, oppDir);
1179 VectorNormalize(oppDir);
1180
1181 if (noKnockdown)
1182 {
1183 if (!genemy->saberEntityNum)
1184 { //if he has already lost his saber then just knock him down
1185 noKnockdown = qfalse;
1186 }
1187 }
1188
1189 if (!noKnockdown && BG_KnockDownable(genemy))
1190 {
1191 genemy->forceHandExtend = HANDEXTEND_KNOCKDOWN;
1192 genemy->forceHandExtendTime = pm->cmd.serverTime + 1100;
1193 genemy->forceDodgeAnim = 0; //this toggles between 1 and 0, when it's 1 we should play the get up anim
1194
1195 genemy->otherKiller = pm->ps->clientNum;
1196 genemy->otherKillerTime = pm->cmd.serverTime + 5000;
1197 genemy->otherKillerDebounceTime = pm->cmd.serverTime + 100;
1198
1199 genemy->velocity[0] = oppDir[0]*(newstrength*40);
1200 genemy->velocity[1] = oppDir[1]*(newstrength*40);
1201 genemy->velocity[2] = 100;
1202 }
1203
1204 pm->checkDuelLoss = genemy->clientNum+1;
1205
1206 pm->ps->saberEventFlags |= SEF_LOCK_WON;
1207 }
1208 }
1209 else
1210 { //If no one lost, then shove each player away from the other
1211 vec3_t oppDir;
1212
1213 int newstrength = 4;
1214
1215 VectorSubtract(genemy->origin, pm->ps->origin, oppDir);
1216 VectorNormalize(oppDir);
1217 genemy->velocity[0] = oppDir[0]*(newstrength*40);
1218 genemy->velocity[1] = oppDir[1]*(newstrength*40);
1219 genemy->velocity[2] = 150;
1220
1221 VectorSubtract(pm->ps->origin, genemy->origin, oppDir);
1222 VectorNormalize(oppDir);
1223 pm->ps->velocity[0] = oppDir[0]*(newstrength*40);
1224 pm->ps->velocity[1] = oppDir[1]*(newstrength*40);
1225 pm->ps->velocity[2] = 150;
1226
1227 genemy->forceHandExtend = HANDEXTEND_WEAPONREADY;
1228 }
1229
1230 pm->ps->weaponTime = 0;
1231 genemy->weaponTime = 0;
1232
1233 pm->ps->saberLockTime = genemy->saberLockTime = 0;
1234 pm->ps->saberLockFrame = genemy->saberLockFrame = 0;
1235 pm->ps->saberLockEnemy = genemy->saberLockEnemy = 0;
1236
1237 pm->ps->forceHandExtend = HANDEXTEND_WEAPONREADY;
1238
1239 PM_AddEvent( EV_JUMP );
1240 if ( !victory )
1241 {//no-one won
1242 BG_AddPredictableEventToPlayerstate(EV_JUMP, 0, genemy);
1243 }
1244 else
1245 {
1246 if ( PM_irand_timesync( 0, 1 ) )
1247 {
1248 BG_AddPredictableEventToPlayerstate(EV_JUMP, PM_irand_timesync( 0, 75 ), genemy);
1249 }
1250 }
1251 }
1252
BG_CheckIncrementLockAnim(int anim,int winOrLose)1253 qboolean BG_CheckIncrementLockAnim( int anim, int winOrLose )
1254 {
1255 qboolean increment = qfalse;//???
1256 //RULE: if you are the first style in the lock anim, you advance from LOSING position to WINNING position
1257 // if you are the second style in the lock anim, you advance from WINNING position to LOSING position
1258 switch ( anim )
1259 {
1260 //increment to win:
1261 case BOTH_LK_DL_DL_S_L_1: //lock if I'm using dual vs. dual and I initiated
1262 case BOTH_LK_DL_DL_S_L_2: //lock if I'm using dual vs. dual and other initiated
1263 case BOTH_LK_DL_DL_T_L_1: //lock if I'm using dual vs. dual and I initiated
1264 case BOTH_LK_DL_DL_T_L_2: //lock if I'm using dual vs. dual and other initiated
1265 case BOTH_LK_DL_S_S_L_1: //lock if I'm using dual vs. a single
1266 case BOTH_LK_DL_S_T_L_1: //lock if I'm using dual vs. a single
1267 case BOTH_LK_DL_ST_S_L_1: //lock if I'm using dual vs. a staff
1268 case BOTH_LK_DL_ST_T_L_1: //lock if I'm using dual vs. a staff
1269 case BOTH_LK_S_S_S_L_1: //lock if I'm using single vs. a single and I initiated
1270 case BOTH_LK_S_S_T_L_2: //lock if I'm using single vs. a single and other initiated
1271 case BOTH_LK_ST_S_S_L_1: //lock if I'm using staff vs. a single
1272 case BOTH_LK_ST_S_T_L_1: //lock if I'm using staff vs. a single
1273 case BOTH_LK_ST_ST_T_L_1: //lock if I'm using staff vs. a staff and I initiated
1274 case BOTH_LK_ST_ST_T_L_2: //lock if I'm using staff vs. a staff and other initiated
1275 if ( winOrLose == SABERLOCK_WIN )
1276 {
1277 increment = qtrue;
1278 }
1279 else
1280 {
1281 increment = qfalse;
1282 }
1283 break;
1284
1285 //decrement to win:
1286 case BOTH_LK_S_DL_S_L_1: //lock if I'm using single vs. a dual
1287 case BOTH_LK_S_DL_T_L_1: //lock if I'm using single vs. a dual
1288 case BOTH_LK_S_S_S_L_2: //lock if I'm using single vs. a single and other intitiated
1289 case BOTH_LK_S_S_T_L_1: //lock if I'm using single vs. a single and I initiated
1290 case BOTH_LK_S_ST_S_L_1: //lock if I'm using single vs. a staff
1291 case BOTH_LK_S_ST_T_L_1: //lock if I'm using single vs. a staff
1292 case BOTH_LK_ST_DL_S_L_1: //lock if I'm using staff vs. dual
1293 case BOTH_LK_ST_DL_T_L_1: //lock if I'm using staff vs. dual
1294 case BOTH_LK_ST_ST_S_L_1: //lock if I'm using staff vs. a staff and I initiated
1295 case BOTH_LK_ST_ST_S_L_2: //lock if I'm using staff vs. a staff and other initiated
1296 if ( winOrLose == SABERLOCK_WIN )
1297 {
1298 increment = qfalse;
1299 }
1300 else
1301 {
1302 increment = qtrue;
1303 }
1304 break;
1305 default:
1306 break;
1307 }
1308 return increment;
1309 }
1310
1311 extern qboolean ValidAnimFileIndex ( int index );
PM_SaberLocked(void)1312 void PM_SaberLocked( void )
1313 {
1314 int remaining = 0;
1315 playerState_t *genemy;
1316 bgEntity_t *eGenemy = PM_BGEntForNum(pm->ps->saberLockEnemy);
1317
1318 if (!eGenemy)
1319 {
1320 return;
1321 }
1322
1323 genemy = eGenemy->playerState;
1324
1325 if ( !genemy )
1326 {
1327 return;
1328 }
1329 /*if ( ( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
1330 (pm->ps->torsoAnim) == BOTH_BF1LOCK ||
1331 (pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
1332 (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK )
1333 && ( (genemy->torsoAnim) == BOTH_BF2LOCK ||
1334 (genemy->torsoAnim) == BOTH_BF1LOCK ||
1335 (genemy->torsoAnim) == BOTH_CWCIRCLELOCK ||
1336 (genemy->torsoAnim) == BOTH_CCWCIRCLELOCK )
1337 )
1338 */ //yeah..
1339 if (pm->ps->saberLockFrame &&
1340 genemy->saberLockFrame &&
1341 BG_InSaberLock(pm->ps->torsoAnim) &&
1342 BG_InSaberLock(genemy->torsoAnim))
1343 {
1344 float dist = 0;
1345
1346 pm->ps->torsoTimer = 0;
1347 pm->ps->weaponTime = 0;
1348 genemy->torsoTimer = 0;
1349 genemy->weaponTime = 0;
1350
1351 dist = DistanceSquared(pm->ps->origin,genemy->origin);
1352 if ( dist < 64 || dist > 6400 )
1353 {//between 8 and 80 from each other
1354 PM_SaberLockBreak( genemy, qfalse, 0 );
1355 return;
1356 }
1357 /*
1358 //NOTE: time-out is handled around where PM_SaberLocked is called
1359 if ( pm->ps->saberLockTime <= pm->cmd.serverTime + 500 )
1360 {//lock just ended
1361 PM_SaberLockBreak( genemy, qfalse, 0 );
1362 return;
1363 }
1364 */
1365 if ( pm->ps->saberLockAdvance )
1366 {//holding attack
1367 animation_t *anim;
1368 float currentFrame;
1369 int curFrame;
1370 int strength = pm->ps->fd.forcePowerLevel[FP_SABER_OFFENSE]+1;
1371
1372 pm->ps->saberLockAdvance = qfalse;
1373
1374 anim = &pm->animations[pm->ps->torsoAnim];
1375
1376 currentFrame = pm->ps->saberLockFrame;
1377
1378 //advance/decrement my frame number
1379 if ( BG_InSaberLockOld( pm->ps->torsoAnim ) )
1380 { //old locks
1381 if ( (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||
1382 (pm->ps->torsoAnim) == BOTH_BF2LOCK )
1383 {
1384 curFrame = floor( currentFrame )-strength;
1385 //drop my frame one
1386 if ( curFrame <= anim->firstFrame )
1387 {//I won! Break out
1388 PM_SaberLockBreak( genemy, qtrue, strength );
1389 return;
1390 }
1391 else
1392 {
1393 PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
1394 remaining = curFrame-anim->firstFrame;
1395 }
1396 }
1397 else
1398 {
1399 curFrame = ceil( currentFrame )+strength;
1400 //advance my frame one
1401 if ( curFrame >= anim->firstFrame+anim->numFrames )
1402 {//I won! Break out
1403 PM_SaberLockBreak( genemy, qtrue, strength );
1404 return;
1405 }
1406 else
1407 {
1408 PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
1409 remaining = anim->firstFrame+anim->numFrames-curFrame;
1410 }
1411 }
1412 }
1413 else
1414 { //new locks
1415 if ( BG_CheckIncrementLockAnim( pm->ps->torsoAnim, SABERLOCK_WIN ) )
1416 {
1417 curFrame = ceil( currentFrame )+strength;
1418 //advance my frame one
1419 if ( curFrame >= anim->firstFrame+anim->numFrames )
1420 {//I won! Break out
1421 PM_SaberLockBreak( genemy, qtrue, strength );
1422 return;
1423 }
1424 else
1425 {
1426 PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
1427 remaining = anim->firstFrame+anim->numFrames-curFrame;
1428 }
1429 }
1430 else
1431 {
1432 curFrame = floor( currentFrame )-strength;
1433 //drop my frame one
1434 if ( curFrame <= anim->firstFrame )
1435 {//I won! Break out
1436 PM_SaberLockBreak( genemy, qtrue, strength );
1437 return;
1438 }
1439 else
1440 {
1441 PM_SetAnimFrame( pm->ps, curFrame, qtrue, qtrue );
1442 remaining = curFrame-anim->firstFrame;
1443 }
1444 }
1445 }
1446 if ( !PM_irand_timesync( 0, 2 ) )
1447 {
1448 PM_AddEvent( EV_JUMP );
1449 }
1450 //advance/decrement enemy frame number
1451 anim = &pm->animations[(genemy->torsoAnim)];
1452
1453 if ( BG_InSaberLockOld( genemy->torsoAnim ) )
1454 {
1455 if ( (genemy->torsoAnim) == BOTH_CWCIRCLELOCK ||
1456 (genemy->torsoAnim) == BOTH_BF1LOCK )
1457 {
1458 if ( !PM_irand_timesync( 0, 2 ) )
1459 {
1460 BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy);
1461 }
1462 PM_SetAnimFrame( genemy, anim->firstFrame+remaining, qtrue, qtrue );
1463 }
1464 else
1465 {
1466 PM_SetAnimFrame( genemy, anim->firstFrame+anim->numFrames-remaining, qtrue, qtrue );
1467 }
1468 }
1469 else
1470 {//new locks
1471 if ( BG_CheckIncrementLockAnim( genemy->torsoAnim, SABERLOCK_LOSE ) )
1472 {
1473 if ( !PM_irand_timesync( 0, 2 ) )
1474 {
1475 BG_AddPredictableEventToPlayerstate(EV_PAIN, floor((float)80/100*100.0f), genemy);
1476 }
1477 PM_SetAnimFrame( genemy, anim->firstFrame+anim->numFrames-remaining, qtrue, qtrue );
1478 }
1479 else
1480 {
1481 PM_SetAnimFrame( genemy, anim->firstFrame+remaining, qtrue, qtrue );
1482 }
1483 }
1484 }
1485 }
1486 else
1487 {//something broke us out of it
1488 PM_SaberLockBreak( genemy, qfalse, 0 );
1489 }
1490 }
1491
PM_SaberInBrokenParry(int move)1492 qboolean PM_SaberInBrokenParry( int move )
1493 {
1494 if ( move >= LS_V1_BR && move <= LS_V1_B_ )
1495 {
1496 return qtrue;
1497 }
1498 if ( move >= LS_H1_T_ && move <= LS_H1_BL )
1499 {
1500 return qtrue;
1501 }
1502 return qfalse;
1503 }
1504
1505
PM_BrokenParryForParry(int move)1506 int PM_BrokenParryForParry( int move )
1507 {
1508 switch ( move )
1509 {
1510 case LS_PARRY_UP:
1511 return LS_H1_T_;
1512 break;
1513 case LS_PARRY_UR:
1514 return LS_H1_TR;
1515 break;
1516 case LS_PARRY_UL:
1517 return LS_H1_TL;
1518 break;
1519 case LS_PARRY_LR:
1520 return LS_H1_BL;
1521 break;
1522 case LS_PARRY_LL:
1523 return LS_H1_BR;
1524 break;
1525 case LS_READY:
1526 return LS_H1_B_;
1527 break;
1528 }
1529 return LS_NONE;
1530 }
1531
1532 #define BACK_STAB_DISTANCE 128
1533
PM_CanBackstab(void)1534 qboolean PM_CanBackstab(void)
1535 {
1536 trace_t tr;
1537 vec3_t flatAng;
1538 vec3_t fwd, back;
1539 vec3_t trmins = {-15, -15, -8};
1540 vec3_t trmaxs = {15, 15, 8};
1541
1542 VectorCopy(pm->ps->viewangles, flatAng);
1543 flatAng[PITCH] = 0;
1544
1545 AngleVectors(flatAng, fwd, 0, 0);
1546
1547 back[0] = pm->ps->origin[0] - fwd[0]*BACK_STAB_DISTANCE;
1548 back[1] = pm->ps->origin[1] - fwd[1]*BACK_STAB_DISTANCE;
1549 back[2] = pm->ps->origin[2] - fwd[2]*BACK_STAB_DISTANCE;
1550
1551 pm->trace(&tr, pm->ps->origin, trmins, trmaxs, back, pm->ps->clientNum, MASK_PLAYERSOLID);
1552
1553 if (tr.fraction != 1.0 && tr.entityNum >= 0 && tr.entityNum < ENTITYNUM_NONE)
1554 {
1555 bgEntity_t *bgEnt = PM_BGEntForNum(tr.entityNum);
1556
1557 if (bgEnt && (bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
1558 {
1559 return qtrue;
1560 }
1561 }
1562
1563 return qfalse;
1564 }
1565
PM_SaberFlipOverAttackMove(void)1566 saberMoveName_t PM_SaberFlipOverAttackMove(void)
1567 {
1568 vec3_t fwdAngles, jumpFwd;
1569 // float zDiff = 0;
1570 // playerState_t *psData;
1571 // bgEntity_t *bgEnt;
1572
1573 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
1574 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
1575 //see if we have an overridden (or cancelled) lunge move
1576 if ( saber1
1577 && saber1->jumpAtkFwdMove != LS_INVALID )
1578 {
1579 if ( saber1->jumpAtkFwdMove != LS_NONE )
1580 {
1581 return (saberMoveName_t)saber1->jumpAtkFwdMove;
1582 }
1583 }
1584 if ( saber2
1585 && saber2->jumpAtkFwdMove != LS_INVALID )
1586 {
1587 if ( saber2->jumpAtkFwdMove != LS_NONE )
1588 {
1589 return (saberMoveName_t)saber2->jumpAtkFwdMove;
1590 }
1591 }
1592 //no overrides, cancelled?
1593 if ( saber1
1594 && saber1->jumpAtkFwdMove == LS_NONE )
1595 {
1596 return LS_A_T2B;//LS_NONE;
1597 }
1598 if ( saber2
1599 && saber2->jumpAtkFwdMove == LS_NONE )
1600 {
1601 return LS_A_T2B;//LS_NONE;
1602 }
1603 //just do it
1604 VectorCopy( pm->ps->viewangles, fwdAngles );
1605 fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
1606 AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
1607 VectorScale( jumpFwd, 150, pm->ps->velocity );//was 50
1608 pm->ps->velocity[2] = 400;
1609
1610 /*
1611 bgEnt = PM_BGEntForNum(tr->entityNum);
1612
1613 if (!bgEnt)
1614 {
1615 return LS_A_FLIP_STAB;
1616 }
1617
1618 psData = bgEnt->playerState;
1619
1620 //go higher for enemies higher than you, lower for those lower than you
1621 if (psData)
1622 {
1623 zDiff = psData->origin[2] - pm->ps->origin[2];
1624
1625 }
1626 else
1627 {
1628 zDiff = 0;
1629 }
1630 pm->ps->velocity[2] += (zDiff)*1.5f;
1631
1632 //clamp to decent-looking values
1633 if ( zDiff <= 0 && pm->ps->velocity[2] < 200 )
1634 {//if we're on same level, don't let me jump so low, I clip into the ground
1635 pm->ps->velocity[2] = 200;
1636 }
1637 else if ( pm->ps->velocity[2] < 100 )
1638 {
1639 pm->ps->velocity[2] = 100;
1640 }
1641 else if ( pm->ps->velocity[2] > 400 )
1642 {
1643 pm->ps->velocity[2] = 400;
1644 }
1645 */
1646
1647 PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height
1648
1649 PM_AddEvent( EV_JUMP );
1650 pm->ps->fd.forceJumpSound = 1;
1651 pm->cmd.upmove = 0;
1652
1653 /*
1654 if ( PM_irand_timesync( 0, 1 ) )
1655 {
1656 return LS_A_FLIP_STAB;
1657 }
1658 else
1659 */
1660 {
1661 return LS_A_FLIP_SLASH;
1662 }
1663 }
1664
PM_SaberBackflipAttackMove(void)1665 int PM_SaberBackflipAttackMove( void )
1666 {
1667 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
1668 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
1669 //see if we have an overridden (or cancelled) lunge move
1670 if ( saber1
1671 && saber1->jumpAtkBackMove != LS_INVALID )
1672 {
1673 if ( saber1->jumpAtkBackMove != LS_NONE )
1674 {
1675 return (saberMoveName_t)saber1->jumpAtkBackMove;
1676 }
1677 }
1678 if ( saber2
1679 && saber2->jumpAtkBackMove != LS_INVALID )
1680 {
1681 if ( saber2->jumpAtkBackMove != LS_NONE )
1682 {
1683 return (saberMoveName_t)saber2->jumpAtkBackMove;
1684 }
1685 }
1686 //no overrides, cancelled?
1687 if ( saber1
1688 && saber1->jumpAtkBackMove == LS_NONE )
1689 {
1690 return LS_A_T2B;//LS_NONE;
1691 }
1692 if ( saber2
1693 && saber2->jumpAtkBackMove == LS_NONE )
1694 {
1695 return LS_A_T2B;//LS_NONE;
1696 }
1697 //just do it
1698 pm->cmd.upmove = 127;
1699 pm->ps->velocity[2] = 500;
1700 return LS_A_BACKFLIP_ATK;
1701 }
1702
PM_SaberDualJumpAttackMove(void)1703 int PM_SaberDualJumpAttackMove( void )
1704 {
1705 //FIXME: to make this move easier to execute, should be allowed to do it
1706 // after you've already started your jump... but jump is delayed in
1707 // this anim, so how do we undo the jump?
1708 pm->cmd.upmove = 0;//no jump just yet
1709 return LS_JUMPATTACK_DUAL;
1710 }
1711
1712 #define FLIPHACK_DISTANCE 200
1713
PM_SomeoneInFront(trace_t * tr)1714 qboolean PM_SomeoneInFront(trace_t *tr)
1715 { //Also a very simplified version of the sp counterpart
1716 vec3_t flatAng;
1717 vec3_t fwd, back;
1718 vec3_t trmins = {-15, -15, -8};
1719 vec3_t trmaxs = {15, 15, 8};
1720
1721 VectorCopy(pm->ps->viewangles, flatAng);
1722 flatAng[PITCH] = 0;
1723
1724 AngleVectors(flatAng, fwd, 0, 0);
1725
1726 back[0] = pm->ps->origin[0] + fwd[0]*FLIPHACK_DISTANCE;
1727 back[1] = pm->ps->origin[1] + fwd[1]*FLIPHACK_DISTANCE;
1728 back[2] = pm->ps->origin[2] + fwd[2]*FLIPHACK_DISTANCE;
1729
1730 pm->trace(tr, pm->ps->origin, trmins, trmaxs, back, pm->ps->clientNum, MASK_PLAYERSOLID);
1731
1732 if (tr->fraction != 1.0 && tr->entityNum >= 0 && tr->entityNum < ENTITYNUM_NONE)
1733 {
1734 bgEntity_t *bgEnt = PM_BGEntForNum(tr->entityNum);
1735
1736 if (bgEnt && (bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
1737 {
1738 return qtrue;
1739 }
1740 }
1741
1742 return qfalse;
1743 }
1744
PM_SaberLungeAttackMove(qboolean noSpecials)1745 saberMoveName_t PM_SaberLungeAttackMove( qboolean noSpecials )
1746 {
1747 vec3_t fwdAngles, jumpFwd;
1748 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
1749 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
1750 //see if we have an overridden (or cancelled) lunge move
1751 if ( saber1
1752 && saber1->lungeAtkMove != LS_INVALID )
1753 {
1754 if ( saber1->lungeAtkMove != LS_NONE )
1755 {
1756 return (saberMoveName_t)saber1->lungeAtkMove;
1757 }
1758 }
1759 if ( saber2
1760 && saber2->lungeAtkMove != LS_INVALID )
1761 {
1762 if ( saber2->lungeAtkMove != LS_NONE )
1763 {
1764 return (saberMoveName_t)saber2->lungeAtkMove;
1765 }
1766 }
1767 //no overrides, cancelled?
1768 if ( saber1
1769 && saber1->lungeAtkMove == LS_NONE )
1770 {
1771 return LS_A_T2B;//LS_NONE;
1772 }
1773 if ( saber2
1774 && saber2->lungeAtkMove == LS_NONE )
1775 {
1776 return LS_A_T2B;//LS_NONE;
1777 }
1778 //just do it
1779 if (pm->ps->fd.saberAnimLevel == SS_FAST)
1780 {
1781 VectorCopy( pm->ps->viewangles, fwdAngles );
1782 fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
1783 //do the lunge
1784 AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
1785 VectorScale( jumpFwd, 150, pm->ps->velocity );
1786 PM_AddEvent( EV_JUMP );
1787
1788 return LS_A_LUNGE;
1789 }
1790 else if ( !noSpecials && pm->ps->fd.saberAnimLevel == SS_STAFF)
1791 {
1792 return LS_SPINATTACK;
1793 }
1794 else if ( !noSpecials )
1795 {
1796 return LS_SPINATTACK_DUAL;
1797 }
1798 return LS_A_T2B;
1799 }
1800
PM_SaberJumpAttackMove2(void)1801 saberMoveName_t PM_SaberJumpAttackMove2( void )
1802 {
1803 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
1804 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
1805 //see if we have an overridden (or cancelled) lunge move
1806 if ( saber1
1807 && saber1->jumpAtkFwdMove != LS_INVALID )
1808 {
1809 if ( saber1->jumpAtkFwdMove != LS_NONE )
1810 {
1811 return (saberMoveName_t)saber1->jumpAtkFwdMove;
1812 }
1813 }
1814 if ( saber2
1815 && saber2->jumpAtkFwdMove != LS_INVALID )
1816 {
1817 if ( saber2->jumpAtkFwdMove != LS_NONE )
1818 {
1819 return (saberMoveName_t)saber2->jumpAtkFwdMove;
1820 }
1821 }
1822 //no overrides, cancelled?
1823 if ( saber1
1824 && saber1->jumpAtkFwdMove == LS_NONE )
1825 {
1826 return LS_A_T2B;//LS_NONE;
1827 }
1828 if ( saber2
1829 && saber2->jumpAtkFwdMove == LS_NONE )
1830 {
1831 return LS_A_T2B;//LS_NONE;
1832 }
1833 //just do it
1834 if (pm->ps->fd.saberAnimLevel == SS_DUAL)
1835 {
1836 return PM_SaberDualJumpAttackMove();
1837 }
1838 else
1839 {
1840 //rwwFIXMEFIXME I don't like randomness for this sort of thing, gives people reason to
1841 //complain combat is unpredictable. Maybe do something more clever to determine
1842 //if we should do a left or right?
1843 /*
1844 if (PM_irand_timesync(0, 1))
1845 {
1846 newmove = LS_JUMPATTACK_STAFF_LEFT;
1847 }
1848 else
1849 */
1850 {
1851 return LS_JUMPATTACK_STAFF_RIGHT;
1852 }
1853 }
1854 // return LS_A_T2B;
1855 }
1856
PM_SaberJumpAttackMove(void)1857 saberMoveName_t PM_SaberJumpAttackMove( void )
1858 {
1859 vec3_t fwdAngles, jumpFwd;
1860 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
1861 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
1862 //see if we have an overridden (or cancelled) lunge move
1863 if ( saber1
1864 && saber1->jumpAtkFwdMove != LS_INVALID )
1865 {
1866 if ( saber1->jumpAtkFwdMove != LS_NONE )
1867 {
1868 return (saberMoveName_t)saber1->jumpAtkFwdMove;
1869 }
1870 }
1871 if ( saber2
1872 && saber2->jumpAtkFwdMove != LS_INVALID )
1873 {
1874 if ( saber2->jumpAtkFwdMove != LS_NONE )
1875 {
1876 return (saberMoveName_t)saber2->jumpAtkFwdMove;
1877 }
1878 }
1879 //no overrides, cancelled?
1880 if ( saber1
1881 && saber1->jumpAtkFwdMove == LS_NONE )
1882 {
1883 return LS_A_T2B;//LS_NONE;
1884 }
1885 if ( saber2
1886 && saber2->jumpAtkFwdMove == LS_NONE )
1887 {
1888 return LS_A_T2B;//LS_NONE;
1889 }
1890 //just do it
1891 VectorCopy( pm->ps->viewangles, fwdAngles );
1892 fwdAngles[PITCH] = fwdAngles[ROLL] = 0;
1893 AngleVectors( fwdAngles, jumpFwd, NULL, NULL );
1894 VectorScale( jumpFwd, 300, pm->ps->velocity );
1895 pm->ps->velocity[2] = 280;
1896 PM_SetForceJumpZStart(pm->ps->origin[2]);//so we don't take damage if we land at same height
1897
1898 PM_AddEvent( EV_JUMP );
1899 pm->ps->fd.forceJumpSound = 1;
1900 pm->cmd.upmove = 0;
1901
1902 return LS_A_JUMP_T__B_;
1903 }
1904
PM_GroundDistance(void)1905 float PM_GroundDistance(void)
1906 {
1907 trace_t tr;
1908 vec3_t down;
1909
1910 VectorCopy(pm->ps->origin, down);
1911
1912 down[2] -= 4096;
1913
1914 pm->trace(&tr, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, MASK_SOLID);
1915
1916 VectorSubtract(pm->ps->origin, tr.endpos, down);
1917
1918 return VectorLength(down);
1919 }
1920
PM_WalkableGroundDistance(void)1921 float PM_WalkableGroundDistance(void)
1922 {
1923 trace_t tr;
1924 vec3_t down;
1925
1926 VectorCopy(pm->ps->origin, down);
1927
1928 down[2] -= 4096;
1929
1930 pm->trace(&tr, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, MASK_SOLID);
1931
1932 if ( tr.plane.normal[2] < MIN_WALK_NORMAL )
1933 {//can't stand on this plane
1934 return 4096;
1935 }
1936
1937 VectorSubtract(pm->ps->origin, tr.endpos, down);
1938
1939 return VectorLength(down);
1940 }
1941
1942 qboolean BG_SaberInTransitionAny( int move );
PM_CanDoDualDoubleAttacks(void)1943 static qboolean PM_CanDoDualDoubleAttacks(void)
1944 {
1945 if ( pm->ps->weapon == WP_SABER )
1946 {
1947 saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
1948 if ( saber
1949 && (saber->saberFlags&SFL_NO_MIRROR_ATTACKS) )
1950 {
1951 return qfalse;
1952 }
1953 saber = BG_MySaber( pm->ps->clientNum, 1 );
1954 if ( saber
1955 && (saber->saberFlags&SFL_NO_MIRROR_ATTACKS) )
1956 {
1957 return qfalse;
1958 }
1959 }
1960 if (BG_SaberInSpecialAttack(pm->ps->torsoAnim) ||
1961 BG_SaberInSpecialAttack(pm->ps->legsAnim))
1962 {
1963 return qfalse;
1964 }
1965 return qtrue;
1966 }
1967
PM_CheckEnemyPresence(int dir,float radius)1968 static qboolean PM_CheckEnemyPresence( int dir, float radius )
1969 { //anyone in this dir?
1970 vec3_t angles;
1971 vec3_t checkDir = { 0.0f };
1972 vec3_t tTo;
1973 vec3_t tMins, tMaxs;
1974 trace_t tr;
1975 const float tSize = 12.0f;
1976 //sp uses a bbox ent list check, but.. that's not so easy/fast to
1977 //do in predicted code. So I'll just do a single box trace in the proper direction,
1978 //and take whatever is first hit.
1979
1980 VectorSet(tMins, -tSize, -tSize, -tSize);
1981 VectorSet(tMaxs, tSize, tSize, tSize);
1982
1983 VectorCopy(pm->ps->viewangles, angles);
1984 angles[PITCH] = 0.0f;
1985
1986 switch( dir )
1987 {
1988 case DIR_RIGHT:
1989 AngleVectors( angles, NULL, checkDir, NULL );
1990 break;
1991 case DIR_LEFT:
1992 AngleVectors( angles, NULL, checkDir, NULL );
1993 VectorScale( checkDir, -1, checkDir );
1994 break;
1995 case DIR_FRONT:
1996 AngleVectors( angles, checkDir, NULL, NULL );
1997 break;
1998 case DIR_BACK:
1999 AngleVectors( angles, checkDir, NULL, NULL );
2000 VectorScale( checkDir, -1, checkDir );
2001 break;
2002 }
2003
2004 VectorMA(pm->ps->origin, radius, checkDir, tTo);
2005 pm->trace(&tr, pm->ps->origin, tMins, tMaxs, tTo, pm->ps->clientNum, MASK_PLAYERSOLID);
2006
2007 if (tr.fraction != 1.0f && tr.entityNum < ENTITYNUM_WORLD)
2008 { //let's see who we hit
2009 bgEntity_t *bgEnt = PM_BGEntForNum(tr.entityNum);
2010
2011 if (bgEnt &&
2012 (bgEnt->s.eType == ET_PLAYER || bgEnt->s.eType == ET_NPC))
2013 { //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).
2014 return qtrue;
2015 }
2016 }
2017
2018 //no one in the trace
2019 return qfalse;
2020 }
2021
2022 #define SABER_ALT_ATTACK_POWER 50//75?
2023 #define SABER_ALT_ATTACK_POWER_LR 10//30?
2024 #define SABER_ALT_ATTACK_POWER_FB 25//30/50?
2025
2026 extern qboolean PM_SaberInReturn( int move ); //bg_panimate.c
PM_CheckPullAttack(void)2027 saberMoveName_t PM_CheckPullAttack( void )
2028 {
2029 #if 0 //disabling these for MP, they aren't useful
2030 if (!(pm->cmd.buttons & BUTTON_ATTACK))
2031 {
2032 return LS_NONE;
2033 }
2034
2035 if ( (pm->ps->saberMove == LS_READY||PM_SaberInReturn(pm->ps->saberMove)||PM_SaberInReflect(pm->ps->saberMove))//ready
2036 //&& (pm->ps->clientNum < MAX_CLIENTS||PM_ControlledByPlayer())//PLAYER ONLY
2037 && pm->ps->fd.saberAnimLevel >= SS_FAST//single saber styles - FIXME: Tavion?
2038 && pm->ps->fd.saberAnimLevel <= SS_STRONG//single saber styles - FIXME: Tavion?
2039 //&& G_TryingPullAttack( pm->gent, &pm->cmd, qfalse )
2040 //&& pm->ps->fd.forcePowerLevel[FP_PULL]
2041 //rwwFIXMEFIXME: rick has the damn msg.cpp file checked out exclusively so I can't update the bloody psf to send this for prediction
2042 && pm->ps->powerups[PW_DISINT_4] > pm->cmd.serverTime
2043 && !(pm->ps->fd.forcePowersActive & (1<<FP_GRIP))
2044 && pm->ps->powerups[PW_PULL] > pm->cmd.serverTime
2045 //&& pm->cmd.forwardmove<0//pulling back
2046 && (pm->cmd.buttons&BUTTON_ATTACK)//attacking
2047 && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_FB ) )//pm->ps->forcePower >= SABER_ALT_ATTACK_POWER_FB//have enough power
2048 {//FIXME: some NPC logic to do this?
2049 qboolean doMove = qtrue;
2050 // if ( g_saberNewControlScheme->integer
2051 // || g_crosshairEntNum < ENTITYNUM_WORLD )//in old control scheme, there has to be someone there
2052 {
2053 saberMoveName_t pullAttackMove = LS_NONE;
2054 if ( pm->ps->fd.saberAnimLevel == SS_FAST )
2055 {
2056 pullAttackMove = LS_PULL_ATTACK_STAB;
2057 }
2058 else
2059 {
2060 pullAttackMove = LS_PULL_ATTACK_SWING;
2061 }
2062
2063 /*
2064 if ( g_crosshairEntNum < ENTITYNUM_WORLD
2065 && pm->gent && pm->gent->client )
2066 {
2067 gentity_t *targEnt = &g_entities[g_crosshairEntNum];
2068 if ( targEnt->client
2069 && targEnt->health > 0
2070 //FIXME: check other things like in knockdown, saberlock, uninterruptable anims, etc.
2071 && !PM_InOnGroundAnim( &targEnt->client->ps )
2072 && !PM_LockedAnim( targEnt->client->ps.legsAnim )
2073 && !PM_SuperBreakLoseAnim( targEnt->client->ps.legsAnim )
2074 && !PM_SuperBreakWinAnim( targEnt->client->ps.legsAnim )
2075 && targEnt->client->ps.saberLockTime <= 0
2076 && WP_ForceThrowable( targEnt, targEnt, pm->gent, qtrue, 1.0f, 0.0f, NULL ) )
2077 {
2078 if ( !g_saberNewControlScheme->integer )
2079 {//in old control scheme, make sure they're close or far enough away for the move we'll be doing
2080 float targDist = Distance( targEnt->currentOrigin, pm->ps->origin );
2081 if ( pullAttackMove == LS_PULL_ATTACK_STAB )
2082 {//must be closer than 512
2083 if ( targDist > 384.0f )
2084 {
2085 return LS_NONE;
2086 }
2087 }
2088 else//if ( pullAttackMove == LS_PULL_ATTACK_SWING )
2089 {//must be farther than 256
2090 if ( targDist > 512.0f )
2091 {
2092 return LS_NONE;
2093 }
2094 if ( targDist < 192.0f )
2095 {
2096 return LS_NONE;
2097 }
2098 }
2099 }
2100
2101 vec3_t targAngles = {0,targEnt->client->ps.viewangles[YAW],0};
2102 if ( InFront( pm->ps->origin, targEnt->currentOrigin, targAngles ) )
2103 {
2104 NPC_SetAnim( targEnt, SETANIM_BOTH, BOTH_PULLED_INAIR_F, SETANIM_FLAG_OVERRIDE, SETANIM_FLAG_HOLD );
2105 }
2106 else
2107 {
2108 NPC_SetAnim( targEnt, SETANIM_BOTH, BOTH_PULLED_INAIR_B, SETANIM_FLAG_OVERRIDE, SETANIM_FLAG_HOLD );
2109 }
2110 //hold the anim until I'm with done pull anim
2111 targEnt->client->ps.legsAnimTimer = targEnt->client->ps.torsoAnimTimer = PM_AnimLength( pm->gent->client->clientInfo.animFileIndex, (animNumber_t)saberMoveData[pullAttackMove].animToUse );
2112 //set pullAttackTime
2113 pm->gent->client->ps.pullAttackTime = targEnt->client->ps.pullAttackTime = level.time+targEnt->client->ps.legsAnimTimer;
2114 //make us know about each other
2115 pm->gent->client->ps.pullAttackEntNum = g_crosshairEntNum;
2116 targEnt->client->ps.pullAttackEntNum = pm->ps->clientNum;
2117 //do effect and sound on me
2118 pm->ps->powerups[PW_FORCE_PUSH] = level.time + 1000;
2119 if ( pm->gent )
2120 {
2121 G_Sound( pm->gent, G_SoundIndex( "sound/weapons/force/pull.wav" ) );
2122 }
2123 doMove = qtrue;
2124 }
2125 }
2126 */
2127 if ( doMove )
2128 {
2129 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB );
2130 return pullAttackMove;
2131 }
2132 }
2133 }
2134 #endif
2135 return LS_NONE;
2136 }
2137
PM_InSecondaryStyle(void)2138 qboolean PM_InSecondaryStyle( void )
2139 {
2140 if ( pm->ps->fd.saberAnimLevelBase == SS_STAFF
2141 || pm->ps->fd.saberAnimLevelBase == SS_DUAL )
2142 {
2143 if ( pm->ps->fd.saberAnimLevel != pm->ps->fd.saberAnimLevelBase )
2144 {
2145 return qtrue;
2146 }
2147 }
2148 return qfalse;
2149 }
2150
PM_SaberAttackForMovement(saberMoveName_t curmove)2151 saberMoveName_t PM_SaberAttackForMovement(saberMoveName_t curmove)
2152 {
2153 saberMoveName_t newmove = LS_NONE;
2154 qboolean noSpecials = PM_InSecondaryStyle();
2155 qboolean allowCartwheels = qtrue;
2156 saberMoveName_t overrideJumpRightAttackMove = LS_INVALID;
2157 saberMoveName_t overrideJumpLeftAttackMove = LS_INVALID;
2158
2159 if ( pm->ps->weapon == WP_SABER )
2160 {
2161 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
2162 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
2163
2164 if ( saber1
2165 && saber1->jumpAtkRightMove != LS_INVALID )
2166 {
2167 if ( saber1->jumpAtkRightMove != LS_NONE )
2168 {//actually overriding
2169 overrideJumpRightAttackMove = (saberMoveName_t)saber1->jumpAtkRightMove;
2170 }
2171 else if ( saber2
2172 && saber2->jumpAtkRightMove > LS_NONE )
2173 {//would be cancelling it, but check the second saber, too
2174 overrideJumpRightAttackMove = (saberMoveName_t)saber2->jumpAtkRightMove;
2175 }
2176 else
2177 {//nope, just cancel it
2178 overrideJumpRightAttackMove = LS_NONE;
2179 }
2180 }
2181 else if ( saber2
2182 && saber2->jumpAtkRightMove != LS_INVALID )
2183 {//first saber not overridden, check second
2184 overrideJumpRightAttackMove = (saberMoveName_t)saber2->jumpAtkRightMove;
2185 }
2186
2187 if ( saber1
2188 && saber1->jumpAtkLeftMove != LS_INVALID )
2189 {
2190 if ( saber1->jumpAtkLeftMove != LS_NONE )
2191 {//actually overriding
2192 overrideJumpLeftAttackMove = (saberMoveName_t)saber1->jumpAtkLeftMove;
2193 }
2194 else if ( saber2
2195 && saber2->jumpAtkLeftMove > LS_NONE )
2196 {//would be cancelling it, but check the second saber, too
2197 overrideJumpLeftAttackMove = (saberMoveName_t)saber2->jumpAtkLeftMove;
2198 }
2199 else
2200 {//nope, just cancel it
2201 overrideJumpLeftAttackMove = LS_NONE;
2202 }
2203 }
2204 else if ( saber2
2205 && saber2->jumpAtkLeftMove != LS_INVALID )
2206 {//first saber not overridden, check second
2207 overrideJumpLeftAttackMove = (saberMoveName_t)saber1->jumpAtkLeftMove;
2208 }
2209
2210 if ( saber1
2211 && (saber1->saberFlags&SFL_NO_CARTWHEELS) )
2212 {
2213 allowCartwheels = qfalse;
2214 }
2215 if ( saber2
2216 && (saber2->saberFlags&SFL_NO_CARTWHEELS) )
2217 {
2218 allowCartwheels = qfalse;
2219 }
2220 }
2221
2222 if ( pm->cmd.rightmove > 0 )
2223 {//moving right
2224 if ( !noSpecials
2225 && overrideJumpRightAttackMove != LS_NONE
2226 && pm->ps->velocity[2] > 20.0f //pm->ps->groundEntityNum != ENTITYNUM_NONE//on ground
2227 && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack
2228 && PM_GroundDistance() < 70.0f //not too high above ground
2229 && ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player
2230 && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power
2231 {//cartwheel right
2232 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR);
2233 if ( overrideJumpRightAttackMove != LS_INVALID )
2234 {//overridden with another move
2235 return overrideJumpRightAttackMove;
2236 }
2237 else
2238 {
2239 vec3_t right, fwdAngles;
2240
2241 VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f);
2242
2243 AngleVectors( fwdAngles, NULL, right, NULL );
2244 pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f;
2245 VectorMA( pm->ps->velocity, 190.0f, right, pm->ps->velocity );
2246 if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
2247 {
2248 newmove = LS_BUTTERFLY_RIGHT;
2249 pm->ps->velocity[2] = 350.0f;
2250 }
2251 else if ( allowCartwheels )
2252 {
2253 //PM_SetJumped( JUMP_VELOCITY, qtrue );
2254 PM_AddEvent( EV_JUMP );
2255 pm->ps->velocity[2] = 300.0f;
2256
2257 //if ( !Q_irand( 0, 1 ) )
2258 //if (PM_GroundDistance() >= 25.0f)
2259 if (1)
2260 {
2261 newmove = LS_JUMPATTACK_ARIAL_RIGHT;
2262 }
2263 else
2264 {
2265 newmove = LS_JUMPATTACK_CART_RIGHT;
2266 }
2267 }
2268 }
2269 }
2270 else if ( pm->cmd.forwardmove > 0 )
2271 {//forward right = TL2BR slash
2272 newmove = LS_A_TL2BR;
2273 }
2274 else if ( pm->cmd.forwardmove < 0 )
2275 {//backward right = BL2TR uppercut
2276 newmove = LS_A_BL2TR;
2277 }
2278 else
2279 {//just right is a left slice
2280 newmove = LS_A_L2R;
2281 }
2282 }
2283 else if ( pm->cmd.rightmove < 0 )
2284 {//moving left
2285 if ( !noSpecials
2286 && overrideJumpLeftAttackMove != LS_NONE
2287 && pm->ps->velocity[2] > 20.0f //pm->ps->groundEntityNum != ENTITYNUM_NONE//on ground
2288 && (pm->cmd.buttons&BUTTON_ATTACK)//hitting attack
2289 && PM_GroundDistance() < 70.0f //not too high above ground
2290 && ( pm->cmd.upmove > 0 || (pm->ps->pm_flags & PMF_JUMP_HELD) )//focus-holding player
2291 && BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_LR ) )//have enough power
2292 {//cartwheel left
2293 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_LR);
2294
2295 if ( overrideJumpLeftAttackMove != LS_INVALID )
2296 {//overridden with another move
2297 return overrideJumpLeftAttackMove;
2298 }
2299 else
2300 {
2301 vec3_t right, fwdAngles;
2302
2303 VectorSet(fwdAngles, 0.0f, pm->ps->viewangles[YAW], 0.0f);
2304 AngleVectors( fwdAngles, NULL, right, NULL );
2305 pm->ps->velocity[0] = pm->ps->velocity[1] = 0.0f;
2306 VectorMA( pm->ps->velocity, -190.0f, right, pm->ps->velocity );
2307 if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
2308 {
2309 newmove = LS_BUTTERFLY_LEFT;
2310 pm->ps->velocity[2] = 250.0f;
2311 }
2312 else if ( allowCartwheels )
2313 {
2314 //PM_SetJumped( JUMP_VELOCITY, qtrue );
2315 PM_AddEvent( EV_JUMP );
2316 pm->ps->velocity[2] = 350.0f;
2317
2318 //if ( !Q_irand( 0, 1 ) )
2319 //if (PM_GroundDistance() >= 25.0f)
2320 if (1)
2321 {
2322 newmove = LS_JUMPATTACK_ARIAL_LEFT;
2323 }
2324 else
2325 {
2326 newmove = LS_JUMPATTACK_CART_LEFT;
2327 }
2328 }
2329 }
2330 }
2331 else if ( pm->cmd.forwardmove > 0 )
2332 {//forward left = TR2BL slash
2333 newmove = LS_A_TR2BL;
2334 }
2335 else if ( pm->cmd.forwardmove < 0 )
2336 {//backward left = BR2TL uppercut
2337 newmove = LS_A_BR2TL;
2338 }
2339 else
2340 {//just left is a right slice
2341 newmove = LS_A_R2L;
2342 }
2343 }
2344 else
2345 {//not moving left or right
2346 if ( pm->cmd.forwardmove > 0 )
2347 {//forward= T2B slash
2348 if (!noSpecials&&
2349 (pm->ps->fd.saberAnimLevel == SS_DUAL || pm->ps->fd.saberAnimLevel == SS_STAFF) &&
2350 pm->ps->fd.forceRageRecoveryTime < pm->cmd.serverTime &&
2351 //pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 &&
2352 (pm->ps->groundEntityNum != ENTITYNUM_NONE || PM_GroundDistance() <= 40) &&
2353 pm->ps->velocity[2] >= 0 &&
2354 (pm->cmd.upmove > 0 || pm->ps->pm_flags & PMF_JUMP_HELD) &&
2355 !BG_SaberInTransitionAny(pm->ps->saberMove) &&
2356 !BG_SaberInAttack(pm->ps->saberMove) &&
2357 pm->ps->weaponTime <= 0 &&
2358 pm->ps->forceHandExtend == HANDEXTEND_NONE &&
2359 (pm->cmd.buttons & BUTTON_ATTACK)&&
2360 BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) )
2361 { //DUAL/STAFF JUMP ATTACK
2362 newmove = PM_SaberJumpAttackMove2();
2363 if ( newmove != LS_A_T2B
2364 && newmove != LS_NONE )
2365 {
2366 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
2367 }
2368 }
2369 else if (!noSpecials&&
2370 pm->ps->fd.saberAnimLevel == SS_MEDIUM &&
2371 pm->ps->velocity[2] > 100 &&
2372 PM_GroundDistance() < 32 &&
2373 !BG_InSpecialJump(pm->ps->legsAnim) &&
2374 !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
2375 BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB))
2376 { //FLIP AND DOWNWARD ATTACK
2377 //trace_t tr;
2378
2379 //if (PM_SomeoneInFront(&tr))
2380 {
2381 newmove = PM_SaberFlipOverAttackMove();
2382 if ( newmove != LS_A_T2B
2383 && newmove != LS_NONE )
2384 {
2385 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
2386 }
2387 }
2388 }
2389 else if (!noSpecials&&
2390 pm->ps->fd.saberAnimLevel == SS_STRONG &&
2391 pm->ps->velocity[2] > 100 &&
2392 PM_GroundDistance() < 32 &&
2393 !BG_InSpecialJump(pm->ps->legsAnim) &&
2394 !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
2395 BG_EnoughForcePowerForMove( SABER_ALT_ATTACK_POWER_FB ))
2396 { //DFA
2397 //trace_t tr;
2398
2399 //if (PM_SomeoneInFront(&tr))
2400 {
2401 newmove = PM_SaberJumpAttackMove();
2402 if ( newmove != LS_A_T2B
2403 && newmove != LS_NONE )
2404 {
2405 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
2406 }
2407 }
2408 }
2409 else if ((pm->ps->fd.saberAnimLevel == SS_FAST || pm->ps->fd.saberAnimLevel == SS_DUAL || pm->ps->fd.saberAnimLevel == SS_STAFF) &&
2410 pm->ps->groundEntityNum != ENTITYNUM_NONE &&
2411 (pm->ps->pm_flags & PMF_DUCKED) &&
2412 pm->ps->weaponTime <= 0 &&
2413 !BG_SaberInSpecialAttack(pm->ps->torsoAnim)&&
2414 BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB))
2415 { //LUNGE (weak)
2416 newmove = PM_SaberLungeAttackMove( noSpecials );
2417 if ( newmove != LS_A_T2B
2418 && newmove != LS_NONE )
2419 {
2420 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
2421 }
2422 }
2423 else if ( !noSpecials )
2424 {
2425 saberMoveName_t stabDownMove = PM_CheckStabDown();
2426 if (stabDownMove != LS_NONE
2427 && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) )
2428 {
2429 newmove = stabDownMove;
2430 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
2431 }
2432 else
2433 {
2434 newmove = LS_A_T2B;
2435 }
2436 }
2437 }
2438 else if ( pm->cmd.forwardmove < 0 )
2439 {//backward= T2B slash//B2T uppercut?
2440 if (!noSpecials&&
2441 pm->ps->fd.saberAnimLevel == SS_STAFF &&
2442 pm->ps->fd.forceRageRecoveryTime < pm->cmd.serverTime &&
2443 pm->ps->fd.forcePowerLevel[FP_LEVITATION] > FORCE_LEVEL_1 &&
2444 (pm->ps->groundEntityNum != ENTITYNUM_NONE || PM_GroundDistance() <= 40) &&
2445 pm->ps->velocity[2] >= 0 &&
2446 (pm->cmd.upmove > 0 || pm->ps->pm_flags & PMF_JUMP_HELD) &&
2447 !BG_SaberInTransitionAny(pm->ps->saberMove) &&
2448 !BG_SaberInAttack(pm->ps->saberMove) &&
2449 pm->ps->weaponTime <= 0 &&
2450 pm->ps->forceHandExtend == HANDEXTEND_NONE &&
2451 (pm->cmd.buttons & BUTTON_ATTACK))
2452 { //BACKFLIP ATTACK
2453 newmove = PM_SaberBackflipAttackMove();
2454 }
2455 else if (PM_CanBackstab() && !BG_SaberInSpecialAttack(pm->ps->torsoAnim))
2456 { //BACKSTAB (attack varies by level)
2457 if (pm->ps->fd.saberAnimLevel >= FORCE_LEVEL_2 && pm->ps->fd.saberAnimLevel != SS_STAFF)
2458 {//medium and higher attacks
2459 if ( (pm->ps->pm_flags&PMF_DUCKED) || pm->cmd.upmove < 0 )
2460 {
2461 newmove = LS_A_BACK_CR;
2462 }
2463 else
2464 {
2465 newmove = LS_A_BACK;
2466 }
2467 }
2468 else
2469 { //weak attack
2470 newmove = LS_A_BACKSTAB;
2471 }
2472 }
2473 else
2474 {
2475 newmove = LS_A_T2B;
2476 }
2477 }
2478 else if ( PM_SaberInBounce( curmove ) )
2479 {//bounces should go to their default attack if you don't specify a direction but are attacking
2480 newmove = saberMoveData[curmove].chain_attack;
2481
2482 if ( PM_SaberKataDone(curmove, newmove) )
2483 {
2484 newmove = saberMoveData[curmove].chain_idle;
2485 }
2486 else
2487 {
2488 newmove = saberMoveData[curmove].chain_attack;
2489 }
2490 }
2491 else if ( curmove == LS_READY )
2492 {//Not moving at all, shouldn't have gotten here...?
2493 //for now, just pick a random attack
2494 //newmove = Q_irand( LS_A_TL2BR, LS_A_T2B );
2495 //rww - If we don't seed with a "common" value, the client and server will get mismatched
2496 //prediction values. Under laggy conditions this will cause the appearance of rapid swing
2497 //sequence changes.
2498
2499 newmove = LS_A_T2B; //decided we don't like random attacks when idle, use an overhead instead.
2500 }
2501 }
2502
2503 if (pm->ps->fd.saberAnimLevel == SS_DUAL)
2504 {
2505 if ( ( newmove == LS_A_R2L || newmove == LS_S_R2L
2506 || newmove == LS_A_L2R || newmove == LS_S_L2R )
2507 && PM_CanDoDualDoubleAttacks()
2508 && PM_CheckEnemyPresence( DIR_RIGHT, 100.0f )
2509 && PM_CheckEnemyPresence( DIR_LEFT, 100.0f ) )
2510 {//enemy both on left and right
2511 newmove = LS_DUAL_LR;
2512 //probably already moved, but...
2513 pm->cmd.rightmove = 0;
2514 }
2515 else if ( (newmove == LS_A_T2B || newmove == LS_S_T2B
2516 || newmove == LS_A_BACK || newmove == LS_A_BACK_CR )
2517 && PM_CanDoDualDoubleAttacks()
2518 && PM_CheckEnemyPresence( DIR_FRONT, 100.0f )
2519 && PM_CheckEnemyPresence( DIR_BACK, 100.0f ) )
2520 {//enemy both in front and back
2521 newmove = LS_DUAL_FB;
2522 //probably already moved, but...
2523 pm->cmd.forwardmove = 0;
2524 }
2525 }
2526
2527 return newmove;
2528 }
2529
PM_KickMoveForConditions(void)2530 int PM_KickMoveForConditions(void)
2531 {
2532 int kickMove = -1;
2533
2534 //FIXME: only if FP_SABER_OFFENSE >= 3
2535 if ( pm->cmd.rightmove )
2536 {//kick to side
2537 if ( pm->cmd.rightmove > 0 )
2538 {//kick right
2539 kickMove = LS_KICK_R;
2540 }
2541 else
2542 {//kick left
2543 kickMove = LS_KICK_L;
2544 }
2545 pm->cmd.rightmove = 0;
2546 }
2547 else if ( pm->cmd.forwardmove )
2548 {//kick front/back
2549 if ( pm->cmd.forwardmove > 0 )
2550 {//kick fwd
2551 /*
2552 if (pm->ps->groundEntityNum != ENTITYNUM_NONE &&
2553 PM_CheckEnemyPresence( DIR_FRONT, 64.0f ))
2554 {
2555 kickMove = LS_HILT_BASH;
2556 }
2557 else
2558 */
2559 {
2560 kickMove = LS_KICK_F;
2561 }
2562 }
2563 else
2564 {//kick back
2565 kickMove = LS_KICK_B;
2566 }
2567 pm->cmd.forwardmove = 0;
2568 }
2569 else
2570 {
2571 //if (pm->cmd.buttons & BUTTON_ATTACK)
2572 //if (pm->ps->pm_flags & PMF_JUMP_HELD)
2573 if (0)
2574 { //ok, let's try some fancy kicks
2575 //qboolean is actually of type int anyway, but just for safeness.
2576 int front = (int)PM_CheckEnemyPresence( DIR_FRONT, 100.0f );
2577 int back = (int)PM_CheckEnemyPresence( DIR_BACK, 100.0f );
2578 int right = (int)PM_CheckEnemyPresence( DIR_RIGHT, 100.0f );
2579 int left = (int)PM_CheckEnemyPresence( DIR_LEFT, 100.0f );
2580 int numEnemy = front+back+right+left;
2581
2582 if (numEnemy >= 3 ||
2583 ((!right || !left) && numEnemy >= 2))
2584 { //> 2 enemies near, or, >= 2 enemies near and they are not to the right and left.
2585 kickMove = LS_KICK_S;
2586 }
2587 else if (right && left)
2588 { //enemies on both sides
2589 kickMove = LS_KICK_RL;
2590 }
2591 else
2592 { //oh well, just do a forward kick
2593 kickMove = LS_KICK_F;
2594 }
2595
2596 pm->cmd.upmove = 0;
2597 }
2598 }
2599
2600 return kickMove;
2601 }
2602
2603 qboolean BG_InSlopeAnim( int anim );
2604 qboolean PM_RunningAnim( int anim );
2605
PM_SaberMoveOkayForKata(void)2606 qboolean PM_SaberMoveOkayForKata( void )
2607 {
2608 if ( pm->ps->saberMove == LS_READY
2609 || PM_SaberInStart( pm->ps->saberMove ) )
2610 {
2611 return qtrue;
2612 }
2613 else
2614 {
2615 return qfalse;
2616 }
2617 }
2618
PM_CanDoKata(void)2619 qboolean PM_CanDoKata( void )
2620 {
2621 if ( PM_InSecondaryStyle() )
2622 {
2623 return qfalse;
2624 }
2625
2626 if ( !pm->ps->saberInFlight//not throwing saber
2627 && PM_SaberMoveOkayForKata()
2628 && !BG_SaberInKata(pm->ps->saberMove)
2629 && !BG_InKataAnim(pm->ps->legsAnim)
2630 && !BG_InKataAnim(pm->ps->torsoAnim)
2631 /*
2632 && pm->ps->saberAnimLevel >= SS_FAST//fast, med or strong style
2633 && pm->ps->saberAnimLevel <= SS_STRONG//FIXME: Tavion, too?
2634 */
2635 && pm->ps->groundEntityNum != ENTITYNUM_NONE//not in the air
2636 && (pm->cmd.buttons&BUTTON_ATTACK)//pressing attack
2637 && (pm->cmd.buttons&BUTTON_ALT_ATTACK)//pressing alt attack
2638 && !pm->cmd.forwardmove//not moving f/b
2639 && !pm->cmd.rightmove//not moving r/l
2640 && pm->cmd.upmove <= 0//not jumping...?
2641 && BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER) )// have enough power
2642 {//FIXME: check rage, etc...
2643 saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
2644 if ( saber
2645 && saber->kataMove == LS_NONE )
2646 {//kata move has been overridden in a way that should stop you from doing it at all
2647 return qfalse;
2648 }
2649 saber = BG_MySaber( pm->ps->clientNum, 1 );
2650 if ( saber
2651 && saber->kataMove == LS_NONE )
2652 {//kata move has been overridden in a way that should stop you from doing it at all
2653 return qfalse;
2654 }
2655 return qtrue;
2656 }
2657 return qfalse;
2658 }
2659
PM_CheckAltKickAttack(void)2660 qboolean PM_CheckAltKickAttack( void )
2661 {
2662 if ( pm->ps->weapon == WP_SABER )
2663 {
2664 saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
2665 if ( saber
2666 && (saber->saberFlags&SFL_NO_KICKS) )
2667 {
2668 return qfalse;
2669 }
2670 saber = BG_MySaber( pm->ps->clientNum, 1 );
2671 if ( saber
2672 && (saber->saberFlags&SFL_NO_KICKS) )
2673 {
2674 return qfalse;
2675 }
2676 }
2677 if ( (pm->cmd.buttons&BUTTON_ALT_ATTACK)
2678 //&& (!(pm->ps->pm_flags&PMF_ALT_ATTACK_HELD)||PM_SaberInReturn(pm->ps->saberMove))
2679 && (!BG_FlippingAnim(pm->ps->legsAnim)||pm->ps->legsTimer<=250)
2680 && (pm->ps->fd.saberAnimLevel == SS_STAFF/*||!pm->ps->saber[0].throwable*/) && !pm->ps->saberHolstered )
2681 {
2682 return qtrue;
2683 }
2684 return qfalse;
2685 }
2686
2687 int bg_parryDebounce[NUM_FORCE_POWER_LEVELS] =
2688 {
2689 500,//if don't even have defense, can't use defense!
2690 300,
2691 150,
2692 50
2693 };
2694
PM_SaberPowerCheck(void)2695 qboolean PM_SaberPowerCheck(void)
2696 {
2697 if (pm->ps->saberInFlight)
2698 { //so we don't keep doing stupid force out thing while guiding saber.
2699 if (pm->ps->fd.forcePower > forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW])
2700 {
2701 return qtrue;
2702 }
2703 }
2704 else
2705 {
2706 return BG_EnoughForcePowerForMove(forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW]);
2707 }
2708
2709 return qfalse;
2710 }
2711
PM_CanDoRollStab(void)2712 qboolean PM_CanDoRollStab( void )
2713 {
2714 if ( pm->ps->weapon == WP_SABER )
2715 {
2716 saberInfo_t *saber = BG_MySaber( pm->ps->clientNum, 0 );
2717 if ( saber
2718 && (saber->saberFlags&SFL_NO_ROLL_STAB) )
2719 {
2720 return qfalse;
2721 }
2722 saber = BG_MySaber( pm->ps->clientNum, 1 );
2723 if ( saber
2724 && (saber->saberFlags&SFL_NO_ROLL_STAB) )
2725 {
2726 return qfalse;
2727 }
2728 }
2729 return qtrue;
2730 }
2731 /*
2732 =================
2733 PM_WeaponLightsaber
2734
2735 Consults a chart to choose what to do with the lightsaber.
2736 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.
2737 =================
2738 */
2739 // Ultimate goal is to set the sabermove to the proper next location
2740 // Note that if the resultant animation is NONE, then the animation is essentially "idle", and is set in WP_TorsoAnim
2741 qboolean PM_WalkingAnim( int anim );
2742 qboolean PM_SwimmingAnim( int anim );
2743 int PM_SaberBounceForAttack( int move );
2744 qboolean BG_SuperBreakLoseAnim( int anim );
2745 qboolean BG_SuperBreakWinAnim( int anim );
PM_WeaponLightsaber(void)2746 void PM_WeaponLightsaber(void)
2747 {
2748 int addTime;
2749 qboolean delayed_fire = qfalse;
2750 int anim=-1, curmove, newmove=LS_NONE;
2751
2752 qboolean checkOnlyWeap = qfalse;
2753
2754 if ( PM_InKnockDown( pm->ps ) || BG_InRoll( pm->ps, pm->ps->legsAnim ))
2755 {//in knockdown
2756 // make weapon function
2757 if ( pm->ps->weaponTime > 0 ) {
2758 pm->ps->weaponTime -= pml.msec;
2759 if ( pm->ps->weaponTime <= 0 )
2760 {
2761 pm->ps->weaponTime = 0;
2762 }
2763 }
2764 if ( pm->ps->legsAnim == BOTH_ROLL_F
2765 && pm->ps->legsTimer <= 250 )
2766 {
2767 if ( (pm->cmd.buttons&BUTTON_ATTACK) )
2768 {
2769 if ( BG_EnoughForcePowerForMove(SABER_ALT_ATTACK_POWER_FB) && !pm->ps->saberInFlight )
2770 {
2771 if ( PM_CanDoRollStab() )
2772 {
2773 //make sure the saber is on for this move!
2774 if ( pm->ps->saberHolstered == 2 )
2775 {//all the way off
2776 pm->ps->saberHolstered = 0;
2777 PM_AddEvent(EV_SABER_UNHOLSTER);
2778 }
2779 PM_SetSaberMove( LS_ROLL_STAB );
2780 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER_FB);
2781 }
2782 }
2783 }
2784 }
2785 return;
2786 }
2787
2788 if ( pm->ps->saberLockTime > pm->cmd.serverTime )
2789 {
2790 pm->ps->saberMove = LS_NONE;
2791 PM_SaberLocked();
2792 return;
2793 }
2794 else
2795 {
2796 if ( /*( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
2797 (pm->ps->torsoAnim) == BOTH_BF1LOCK ||
2798 (pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
2799 (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||*/
2800 pm->ps->saberLockFrame
2801 )
2802 {
2803 if (pm->ps->saberLockEnemy < ENTITYNUM_NONE &&
2804 pm->ps->saberLockEnemy >= 0)
2805 {
2806 bgEntity_t *bgEnt;
2807 playerState_t *en;
2808
2809 bgEnt = PM_BGEntForNum(pm->ps->saberLockEnemy);
2810
2811 if (bgEnt)
2812 {
2813 en = bgEnt->playerState;
2814
2815 if (en)
2816 {
2817 PM_SaberLockBreak(en, qfalse, 0);
2818 return;
2819 }
2820 }
2821 }
2822
2823 if (/* ( (pm->ps->torsoAnim) == BOTH_BF2LOCK ||
2824 (pm->ps->torsoAnim) == BOTH_BF1LOCK ||
2825 (pm->ps->torsoAnim) == BOTH_CWCIRCLELOCK ||
2826 (pm->ps->torsoAnim) == BOTH_CCWCIRCLELOCK ||*/
2827 pm->ps->saberLockFrame
2828 )
2829 {
2830 pm->ps->torsoTimer = 0;
2831 PM_SetAnim(SETANIM_TORSO,BOTH_STAND1,SETANIM_FLAG_OVERRIDE);
2832 pm->ps->saberLockFrame = 0;
2833 }
2834 }
2835 }
2836
2837 if ( BG_KickingAnim( pm->ps->legsAnim ) ||
2838 BG_KickingAnim( pm->ps->torsoAnim ))
2839 {
2840 if ( pm->ps->legsTimer > 0 )
2841 {//you're kicking, no interruptions
2842 return;
2843 }
2844 //done? be immeditately ready to do an attack
2845 pm->ps->saberMove = LS_READY;
2846 pm->ps->weaponTime = 0;
2847 }
2848
2849 if ( BG_SuperBreakLoseAnim( pm->ps->torsoAnim )
2850 || BG_SuperBreakWinAnim( pm->ps->torsoAnim ) )
2851 {
2852 if ( pm->ps->torsoTimer > 0 )
2853 {//never interrupt these
2854 return;
2855 }
2856 }
2857
2858 if (BG_SabersOff( pm->ps ))
2859 {
2860 if (pm->ps->saberMove != LS_READY)
2861 {
2862 PM_SetSaberMove( LS_READY );
2863 }
2864
2865 if ((pm->ps->legsAnim) != (pm->ps->torsoAnim) && !BG_InSlopeAnim(pm->ps->legsAnim) &&
2866 pm->ps->torsoTimer <= 0)
2867 {
2868 PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE);
2869 }
2870 else if (BG_InSlopeAnim(pm->ps->legsAnim) && pm->ps->torsoTimer <= 0)
2871 {
2872 PM_SetAnim(SETANIM_TORSO,PM_GetSaberStance(),SETANIM_FLAG_OVERRIDE);
2873 }
2874
2875 if (pm->ps->weaponTime < 1 && ((pm->cmd.buttons & BUTTON_ALT_ATTACK) || (pm->cmd.buttons & BUTTON_ATTACK)))
2876 {
2877 if (pm->ps->duelTime < pm->cmd.serverTime)
2878 {
2879 if (!pm->ps->m_iVehicleNum)
2880 { //don't let em unholster the saber by attacking while on vehicle
2881 pm->ps->saberHolstered = 0;
2882 PM_AddEvent(EV_SABER_UNHOLSTER);
2883 }
2884 else
2885 {
2886 pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
2887 pm->cmd.buttons &= ~BUTTON_ATTACK;
2888 }
2889 }
2890 }
2891
2892 if ( pm->ps->weaponTime > 0 )
2893 {
2894 pm->ps->weaponTime -= pml.msec;
2895 }
2896
2897 checkOnlyWeap = qtrue;
2898 goto weapChecks;
2899 }
2900
2901 if (!pm->ps->saberEntityNum && pm->ps->saberInFlight)
2902 { //this means our saber has been knocked away
2903 /*
2904 if (pm->ps->saberMove != LS_READY)
2905 {
2906 PM_SetSaberMove( LS_READY );
2907 }
2908
2909 if ((pm->ps->legsAnim) != (pm->ps->torsoAnim) && !BG_InSlopeAnim(pm->ps->legsAnim))
2910 {
2911 PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE);
2912 }
2913
2914 if (BG_InSaberStandAnim(pm->ps->torsoAnim) || pm->ps->torsoAnim == BOTH_SABERPULL)
2915 {
2916 PM_SetAnim(SETANIM_TORSO,BOTH_STAND1,SETANIM_FLAG_OVERRIDE);
2917 }
2918
2919 return;
2920 */
2921 //Old method, don't want to do this now because we want to finish up reflected attacks and things
2922 //if our saber is pried out of our hands from one.
2923 if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
2924 {
2925 if ( pm->ps->saberHolstered > 1 )
2926 {
2927 pm->ps->saberHolstered = 1;
2928 }
2929 }
2930 else
2931 {
2932 pm->cmd.buttons &= ~BUTTON_ATTACK;
2933 }
2934 pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
2935 }
2936
2937 if ( (pm->cmd.buttons & BUTTON_ALT_ATTACK) )
2938 { //might as well just check for a saber throw right here
2939 if (pm->ps->fd.saberAnimLevel == SS_STAFF)
2940 { //kick instead of doing a throw
2941 //if in a saber attack return anim, can interrupt it with a kick
2942 if ( pm->ps->weaponTime > 0//can't fire yet
2943 && PM_SaberInReturn( pm->ps->saberMove )//in a saber return move - FIXME: what about transitions?
2944 //&& pm->ps->weaponTime <= 250//should be able to fire soon
2945 //&& pm->ps->torsoTimer <= 250//torso almost done
2946 && pm->ps->saberBlocked == BLOCKED_NONE//not interacting with any other saber
2947 && !(pm->cmd.buttons&BUTTON_ATTACK) )//not trying to swing the saber
2948 {
2949 if ( (pm->cmd.forwardmove||pm->cmd.rightmove)//trying to kick in a specific direction
2950 && PM_CheckAltKickAttack() )//trying to do a kick
2951 {//allow them to do the kick now!
2952 int kickMove = PM_KickMoveForConditions();
2953 if (kickMove != -1)
2954 {
2955 pm->ps->weaponTime = 0;
2956 PM_SetSaberMove( kickMove );
2957 return;
2958 }
2959 }
2960 }
2961 }
2962 else if ( pm->ps->weaponTime < 1&&
2963 pm->ps->saberCanThrow &&
2964 //pm->ps->fd.forcePower >= forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW] &&
2965 !BG_HasYsalamiri(pm->gametype, pm->ps) &&
2966 BG_CanUseFPNow(pm->gametype, pm->ps, pm->cmd.serverTime, FP_SABERTHROW) &&
2967 pm->ps->fd.forcePowerLevel[FP_SABERTHROW] > 0 &&
2968 PM_SaberPowerCheck() )
2969 {
2970 trace_t sabTr;
2971 vec3_t fwd, minFwd, sabMins, sabMaxs;
2972
2973 VectorSet( sabMins, SABERMINS_X, SABERMINS_Y, SABERMINS_Z );
2974 VectorSet( sabMaxs, SABERMAXS_X, SABERMAXS_Y, SABERMAXS_Z );
2975
2976 AngleVectors( pm->ps->viewangles, fwd, NULL, NULL );
2977 VectorMA( pm->ps->origin, SABER_MIN_THROW_DIST, fwd, minFwd );
2978
2979 pm->trace(&sabTr, pm->ps->origin, sabMins, sabMaxs, minFwd, pm->ps->clientNum, MASK_PLAYERSOLID);
2980
2981 if ( sabTr.allsolid || sabTr.startsolid || sabTr.fraction < 1.0f )
2982 {//not enough room to throw
2983 }
2984 else
2985 {//throw it
2986 //This will get set to false again once the saber makes it back to its owner game-side
2987 if (!pm->ps->saberInFlight)
2988 {
2989 pm->ps->fd.forcePower -= forcePowerNeeded[pm->ps->fd.forcePowerLevel[FP_SABERTHROW]][FP_SABERTHROW];
2990 }
2991
2992 pm->ps->saberInFlight = qtrue;
2993 }
2994 }
2995 }
2996
2997 if ( pm->ps->saberInFlight && pm->ps->saberEntityNum )
2998 {//guiding saber
2999 if ( (pm->ps->fd.saberAnimLevel != SS_DUAL //not using 2 sabers
3000 || pm->ps->saberHolstered //left one off - FIXME: saberHolstered 1 should be left one off, 0 should be both on, 2 should be both off
3001 || (!(pm->cmd.buttons&BUTTON_ATTACK)//not trying to start an attack AND...
3002 && (pm->ps->torsoAnim == BOTH_SABERDUAL_STANCE//not already attacking
3003 || pm->ps->torsoAnim == BOTH_SABERPULL//not already attacking
3004 || pm->ps->torsoAnim == BOTH_STAND1//not already attacking
3005 || PM_RunningAnim( pm->ps->torsoAnim ) //not already attacking
3006 || PM_WalkingAnim( pm->ps->torsoAnim ) //not already attacking
3007 || PM_JumpingAnim( pm->ps->torsoAnim )//not already attacking
3008 || PM_SwimmingAnim( pm->ps->torsoAnim ))//not already attacking
3009 )
3010 )
3011 )
3012 {
3013 PM_SetAnim(SETANIM_TORSO, BOTH_SABERPULL, SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD);
3014 pm->ps->torsoTimer = 1;
3015 return;
3016 }
3017 }
3018
3019 // don't allow attack until all buttons are up
3020 //This is bad. It freezes the attack state and the animations if you hold the button after respawning, and it looks strange.
3021 /*
3022 if ( pm->ps->pm_flags & PMF_RESPAWNED ) {
3023 return;
3024 }
3025 */
3026
3027 // check for dead player
3028 if ( pm->ps->stats[STAT_HEALTH] <= 0 ) {
3029 return;
3030 }
3031
3032 /*
3033
3034 if (pm->ps->weaponstate == WEAPON_READY ||
3035 pm->ps->weaponstate == WEAPON_IDLE)
3036 {
3037 if (pm->ps->saberMove != LS_READY && pm->ps->weaponTime <= 0 && !pm->ps->saberBlocked)
3038 {
3039 PM_SetSaberMove( LS_READY );
3040 }
3041 }
3042
3043 if(PM_RunningAnim(pm->ps->torsoAnim))
3044 {
3045 if ((pm->ps->torsoAnim) != (pm->ps->legsAnim))
3046 {
3047 PM_SetAnim(SETANIM_TORSO,(pm->ps->legsAnim),SETANIM_FLAG_OVERRIDE);
3048 }
3049 }
3050 */
3051
3052 // make weapon function
3053 if ( pm->ps->weaponTime > 0 )
3054 {
3055 //check for special pull move while busy
3056 saberMoveName_t pullmove = PM_CheckPullAttack();
3057 if (pullmove != LS_NONE)
3058 {
3059 pm->ps->weaponTime = 0;
3060 pm->ps->torsoTimer = 0;
3061 pm->ps->legsTimer = 0;
3062 pm->ps->forceHandExtend = HANDEXTEND_NONE;
3063 pm->ps->weaponstate = WEAPON_READY;
3064 PM_SetSaberMove(pullmove);
3065 return;
3066 }
3067
3068 pm->ps->weaponTime -= pml.msec;
3069
3070 //This was stupid and didn't work right. Looks like things are fine without it.
3071 // if (pm->ps->saberBlocked && pm->ps->torsoAnim != saberMoveData[pm->ps->saberMove].animToUse)
3072 // { //rww - keep him in the blocking pose until he can attack again
3073 // PM_SetAnim(SETANIM_TORSO,saberMoveData[pm->ps->saberMove].animToUse,saberMoveData[pm->ps->saberMove].animSetFlags|SETANIM_FLAG_HOLD);
3074 // return;
3075 // }
3076 }
3077 else
3078 {
3079 pm->ps->weaponstate = WEAPON_READY;
3080 }
3081
3082 // Now we react to a block action by the player's lightsaber.
3083 if ( pm->ps->saberBlocked )
3084 {
3085 if ( pm->ps->saberBlocked >= BLOCKED_UPPER_RIGHT
3086 && pm->ps->saberBlocked < BLOCKED_UPPER_RIGHT_PROJ)
3087 {//hold the parry for a bit
3088 pm->ps->weaponTime = bg_parryDebounce[pm->ps->fd.forcePowerLevel[FP_SABER_DEFENSE]]+200;
3089 }
3090 switch ( pm->ps->saberBlocked )
3091 {
3092 case BLOCKED_BOUNCE_MOVE:
3093 { //act as a bounceMove and reset the saberMove instead of using a seperate value for it
3094 pm->ps->torsoTimer = 0;
3095 PM_SetSaberMove( pm->ps->saberMove );
3096 pm->ps->weaponTime = pm->ps->torsoTimer;
3097 pm->ps->saberBlocked = 0;
3098 }
3099 break;
3100 case BLOCKED_PARRY_BROKEN:
3101 //whatever parry we were is in now broken, play the appropriate knocked-away anim
3102 {
3103 int nextMove;
3104
3105 if ( PM_SaberInBrokenParry( pm->ps->saberMove ) )
3106 {//already have one...?
3107 nextMove = pm->ps->saberMove;
3108 }
3109 else
3110 {
3111 nextMove = PM_BrokenParryForParry( pm->ps->saberMove );
3112 }
3113 if ( nextMove != LS_NONE )
3114 {
3115 PM_SetSaberMove( nextMove );
3116 pm->ps->weaponTime = pm->ps->torsoTimer;
3117 }
3118 else
3119 {//Maybe in a knockaway?
3120 }
3121 }
3122 break;
3123 case BLOCKED_ATK_BOUNCE:
3124 // If there is absolutely no blocked move in the chart, don't even mess with the animation.
3125 // OR if we are already in a block or parry.
3126 if (pm->ps->saberMove >= LS_T1_BR__R)
3127 {//an actual bounce? Other bounces before this are actually transitions?
3128 pm->ps->saberBlocked = BLOCKED_NONE;
3129 }
3130 else
3131 {
3132 int bounceMove;
3133
3134 if ( PM_SaberInBounce( pm->ps->saberMove ) || !BG_SaberInAttack( pm->ps->saberMove ) )
3135 {
3136 if ( pm->cmd.buttons & BUTTON_ATTACK )
3137 {//transition to a new attack
3138 int newQuad = PM_SaberMoveQuadrantForMovement( &pm->cmd );
3139 while ( newQuad == saberMoveData[pm->ps->saberMove].startQuad )
3140 {//player is still in same attack quad, don't repeat that attack because it looks bad,
3141 //FIXME: try to pick one that might look cool?
3142 //newQuad = Q_irand( Q_BR, Q_BL );
3143 newQuad = PM_irand_timesync( Q_BR, Q_BL );
3144 //FIXME: sanity check, just in case?
3145 }//else player is switching up anyway, take the new attack dir
3146 bounceMove = transitionMove[saberMoveData[pm->ps->saberMove].startQuad][newQuad];
3147 }
3148 else
3149 {//return to ready
3150 if ( saberMoveData[pm->ps->saberMove].startQuad == Q_T )
3151 {
3152 bounceMove = LS_R_BL2TR;
3153 }
3154 else if ( saberMoveData[pm->ps->saberMove].startQuad < Q_T )
3155 {
3156 bounceMove = LS_R_TL2BR+saberMoveData[pm->ps->saberMove].startQuad-Q_BR;
3157 }
3158 else// if ( saberMoveData[pm->ps->saberMove].startQuad > Q_T )
3159 {
3160 bounceMove = LS_R_BR2TL+saberMoveData[pm->ps->saberMove].startQuad-Q_TL;
3161 }
3162 }
3163 }
3164 else
3165 {//start the bounce
3166 bounceMove = PM_SaberBounceForAttack( (saberMoveName_t)pm->ps->saberMove );
3167 }
3168
3169 PM_SetSaberMove( bounceMove );
3170
3171 pm->ps->weaponTime = pm->ps->torsoTimer;//+saberMoveData[bounceMove].blendTime+SABER_BLOCK_DUR;
3172
3173 }
3174 break;
3175 case BLOCKED_UPPER_RIGHT:
3176 PM_SetSaberMove( LS_PARRY_UR );
3177 break;
3178 case BLOCKED_UPPER_RIGHT_PROJ:
3179 PM_SetSaberMove( LS_REFLECT_UR );
3180 break;
3181 case BLOCKED_UPPER_LEFT:
3182 PM_SetSaberMove( LS_PARRY_UL );
3183 break;
3184 case BLOCKED_UPPER_LEFT_PROJ:
3185 PM_SetSaberMove( LS_REFLECT_UL );
3186 break;
3187 case BLOCKED_LOWER_RIGHT:
3188 PM_SetSaberMove( LS_PARRY_LR );
3189 break;
3190 case BLOCKED_LOWER_RIGHT_PROJ:
3191 PM_SetSaberMove( LS_REFLECT_LR );
3192 break;
3193 case BLOCKED_LOWER_LEFT:
3194 PM_SetSaberMove( LS_PARRY_LL );
3195 break;
3196 case BLOCKED_LOWER_LEFT_PROJ:
3197 PM_SetSaberMove( LS_REFLECT_LL);
3198 break;
3199 case BLOCKED_TOP:
3200 PM_SetSaberMove( LS_PARRY_UP );
3201 break;
3202 case BLOCKED_TOP_PROJ:
3203 PM_SetSaberMove( LS_REFLECT_UP );
3204 break;
3205 default:
3206 pm->ps->saberBlocked = BLOCKED_NONE;
3207 break;
3208 }
3209 if ( pm->ps->saberBlocked >= BLOCKED_UPPER_RIGHT
3210 && pm->ps->saberBlocked < BLOCKED_UPPER_RIGHT_PROJ)
3211 {//hold the parry for a bit
3212 if ( pm->ps->torsoTimer < pm->ps->weaponTime )
3213 {
3214 pm->ps->torsoTimer = pm->ps->weaponTime;
3215 }
3216 }
3217
3218 //what the? I don't know why I was doing this.
3219 /*
3220 if (pm->ps->saberBlocked != BLOCKED_ATK_BOUNCE && pm->ps->saberBlocked != BLOCKED_PARRY_BROKEN && pm->ps->weaponTime < 1)
3221 {
3222 pm->ps->torsoTimer = SABER_BLOCK_DUR;
3223 pm->ps->weaponTime = pm->ps->torsoTimer;
3224 }
3225 */
3226
3227 //clear block
3228 pm->ps->saberBlocked = 0;
3229
3230 // Charging is like a lead-up before attacking again. This is an appropriate use, or we can create a new weaponstate for blocking
3231 pm->ps->weaponstate = WEAPON_READY;
3232
3233 // Done with block, so stop these active weapon branches.
3234 return;
3235 }
3236
3237 weapChecks:
3238 if (pm->ps->saberEntityNum)
3239 { //only check if we have our saber with us
3240 // check for weapon change
3241 // can't change if weapon is firing, but can change again if lowering or raising
3242 //if ( pm->ps->weaponTime <= 0 || pm->ps->weaponstate != WEAPON_FIRING ) {
3243 if (pm->ps->weaponTime <= 0 && pm->ps->torsoTimer <= 0)
3244 {
3245 if ( pm->ps->weapon != pm->cmd.weapon ) {
3246 PM_BeginWeaponChange( pm->cmd.weapon );
3247 }
3248 }
3249 }
3250
3251 if ( PM_CanDoKata() )
3252 {
3253 saberMoveName_t overrideMove = LS_INVALID;
3254 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
3255 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
3256 //see if we have an overridden (or cancelled) kata move
3257 if ( saber1 && saber1->kataMove != LS_INVALID )
3258 {
3259 if ( saber1->kataMove != LS_NONE )
3260 {
3261 overrideMove = (saberMoveName_t)saber1->kataMove;
3262 }
3263 }
3264 if ( overrideMove == LS_INVALID )
3265 {//not overridden by first saber, check second
3266 if ( saber2
3267 && saber2->kataMove != LS_INVALID )
3268 {
3269 if ( saber2->kataMove != LS_NONE )
3270 {
3271 overrideMove = (saberMoveName_t)saber2->kataMove;
3272 }
3273 }
3274 }
3275 //no overrides, cancelled?
3276 if ( overrideMove == LS_INVALID )
3277 {
3278 if ( saber2
3279 && saber2->kataMove == LS_NONE )
3280 {
3281 overrideMove = LS_NONE;
3282 }
3283 else if ( saber2
3284 && saber2->kataMove == LS_NONE )
3285 {
3286 overrideMove = LS_NONE;
3287 }
3288 }
3289 if ( overrideMove == LS_INVALID )
3290 {//not overridden
3291 //FIXME: make sure to turn on saber(s)!
3292 switch ( pm->ps->fd.saberAnimLevel )
3293 {
3294 case SS_FAST:
3295 case SS_TAVION:
3296 PM_SetSaberMove( LS_A1_SPECIAL );
3297 break;
3298 case SS_MEDIUM:
3299 PM_SetSaberMove( LS_A2_SPECIAL );
3300 break;
3301 case SS_STRONG:
3302 case SS_DESANN:
3303 PM_SetSaberMove( LS_A3_SPECIAL );
3304 break;
3305 case SS_DUAL:
3306 PM_SetSaberMove( LS_DUAL_SPIN_PROTECT );//PM_CheckDualSpinProtect();
3307 break;
3308 case SS_STAFF:
3309 PM_SetSaberMove( LS_STAFF_SOULCAL );
3310 break;
3311 }
3312 pm->ps->weaponstate = WEAPON_FIRING;
3313 //G_DrainPowerForSpecialMove( pm->gent, FP_SABER_OFFENSE, SABER_ALT_ATTACK_POWER );//FP_SPEED, SINGLE_SPECIAL_POWER );
3314 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER);
3315 }
3316 else if ( overrideMove != LS_NONE )
3317 {
3318 PM_SetSaberMove( overrideMove );
3319 pm->ps->weaponstate = WEAPON_FIRING;
3320 BG_ForcePowerDrain(pm->ps, FP_GRIP, SABER_ALT_ATTACK_POWER);
3321 }
3322 if ( overrideMove != LS_NONE )
3323 {//not cancelled
3324 return;
3325 }
3326 }
3327
3328 if ( pm->ps->weaponTime > 0 )
3329 {
3330 return;
3331 }
3332
3333 // *********************************************************
3334 // WEAPON_DROPPING
3335 // *********************************************************
3336
3337 // change weapon if time
3338 if ( pm->ps->weaponstate == WEAPON_DROPPING ) {
3339 PM_FinishWeaponChange();
3340 return;
3341 }
3342
3343 // *********************************************************
3344 // WEAPON_RAISING
3345 // *********************************************************
3346
3347 if ( pm->ps->weaponstate == WEAPON_RAISING )
3348 {//Just selected the weapon
3349 pm->ps->weaponstate = WEAPON_IDLE;
3350 if((pm->ps->legsAnim) == BOTH_WALK1 )
3351 {
3352 PM_SetAnim(SETANIM_TORSO,BOTH_WALK1,SETANIM_FLAG_NORMAL);
3353 }
3354 else if((pm->ps->legsAnim) == BOTH_RUN1 )
3355 {
3356 PM_SetAnim(SETANIM_TORSO,BOTH_RUN1,SETANIM_FLAG_NORMAL);
3357 }
3358 else if((pm->ps->legsAnim) == BOTH_RUN2 )
3359 {
3360 PM_SetAnim(SETANIM_TORSO,BOTH_RUN2,SETANIM_FLAG_NORMAL);
3361 }
3362 else if( pm->ps->legsAnim == BOTH_RUN_STAFF)
3363 {
3364 PM_SetAnim(SETANIM_TORSO,BOTH_RUN_STAFF,SETANIM_FLAG_NORMAL);
3365 }
3366 else if( pm->ps->legsAnim == BOTH_RUN_DUAL)
3367 {
3368 PM_SetAnim(SETANIM_TORSO,BOTH_RUN_DUAL,SETANIM_FLAG_NORMAL);
3369 }
3370 else if((pm->ps->legsAnim) == BOTH_WALK1 )
3371 {
3372 PM_SetAnim(SETANIM_TORSO,BOTH_WALK1,SETANIM_FLAG_NORMAL);
3373 }
3374 else if( pm->ps->legsAnim == BOTH_WALK2)
3375 {
3376 PM_SetAnim(SETANIM_TORSO,BOTH_WALK2,SETANIM_FLAG_NORMAL);
3377 }
3378 else if( pm->ps->legsAnim == BOTH_WALK_STAFF)
3379 {
3380 PM_SetAnim(SETANIM_TORSO,BOTH_WALK_STAFF,SETANIM_FLAG_NORMAL);
3381 }
3382 else if( pm->ps->legsAnim == BOTH_WALK_DUAL)
3383 {
3384 PM_SetAnim(SETANIM_TORSO,BOTH_WALK_DUAL,SETANIM_FLAG_NORMAL);
3385 }
3386 else
3387 {
3388 PM_SetAnim(SETANIM_TORSO,PM_GetSaberStance(),SETANIM_FLAG_NORMAL);
3389 }
3390
3391 if (pm->ps->weaponstate == WEAPON_RAISING)
3392 {
3393 return;
3394 }
3395
3396 }
3397
3398 if (checkOnlyWeap)
3399 {
3400 return;
3401 }
3402
3403 // *********************************************************
3404 // Check for WEAPON ATTACK
3405 // *********************************************************
3406 if (pm->ps->fd.saberAnimLevel == SS_STAFF &&
3407 (pm->cmd.buttons & BUTTON_ALT_ATTACK))
3408 { //ok, try a kick I guess.
3409 int kickMove = -1;
3410
3411 if ( !BG_KickingAnim(pm->ps->torsoAnim) &&
3412 !BG_KickingAnim(pm->ps->legsAnim) &&
3413 !BG_InRoll(pm->ps, pm->ps->legsAnim) &&
3414 // !BG_KickMove( pm->ps->saberMove )//not already in a kick
3415 pm->ps->saberMove == LS_READY
3416 && !(pm->ps->pm_flags&PMF_DUCKED)//not ducked
3417 && (pm->cmd.upmove >= 0 ) //not trying to duck
3418 )//&& pm->ps->groundEntityNum != ENTITYNUM_NONE)
3419 {//player kicks
3420 kickMove = PM_KickMoveForConditions();
3421 }
3422
3423 if (kickMove != -1)
3424 {
3425 if ( pm->ps->groundEntityNum == ENTITYNUM_NONE )
3426 {//if in air, convert kick to an in-air kick
3427 float gDist = PM_GroundDistance();
3428 //let's only allow air kicks if a certain distance from the ground
3429 //it's silly to be able to do them right as you land.
3430 //also looks wrong to transition from a non-complete flip anim...
3431 if ((!BG_FlippingAnim( pm->ps->legsAnim ) || pm->ps->legsTimer <= 0) &&
3432 gDist > 64.0f && //strict minimum
3433 gDist > (-pm->ps->velocity[2])-64.0f //make sure we are high to ground relative to downward velocity as well
3434 )
3435 {
3436 switch ( kickMove )
3437 {
3438 case LS_KICK_F:
3439 kickMove = LS_KICK_F_AIR;
3440 break;
3441 case LS_KICK_B:
3442 kickMove = LS_KICK_B_AIR;
3443 break;
3444 case LS_KICK_R:
3445 kickMove = LS_KICK_R_AIR;
3446 break;
3447 case LS_KICK_L:
3448 kickMove = LS_KICK_L_AIR;
3449 break;
3450 default: //oh well, can't do any other kick move while in-air
3451 kickMove = -1;
3452 break;
3453 }
3454 }
3455 else
3456 {//leave it as a normal kick unless we're too high up
3457 if ( gDist > 128.0f || pm->ps->velocity[2] >= 0 )
3458 { //off ground, but too close to ground
3459 kickMove = -1;
3460 }
3461 }
3462 }
3463
3464 if (kickMove != -1)
3465 {
3466 PM_SetSaberMove( kickMove );
3467 return;
3468 }
3469 }
3470 }
3471
3472 //this is never a valid regular saber attack button
3473 pm->cmd.buttons &= ~BUTTON_ALT_ATTACK;
3474
3475 if(!delayed_fire)
3476 {
3477 // Start with the current move, and cross index it with the current control states.
3478 if ( pm->ps->saberMove > LS_NONE && pm->ps->saberMove < LS_MOVE_MAX )
3479 {
3480 curmove = pm->ps->saberMove;
3481 }
3482 else
3483 {
3484 curmove = LS_READY;
3485 }
3486
3487 if ( curmove == LS_A_JUMP_T__B_ || pm->ps->torsoAnim == BOTH_FORCELEAP2_T__B_ )
3488 {//must transition back to ready from this anim
3489 newmove = LS_R_T2B;
3490 }
3491 // check for fire
3492 else if ( !(pm->cmd.buttons & (BUTTON_ATTACK|BUTTON_ALT_ATTACK)) )
3493 {//not attacking
3494 pm->ps->weaponTime = 0;
3495
3496 if ( pm->ps->weaponTime > 0 )
3497 {//Still firing
3498 pm->ps->weaponstate = WEAPON_FIRING;
3499 }
3500 else if ( pm->ps->weaponstate != WEAPON_READY )
3501 {
3502 pm->ps->weaponstate = WEAPON_IDLE;
3503 }
3504 //Check for finishing an anim if necc.
3505 if ( curmove >= LS_S_TL2BR && curmove <= LS_S_T2B )
3506 {//started a swing, must continue from here
3507 newmove = LS_A_TL2BR + (curmove-LS_S_TL2BR);
3508 }
3509 else if ( curmove >= LS_A_TL2BR && curmove <= LS_A_T2B )
3510 {//finished an attack, must continue from here
3511 newmove = LS_R_TL2BR + (curmove-LS_A_TL2BR);
3512 }
3513 else if ( PM_SaberInTransition( curmove ) )
3514 {//in a transition, must play sequential attack
3515 newmove = saberMoveData[curmove].chain_attack;
3516 }
3517 else if ( PM_SaberInBounce( curmove ) )
3518 {//in a bounce
3519 newmove = saberMoveData[curmove].chain_idle;//oops, not attacking, so don't chain
3520 }
3521 else
3522 {//FIXME: what about returning from a parry?
3523 //PM_SetSaberMove( LS_READY );
3524 //if ( pm->ps->saberBlockingTime > pm->cmd.serverTime )
3525 {
3526 PM_SetSaberMove( LS_READY );
3527 }
3528 return;
3529 }
3530 }
3531
3532 // ***************************************************
3533 // Pressing attack, so we must look up the proper attack move.
3534
3535 if ( pm->ps->weaponTime > 0 )
3536 { // Last attack is not yet complete.
3537 pm->ps->weaponstate = WEAPON_FIRING;
3538 return;
3539 }
3540 else
3541 {
3542 int both = qfalse;
3543 if ( pm->ps->torsoAnim == BOTH_FORCELONGLEAP_ATTACK
3544 || pm->ps->torsoAnim == BOTH_FORCELONGLEAP_LAND )
3545 {//can't attack in these anims
3546 return;
3547 }
3548 else if ( pm->ps->torsoAnim == BOTH_FORCELONGLEAP_START )
3549 {//only 1 attack you can do from this anim
3550 if ( pm->ps->torsoTimer >= 200 )
3551 {//hit it early enough to do the attack
3552 PM_SetSaberMove( LS_LEAP_ATTACK );
3553 }
3554 return;
3555 }
3556 if ( curmove >= LS_PARRY_UP && curmove <= LS_REFLECT_LL )
3557 {//from a parry or reflection, can go directly into an attack
3558 switch ( saberMoveData[curmove].endQuad )
3559 {
3560 case Q_T:
3561 newmove = LS_A_T2B;
3562 break;
3563 case Q_TR:
3564 newmove = LS_A_TR2BL;
3565 break;
3566 case Q_TL:
3567 newmove = LS_A_TL2BR;
3568 break;
3569 case Q_BR:
3570 newmove = LS_A_BR2TL;
3571 break;
3572 case Q_BL:
3573 newmove = LS_A_BL2TR;
3574 break;
3575 //shouldn't be a parry that ends at L, R or B
3576 }
3577 }
3578
3579 if ( newmove != LS_NONE )
3580 {//have a valid, final LS_ move picked, so skip findingt he transition move and just get the anim
3581 anim = saberMoveData[newmove].animToUse;
3582 }
3583
3584 //FIXME: diagonal dirs use the figure-eight attacks from ready pose?
3585 if ( anim == -1 )
3586 {
3587 //FIXME: take FP_SABER_OFFENSE into account here somehow?
3588 if ( PM_SaberInTransition( curmove ) )
3589 {//in a transition, must play sequential attack
3590 newmove = saberMoveData[curmove].chain_attack;
3591 }
3592 else if ( curmove >= LS_S_TL2BR && curmove <= LS_S_T2B )
3593 {//started a swing, must continue from here
3594 newmove = LS_A_TL2BR + (curmove-LS_S_TL2BR);
3595 }
3596 else if ( PM_SaberInBrokenParry( curmove ) )
3597 {//broken parries must always return to ready
3598 newmove = LS_READY;
3599 }
3600 else//if ( pm->cmd.buttons&BUTTON_ATTACK && !(pm->ps->pm_flags&PMF_ATTACK_HELD) )//only do this if just pressed attack button?
3601 {//get attack move from movement command
3602 /*
3603 if ( PM_SaberKataDone() )
3604 {//we came from a bounce and cannot chain to another attack because our kata is done
3605 newmove = saberMoveData[curmove].chain_idle;
3606 }
3607 else */
3608 newmove = PM_SaberAttackForMovement( curmove );
3609 if ( (PM_SaberInBounce( curmove )||PM_SaberInBrokenParry( curmove ))
3610 && saberMoveData[newmove].startQuad == saberMoveData[curmove].endQuad )
3611 {//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
3612 newmove = saberMoveData[curmove].chain_attack;
3613 }
3614
3615 if ( PM_SaberKataDone( curmove, newmove ) )
3616 {//cannot chain this time
3617 newmove = saberMoveData[curmove].chain_idle;
3618 }
3619 }
3620 /*
3621 if ( newmove == LS_NONE )
3622 {//FIXME: should we allow this? Are there some anims that you should never be able to chain into an attack?
3623 //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
3624 newmove = PM_AttackMoveForQuad( saberMoveData[curmove].endQuad );
3625 }
3626 */
3627 if ( newmove != LS_NONE )
3628 {
3629 //Now get the proper transition move
3630 newmove = PM_SaberAnimTransitionAnim( curmove, newmove );
3631 anim = saberMoveData[newmove].animToUse;
3632 }
3633 }
3634
3635 if (anim == -1)
3636 {//not side-stepping, pick neutral anim
3637 // Add randomness for prototype?
3638 newmove = saberMoveData[curmove].chain_attack;
3639
3640 anim= saberMoveData[newmove].animToUse;
3641
3642 if ( !pm->cmd.forwardmove && !pm->cmd.rightmove && pm->cmd.upmove >= 0 && pm->ps->groundEntityNum != ENTITYNUM_NONE )
3643 {//not moving at all, so set the anim on entire body
3644 both = qtrue;
3645 }
3646
3647 }
3648
3649 if ( anim == -1)
3650 {
3651 switch ( pm->ps->legsAnim )
3652 {
3653 case BOTH_WALK1:
3654 case BOTH_WALK2:
3655 case BOTH_WALK_STAFF:
3656 case BOTH_WALK_DUAL:
3657 case BOTH_WALKBACK1:
3658 case BOTH_WALKBACK2:
3659 case BOTH_WALKBACK_STAFF:
3660 case BOTH_WALKBACK_DUAL:
3661 case BOTH_RUN1:
3662 case BOTH_RUN2:
3663 case BOTH_RUN_STAFF:
3664 case BOTH_RUN_DUAL:
3665 case BOTH_RUNBACK1:
3666 case BOTH_RUNBACK2:
3667 case BOTH_RUNBACK_STAFF:
3668 anim = pm->ps->legsAnim;
3669 break;
3670 default:
3671 anim = PM_GetSaberStance();
3672 break;
3673 }
3674
3675 // if (PM_RunningAnim(anim) && !pm->cmd.forwardmove && !pm->cmd.rightmove)
3676 // { //semi-hacky (if not moving on x-y and still playing the running anim, force the player out of it)
3677 // anim = PM_GetSaberStance();
3678 // }
3679 newmove = LS_READY;
3680 }
3681
3682 PM_SetSaberMove( newmove );
3683
3684 if ( both && pm->ps->torsoAnim == anim )
3685 {
3686 PM_SetAnim(SETANIM_LEGS,anim,SETANIM_FLAG_OVERRIDE|SETANIM_FLAG_HOLD);
3687 }
3688
3689 //don't fire again until anim is done
3690 pm->ps->weaponTime = pm->ps->torsoTimer;
3691 }
3692 }
3693
3694 // *********************************************************
3695 // WEAPON_FIRING
3696 // *********************************************************
3697
3698 pm->ps->weaponstate = WEAPON_FIRING;
3699
3700 addTime = pm->ps->weaponTime;
3701
3702 pm->ps->saberAttackSequence = pm->ps->torsoAnim;
3703 if ( !addTime )
3704 {
3705 addTime = weaponData[pm->ps->weapon].fireTime;
3706 }
3707 pm->ps->weaponTime = addTime;
3708 }
3709
PM_SetSaberMove(short newMove)3710 void PM_SetSaberMove(short newMove)
3711 {
3712 unsigned int setflags = saberMoveData[newMove].animSetFlags;
3713 int anim = saberMoveData[newMove].animToUse;
3714 int parts = SETANIM_TORSO;
3715
3716 if ( newMove == LS_READY || newMove == LS_A_FLIP_STAB || newMove == LS_A_FLIP_SLASH )
3717 {//finished with a kata (or in a special move) reset attack counter
3718 pm->ps->saberAttackChainCount = 0;
3719 }
3720 else if ( BG_SaberInAttack( newMove ) )
3721 {//continuing with a kata, increment attack counter
3722 pm->ps->saberAttackChainCount++;
3723 }
3724
3725 if (pm->ps->saberAttackChainCount > 16)
3726 { //for the sake of being able to send the value over the net within a reasonable bit count
3727 pm->ps->saberAttackChainCount = 16;
3728 }
3729
3730 if ( newMove == LS_DRAW )
3731 {
3732 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
3733 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
3734 if ( saber1
3735 && saber1->drawAnim != -1 )
3736 {
3737 anim = saber1->drawAnim;
3738 }
3739 else if ( saber2
3740 && saber2->drawAnim != -1 )
3741 {
3742 anim = saber2->drawAnim;
3743 }
3744 else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
3745 {
3746 anim = BOTH_S1_S7;
3747 }
3748 else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
3749 {
3750 anim = BOTH_S1_S6;
3751 }
3752 }
3753 else if ( newMove == LS_PUTAWAY )
3754 {
3755 saberInfo_t *saber1 = BG_MySaber( pm->ps->clientNum, 0 );
3756 saberInfo_t *saber2 = BG_MySaber( pm->ps->clientNum, 1 );
3757 if ( saber1
3758 && saber1->putawayAnim != -1 )
3759 {
3760 anim = saber1->putawayAnim;
3761 }
3762 else if ( saber2
3763 && saber2->putawayAnim != -1 )
3764 {
3765 anim = saber2->putawayAnim;
3766 }
3767 else if ( pm->ps->fd.saberAnimLevel == SS_STAFF )
3768 {
3769 anim = BOTH_S7_S1;
3770 }
3771 else if ( pm->ps->fd.saberAnimLevel == SS_DUAL )
3772 {
3773 anim = BOTH_S6_S1;
3774 }
3775 }
3776 else if ( pm->ps->fd.saberAnimLevel == SS_STAFF && newMove >= LS_S_TL2BR && newMove < LS_REFLECT_LL )
3777 {//staff has an entirely new set of anims, besides special attacks
3778 //FIXME: include ready and draw/putaway?
3779 //FIXME: get hand-made bounces and deflections?
3780 if ( newMove >= LS_V1_BR && newMove <= LS_REFLECT_LL )
3781 {//there aren't 1-7, just 1, 6 and 7, so just set it
3782 anim = BOTH_P7_S7_T_ + (anim-BOTH_P1_S1_T_);//shift it up to the proper set
3783 }
3784 else
3785 {//add the appropriate animLevel
3786 anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
3787 }
3788 }
3789 else if ( pm->ps->fd.saberAnimLevel == SS_DUAL && newMove >= LS_S_TL2BR && newMove < LS_REFLECT_LL )
3790 { //akimbo has an entirely new set of anims, besides special attacks
3791 //FIXME: include ready and draw/putaway?
3792 //FIXME: get hand-made bounces and deflections?
3793 if ( newMove >= LS_V1_BR && newMove <= LS_REFLECT_LL )
3794 {//there aren't 1-7, just 1, 6 and 7, so just set it
3795 anim = BOTH_P6_S6_T_ + (anim-BOTH_P1_S1_T_);//shift it up to the proper set
3796 }
3797 else
3798 {//add the appropriate animLevel
3799 anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
3800 }
3801 }
3802 /*
3803 else if ( newMove == LS_DRAW && pm->ps->SaberStaff() )
3804 {//hold saber out front as we turn it on
3805 //FIXME: need a real "draw" anim for this (and put-away)
3806 anim = BOTH_SABERSTAFF_STANCE;
3807 }
3808 */
3809 else if ( pm->ps->fd.saberAnimLevel > FORCE_LEVEL_1 &&
3810 !BG_SaberInIdle( newMove ) && !PM_SaberInParry( newMove ) && !PM_SaberInKnockaway( newMove ) && !PM_SaberInBrokenParry( newMove ) && !PM_SaberInReflect( newMove ) && !BG_SaberInSpecial(newMove))
3811 {//readies, parries and reflections have only 1 level
3812 anim += (pm->ps->fd.saberAnimLevel-FORCE_LEVEL_1) * SABER_ANIM_GROUP_SIZE;
3813 }
3814
3815 // If the move does the same animation as the last one, we need to force a restart...
3816 if ( saberMoveData[pm->ps->saberMove].animToUse == anim && newMove > LS_PUTAWAY)
3817 {
3818 setflags |= SETANIM_FLAG_RESTART;
3819 }
3820
3821 //saber torso anims should always be highest priority (4/12/02 - for special anims only)
3822 if (!pm->ps->m_iVehicleNum)
3823 { //if not riding a vehicle
3824 if (BG_SaberInSpecial(newMove))
3825 {
3826 setflags |= SETANIM_FLAG_OVERRIDE;
3827 }
3828 /*
3829 if ( newMove == LS_A_LUNGE
3830 || newMove == LS_A_JUMP_T__B_
3831 || newMove == LS_A_BACKSTAB
3832 || newMove == LS_A_BACK
3833 || newMove == LS_A_BACK_CR
3834 || newMove == LS_A_FLIP_STAB
3835 || newMove == LS_A_FLIP_SLASH
3836 || newMove == LS_JUMPATTACK_DUAL
3837 || newMove == LS_A_BACKFLIP_ATK)
3838 {
3839 setflags |= SETANIM_FLAG_OVERRIDE;
3840 }
3841 */
3842 }
3843 if ( BG_InSaberStandAnim(anim) || anim == BOTH_STAND1 )
3844 {
3845 anim = (pm->ps->legsAnim);
3846
3847 if ((anim >= BOTH_STAND1 && anim <= BOTH_STAND4TOATTACK2) ||
3848 (anim >= TORSO_DROPWEAP1 && anim <= TORSO_WEAPONIDLE10))
3849 { //If standing then use the special saber stand anim
3850 anim = PM_GetSaberStance();
3851 }
3852
3853 if (pm->ps->pm_flags & PMF_DUCKED)
3854 { //Playing torso walk anims while crouched makes you look like a monkey
3855 anim = PM_GetSaberStance();
3856 }
3857
3858 if (anim == BOTH_WALKBACK1 || anim == BOTH_WALKBACK2 || anim == BOTH_WALK1)
3859 { //normal stance when walking backward so saber doesn't look like it's cutting through leg
3860 anim = PM_GetSaberStance();
3861 }
3862
3863 if (BG_InSlopeAnim( anim ))
3864 {
3865 anim = PM_GetSaberStance();
3866 }
3867
3868 parts = SETANIM_TORSO;
3869 }
3870
3871 if (!pm->ps->m_iVehicleNum)
3872 { //if not riding a vehicle
3873 if (newMove == LS_JUMPATTACK_ARIAL_RIGHT ||
3874 newMove == LS_JUMPATTACK_ARIAL_LEFT)
3875 { //force only on legs
3876 parts = SETANIM_LEGS;
3877 }
3878 else if ( newMove == LS_A_LUNGE
3879 || newMove == LS_A_JUMP_T__B_
3880 || newMove == LS_A_BACKSTAB
3881 || newMove == LS_A_BACK
3882 || newMove == LS_A_BACK_CR
3883 || newMove == LS_ROLL_STAB
3884 || newMove == LS_A_FLIP_STAB
3885 || newMove == LS_A_FLIP_SLASH
3886 || newMove == LS_JUMPATTACK_DUAL
3887 || newMove == LS_JUMPATTACK_ARIAL_LEFT
3888 || newMove == LS_JUMPATTACK_ARIAL_RIGHT
3889 || newMove == LS_JUMPATTACK_CART_LEFT
3890 || newMove == LS_JUMPATTACK_CART_RIGHT
3891 || newMove == LS_JUMPATTACK_STAFF_LEFT
3892 || newMove == LS_JUMPATTACK_STAFF_RIGHT
3893 || newMove == LS_A_BACKFLIP_ATK
3894 || newMove == LS_STABDOWN
3895 || newMove == LS_STABDOWN_STAFF
3896 || newMove == LS_STABDOWN_DUAL
3897 || newMove == LS_DUAL_SPIN_PROTECT
3898 || newMove == LS_STAFF_SOULCAL
3899 || newMove == LS_A1_SPECIAL
3900 || newMove == LS_A2_SPECIAL
3901 || newMove == LS_A3_SPECIAL
3902 || newMove == LS_UPSIDE_DOWN_ATTACK
3903 || newMove == LS_PULL_ATTACK_STAB
3904 || newMove == LS_PULL_ATTACK_SWING
3905 || BG_KickMove( newMove ) )
3906 {
3907 parts = SETANIM_BOTH;
3908 }
3909 else if ( BG_SpinningSaberAnim( anim ) )
3910 {//spins must be played on entire body
3911 parts = SETANIM_BOTH;
3912 }
3913 else if ( (!pm->cmd.forwardmove&&!pm->cmd.rightmove&&!pm->cmd.upmove))
3914 {//not trying to run, duck or jump
3915 if ( !BG_FlippingAnim( pm->ps->legsAnim ) &&
3916 !BG_InRoll( pm->ps, pm->ps->legsAnim ) &&
3917 !PM_InKnockDown( pm->ps ) &&
3918 !PM_JumpingAnim( pm->ps->legsAnim ) &&
3919 !BG_InSpecialJump( pm->ps->legsAnim ) &&
3920 anim != PM_GetSaberStance() &&
3921 pm->ps->groundEntityNum != ENTITYNUM_NONE &&
3922 !(pm->ps->pm_flags & PMF_DUCKED))
3923 {
3924 parts = SETANIM_BOTH;
3925 }
3926 else if ( !(pm->ps->pm_flags & PMF_DUCKED)
3927 && ( newMove == LS_SPINATTACK_DUAL || newMove == LS_SPINATTACK ) )
3928 {
3929 parts = SETANIM_BOTH;
3930 }
3931 }
3932
3933 PM_SetAnim(parts, anim, setflags);
3934 if (parts != SETANIM_LEGS &&
3935 (pm->ps->legsAnim == BOTH_ARIAL_LEFT ||
3936 pm->ps->legsAnim == BOTH_ARIAL_RIGHT))
3937 {
3938 if (pm->ps->legsTimer > pm->ps->torsoTimer)
3939 {
3940 pm->ps->legsTimer = pm->ps->torsoTimer;
3941 }
3942 }
3943
3944 }
3945
3946 if ( (pm->ps->torsoAnim) == anim )
3947 {//successfully changed anims
3948 //special check for *starting* a saber swing
3949 //playing at attack
3950 if ( BG_SaberInAttack( newMove ) || BG_SaberInSpecialAttack( anim ) )
3951 {
3952 if ( pm->ps->saberMove != newMove )
3953 {//wasn't playing that attack before
3954 if ( newMove != LS_KICK_F
3955 && newMove != LS_KICK_B
3956 && newMove != LS_KICK_R
3957 && newMove != LS_KICK_L
3958 && newMove != LS_KICK_F_AIR
3959 && newMove != LS_KICK_B_AIR
3960 && newMove != LS_KICK_R_AIR
3961 && newMove != LS_KICK_L_AIR )
3962 {
3963 PM_AddEvent(EV_SABER_ATTACK);
3964 }
3965
3966 if (pm->ps->brokenLimbs)
3967 { //randomly make pain sounds with a broken arm because we are suffering.
3968 int iFactor = -1;
3969
3970 if (pm->ps->brokenLimbs & (1<<BROKENLIMB_RARM))
3971 { //You're using it more. So it hurts more.
3972 iFactor = 5;
3973 }
3974 else if (pm->ps->brokenLimbs & (1<<BROKENLIMB_LARM))
3975 {
3976 iFactor = 10;
3977 }
3978
3979 if (iFactor != -1)
3980 {
3981 if ( !PM_irand_timesync( 0, iFactor ) )
3982 {
3983 BG_AddPredictableEventToPlayerstate(EV_PAIN, PM_irand_timesync( 1, 100 ), pm->ps);
3984 }
3985 }
3986 }
3987 }
3988 }
3989
3990 if (BG_SaberInSpecial(newMove) &&
3991 pm->ps->weaponTime < pm->ps->torsoTimer)
3992 { //rww 01-02-03 - I think this will solve the issue of special attacks being interruptable, hopefully without side effects
3993 pm->ps->weaponTime = pm->ps->torsoTimer;
3994 }
3995
3996 pm->ps->saberMove = newMove;
3997 pm->ps->saberBlocking = saberMoveData[newMove].blocking;
3998
3999 pm->ps->torsoAnim = anim;
4000
4001 if (pm->ps->weaponTime <= 0)
4002 {
4003 pm->ps->saberBlocked = BLOCKED_NONE;
4004 }
4005 }
4006 }
4007
BG_MySaber(int clientNum,int saberNum)4008 saberInfo_t *BG_MySaber( int clientNum, int saberNum )
4009 {
4010 //returns a pointer to the requested saberNum
4011 #ifdef _GAME
4012 gentity_t *ent = &g_entities[clientNum];
4013 if ( ent->inuse && ent->client )
4014 {
4015 if ( !ent->client->saber[saberNum].model[0] )
4016 { //don't have saber anymore!
4017 return NULL;
4018 }
4019 return &ent->client->saber[saberNum];
4020 }
4021 #elif defined(_CGAME)
4022 clientInfo_t *ci = NULL;
4023 if (clientNum < MAX_CLIENTS)
4024 {
4025 ci = &cgs.clientinfo[clientNum];
4026 }
4027 else
4028 {
4029 centity_t *cent = &cg_entities[clientNum];
4030 if (cent->npcClient)
4031 {
4032 ci = cent->npcClient;
4033 }
4034 }
4035 if ( ci
4036 && ci->infoValid )
4037 {
4038 if ( !ci->saber[saberNum].model[0] )
4039 { //don't have sabers anymore!
4040 return NULL;
4041 }
4042 return &ci->saber[saberNum];
4043 }
4044 #endif
4045
4046 return NULL;
4047 }
4048
4049