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