PageRenderTime 9ms CodeModel.GetById 25ms app.highlight 106ms RepoModel.GetById 1ms app.codeStats 2ms

/codemp/game/w_force.c

https://github.com/Stoiss/jaMME
C | 5792 lines | 4893 code | 677 blank | 222 comment | 1442 complexity | 5c05792ec0909128ed6bb1696fe073f0 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   1#include "b_local.h"
   2#include "w_saber.h"
   3#include "ai_main.h"
   4#include "ghoul2/G2.h"
   5
   6#define METROID_JUMP 1
   7
   8//NEEDED FOR MIND-TRICK on NPCS=========================================================
   9extern void NPC_PlayConfusionSound( gentity_t *self );
  10extern void NPC_Jedi_PlayConfusionSound( gentity_t *self );
  11extern void NPC_UseResponse( gentity_t *self, gentity_t *user, qboolean useWhenDone );
  12//NEEDED FOR MIND-TRICK on NPCS=========================================================
  13extern void Jedi_Decloak( gentity_t *self );
  14
  15extern qboolean BG_FullBodyTauntAnim( int anim );
  16
  17extern bot_state_t *botstates[MAX_CLIENTS];
  18
  19int		speedLoopSound		= 0;
  20int		rageLoopSound		= 0;
  21int		protectLoopSound	= 0;
  22int		absorbLoopSound		= 0;
  23int		seeLoopSound		= 0;
  24int		ysalamiriLoopSound	= 0;
  25
  26#define FORCE_VELOCITY_DAMAGE 0
  27
  28int ForceShootDrain( gentity_t *self );
  29
  30gentity_t *G_PreDefSound(vec3_t org, int pdSound)
  31{
  32	gentity_t	*te;
  33
  34	te = G_TempEntity( org, EV_PREDEFSOUND );
  35	te->s.eventParm = pdSound;
  36	VectorCopy(org, te->s.origin);
  37
  38	return te;
  39}
  40const int forcePowerMinRank[NUM_FORCE_POWER_LEVELS][NUM_FORCE_POWERS] = //0 == neutral
  41{
  42	{
  43		999,//FP_HEAL,//instant
  44		999,//FP_LEVITATION,//hold/duration
  45		999,//FP_SPEED,//duration
  46		999,//FP_PUSH,//hold/duration
  47		999,//FP_PULL,//hold/duration
  48		999,//FP_TELEPATHY,//instant
  49		999,//FP_GRIP,//hold/duration
  50		999,//FP_LIGHTNING,//hold/duration
  51		999,//FP_RAGE,//duration
  52		999,//FP_PROTECT,//duration
  53		999,//FP_ABSORB,//duration
  54		999,//FP_TEAM_HEAL,//instant
  55		999,//FP_TEAM_FORCE,//instant
  56		999,//FP_DRAIN,//hold/duration
  57		999,//FP_SEE,//duration
  58		999,//FP_SABER_OFFENSE,
  59		999,//FP_SABER_DEFENSE,
  60		999//FP_SABERTHROW,
  61		//NUM_FORCE_POWERS
  62	},
  63	{
  64		10,//FP_HEAL,//instant
  65		0,//FP_LEVITATION,//hold/duration
  66		0,//FP_SPEED,//duration
  67		0,//FP_PUSH,//hold/duration
  68		0,//FP_PULL,//hold/duration
  69		10,//FP_TELEPATHY,//instant
  70		15,//FP_GRIP,//hold/duration
  71		10,//FP_LIGHTNING,//hold/duration
  72		15,//FP_RAGE,//duration
  73		15,//FP_PROTECT,//duration
  74		15,//FP_ABSORB,//duration
  75		10,//FP_TEAM_HEAL,//instant
  76		10,//FP_TEAM_FORCE,//instant
  77		10,//FP_DRAIN,//hold/duration
  78		5,//FP_SEE,//duration
  79		0,//FP_SABER_OFFENSE,
  80		0,//FP_SABER_DEFENSE,
  81		0//FP_SABERTHROW,
  82		//NUM_FORCE_POWERS
  83	},
  84	{
  85		10,//FP_HEAL,//instant
  86		0,//FP_LEVITATION,//hold/duration
  87		0,//FP_SPEED,//duration
  88		0,//FP_PUSH,//hold/duration
  89		0,//FP_PULL,//hold/duration
  90		10,//FP_TELEPATHY,//instant
  91		15,//FP_GRIP,//hold/duration
  92		10,//FP_LIGHTNING,//hold/duration
  93		15,//FP_RAGE,//duration
  94		15,//FP_PROTECT,//duration
  95		15,//FP_ABSORB,//duration
  96		10,//FP_TEAM_HEAL,//instant
  97		10,//FP_TEAM_FORCE,//instant
  98		10,//FP_DRAIN,//hold/duration
  99		5,//FP_SEE,//duration
 100		5,//FP_SABER_OFFENSE,
 101		5,//FP_SABER_DEFENSE,
 102		5//FP_SABERTHROW,
 103		//NUM_FORCE_POWERS
 104	},
 105	{
 106		10,//FP_HEAL,//instant
 107		0,//FP_LEVITATION,//hold/duration
 108		0,//FP_SPEED,//duration
 109		0,//FP_PUSH,//hold/duration
 110		0,//FP_PULL,//hold/duration
 111		10,//FP_TELEPATHY,//instant
 112		15,//FP_GRIP,//hold/duration
 113		10,//FP_LIGHTNING,//hold/duration
 114		15,//FP_RAGE,//duration
 115		15,//FP_PROTECT,//duration
 116		15,//FP_ABSORB,//duration
 117		10,//FP_TEAM_HEAL,//instant
 118		10,//FP_TEAM_FORCE,//instant
 119		10,//FP_DRAIN,//hold/duration
 120		5,//FP_SEE,//duration
 121		10,//FP_SABER_OFFENSE,
 122		10,//FP_SABER_DEFENSE,
 123		10//FP_SABERTHROW,
 124		//NUM_FORCE_POWERS
 125	}
 126};
 127
 128const int mindTrickTime[NUM_FORCE_POWER_LEVELS] =
 129{
 130	0,//none
 131	5000,
 132	10000,
 133	15000
 134};
 135
 136void WP_InitForcePowers( gentity_t *ent )
 137{
 138	int i;
 139	int i_r;
 140	int maxRank = g_maxForceRank.integer;
 141	qboolean warnClient = qfalse;
 142	qboolean warnClientLimit = qfalse;
 143	char userinfo[MAX_INFO_STRING];
 144	char forcePowers[256];
 145	char readBuf[256];
 146	int lastFPKnown = -1;
 147	qboolean didEvent = qfalse;
 148
 149	if (!maxRank)
 150	{ //if server has no max rank, default to max (50)
 151		maxRank = FORCE_MASTERY_JEDI_MASTER;
 152	}
 153	else if (maxRank >= NUM_FORCE_MASTERY_LEVELS)
 154	{//ack, prevent user from being dumb
 155		maxRank = FORCE_MASTERY_JEDI_MASTER;
 156		trap_Cvar_Set( "g_maxForceRank", va("%i", maxRank) );
 157	}
 158
 159	/*
 160	if (g_forcePowerDisable.integer)
 161	{
 162		maxRank = FORCE_MASTERY_UNINITIATED;
 163	}
 164	*/
 165	//rww - don't do this
 166
 167	if ( !ent || !ent->client )
 168	{
 169		return;
 170	}
 171
 172	ent->client->ps.fd.saberAnimLevel = ent->client->sess.saberLevel;
 173
 174	if (ent->client->ps.fd.saberAnimLevel < FORCE_LEVEL_1 ||
 175		ent->client->ps.fd.saberAnimLevel > FORCE_LEVEL_3)
 176	{
 177		ent->client->ps.fd.saberAnimLevel = FORCE_LEVEL_1;
 178	}
 179
 180	if (!speedLoopSound)
 181	{ //so that the client configstring is already modified with this when we need it
 182		speedLoopSound = G_SoundIndex("sound/weapons/force/speedloop.wav");
 183	}
 184
 185	if (!rageLoopSound)
 186	{
 187		rageLoopSound = G_SoundIndex("sound/weapons/force/rageloop.wav");
 188	}
 189
 190	if (!absorbLoopSound)
 191	{
 192		absorbLoopSound = G_SoundIndex("sound/weapons/force/absorbloop.wav");
 193	}
 194
 195	if (!protectLoopSound)
 196	{
 197		protectLoopSound = G_SoundIndex("sound/weapons/force/protectloop.wav");
 198	}
 199
 200	if (!seeLoopSound)
 201	{
 202		seeLoopSound = G_SoundIndex("sound/weapons/force/seeloop.wav");
 203	}
 204
 205	if (!ysalamiriLoopSound)
 206	{
 207		ysalamiriLoopSound = G_SoundIndex("sound/player/nullifyloop.wav");
 208	}
 209
 210	if (ent->s.eType == ET_NPC)
 211	{ //just stop here then.
 212		return;
 213	}
 214
 215	i = 0;
 216	while (i < NUM_FORCE_POWERS)
 217	{
 218		ent->client->ps.fd.forcePowerLevel[i] = 0;
 219		ent->client->ps.fd.forcePowersKnown &= ~(1 << i);
 220		i++;
 221	}
 222
 223	ent->client->ps.fd.forcePowerSelected = -1;
 224
 225	ent->client->ps.fd.forceSide = 0;
 226
 227	if (level.gametype == GT_SIEGE &&
 228		ent->client->siegeClass != -1)
 229	{ //Then use the powers for this class, and skip all this nonsense.
 230		i = 0;
 231
 232		while (i < NUM_FORCE_POWERS)
 233		{
 234			ent->client->ps.fd.forcePowerLevel[i] = bgSiegeClasses[ent->client->siegeClass].forcePowerLevels[i];
 235
 236			if (!ent->client->ps.fd.forcePowerLevel[i])
 237			{
 238				ent->client->ps.fd.forcePowersKnown &= ~(1 << i);
 239			}
 240			else
 241			{
 242				ent->client->ps.fd.forcePowersKnown |= (1 << i);
 243			}
 244			i++;
 245		}
 246
 247		if (!ent->client->sess.setForce)
 248		{
 249			//bring up the class selection menu
 250			trap_SendServerCommand(ent-g_entities, "scl");
 251		}
 252		ent->client->sess.setForce = qtrue;
 253
 254		return;
 255	}
 256
 257	if (ent->s.eType == ET_NPC && ent->s.number >= MAX_CLIENTS)
 258	{ //rwwFIXMEFIXME: Temp
 259		Q_strncpyz( userinfo, "forcepowers\\7-1-333003000313003120", sizeof( userinfo ) );
 260	}
 261	else
 262	{
 263		trap_GetUserinfo( ent->s.number, userinfo, sizeof( userinfo ) );
 264	}
 265
 266	Q_strncpyz( forcePowers, Info_ValueForKey( userinfo, "forcepowers" ), sizeof( forcePowers ) );
 267
 268	if ( strlen( forcePowers ) < strlen( DEFAULT_FORCEPOWERS ) )
 269	{
 270		Q_strncpyz( forcePowers, DEFAULT_FORCEPOWERS, sizeof( forcePowers ) );
 271		trap_SendServerCommand( ent-g_entities, "print \"^1Invalid forcepowers string, setting default\n\"" );
 272	}
 273
 274	//if it's a bot just copy the info directly from its personality
 275	if ( (ent->r.svFlags & SVF_BOT) && botstates[ent->s.number] )
 276		Q_strncpyz( forcePowers, botstates[ent->s.number]->forceinfo, sizeof( forcePowers ) );
 277
 278	//rww - parse through the string manually and eat out all the appropriate data
 279	i = 0;
 280
 281	if (g_forceBasedTeams.integer)
 282	{
 283		if (ent->client->sess.sessionTeam == TEAM_RED)
 284		{
 285			warnClient = !(BG_LegalizedForcePowers(forcePowers, maxRank, HasSetSaberOnly(), FORCE_DARKSIDE, level.gametype, g_forcePowerDisable.integer));
 286		}
 287		else if (ent->client->sess.sessionTeam == TEAM_BLUE)
 288		{
 289			warnClient = !(BG_LegalizedForcePowers(forcePowers, maxRank, HasSetSaberOnly(), FORCE_LIGHTSIDE, level.gametype, g_forcePowerDisable.integer));
 290		}
 291		else
 292		{
 293			warnClient = !(BG_LegalizedForcePowers(forcePowers, maxRank, HasSetSaberOnly(), 0, level.gametype, g_forcePowerDisable.integer));
 294		}
 295	}
 296	else
 297	{
 298		warnClient = !(BG_LegalizedForcePowers(forcePowers, maxRank, HasSetSaberOnly(), 0, level.gametype, g_forcePowerDisable.integer));
 299	}
 300
 301	i_r = 0;
 302	while (forcePowers[i] && forcePowers[i] != '-')
 303	{
 304		readBuf[i_r] = forcePowers[i];
 305		i_r++;
 306		i++;
 307	}
 308	readBuf[i_r] = 0;
 309	//THE RANK
 310	ent->client->ps.fd.forceRank = atoi(readBuf);
 311	i++;
 312
 313	i_r = 0;
 314	while (forcePowers[i] && forcePowers[i] != '-')
 315	{
 316		readBuf[i_r] = forcePowers[i];
 317		i_r++;
 318		i++;
 319	}
 320	readBuf[i_r] = 0;
 321	//THE SIDE
 322	ent->client->ps.fd.forceSide = atoi(readBuf);
 323	i++;
 324
 325
 326	if ( level.gametype != GT_SIEGE && (ent->r.svFlags & SVF_BOT) && botstates[ent->s.number] )
 327	{ //hmm..I'm going to cheat here.
 328		int oldI = i;
 329		i_r = 0;
 330		while (forcePowers[i] && forcePowers[i] != '\n' &&
 331			i_r < NUM_FORCE_POWERS)
 332		{
 333			if (ent->client->ps.fd.forceSide == FORCE_LIGHTSIDE)
 334			{
 335				if (i_r == FP_ABSORB)
 336				{
 337					forcePowers[i] = '3';
 338				}
 339				if (botstates[ent->s.number]->settings.skill >= 4)
 340				{ //cheat and give them more stuff
 341					if (i_r == FP_HEAL)
 342					{
 343						forcePowers[i] = '3';
 344					}
 345					else if (i_r == FP_PROTECT)
 346					{
 347						forcePowers[i] = '3';
 348					}
 349				}
 350			}
 351			else if (ent->client->ps.fd.forceSide == FORCE_DARKSIDE)
 352			{
 353				if (botstates[ent->s.number]->settings.skill >= 4)
 354				{
 355					if (i_r == FP_GRIP)
 356					{
 357						forcePowers[i] = '3';
 358					}
 359					else if (i_r == FP_LIGHTNING)
 360					{
 361						forcePowers[i] = '3';
 362					}
 363					else if (i_r == FP_RAGE)
 364					{
 365						forcePowers[i] = '3';
 366					}
 367					else if (i_r == FP_DRAIN)
 368					{
 369						forcePowers[i] = '3';
 370					}
 371				}
 372			}
 373
 374			if (i_r == FP_PUSH)
 375			{
 376				forcePowers[i] = '3';
 377			}
 378			else if (i_r == FP_PULL)
 379			{
 380				forcePowers[i] = '3';
 381			}
 382
 383			i++;
 384			i_r++;
 385		}
 386		i = oldI;
 387	}
 388
 389	i_r = 0;
 390	while (forcePowers[i] && forcePowers[i] != '\n' &&
 391		i_r < NUM_FORCE_POWERS)
 392	{
 393		readBuf[0] = forcePowers[i];
 394		readBuf[1] = 0;
 395
 396		ent->client->ps.fd.forcePowerLevel[i_r] = atoi(readBuf);
 397		if (ent->client->ps.fd.forcePowerLevel[i_r])
 398		{
 399			ent->client->ps.fd.forcePowersKnown |= (1 << i_r);
 400		}
 401		else
 402		{
 403			ent->client->ps.fd.forcePowersKnown &= ~(1 << i_r);
 404		}
 405		i++;
 406		i_r++;
 407	}
 408	//THE POWERS
 409
 410	if (ent->s.eType != ET_NPC)
 411	{
 412		if (HasSetSaberOnly())
 413		{
 414			gentity_t *te = G_TempEntity( vec3_origin, EV_SET_FREE_SABER );
 415			te->r.svFlags |= SVF_BROADCAST;
 416			te->s.eventParm = 1;
 417		}
 418		else
 419		{
 420			gentity_t *te = G_TempEntity( vec3_origin, EV_SET_FREE_SABER );
 421			te->r.svFlags |= SVF_BROADCAST;
 422			te->s.eventParm = 0;
 423		}
 424
 425		if (g_forcePowerDisable.integer)
 426		{
 427			gentity_t *te = G_TempEntity( vec3_origin, EV_SET_FORCE_DISABLE );
 428			te->r.svFlags |= SVF_BROADCAST;
 429			te->s.eventParm = 1;
 430		}
 431		else
 432		{
 433			gentity_t *te = G_TempEntity( vec3_origin, EV_SET_FORCE_DISABLE );
 434			te->r.svFlags |= SVF_BROADCAST;
 435			te->s.eventParm = 0;
 436		}
 437	}
 438
 439	//rww - It seems we currently want to always do this, even if the player isn't exceeding the max
 440	//rank, so..
 441//	if (level.gametype == GT_DUEL || level.gametype == GT_POWERDUEL)
 442//	{ //totally messes duel up to force someone into spec mode, and besides, each "round" is
 443	  //counted as a full restart
 444//		ent->client->sess.setForce = qtrue;
 445//	}
 446
 447	if (ent->s.eType == ET_NPC)
 448	{
 449		ent->client->sess.setForce = qtrue;
 450	}
 451	else if (level.gametype == GT_SIEGE)
 452	{
 453		if (!ent->client->sess.setForce)
 454		{
 455			ent->client->sess.setForce = qtrue;
 456			//bring up the class selection menu
 457			trap_SendServerCommand(ent-g_entities, "scl");
 458		}
 459	}
 460	else
 461	{
 462		if (warnClient || !ent->client->sess.setForce)
 463		{ //the client's rank is too high for the server and has been autocapped, so tell them
 464			if (level.gametype != GT_HOLOCRON && level.gametype != GT_JEDIMASTER )
 465			{
 466#ifdef EVENT_FORCE_RANK
 467				gentity_t *te = G_TempEntity( vec3_origin, EV_GIVE_NEW_RANK );
 468
 469				te->r.svFlags |= SVF_BROADCAST;
 470				te->s.trickedentindex = ent->s.number;
 471				te->s.eventParm = maxRank;
 472				te->s.bolt1 = 0;
 473#endif
 474				didEvent = qtrue;
 475
 476//				if (!(ent->r.svFlags & SVF_BOT) && level.gametype != GT_DUEL && level.gametype != GT_POWERDUEL && ent->s.eType != ET_NPC)
 477				if (!(ent->r.svFlags & SVF_BOT) && ent->s.eType != ET_NPC)
 478				{
 479					if (!g_teamAutoJoin.integer)
 480					{
 481						//Make them a spectator so they can set their powerups up without being bothered.
 482						ent->client->sess.sessionTeam = TEAM_SPECTATOR;
 483						ent->client->sess.spectatorState = SPECTATOR_FREE;
 484						ent->client->sess.spectatorClient = 0;
 485
 486						ent->client->pers.teamState.state = TEAM_BEGIN;
 487						trap_SendServerCommand(ent-g_entities, "spc");	// Fire up the profile menu
 488					}
 489				}
 490
 491#ifdef EVENT_FORCE_RANK
 492				te->s.bolt2 = ent->client->sess.sessionTeam;
 493#else
 494				//Event isn't very reliable, I made it a string. This way I can send it to just one
 495				//client also, as opposed to making a broadcast event.
 496				trap_SendServerCommand(ent->s.number, va("nfr %i %i %i", maxRank, 1, ent->client->sess.sessionTeam));
 497				//Arg1 is new max rank, arg2 is non-0 if force menu should be shown, arg3 is the current team
 498#endif
 499			}
 500			ent->client->sess.setForce = qtrue;
 501		}
 502
 503		if (!didEvent )
 504		{
 505#ifdef EVENT_FORCE_RANK
 506			gentity_t *te = G_TempEntity( vec3_origin, EV_GIVE_NEW_RANK );
 507
 508			te->r.svFlags |= SVF_BROADCAST;
 509			te->s.trickedentindex = ent->s.number;
 510			te->s.eventParm = maxRank;
 511			te->s.bolt1 = 1;
 512			te->s.bolt2 = ent->client->sess.sessionTeam;
 513#else
 514			trap_SendServerCommand(ent->s.number, va("nfr %i %i %i", maxRank, 0, ent->client->sess.sessionTeam));
 515#endif
 516		}
 517
 518		if (warnClientLimit)
 519		{ //the server has one or more force powers disabled and the client is using them in his config
 520			//trap_SendServerCommand(ent-g_entities, va("print \"The server has one or more force powers that you have chosen disabled.\nYou will not be able to use the disable force power(s) while playing on this server.\n\""));
 521		}
 522	}
 523
 524	i = 0;
 525	while (i < NUM_FORCE_POWERS)
 526	{
 527		if ((ent->client->ps.fd.forcePowersKnown & (1 << i)) &&
 528			!ent->client->ps.fd.forcePowerLevel[i])
 529		{ //err..
 530			ent->client->ps.fd.forcePowersKnown &= ~(1 << i);
 531		}
 532		else
 533		{
 534			if (i != FP_LEVITATION && i != FP_SABER_OFFENSE && i != FP_SABER_DEFENSE && i != FP_SABERTHROW)
 535			{
 536				lastFPKnown = i;
 537			}
 538		}
 539
 540		i++;
 541	}
 542
 543	if (ent->client->ps.fd.forcePowersKnown & ent->client->sess.selectedFP)
 544	{
 545		ent->client->ps.fd.forcePowerSelected = ent->client->sess.selectedFP;
 546	}
 547
 548	if (!(ent->client->ps.fd.forcePowersKnown & (1 << ent->client->ps.fd.forcePowerSelected)))
 549	{
 550		if (lastFPKnown != -1)
 551		{
 552			ent->client->ps.fd.forcePowerSelected = lastFPKnown;
 553		}
 554		else
 555		{
 556			ent->client->ps.fd.forcePowerSelected = 0;
 557		}
 558	}
 559
 560	while (i < NUM_FORCE_POWERS)
 561	{
 562		ent->client->ps.fd.forcePowerBaseLevel[i] = ent->client->ps.fd.forcePowerLevel[i];
 563		i++;
 564	}
 565	ent->client->ps.fd.forceUsingAdded = 0;
 566}
 567
 568void WP_SpawnInitForcePowers( gentity_t *ent )
 569{
 570	int i = 0;
 571
 572	ent->client->ps.saberAttackChainCount = 0;
 573
 574	i = 0;
 575
 576	while (i < NUM_FORCE_POWERS)
 577	{
 578		if (ent->client->ps.fd.forcePowersActive & (1 << i))
 579		{
 580			WP_ForcePowerStop(ent, i);
 581		}
 582
 583		i++;
 584	}
 585
 586	ent->client->ps.fd.forceDeactivateAll = 0;
 587
 588	ent->client->ps.fd.forcePower = ent->client->ps.fd.forcePowerMax = FORCE_POWER_MAX;
 589	ent->client->ps.fd.forcePowerRegenDebounceTime = 0;
 590	ent->client->ps.fd.forceGripEntityNum = ENTITYNUM_NONE;
 591	ent->client->ps.fd.forceMindtrickTargetIndex = 0;
 592	ent->client->ps.fd.forceMindtrickTargetIndex2 = 0;
 593	ent->client->ps.fd.forceMindtrickTargetIndex3 = 0;
 594	ent->client->ps.fd.forceMindtrickTargetIndex4 = 0;
 595
 596	ent->client->ps.holocronBits = 0;
 597
 598	i = 0;
 599	while (i < NUM_FORCE_POWERS)
 600	{
 601		ent->client->ps.holocronsCarried[i] = 0;
 602		i++;
 603	}
 604
 605	if (level.gametype == GT_HOLOCRON)
 606	{
 607		i = 0;
 608		while (i < NUM_FORCE_POWERS)
 609		{
 610			ent->client->ps.fd.forcePowerLevel[i] = FORCE_LEVEL_0;
 611			i++;
 612		}
 613
 614		if (HasSetSaberOnly())
 615		{
 616			if (ent->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE] < FORCE_LEVEL_1)
 617			{
 618				ent->client->ps.fd.forcePowerLevel[FP_SABER_OFFENSE] = FORCE_LEVEL_1;
 619			}
 620			if (ent->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] < FORCE_LEVEL_1)
 621			{
 622				ent->client->ps.fd.forcePowerLevel[FP_SABER_DEFENSE] = FORCE_LEVEL_1;
 623			}
 624		}
 625	}
 626
 627	i = 0;
 628
 629	while (i < NUM_FORCE_POWERS)
 630	{
 631		ent->client->ps.fd.forcePowerDebounce[i] = 0;
 632		ent->client->ps.fd.forcePowerDuration[i] = 0;
 633
 634		i++;
 635	}
 636
 637	ent->client->ps.fd.forcePowerRegenDebounceTime = 0;
 638	ent->client->ps.fd.forceJumpZStart = 0;
 639	ent->client->ps.fd.forceJumpCharge = 0;
 640	ent->client->ps.fd.forceJumpSound = 0;
 641	ent->client->ps.fd.forceGripDamageDebounceTime = 0;
 642	ent->client->ps.fd.forceGripBeingGripped = 0;
 643	ent->client->ps.fd.forceGripCripple = 0;
 644	ent->client->ps.fd.forceGripUseTime = 0;
 645	ent->client->ps.fd.forceGripSoundTime = 0;
 646	ent->client->ps.fd.forceGripStarted = 0;
 647	ent->client->ps.fd.forceHealTime = 0;
 648	ent->client->ps.fd.forceHealAmount = 0;
 649	ent->client->ps.fd.forceRageRecoveryTime = 0;
 650	ent->client->ps.fd.forceDrainEntNum = ENTITYNUM_NONE;
 651	ent->client->ps.fd.forceDrainTime = 0;
 652
 653	i = 0;
 654	while (i < NUM_FORCE_POWERS)
 655	{
 656		if ((ent->client->ps.fd.forcePowersKnown & (1 << i)) &&
 657			!ent->client->ps.fd.forcePowerLevel[i])
 658		{ //make sure all known powers are cleared if we have level 0 in them
 659			ent->client->ps.fd.forcePowersKnown &= ~(1 << i);
 660		}
 661
 662		i++;
 663	}
 664
 665	if (level.gametype == GT_SIEGE &&
 666		ent->client->siegeClass != -1)
 667	{ //Then use the powers for this class.
 668		i = 0;
 669
 670		while (i < NUM_FORCE_POWERS)
 671		{
 672			ent->client->ps.fd.forcePowerLevel[i] = bgSiegeClasses[ent->client->siegeClass].forcePowerLevels[i];
 673
 674			if (!ent->client->ps.fd.forcePowerLevel[i])
 675			{
 676				ent->client->ps.fd.forcePowersKnown &= ~(1 << i);
 677			}
 678			else
 679			{
 680				ent->client->ps.fd.forcePowersKnown |= (1 << i);
 681			}
 682			i++;
 683		}
 684	}
 685}
 686
 687extern qboolean BG_InKnockDown( int anim ); //bg_pmove.c
 688
 689int ForcePowerUsableOn(gentity_t *attacker, gentity_t *other, forcePowers_t forcePower)
 690{
 691	if (other && other->client && BG_HasYsalamiri(level.gametype, &other->client->ps))
 692	{
 693		return 0;
 694	}
 695
 696	if (attacker && attacker->client && !BG_CanUseFPNow(level.gametype, &attacker->client->ps, level.time, forcePower))
 697	{
 698		return 0;
 699	}
 700
 701	//Dueling fighters cannot use force powers on others, with the exception of force push when locked with each other
 702	if (attacker && attacker->client && attacker->client->ps.duelInProgress)
 703	{
 704		return 0;
 705	}
 706
 707	if (other && other->client && other->client->ps.duelInProgress)
 708	{
 709		return 0;
 710	}
 711
 712	if (forcePower == FP_GRIP)
 713	{
 714		if (other && other->client &&
 715			(other->client->ps.fd.forcePowersActive & (1<<FP_ABSORB)))
 716		{ //don't allow gripping to begin with if they are absorbing
 717			//play sound indicating that attack was absorbed
 718			if (other->client->forcePowerSoundDebounce < level.time)
 719			{
 720				gentity_t *abSound = G_PreDefSound(other->client->ps.origin, PDSOUND_ABSORBHIT);
 721				abSound->s.trickedentindex = other->s.number;
 722				other->client->forcePowerSoundDebounce = level.time + 400;
 723			}
 724			return 0;
 725		}
 726		else if (other && other->client &&
 727			other->client->ps.weapon == WP_SABER &&
 728			BG_SaberInSpecial(other->client->ps.saberMove))
 729		{ //don't grip person while they are in a special or some really bad things can happen.
 730			return 0;
 731		}
 732	}
 733
 734	if (other && other->client &&
 735		(forcePower == FP_PUSH ||
 736		forcePower == FP_PULL))
 737	{
 738		if (BG_InKnockDown(other->client->ps.legsAnim))
 739		{
 740			return 0;
 741		}
 742	}
 743
 744	if (other && other->client && other->s.eType == ET_NPC &&
 745		other->s.NPC_class == CLASS_VEHICLE)
 746	{ //can't use the force on vehicles.. except lightning
 747		if (forcePower == FP_LIGHTNING)
 748		{
 749			return 1;
 750		}
 751		else
 752		{
 753			return 0;
 754		}
 755	}
 756
 757	if (other && other->client && other->s.eType == ET_NPC &&
 758		level.gametype == GT_SIEGE)
 759	{ //can't use powers at all on npc's normally in siege...
 760		return 0;
 761	}
 762
 763	return 1;
 764}
 765
 766qboolean WP_ForcePowerAvailable( gentity_t *self, forcePowers_t forcePower, int overrideAmt )
 767{
 768	int	drain = overrideAmt ? overrideAmt :
 769				forcePowerNeeded[self->client->ps.fd.forcePowerLevel[forcePower]][forcePower];
 770
 771	if (self->client->ps.fd.forcePowersActive & (1 << forcePower))
 772	{ //we're probably going to deactivate it..
 773		return qtrue;
 774	}
 775	if ( forcePower == FP_LEVITATION )
 776	{
 777		return qtrue;
 778	}
 779	if ( !drain )
 780	{
 781		return qtrue;
 782	}
 783	if ((forcePower == FP_DRAIN || forcePower == FP_LIGHTNING) &&
 784		self->client->ps.fd.forcePower >= 25)
 785	{ //it's ok then, drain/lightning are actually duration
 786		return qtrue;
 787	}
 788	if ( self->client->ps.fd.forcePower < drain )
 789	{
 790		return qfalse;
 791	}
 792	return qtrue;
 793}
 794
 795qboolean WP_ForcePowerInUse( gentity_t *self, forcePowers_t forcePower )
 796{
 797	if ( (self->client->ps.fd.forcePowersActive & ( 1 << forcePower )) )
 798	{//already using this power
 799		return qtrue;
 800	}
 801
 802	return qfalse;
 803}
 804
 805qboolean WP_ForcePowerUsable( gentity_t *self, forcePowers_t forcePower )
 806{
 807	if (BG_HasYsalamiri(level.gametype, &self->client->ps))
 808	{
 809		return qfalse;
 810	}
 811
 812	if (self->health <= 0 || self->client->ps.stats[STAT_HEALTH] <= 0 ||
 813		(self->client->ps.eFlags & EF_DEAD))
 814	{
 815		return qfalse;
 816	}
 817
 818	if (self->client->ps.pm_flags & PMF_FOLLOW)
 819	{ //specs can't use powers through people
 820		return qfalse;
 821	}
 822	if (self->client->sess.sessionTeam == TEAM_SPECTATOR)
 823	{
 824		return qfalse;
 825	}
 826	if (self->client->tempSpectate >= level.time)
 827	{
 828		return qfalse;
 829	}
 830
 831	if (!BG_CanUseFPNow(level.gametype, &self->client->ps, level.time, forcePower))
 832	{
 833		return qfalse;
 834	}
 835
 836	if ( !(self->client->ps.fd.forcePowersKnown & ( 1 << forcePower )) )
 837	{//don't know this power
 838		return qfalse;
 839	}
 840	
 841	if ( (self->client->ps.fd.forcePowersActive & ( 1 << forcePower )) )
 842	{//already using this power
 843		if (forcePower != FP_LEVITATION)
 844		{
 845			return qfalse;
 846		}
 847	}
 848
 849	if (forcePower == FP_LEVITATION && self->client->fjDidJump)
 850	{
 851		return qfalse;
 852	}
 853
 854	if (!self->client->ps.fd.forcePowerLevel[forcePower])
 855	{
 856		return qfalse;
 857	}
 858
 859	if ( g_debugMelee.integer )
 860	{
 861		if ( (self->client->ps.pm_flags&PMF_STUCK_TO_WALL) )
 862		{//no offensive force powers when stuck to wall
 863			switch ( forcePower )
 864			{
 865			case FP_GRIP:
 866			case FP_LIGHTNING:
 867			case FP_DRAIN:
 868			case FP_SABER_OFFENSE:
 869			case FP_SABER_DEFENSE:
 870			case FP_SABERTHROW:
 871				return qfalse;
 872				break;
 873			default:
 874				break;
 875			}
 876		}
 877	}
 878
 879	if ( !self->client->ps.saberHolstered )
 880	{
 881		if ( (self->client->saber[0].saberFlags&SFL_TWO_HANDED) )
 882		{
 883			if ( g_saberRestrictForce.integer )
 884			{
 885				switch ( forcePower )
 886				{
 887				case FP_PUSH:
 888				case FP_PULL:
 889				case FP_TELEPATHY:
 890				case FP_GRIP:
 891				case FP_LIGHTNING:
 892				case FP_DRAIN:
 893					return qfalse;
 894					break;
 895				default:
 896					break;
 897				}
 898			}
 899		}
 900
 901		if ( (self->client->saber[0].saberFlags&SFL_TWO_HANDED)
 902			|| (self->client->saber[0].model && self->client->saber[0].model[0]) )
 903		{//this saber requires the use of two hands OR our other hand is using an active saber too
 904			if ( (self->client->saber[0].forceRestrictions&(1<<forcePower)) )
 905			{//this power is verboten when using this saber
 906				return qfalse;
 907			}
 908		}
 909
 910		if ( self->client->saber[0].model 
 911			&& self->client->saber[0].model[0] )
 912		{//both sabers on
 913			if ( g_saberRestrictForce.integer )
 914			{
 915				switch ( forcePower )
 916				{
 917				case FP_PUSH:
 918				case FP_PULL:
 919				case FP_TELEPATHY:
 920				case FP_GRIP:
 921				case FP_LIGHTNING:
 922				case FP_DRAIN:
 923					return qfalse;
 924					break;
 925				default:
 926					break;
 927				}
 928			}
 929			if ( (self->client->saber[1].forceRestrictions&(1<<forcePower)) )
 930			{//this power is verboten when using this saber
 931				return qfalse;
 932			}
 933		}
 934	}
 935	return WP_ForcePowerAvailable( self, forcePower, 0 );	// OVERRIDEFIXME
 936}
 937
 938int WP_AbsorbConversion(gentity_t *attacked, int atdAbsLevel, gentity_t *attacker, int atPower, int atPowerLevel, int atForceSpent)
 939{
 940	int getLevel = 0;
 941	int addTot = 0;
 942	gentity_t *abSound;
 943
 944	if (atPower != FP_LIGHTNING &&
 945		atPower != FP_DRAIN &&
 946		atPower != FP_GRIP &&
 947		atPower != FP_PUSH &&
 948		atPower != FP_PULL)
 949	{ //Only these powers can be absorbed
 950		return -1;
 951	}
 952
 953	if (!atdAbsLevel)
 954	{ //looks like attacker doesn't have any absorb power
 955		return -1;
 956	}
 957
 958	if (!(attacked->client->ps.fd.forcePowersActive & (1 << FP_ABSORB)))
 959	{ //absorb is not active
 960		return -1;
 961	}
 962
 963	//Subtract absorb power level from the offensive force power
 964	getLevel = atPowerLevel;
 965	getLevel -= atdAbsLevel;
 966
 967	if (getLevel < 0)
 968	{
 969		getLevel = 0;
 970	}
 971
 972	//let the attacker absorb an amount of force used in this attack based on his level of absorb
 973	addTot = (atForceSpent/3)*attacked->client->ps.fd.forcePowerLevel[FP_ABSORB];
 974
 975	if (addTot < 1 && atForceSpent >= 1)
 976	{
 977		addTot = 1;
 978	}
 979	attacked->client->ps.fd.forcePower += addTot;
 980	if (attacked->client->ps.fd.forcePower > 100)
 981	{
 982		attacked->client->ps.fd.forcePower = 100;
 983	}
 984
 985	//play sound indicating that attack was absorbed
 986	if (attacked->client->forcePowerSoundDebounce < level.time)
 987	{
 988		abSound = G_PreDefSound(attacked->client->ps.origin, PDSOUND_ABSORBHIT);
 989		abSound->s.trickedentindex = attacked->s.number;
 990
 991		attacked->client->forcePowerSoundDebounce = level.time + 400;
 992	}
 993
 994	return getLevel;
 995}
 996
 997void WP_ForcePowerRegenerate( gentity_t *self, int overrideAmt )
 998{ //called on a regular interval to regenerate force power.
 999	if ( !self->client )
1000	{
1001		return;
1002	}
1003
1004	if ( overrideAmt )
1005	{ //custom regen amount
1006		self->client->ps.fd.forcePower += overrideAmt;
1007	}
1008	else
1009	{ //otherwise, just 1
1010		self->client->ps.fd.forcePower++;
1011	}
1012
1013	if ( self->client->ps.fd.forcePower > self->client->ps.fd.forcePowerMax )
1014	{ //cap it off at the max (default 100)
1015		self->client->ps.fd.forcePower = self->client->ps.fd.forcePowerMax;
1016	}
1017}
1018
1019void WP_ForcePowerStart( gentity_t *self, forcePowers_t forcePower, int overrideAmt )
1020{ //activate the given force power
1021	int	duration = 0;
1022	qboolean hearable = qfalse;
1023	float hearDist = 0;
1024
1025	if (!WP_ForcePowerAvailable( self, forcePower, overrideAmt ))
1026	{
1027		return;
1028	}
1029
1030	if ( BG_FullBodyTauntAnim( self->client->ps.legsAnim ) )
1031	{//stop taunt
1032		self->client->ps.legsTimer = 0;
1033	}
1034	if ( BG_FullBodyTauntAnim( self->client->ps.torsoAnim ) )
1035	{//stop taunt
1036		self->client->ps.torsoTimer = 0;
1037	}
1038	//hearable and hearDist are merely for the benefit of bots, and not related to if a sound is actually played.
1039	//If duration is set, the force power will assume to be timer-based.
1040	switch( (int)forcePower )
1041	{
1042	case FP_HEAL:
1043		hearable = qtrue;
1044		hearDist = 256;
1045		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1046		break;
1047	case FP_LEVITATION:
1048		hearable = qtrue;
1049		hearDist = 256;
1050		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1051		break;
1052	case FP_SPEED:
1053		hearable = qtrue;
1054		hearDist = 256;
1055		if (self->client->ps.fd.forcePowerLevel[FP_SPEED] == FORCE_LEVEL_1)
1056		{
1057			duration = 10000;
1058		}
1059		else if (self->client->ps.fd.forcePowerLevel[FP_SPEED] == FORCE_LEVEL_2)
1060		{
1061			duration = 15000;
1062		}
1063		else if (self->client->ps.fd.forcePowerLevel[FP_SPEED] == FORCE_LEVEL_3)
1064		{
1065			duration = 20000;
1066		}
1067		else //shouldn't get here
1068		{
1069			break;
1070		}
1071
1072		if (overrideAmt)
1073		{
1074			duration = overrideAmt;
1075		}
1076
1077		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1078		break;
1079	case FP_PUSH:
1080		hearable = qtrue;
1081		hearDist = 256;
1082		break;
1083	case FP_PULL:
1084		hearable = qtrue;
1085		hearDist = 256;
1086		break;
1087	case FP_TELEPATHY:
1088		hearable = qtrue;
1089		hearDist = 256;
1090		if (self->client->ps.fd.forcePowerLevel[FP_TELEPATHY] == FORCE_LEVEL_1)
1091		{
1092			duration = 20000;
1093		}
1094		else if (self->client->ps.fd.forcePowerLevel[FP_TELEPATHY] == FORCE_LEVEL_2)
1095		{
1096			duration = 25000;
1097		}
1098		else if (self->client->ps.fd.forcePowerLevel[FP_TELEPATHY] == FORCE_LEVEL_3)
1099		{
1100			duration = 30000;
1101		}
1102		else //shouldn't get here
1103		{
1104			break;
1105		}
1106
1107		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1108		break;
1109	case FP_GRIP:
1110		hearable = qtrue;
1111		hearDist = 256;
1112		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1113		self->client->ps.powerups[PW_DISINT_4] = level.time + 60000;
1114		break;
1115	case FP_LIGHTNING:
1116		hearable = qtrue;
1117		hearDist = 512;
1118		duration = overrideAmt;
1119		overrideAmt = 0;
1120		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1121		self->client->ps.activeForcePass = self->client->ps.fd.forcePowerLevel[FP_LIGHTNING];
1122		break;
1123	case FP_RAGE:
1124		hearable = qtrue;
1125		hearDist = 256;
1126		if (self->client->ps.fd.forcePowerLevel[FP_RAGE] == FORCE_LEVEL_1)
1127		{
1128			duration = 8000;
1129		}
1130		else if (self->client->ps.fd.forcePowerLevel[FP_RAGE] == FORCE_LEVEL_2)
1131		{
1132			duration = 14000;
1133		}
1134		else if (self->client->ps.fd.forcePowerLevel[FP_RAGE] == FORCE_LEVEL_3)
1135		{
1136			duration = 20000;
1137		}
1138		else //shouldn't get here
1139		{
1140			break;
1141		}
1142
1143		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1144		break;
1145	case FP_PROTECT:
1146		hearable = qtrue;
1147		hearDist = 256;
1148		duration = 20000;
1149		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1150		break;
1151	case FP_ABSORB:
1152		hearable = qtrue;
1153		hearDist = 256;
1154		duration = 20000;
1155		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1156		break;
1157	case FP_TEAM_HEAL:
1158		hearable = qtrue;
1159		hearDist = 256;
1160		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1161		break;
1162	case FP_TEAM_FORCE:
1163		hearable = qtrue;
1164		hearDist = 256;
1165		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1166		break;
1167	case FP_DRAIN:
1168		hearable = qtrue;
1169		hearDist = 256;
1170		duration = overrideAmt;
1171		overrideAmt = 0;
1172		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1173		//self->client->ps.activeForcePass = self->client->ps.fd.forcePowerLevel[FP_DRAIN];
1174		break;
1175	case FP_SEE:
1176		hearable = qtrue;
1177		hearDist = 256;
1178		if (self->client->ps.fd.forcePowerLevel[FP_SEE] == FORCE_LEVEL_1)
1179		{
1180			duration = 10000;
1181		}
1182		else if (self->client->ps.fd.forcePowerLevel[FP_SEE] == FORCE_LEVEL_2)
1183		{
1184			duration = 20000;
1185		}
1186		else if (self->client->ps.fd.forcePowerLevel[FP_SEE] == FORCE_LEVEL_3)
1187		{
1188			duration = 30000;
1189		}
1190		else //shouldn't get here
1191		{
1192			break;
1193		}
1194
1195		self->client->ps.fd.forcePowersActive |= ( 1 << forcePower );
1196		break;
1197	case FP_SABER_OFFENSE:
1198		break;
1199	case FP_SABER_DEFENSE:
1200		break;
1201	case FP_SABERTHROW:
1202		break;
1203	default:
1204		break;
1205	}
1206
1207	if ( duration )
1208	{
1209		self->client->ps.fd.forcePowerDuration[forcePower] = level.time + duration;
1210	}
1211	else
1212	{
1213		self->client->ps.fd.forcePowerDuration[forcePower] = 0;
1214	}
1215
1216	if (hearable)
1217	{
1218		self->client->ps.otherSoundLen = hearDist;
1219		self->client->ps.otherSoundTime = level.time + 100;
1220	}
1221	
1222	self->client->ps.fd.forcePowerDebounce[forcePower] = 0;
1223
1224	if ((int)forcePower == FP_SPEED && overrideAmt)
1225	{
1226		BG_ForcePowerDrain( &self->client->ps, forcePower, overrideAmt*0.025 );
1227	}
1228	else if ((int)forcePower != FP_GRIP && (int)forcePower != FP_DRAIN)
1229	{ //grip and drain drain as damage is done
1230		BG_ForcePowerDrain( &self->client->ps, forcePower, overrideAmt );
1231	}
1232}
1233
1234void ForceHeal( gentity_t *self )
1235{
1236	if ( self->health <= 0 )
1237	{
1238		return;
1239	}
1240
1241	if ( !WP_ForcePowerUsable( self, FP_HEAL ) )
1242	{
1243		return;
1244	}
1245
1246	if ( self->health >= self->client->ps.stats[STAT_MAX_HEALTH])
1247	{
1248		return;
1249	}
1250
1251	if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_3)
1252	{
1253		self->health += 25; //This was 50, but that angered the Balance God.
1254		
1255		if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
1256		{
1257			self->health = self->client->ps.stats[STAT_MAX_HEALTH];
1258		}
1259		BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
1260	}
1261	else if (self->client->ps.fd.forcePowerLevel[FP_HEAL] == FORCE_LEVEL_2)
1262	{
1263		self->health += 10;
1264		
1265		if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
1266		{
1267			self->health = self->client->ps.stats[STAT_MAX_HEALTH];
1268		}
1269		BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
1270	}
1271	else
1272	{
1273		self->health += 5;
1274		
1275		if (self->health > self->client->ps.stats[STAT_MAX_HEALTH])
1276		{
1277			self->health = self->client->ps.stats[STAT_MAX_HEALTH];
1278		}
1279		BG_ForcePowerDrain( &self->client->ps, FP_HEAL, 0 );
1280	}
1281	/*
1282	else
1283	{
1284		WP_ForcePowerStart( self, FP_HEAL, 0 );
1285	}
1286	*/
1287	//NOTE: Decided to make all levels instant.
1288
1289	G_Sound( self, CHAN_ITEM, G_SoundIndex("sound/weapons/force/heal.wav") );
1290}
1291
1292void WP_AddToClientBitflags(gentity_t *ent, int entNum)
1293{
1294	if (!ent)
1295	{
1296		return;
1297	}
1298
1299	if (entNum > 47)
1300	{
1301		ent->s.trickedentindex4 |= (1 << (entNum-48));
1302	}
1303	else if (entNum > 31)
1304	{
1305		ent->s.trickedentindex3 |= (1 << (entNum-32));
1306	}
1307	else if (entNum > 15)
1308	{
1309		ent->s.trickedentindex2 |= (1 << (entNum-16));
1310	}
1311	else
1312	{
1313		ent->s.trickedentindex |= (1 << entNum);
1314	}
1315}
1316
1317void ForceTeamHeal( gentity_t *self )
1318{
1319	float radius = 256;
1320	int i = 0;
1321	gentity_t *ent;
1322	vec3_t a;
1323	int numpl = 0;
1324	int pl[MAX_CLIENTS];
1325	int healthadd = 0;
1326	gentity_t *te = NULL;
1327
1328	if ( self->health <= 0 )
1329	{
1330		return;
1331	}
1332
1333	if ( !WP_ForcePowerUsable( self, FP_TEAM_HEAL ) )
1334	{
1335		return;
1336	}
1337
1338	if (self->client->ps.fd.forcePowerDebounce[FP_TEAM_HEAL] >= level.time)
1339	{
1340		return;
1341	}
1342
1343	if (self->client->ps.fd.forcePowerLevel[FP_TEAM_HEAL] == FORCE_LEVEL_2)
1344	{
1345		radius *= 1.5;
1346	}
1347	if (self->client->ps.fd.forcePowerLevel[FP_TEAM_HEAL] == FORCE_LEVEL_3)
1348	{
1349		radius *= 2;
1350	}
1351
1352	while (i < MAX_CLIENTS)
1353	{
1354		ent = &g_entities[i];
1355
1356		if (ent && ent->client && self != ent && OnSameTeam(self, ent) && ent->client->ps.stats[STAT_HEALTH] < ent->client->ps.stats[STAT_MAX_HEALTH] && ent->client->ps.stats[STAT_HEALTH] > 0 && ForcePowerUsableOn(self, ent, FP_TEAM_HEAL) &&
1357			trap_InPVS(self->client->ps.origin, ent->client->ps.origin))
1358		{
1359			VectorSubtract(self->client->ps.origin, ent->client->ps.origin, a);
1360
1361			if (VectorLength(a) <= radius)
1362			{
1363				pl[numpl] = i;
1364				numpl++;
1365			}
1366		}
1367
1368		i++;
1369	}
1370
1371	if (numpl < 1)
1372	{
1373		return;
1374	}
1375
1376	if (numpl == 1)
1377	{
1378		healthadd = 50;
1379	}
1380	else if (numpl == 2)
1381	{
1382		healthadd = 33;
1383	}
1384	else
1385	{
1386		healthadd = 25;
1387	}
1388
1389	self->client->ps.fd.forcePowerDebounce[FP_TEAM_HEAL] = level.time + 2000;
1390	i = 0;
1391
1392	while (i < numpl)
1393	{
1394		if (g_entities[pl[i]].client->ps.stats[STAT_HEALTH] > 0 &&
1395			g_entities[pl[i]].health > 0)
1396		{
1397			g_entities[pl[i]].client->ps.stats[STAT_HEALTH] += healthadd;
1398			if (g_entities[pl[i]].client->ps.stats[STAT_HEALTH] > g_entities[pl[i]].client->ps.stats[STAT_MAX_HEALTH])
1399			{
1400				g_entities[pl[i]].client->ps.stats[STAT_HEALTH] = g_entities[pl[i]].client->ps.stats[STAT_MAX_HEALTH];
1401			}
1402
1403			g_entities[pl[i]].health = g_entities[pl[i]].client->ps.stats[STAT_HEALTH];
1404
1405			//At this point we know we got one, so add him into the collective event client bitflag
1406			if (!te)
1407			{
1408				te = G_TempEntity( self->client->ps.origin, EV_TEAM_POWER);
1409				te->s.eventParm = 1; //eventParm 1 is heal, eventParm 2 is force regen
1410
1411				//since we had an extra check above, do the drain now because we got at least one guy
1412				BG_ForcePowerDrain( &self->client->ps, FP_TEAM_HEAL, forcePowerNeeded[self->client->ps.fd.forcePowerLevel[FP_TEAM_HEAL]][FP_TEAM_HEAL] );
1413			}
1414
1415			WP_AddToClientBitflags(te, pl[i]);
1416			//Now cramming it all into one event.. doing this many g_sound events at once was a Bad Thing.
1417		}
1418		i++;
1419	}
1420}
1421
1422void ForceTeamForceReplenish( gentity_t *self )
1423{
1424	float radius = 256;
1425	int i = 0;
1426	gentity_t *ent;
1427	vec3_t a;
1428	int numpl = 0;
1429	int pl[MAX_CLIENTS];
1430	int poweradd = 0;
1431	gentity_t *te = NULL;
1432
1433	if ( self->health <= 0 )
1434	{
1435		return;
1436	}
1437
1438	if ( !WP_ForcePowerUsable( self, FP_TEAM_FORCE ) )
1439	{
1440		return;
1441	}
1442
1443	if (self->client->ps.fd.forcePowerDebounce[FP_TEAM_FORCE] >= level.time)
1444	{
1445		return;
1446	}
1447
1448	if (self->client->ps.fd.forcePowerLevel[FP_TEAM_FORCE] == FORCE_LEVEL_2)
1449	{
1450		radius *= 1.5;
1451	}
1452	if (self->client->ps.fd.forcePowerLevel[FP_TEAM_FORCE] == FORCE_LEVEL_3)
1453	{
1454		radius *= 2;
1455	}
1456
1457	while (i < MAX_CLIENTS)
1458	{
1459		ent = &g_entities[i];
1460
1461		if (ent && ent->client && self != ent && OnSameTeam(self, ent) && ent->client->ps.fd.forcePower < 100 && ForcePowerUsableOn(self, ent, FP_TEAM_FORCE) &&
1462			trap_InPVS(self->client->ps.origin, ent->client->ps.origin))
1463		{
1464			VectorSubtract(self->client->ps.origin, ent->client->ps.origin, a);
1465
1466			if (VectorLength(a) <= radius)
1467			{
1468				pl[numpl] = i;
1469				numpl++;
1470			}
1471		}
1472
1473		i++;
1474	}
1475
1476	if (numpl < 1)
1477	{
1478		return;
1479	}
1480
1481	if (numpl == 1)
1482	{
1483		poweradd = 50;
1484	}
1485	else if (numpl == 2)
1486	{
1487		poweradd = 33;
1488	}
1489	else
1490	{
1491		poweradd = 25;
1492	}
1493	self->client->ps.fd.forcePowerDebounce[FP_TEAM_FORCE] = level.time + 2000;
1494
1495	BG_ForcePowerDrain( &self->client->ps, FP_TEAM_FORCE, forcePowerNeeded[self->client->ps.fd.forcePowerLevel[FP_TEAM_FORCE]][FP_TEAM_FORCE] );
1496
1497	i = 0;
1498
1499	while (i < numpl)
1500	{
1501		g_entities[pl[i]].client->ps.fd.forcePower += poweradd;
1502		if (g_entities[pl[i]].client->ps.fd.forcePower > 100)
1503		{
1504			g_entities[pl[i]].client->ps.fd.forcePower = 100;
1505		}
1506
1507		//At this point we know we got one, so add him into the collective event client bitflag
1508		if (!te)
1509		{
1510			te = G_TempEntity( self->client->ps.origin, EV_TEAM_POWER);
1511			te->s.eventParm = 2; //eventParm 1 is heal, eventParm 2 is force regen
1512		}
1513
1514		WP_AddToClientBitflags(te, pl[i]);
1515		//Now cramming it all into one event.. doing this many g_sound events at once was a Bad Thing.
1516		
1517		i++;
1518	}
1519}
1520
1521void ForceGrip( gentity_t *self )
1522{
1523	trace_t tr;
1524	vec3_t tfrom, tto, fwd;
1525
1526	if ( self->health <= 0 )
1527	{
1528		return;
1529	}
1530
1531	if (self->client->ps.forceHandExtend != HANDEXTEND_NONE)
1532	{
1533		return;
1534	}
1535
1536	if (self->client->ps.weaponTime > 0)
1537	{
1538		return;
1539	}
1540
1541	if (self->client->ps.fd.forceGripUseTime > level.time)
1542	{
1543		return;
1544	}
1545
1546	if ( !WP_ForcePowerUsable( self, FP_GRIP ) )
1547	{
1548		return;
1549	}
1550
1551	VectorCopy(self->client->ps.origin, tfrom);
1552	tfrom[2] += self->client->ps.viewheight;
1553	AngleVectors(self->client->ps.viewangles, fwd, NULL, NULL);
1554	tto[0] = tfrom[0] + fwd[0]*MAX_GRIP_DISTANCE;
1555	tto[1] = tfrom[1] + fwd[1]*MAX_GRIP_DISTANCE;
1556	tto[2] = tfrom[2] + fwd[2]*MAX_GRIP_DISTANCE;
1557
1558	trap_Trace(&tr, tfrom, NULL, NULL, tto, self->s.number, MASK_PLAYERSOLID);
1559
1560	if ( tr.fraction != 1.0 &&
1561		tr.entityNum != ENTITYNUM_NONE &&
1562		g_entities[tr.entityNum].client &&
1563		!g_entities[tr.entityNum].client->ps.fd.forceGripCripple &&
1564		g_entities[tr.entityNum].client->ps.fd.forceGripBeingGripped < level.time &&
1565		ForcePowerUsableOn(self, &g_entities[tr.entityNum], FP_GRIP) &&
1566		(g_friendlyFire.integer || !OnSameTeam(self, &g_entities[tr.entityNum])) ) //don't grip someone who's still crippled
1567	{
1568		if (g_entities[tr.entityNum].s.number < MAX_CLIENTS && g_entities[tr.entityNum].client->ps.m_iVehicleNum)
1569		{ //a player on a vehicle
1570			gentity_t *vehEnt = &g_entities[g_entities[tr.entityNum].client->ps.m_iVehicleNum];
1571			if (vehEnt->inuse && vehEnt->client && vehEnt->m_pVehicle)
1572			{
1573				if (vehEnt->m_pVehicle->m_pVehicleInfo->type == VH_SPEEDER ||
1574					vehEnt->m_pVehicle->m_pVehicleInfo->type == VH_ANIMAL)
1575				{ //push the guy off
1576					vehEnt->m_pVehicle->m_pVehicleInfo->Eject(vehEnt->m_pVehicle, (bgEntity_t *)&g_entities[tr.entityNum], qfalse);
1577				}
1578			}
1579		}
1580		self->client->ps.fd.forceGripEntityNum = tr.entityNum;
1581		g_entities[tr.entityNum].client->ps.fd.forceGripStarted = level.time;
1582		self->client->ps.fd.forceGripDamageDebounceTime = 0;
1583
1584		self->client->ps.forceHandExtend = HANDEXTEND_FORCE_HOLD;
1585		self->client->ps.forceHandExtendTime = level.time + 5000;
1586	}
1587	else
1588	{
1589		self->client->ps.fd.forceGripEntityNum = ENTITYNUM_NONE;
1590		return;
1591	}
1592}
1593
1594void ForceSpeed( gentity_t *self, int forceDuration )
1595{
1596	if ( self->health <= 0 )
1597	{
1598		return;
1599	}
1600
1601	if (self->client->ps.forceAllowDeactivateTime < level.time &&
1602		(self->client->ps.fd.forcePowersActive & (1 << FP_SPEED)) )
1603	{
1604		WP_ForcePowerStop( self, FP_SPEED );
1605		return;
1606	}
1607
1608	if ( !WP_ForcePowerUsable( self, FP_SPEED ) )
1609	{
1610		return;
1611	}
1612
1613	if ( self->client->holdingObjectiveItem >= MAX_CLIENTS  
1614		&& self->client->holdingObjectiveItem < ENTITYNUM_WORLD )
1615	{//holding Siege item
1616		if ( g_entities[self->client->holdingObjectiveItem].genericValue15 )
1617		{//disables force powers
1618			return;
1619		}
1620	}
1621
1622	self->client->ps.forceAllowDeactivateTime = level.time + 1500;
1623
1624	WP_ForcePowerStart( self, FP_SPEED, forceDuration );
1625	G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/speed.wav") );
1626	G_Sound( self, TRACK_CHANNEL_2, speedLoopSound );
1627}
1628
1629void ForceSeeing( gentity_t *self )
1630{
1631	if ( self->health <= 0 )
1632	{
1633		return;
1634	}
1635
1636	if (self->client->ps.forceAllowDeactivateTime < level.time &&
1637		(self->client->ps.fd.forcePowersActive & (1 << FP_SEE)) )
1638	{
1639		WP_ForcePowerStop( self, FP_SEE );
1640		return;
1641	}
1642
1643	if ( !WP_ForcePowerUsable( self, FP_SEE ) )
1644	{
1645		return;
1646	}
1647
1648	self->client->ps.forceAllowDeactivateTime = level.time + 1500;
1649
1650	WP_ForcePowerStart( self, FP_SEE, 0 );
1651
1652	G_Sound( self, CHAN_AUTO, G_SoundIndex("sound/weapons/force/see.wav") );
1653	G_Sound( self, TRACK_CHANNEL_5, seeLoopSound );
1654}
1655
1656void ForceProtect( gentity_t *self )
1657{
1658	if ( self->health <= 0 )
1659	{
1660		return;
1661	}
1662
1663	if (self->client->ps.forceAllowDeactivateTime < level.time &&
1664		(self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT)) )
1665	{
1666		WP_ForcePowerStop( self, FP_PROTECT );
1667		return;
1668	}
1669
1670	if ( !WP_ForcePowerUsable( self, FP_PROTECT ) )
1671	{
1672		return;
1673	}
1674
1675	// Make sure to turn off Force Rage and Force Absorb.
1676	if (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE) )
1677	{
1678		WP_ForcePowerStop( self, FP_RAGE );
1679	}
1680	if (self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB) )
1681	{
1682		WP_ForcePowerStop( self, FP_ABSORB );
1683	}
1684
1685	self->client->ps.forceAllowDeactivateTime = level.time + 1500;
1686
1687	WP_ForcePowerStart( self, FP_PROTECT, 0 );
1688	G_PreDefSound(self->client->ps.origin, PDSOUND_PROTECT);
1689	G_Sound( self, TRACK_CHANNEL_3, protectLoopSound );
1690}
1691
1692void ForceAbsorb( gentity_t *self )
1693{
1694	if ( self->health <= 0 )
1695	{
1696		return;
1697	}
1698
1699	if (self->client->ps.forceAllowDeactivateTime < level.time &&
1700		(self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB)) )
1701	{
1702		WP_ForcePowerStop( self, FP_ABSORB );
1703		return;
1704	}
1705
1706	if ( !WP_ForcePowerUsable( self, FP_ABSORB ) )
1707	{
1708		return;
1709	}
1710
1711	// Make sure to turn off Force Rage and Force Protection.
1712	if (self->client->ps.fd.forcePowersActive & (1 << FP_RAGE) )
1713	{
1714		WP_ForcePowerStop( self, FP_RAGE );
1715	}
1716	if (self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT) )
1717	{
1718		WP_ForcePowerStop( self, FP_PROTECT );
1719	}
1720
1721	self->client->ps.forceAllowDeactivateTime = level.time + 1500;
1722
1723	WP_ForcePowerStart( self, FP_ABSORB, 0 );
1724	G_PreDefSound(self->client->ps.origin, PDSOUND_ABSORB);
1725	G_Sound( self, TRACK_CHANNEL_3, absorbLoopSound );
1726}
1727
1728void ForceRage( gentity_t *self )
1729{
1730	if ( self->health <= 0 )
1731	{
1732		return;
1733	}
1734
1735	if (self->client->ps.forceAllowDeactivateTime < level.time &&
1736		(self->client->ps.fd.forcePowersActive & (1 << FP_RAGE)) )
1737	{
1738		WP_ForcePowerStop( self, FP_RAGE );
1739		return;
1740	}
1741
1742	if ( !WP_ForcePowerUsable( self, FP_RAGE ) )
1743	{
1744		return;
1745	}
1746
1747	if (self->client->ps.fd.forceRageRecoveryTime >= level.time)
1748	{
1749		return;
1750	}
1751
1752	if (self->health < 10)
1753	{
1754		return;
1755	}
1756
1757	// Make sure to turn off Force Protection and Force Absorb.
1758	if (self->client->ps.fd.forcePowersActive & (1 << FP_PROTECT) )
1759	{
1760		WP_ForcePowerStop( self, FP_PROTECT );
1761	}
1762	if (self->client->ps.fd.forcePowersActive & (1 << FP_ABSORB) )
1763	{
1764		WP_ForcePowerStop( self, FP_ABSORB );
1765	}
1766
1767	self->client->ps.forceAllowDeactivateTime = level.time + 1500;
1768
1769	WP_ForcePowerStart( self, FP_RAGE, 0 );
1770
1771	G_Sound( self, TRACK_CHANNEL_4, G_SoundIndex("sound/weapons/force/rage.wav") );
1772	G_Sound( self, TRACK_CHANNEL_3, rageLoopSound );
1773}
1774
1775void ForceLightning( gentity_t *self )
1776{
1777	if ( self->health <= 0 )
1778	{
1779		return;
1780	}
1781	if ( self->client->ps.fd.forcePower < 25 || !WP_ForcePowerUsable( self, FP_LIGHTNING ) )
1782	{
1783		return;
1784	}
1785	if ( self->client->ps.fd.forcePowerDebounce[FP_LIGHTNING] > level.time )
1786	{//stops it while using it and also after using it, up to 3 second delay
1787		return;
1788	}
1789
1790	if (self->client->ps.forceHandExtend != HANDEXTEND_NONE)
1791	{
1792		return;
1793	}
1794
1795	if (self->client->ps.weaponTime > 0)
1796	{
1797		return;
1798	}
1799
1800	// fix: rocket lock bug
1801	BG_ClearRocketLock(&self->client->ps);
1802
1803	//Shoot lightning from hand
1804	//using grip anim now, to extend the burst time
1805	self->client->ps.forceHandExtend = HANDEXTEND_FORCE_HOLD;
1806	self->client->ps.forceHandExtendTime = level.time + 20000;
1807
1808	G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/lightning") );
1809	
1810	WP_ForcePowerStart( self, FP_LIGHTNING, 500 );
1811}
1812
1813void ForceLightningDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t impactPoint )
1814{
1815	self->client->dangerTime = level.time;
1816	self->client->ps.eFlags &= ~EF_INVULNERABLE;
1817	self->client->invulnerableTimer = 0;
1818
1819	if ( traceEnt && traceEnt->takedamage )
1820	{
1821		if (!traceEnt->client && traceEnt->s.eType == ET_NPC)
1822		{ //g2animent
1823			if (traceEnt->s.genericenemyindex < level.time)
1824			{
1825				traceEnt->s.genericenemyindex = level.time + 2000;
1826			}
1827		}
1828		if ( traceEnt->client )
1829		{//an enemy or object
1830			if (traceEnt->client->noLightningTime >= level.time)
1831			{ //give them power and don't hurt them.
1832				traceEnt->client->ps.fd.forcePower++;
1833				if (traceEnt->client->ps.fd.forcePower > 100)
1834				{
1835					traceEnt->client->ps.fd.forcePower = 100;
1836				}
1837				return;
1838			}
1839			if (ForcePowerUsableOn(self, traceEnt, FP_LIGHTNING))
1840			{
1841				int	dmg = Q_irand(1,2); //Q_irand( 1, 3 );
1842				
1843				int modPowerLevel = -1;
1844				
1845				if (traceEnt->client)
1846				{
1847					modPowerLevel = WP_AbsorbConversion(traceEnt, traceEnt->client->ps.fd.forcePowerLevel[FP_ABSORB], self, FP_LIGHTNING, self->client->ps.fd.forcePowerLevel[FP_LIGHTNING], 1);
1848				}
1849
1850				if (modPowerLevel != -1)
1851				{
1852					if (!modPowerLevel)
1853					{
1854						dmg = 0;
1855						traceEnt->client->noLightningTime = level.time + 400;
1856					}
1857					else if (modPowerLevel == 1)
1858					{
1859						dmg = 1;
1860						traceEnt->client->noLightningTime = level.time + 300;
1861					}
1862					else if (modPowerLevel == 2)
1863					{
1864						dmg = 1;
1865						traceEnt->client->noLightningTime = level.time + 100;
1866					}
1867				}
1868
1869				if ( self->client->ps.weapon == WP_MELEE
1870					&& self->client->ps.fd.forcePowerLevel[FP_LIGHTNING] > FORCE_LEVEL_2 )
1871				{//2-handed lightning
1872					//jackin' 'em up, Palpatine-style
1873					dmg *= 2;
1874				}
1875
1876				if (dmg)
1877				{
1878					//rww - Shields can now absorb lightning too.
1879					G_Damage( traceEnt, self, self, dir, impactPoint, dmg, 0, MOD_FORCE_DARK );
1880				}
1881				if ( traceEnt->client )
1882				{
1883					if ( !Q_irand( 0, 2 ) )
1884					{
1885						G_Sound( traceEnt, CHAN_BODY, G_SoundIndex( va("sound/weapons/force/lightninghit%i", Q_irand(1, 3) )) );
1886					}
1887
1888					if (traceEnt->client->ps.electrifyTime < (level.time + 400))
1889					{ //only update every 400ms to reduce bandwidth usage (as it is passing a 32-bit time value)
1890						traceEnt->client->ps.electrifyTime = level.time + 800;
1891					}
1892					if ( traceEnt->client->ps.powerups[PW_CLOAKED] )
1893					{//disable cloak temporarily
1894						Jedi_Decloak( traceEnt );
1895						traceEnt->client->cloakToggleTime = level.time + Q_irand( 3000, 10000 );
1896					}
1897				}
1898			}
1899		}
1900	}
1901}
1902
1903void ForceShootLightning( gentity_t *self )
1904{
1905	trace_t	tr;
1906	vec3_t	end, forward;
1907	gentity_t	*traceEnt;
1908
1909	if ( self->health <= 0 )
1910	{
1911		return;
1912	}
1913	AngleVectors( self->client->ps.viewangles, forward, NULL, NULL );
1914	VectorNormalize( forward );
1915
1916	if ( self->client->ps.fd.forcePowerLevel[FP_LIGHTNING] > FORCE_LEVEL_2 )
1917	{//arc
1918		vec3_t	center, mins, maxs, dir, ent_org, size, v;
1919		float	radius = FORCE_LIGHTNING_RADIUS, dot, dist;
1920		gentity_t	*entityList[MAX_GENTITIES];
1921		int			iEntityList[MAX_GENTITIES];
1922		int		e, numListedEntities, i;
1923
1924		VectorCopy( self->client->ps.origin, center );
1925		for ( i = 0 ; i < 3 ; i++ ) 
1926		{
1927			mins[i] = center[i] - radius;
1928			maxs[i] = center[i] + radius;
1929		}
1930		numListedEntities = trap_EntitiesInBox( mins, maxs, iEntityList, MAX_GENTITIES );
1931
1932		i = 0;
1933		while (i < numListedEntities)
1934		{
1935			entityList[i] = &g_entities[iEntityList[i]];
1936
1937			i++;
1938		}
1939
1940		for ( e = 0 ; e < numListedEntities ; e++ ) 
1941		{
1942			traceEnt = entityList[e];
1943
1944			if ( !traceEnt )
1945				continue;
1946			if ( traceEnt == self )
1947				continue;
1948			if ( traceEnt->r.ownerNum == self->s.number && traceEnt->s.weapon != WP_THERMAL )//can push your own thermals
1949				continue;
1950			if ( !traceEnt->inuse )
1951				continue;
1952			if ( !traceEnt->takedamage )
1953				continue;
1954			if ( traceEnt->health <= 0 )//no torturing corpses
1955				continue;
1956			if ( !g_friendlyFire.integer && OnSameTeam(self, traceEnt))
1957				continue;
1958			//this is all to see if we need to start a saber attack, if it's in flight, this doesn't matter
1959			// find the distance from the edge of the bounding box
1960			for ( i = 0 ; i < 3 ; i++ ) 
1961			{
1962				if ( center[i] < traceEnt->r.absmin[i] ) 
1963				{
1964					v[i] = traceEnt->r.absmin[i] - center[i];
1965				} else if ( center[i] > traceEnt->r.absmax[i] ) 
1966				{
1967					v[i] = center[i] - traceEnt->r.absmax[i];
1968				} else 
1969				{
1970					v[i] = 0;
1971				}
1972			}
1973
1974			VectorSubtract( traceEnt->r.absmax, traceEnt->r.absmin, size );
1975			VectorMA( traceEnt->r.absmin, 0.5, size, ent_org );
1976
1977			//see if they're in front of me
1978			//must be within the forward cone
1979			VectorSubtract( ent_org, center, dir );
1980			VectorNormalize( dir );
1981			if ( (dot = DotProduct( dir, forward )) < 0.5 )
1982				continue;
1983
1984			//must be close enough
1985			dist = VectorLength( v );
1986			if ( dist >= radius ) 
1987			{
1988				continue;
1989			}
1990		
1991			//in PVS?
1992			if ( !traceEnt->r.bmodel && !trap_InPVS( ent_org, self->client->ps.origin ) )
1993			{//must be in PVS
1994				continue;
1995			}
1996
1997			//Now check and see if we can actually hit it
1998			trap_Trace( &tr, self->client->ps.origin, vec3_origin, vec3_origin, ent_org, self->s.number, MASK_SHOT );
1999			if ( tr.fraction < 1.0f && tr.entityNum != traceEnt->s.number )
2000			{//must have clear LOS
2001				continue;
2002			}
2003
2004			// ok, we are within the radius, add us to the incoming list
2005			ForceLightningDamage( self, traceEnt, dir, ent_org );
2006		}
2007	}
2008	else
2009	{//trace-line
2010		VectorMA( self->client->ps.origin, 2048, forward, end );
2011		
2012		trap_Trace( &tr, self->client->ps.origin, vec3_origin, vec3_origin, end, self->s.number, MASK_SHOT );
2013		if ( tr.entityNum == ENTITYNUM_NONE || tr.fraction == 1.0 || tr.allsolid || tr.startsolid )
2014		{
2015			return;
2016		}
2017		
2018		traceEnt = &g_entities[tr.entityNum];
2019		ForceLightningDamage( self, traceEnt, forward, tr.endpos );
2020	}
2021}
2022
2023void ForceDrain( gentity_t *self )
2024{
2025	if ( self->health <= 0 )
2026	{
2027		return;
2028	}
2029
2030	if (self->client->ps.forceHandExtend != HANDEXTEND_NONE)
2031	{
2032		return;
2033	}
2034
2035	if (self->client->ps.weaponTime > 0)
2036	{
2037		return;
2038	}
2039
2040	if ( self->client->ps.fd.forcePower < 25 || !WP_ForcePowerUsable( self, FP_DRAIN ) )
2041	{
2042		return;
2043	}
2044	if ( self->client->ps.fd.forcePowerDebounce[FP_DRAIN] > level.time )
2045	{//stops it while using it and also after using it, up to 3 second delay
2046		return;
2047	}
2048
2049//	self->client->ps.forceHandExtend = HANDEXTEND_FORCEPUSH;
2050//	self->client->ps.forceHandExtendTime = level.time + 1000;
2051	self->client->ps.forceHandExtend = HANDEXTEND_FORCE_HOLD;
2052	self->client->ps.forceHandExtendTime = level.time + 20000;
2053
2054	G_Sound( self, CHAN_BODY, G_SoundIndex("sound/weapons/force/drain.wav") );
2055	
2056	WP_ForcePowerStart( self, FP_DRAIN, 500 );
2057}
2058
2059void ForceDrainDamage( gentity_t *self, gentity_t *traceEnt, vec3_t dir, vec3_t impactPoint )
2060{
2061	gentity_t *tent;
2062
2063	self->client->dangerTime = level.time;
2064	self->client->ps.eFlags &= ~EF_INVULNERAB

Large files files are truncated, but you can click here to view the full file