PageRenderTime 70ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 1ms

/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
Possible License(s): GPL-2.0

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

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