PageRenderTime 57ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/game/w_force.c

https://bitbucket.org/bshaw/jk3game_sdk_mingw
C | 5792 lines | 4895 code | 676 blank | 221 comment | 1433 complexity | 9246377cd634bd52cdb23d9f264484b0 MD5 | raw file

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

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

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