p_view.c 27 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136
  1. /*
  2. Copyright (C) 1997-2001 Id Software, Inc.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. #include "g_local.h"
  16. #include "m_player.h"
  17. static edict_t *current_player;
  18. static gclient_t *current_client;
  19. static vec3_t forward, right, up;
  20. float xyspeed;
  21. float bobmove;
  22. int bobcycle; // odd cycles are right foot going forward
  23. float bobfracsin; // sin(bobfrac*M_PI)
  24. /*
  25. ===============
  26. SV_CalcRoll
  27. ===============
  28. */
  29. float SV_CalcRoll (vec3_t angles, vec3_t velocity)
  30. {
  31. float sign;
  32. float side;
  33. float value;
  34. side = DotProduct (velocity, right);
  35. sign = side < 0 ? -1 : 1;
  36. side = fabs(side);
  37. value = sv_rollangle->value;
  38. if (side < sv_rollspeed->value)
  39. side = side * value / sv_rollspeed->value;
  40. else
  41. side = value;
  42. return side*sign;
  43. }
  44. /*
  45. ===============
  46. P_DamageFeedback
  47. Handles color blends and view kicks
  48. ===============
  49. */
  50. void P_DamageFeedback (edict_t *player)
  51. {
  52. gclient_t *client;
  53. float side;
  54. float realcount, count, kick;
  55. vec3_t v;
  56. int r, l;
  57. static vec3_t power_color = {0.0, 1.0, 0.0};
  58. static vec3_t acolor = {1.0, 1.0, 1.0};
  59. static vec3_t bcolor = {1.0, 0.0, 0.0};
  60. client = player->client;
  61. // flash the backgrounds behind the status numbers
  62. client->ps.stats[STAT_FLASHES] = 0;
  63. if (client->damage_blood)
  64. client->ps.stats[STAT_FLASHES] |= 1;
  65. if (client->damage_armor && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
  66. client->ps.stats[STAT_FLASHES] |= 2;
  67. // total points of damage shot at the player this frame
  68. count = (client->damage_blood + client->damage_armor + client->damage_parmor);
  69. if (count == 0)
  70. return; // didn't take any damage
  71. // start a pain animation if still in the player model
  72. if (client->anim_priority < ANIM_PAIN && player->s.modelindex == 255)
  73. {
  74. static int i;
  75. client->anim_priority = ANIM_PAIN;
  76. if (client->ps.pmove.pm_flags & PMF_DUCKED)
  77. {
  78. player->s.frame = FRAME_crpain1-1;
  79. client->anim_end = FRAME_crpain4;
  80. }
  81. else
  82. {
  83. i = (i+1)%3;
  84. switch (i)
  85. {
  86. case 0:
  87. player->s.frame = FRAME_pain101-1;
  88. client->anim_end = FRAME_pain104;
  89. break;
  90. case 1:
  91. player->s.frame = FRAME_pain201-1;
  92. client->anim_end = FRAME_pain204;
  93. break;
  94. case 2:
  95. player->s.frame = FRAME_pain301-1;
  96. client->anim_end = FRAME_pain304;
  97. break;
  98. }
  99. }
  100. }
  101. realcount = count;
  102. if (count < 10)
  103. count = 10; // allways make a visible effect
  104. // play an apropriate pain sound
  105. if ((level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
  106. {
  107. r = 1 + (rand()&1);
  108. player->pain_debounce_time = level.time + 0.7;
  109. if (player->health < 25)
  110. l = 25;
  111. else if (player->health < 50)
  112. l = 50;
  113. else if (player->health < 75)
  114. l = 75;
  115. else
  116. l = 100;
  117. gi.sound (player, CHAN_VOICE, gi.soundindex(va("*pain%i_%i.wav", l, r)), 1, ATTN_NORM, 0);
  118. }
  119. // the total alpha of the blend is allways proportional to count
  120. if (client->damage_alpha < 0)
  121. client->damage_alpha = 0;
  122. client->damage_alpha += count*0.01;
  123. if (client->damage_alpha < 0.2)
  124. client->damage_alpha = 0.2;
  125. if (client->damage_alpha > 0.6)
  126. client->damage_alpha = 0.6; // don't go too saturated
  127. // the color of the blend will vary based on how much was absorbed
  128. // by different armors
  129. VectorClear (v);
  130. if (client->damage_parmor)
  131. VectorMA (v, (float)client->damage_parmor/realcount, power_color, v);
  132. if (client->damage_armor)
  133. VectorMA (v, (float)client->damage_armor/realcount, acolor, v);
  134. if (client->damage_blood)
  135. VectorMA (v, (float)client->damage_blood/realcount, bcolor, v);
  136. VectorCopy (v, client->damage_blend);
  137. //
  138. // calculate view angle kicks
  139. //
  140. kick = abs(client->damage_knockback);
  141. if (kick && player->health > 0) // kick of 0 means no view adjust at all
  142. {
  143. kick = kick * 100 / player->health;
  144. if (kick < count*0.5)
  145. kick = count*0.5;
  146. if (kick > 50)
  147. kick = 50;
  148. VectorSubtract (client->damage_from, player->s.origin, v);
  149. VectorNormalize (v);
  150. side = DotProduct (v, right);
  151. client->v_dmg_roll = kick*side*0.3;
  152. side = -DotProduct (v, forward);
  153. client->v_dmg_pitch = kick*side*0.3;
  154. client->v_dmg_time = level.time + DAMAGE_TIME;
  155. }
  156. //
  157. // clear totals
  158. //
  159. client->damage_blood = 0;
  160. client->damage_armor = 0;
  161. client->damage_parmor = 0;
  162. client->damage_knockback = 0;
  163. }
  164. /*
  165. ===============
  166. SV_CalcViewOffset
  167. Auto pitching on slopes?
  168. fall from 128: 400 = 160000
  169. fall from 256: 580 = 336400
  170. fall from 384: 720 = 518400
  171. fall from 512: 800 = 640000
  172. fall from 640: 960 =
  173. damage = deltavelocity*deltavelocity * 0.0001
  174. ===============
  175. */
  176. void SV_CalcViewOffset (edict_t *ent)
  177. {
  178. float *angles;
  179. float bob;
  180. float ratio;
  181. float delta;
  182. vec3_t v;
  183. //===================================
  184. // base angles
  185. angles = ent->client->ps.kick_angles;
  186. // if dead, fix the angle and don't add any kick
  187. if (ent->deadflag)
  188. {
  189. VectorClear (angles);
  190. ent->client->ps.viewangles[ROLL] = 40;
  191. ent->client->ps.viewangles[PITCH] = -15;
  192. ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
  193. }
  194. else
  195. {
  196. // add angles based on weapon kick
  197. VectorCopy (ent->client->kick_angles, angles);
  198. // add angles based on damage kick
  199. ratio = (ent->client->v_dmg_time - level.time) / DAMAGE_TIME;
  200. if (ratio < 0)
  201. {
  202. ratio = 0;
  203. ent->client->v_dmg_pitch = 0;
  204. ent->client->v_dmg_roll = 0;
  205. }
  206. angles[PITCH] += ratio * ent->client->v_dmg_pitch;
  207. angles[ROLL] += ratio * ent->client->v_dmg_roll;
  208. // add pitch based on fall kick
  209. ratio = (ent->client->fall_time - level.time) / FALL_TIME;
  210. if (ratio < 0)
  211. ratio = 0;
  212. angles[PITCH] += ratio * ent->client->fall_value;
  213. // add angles based on velocity
  214. delta = DotProduct (ent->velocity, forward);
  215. angles[PITCH] += delta*run_pitch->value;
  216. delta = DotProduct (ent->velocity, right);
  217. angles[ROLL] += delta*run_roll->value;
  218. // add angles based on bob
  219. delta = bobfracsin * bob_pitch->value * xyspeed;
  220. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  221. delta *= 6; // crouching
  222. angles[PITCH] += delta;
  223. delta = bobfracsin * bob_roll->value * xyspeed;
  224. if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
  225. delta *= 6; // crouching
  226. if (bobcycle & 1)
  227. delta = -delta;
  228. angles[ROLL] += delta;
  229. }
  230. //===================================
  231. // base origin
  232. VectorClear (v);
  233. // add view height
  234. v[2] += ent->viewheight;
  235. // add fall height
  236. ratio = (ent->client->fall_time - level.time) / FALL_TIME;
  237. if (ratio < 0)
  238. ratio = 0;
  239. v[2] -= ratio * ent->client->fall_value * 0.4;
  240. // add bob height
  241. bob = bobfracsin * xyspeed * bob_up->value;
  242. if (bob > 6)
  243. bob = 6;
  244. //gi.DebugGraph (bob *2, 255);
  245. v[2] += bob;
  246. // add kick offset
  247. VectorAdd (v, ent->client->kick_origin, v);
  248. // absolutely bound offsets
  249. // so the view can never be outside the player box
  250. if (v[0] < -14)
  251. v[0] = -14;
  252. else if (v[0] > 14)
  253. v[0] = 14;
  254. if (v[1] < -14)
  255. v[1] = -14;
  256. else if (v[1] > 14)
  257. v[1] = 14;
  258. if (v[2] < -22)
  259. v[2] = -22;
  260. else if (v[2] > 30)
  261. v[2] = 30;
  262. VectorCopy (v, ent->client->ps.viewoffset);
  263. }
  264. /*
  265. ==============
  266. SV_CalcGunOffset
  267. ==============
  268. */
  269. void SV_CalcGunOffset (edict_t *ent)
  270. {
  271. int i;
  272. float delta;
  273. // gun angles from bobbing
  274. ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
  275. ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
  276. if (bobcycle & 1)
  277. {
  278. ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
  279. ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW];
  280. }
  281. ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005;
  282. // gun angles from delta movement
  283. for (i=0 ; i<3 ; i++)
  284. {
  285. delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i];
  286. if (delta > 180)
  287. delta -= 360;
  288. if (delta < -180)
  289. delta += 360;
  290. if (delta > 45)
  291. delta = 45;
  292. if (delta < -45)
  293. delta = -45;
  294. if (i == YAW)
  295. ent->client->ps.gunangles[ROLL] += 0.1*delta;
  296. ent->client->ps.gunangles[i] += 0.2 * delta;
  297. }
  298. // gun height
  299. VectorClear (ent->client->ps.gunoffset);
  300. // ent->ps->gunorigin[2] += bob;
  301. // gun_x / gun_y / gun_z are development tools
  302. for (i=0 ; i<3 ; i++)
  303. {
  304. ent->client->ps.gunoffset[i] += forward[i]*(gun_y->value);
  305. ent->client->ps.gunoffset[i] += right[i]*gun_x->value;
  306. ent->client->ps.gunoffset[i] += up[i]* (-gun_z->value);
  307. }
  308. }
  309. /*
  310. =============
  311. SV_AddBlend
  312. =============
  313. */
  314. void SV_AddBlend (float r, float g, float b, float a, float *v_blend)
  315. {
  316. float a2, a3;
  317. if (a <= 0)
  318. return;
  319. a2 = v_blend[3] + (1-v_blend[3])*a; // new total alpha
  320. a3 = v_blend[3]/a2; // fraction of color from old
  321. v_blend[0] = v_blend[0]*a3 + r*(1-a3);
  322. v_blend[1] = v_blend[1]*a3 + g*(1-a3);
  323. v_blend[2] = v_blend[2]*a3 + b*(1-a3);
  324. v_blend[3] = a2;
  325. }
  326. /*
  327. =============
  328. SV_CalcBlend
  329. =============
  330. */
  331. void SV_CalcBlend (edict_t *ent)
  332. {
  333. int contents;
  334. vec3_t vieworg;
  335. int remaining;
  336. ent->client->ps.blend[0] = ent->client->ps.blend[1] =
  337. ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0;
  338. // add for contents
  339. VectorAdd (ent->s.origin, ent->client->ps.viewoffset, vieworg);
  340. contents = gi.pointcontents (vieworg);
  341. if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) )
  342. ent->client->ps.rdflags |= RDF_UNDERWATER;
  343. else
  344. ent->client->ps.rdflags &= ~RDF_UNDERWATER;
  345. if (contents & (CONTENTS_SOLID|CONTENTS_LAVA))
  346. SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.blend);
  347. else if (contents & CONTENTS_SLIME)
  348. SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.blend);
  349. else if (contents & CONTENTS_WATER)
  350. SV_AddBlend (0.5, 0.3, 0.2, 0.4, ent->client->ps.blend);
  351. // add for powerups
  352. if (ent->client->quad_framenum > level.framenum)
  353. {
  354. remaining = ent->client->quad_framenum - level.framenum;
  355. if (remaining == 30) // beginning to fade
  356. gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
  357. if (remaining > 30 || (remaining & 4) )
  358. SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend);
  359. }
  360. else if (ent->client->invincible_framenum > level.framenum)
  361. {
  362. remaining = ent->client->invincible_framenum - level.framenum;
  363. if (remaining == 30) // beginning to fade
  364. gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0);
  365. if (remaining > 30 || (remaining & 4) )
  366. SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend);
  367. }
  368. else if (ent->client->enviro_framenum > level.framenum)
  369. {
  370. remaining = ent->client->enviro_framenum - level.framenum;
  371. if (remaining == 30) // beginning to fade
  372. gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
  373. if (remaining > 30 || (remaining & 4) )
  374. SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend);
  375. }
  376. else if (ent->client->breather_framenum > level.framenum)
  377. {
  378. remaining = ent->client->breather_framenum - level.framenum;
  379. if (remaining == 30) // beginning to fade
  380. gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
  381. if (remaining > 30 || (remaining & 4) )
  382. SV_AddBlend (0.4, 1, 0.4, 0.04, ent->client->ps.blend);
  383. }
  384. // add for damage
  385. if (ent->client->damage_alpha > 0)
  386. SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1]
  387. ,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend);
  388. if (ent->client->bonus_alpha > 0)
  389. SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend);
  390. // drop the damage value
  391. ent->client->damage_alpha -= 0.06;
  392. if (ent->client->damage_alpha < 0)
  393. ent->client->damage_alpha = 0;
  394. // drop the bonus value
  395. ent->client->bonus_alpha -= 0.1;
  396. if (ent->client->bonus_alpha < 0)
  397. ent->client->bonus_alpha = 0;
  398. }
  399. /*
  400. =================
  401. P_FallingDamage
  402. =================
  403. */
  404. void P_FallingDamage (edict_t *ent)
  405. {
  406. float delta;
  407. int damage;
  408. vec3_t dir;
  409. if (ent->s.modelindex != 255)
  410. return; // not in the player model
  411. if (ent->movetype == MOVETYPE_NOCLIP)
  412. return;
  413. if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity))
  414. {
  415. delta = ent->client->oldvelocity[2];
  416. }
  417. else
  418. {
  419. if (!ent->groundentity)
  420. return;
  421. delta = ent->velocity[2] - ent->client->oldvelocity[2];
  422. }
  423. delta = delta*delta * 0.0001;
  424. //ZOID
  425. // never take damage if just release grapple or on grapple
  426. if (level.time - ent->client->ctf_grapplereleasetime <= FRAMETIME * 2 ||
  427. (ent->client->ctf_grapple &&
  428. ent->client->ctf_grapplestate > CTF_GRAPPLE_STATE_FLY))
  429. return;
  430. //ZOID
  431. // never take falling damage if completely underwater
  432. if (ent->waterlevel == 3)
  433. return;
  434. if (ent->waterlevel == 2)
  435. delta *= 0.25;
  436. if (ent->waterlevel == 1)
  437. delta *= 0.5;
  438. if (delta < 1)
  439. return;
  440. if (delta < 15)
  441. {
  442. ent->s.event = EV_FOOTSTEP;
  443. return;
  444. }
  445. ent->client->fall_value = delta*0.5;
  446. if (ent->client->fall_value > 40)
  447. ent->client->fall_value = 40;
  448. ent->client->fall_time = level.time + FALL_TIME;
  449. if (delta > 30)
  450. {
  451. if (ent->health > 0)
  452. {
  453. if (delta >= 55)
  454. ent->s.event = EV_FALLFAR;
  455. else
  456. ent->s.event = EV_FALL;
  457. }
  458. ent->pain_debounce_time = level.time; // no normal pain sound
  459. damage = (delta-30)/2;
  460. if (damage < 1)
  461. damage = 1;
  462. VectorSet (dir, 0, 0, 1);
  463. if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) )
  464. T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
  465. }
  466. else
  467. {
  468. ent->s.event = EV_FALLSHORT;
  469. return;
  470. }
  471. }
  472. /*
  473. =============
  474. P_WorldEffects
  475. =============
  476. */
  477. void P_WorldEffects (void)
  478. {
  479. qboolean breather;
  480. qboolean envirosuit;
  481. int waterlevel, old_waterlevel;
  482. if (current_player->movetype == MOVETYPE_NOCLIP)
  483. {
  484. current_player->air_finished = level.time + 12; // don't need air
  485. return;
  486. }
  487. waterlevel = current_player->waterlevel;
  488. old_waterlevel = current_client->old_waterlevel;
  489. current_client->old_waterlevel = waterlevel;
  490. breather = current_client->breather_framenum > level.framenum;
  491. envirosuit = current_client->enviro_framenum > level.framenum;
  492. //
  493. // if just entered a water volume, play a sound
  494. //
  495. if (!old_waterlevel && waterlevel)
  496. {
  497. PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  498. if (current_player->watertype & CONTENTS_LAVA)
  499. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
  500. else if (current_player->watertype & CONTENTS_SLIME)
  501. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  502. else if (current_player->watertype & CONTENTS_WATER)
  503. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  504. current_player->flags |= FL_INWATER;
  505. // clear damage_debounce, so the pain sound will play immediately
  506. current_player->damage_debounce_time = level.time - 1;
  507. }
  508. //
  509. // if just completely exited a water volume, play a sound
  510. //
  511. if (old_waterlevel && ! waterlevel)
  512. {
  513. PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  514. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
  515. current_player->flags &= ~FL_INWATER;
  516. }
  517. //
  518. // check for head just going under water
  519. //
  520. if (old_waterlevel != 3 && waterlevel == 3)
  521. {
  522. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
  523. }
  524. //
  525. // check for head just coming out of water
  526. //
  527. if (old_waterlevel == 3 && waterlevel != 3)
  528. {
  529. if (current_player->air_finished < level.time)
  530. { // gasp for air
  531. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
  532. PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  533. }
  534. else if (current_player->air_finished < level.time + 11)
  535. { // just break surface
  536. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
  537. }
  538. }
  539. //
  540. // check for drowning
  541. //
  542. if (waterlevel == 3)
  543. {
  544. // breather or envirosuit give air
  545. if (breather || envirosuit)
  546. {
  547. current_player->air_finished = level.time + 10;
  548. if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0)
  549. {
  550. if (!current_client->breather_sound)
  551. gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
  552. else
  553. gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
  554. current_client->breather_sound ^= 1;
  555. PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  556. //FIXME: release a bubble?
  557. }
  558. }
  559. // if out of air, start drowning
  560. if (current_player->air_finished < level.time)
  561. { // drown!
  562. if (current_player->client->next_drown_time < level.time
  563. && current_player->health > 0)
  564. {
  565. current_player->client->next_drown_time = level.time + 1;
  566. // take more damage the longer underwater
  567. current_player->dmg += 2;
  568. if (current_player->dmg > 15)
  569. current_player->dmg = 15;
  570. // play a gurp sound instead of a normal pain sound
  571. if (current_player->health <= current_player->dmg)
  572. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
  573. else if (rand()&1)
  574. gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
  575. else
  576. gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
  577. current_player->pain_debounce_time = level.time;
  578. T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
  579. }
  580. }
  581. }
  582. else
  583. {
  584. current_player->air_finished = level.time + 12;
  585. current_player->dmg = 2;
  586. }
  587. //
  588. // check for sizzle damage
  589. //
  590. if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
  591. {
  592. if (current_player->watertype & CONTENTS_LAVA)
  593. {
  594. if (current_player->health > 0
  595. && current_player->pain_debounce_time <= level.time
  596. && current_client->invincible_framenum < level.framenum)
  597. {
  598. if (rand()&1)
  599. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
  600. else
  601. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
  602. current_player->pain_debounce_time = level.time + 1;
  603. }
  604. if (envirosuit) // take 1/3 damage with envirosuit
  605. T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA);
  606. else
  607. T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA);
  608. }
  609. if (current_player->watertype & CONTENTS_SLIME)
  610. {
  611. if (!envirosuit)
  612. { // no damage from slime with envirosuit
  613. T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME);
  614. }
  615. }
  616. }
  617. }
  618. /*
  619. ===============
  620. G_SetClientEffects
  621. ===============
  622. */
  623. void G_SetClientEffects (edict_t *ent)
  624. {
  625. int pa_type;
  626. int remaining;
  627. ent->s.effects = 0;
  628. ent->s.renderfx = 0;
  629. if (ent->health <= 0 || level.intermissiontime)
  630. return;
  631. if (ent->powerarmor_time > level.time)
  632. {
  633. pa_type = PowerArmorType (ent);
  634. if (pa_type == POWER_ARMOR_SCREEN)
  635. {
  636. ent->s.effects |= EF_POWERSCREEN;
  637. }
  638. else if (pa_type == POWER_ARMOR_SHIELD)
  639. {
  640. ent->s.effects |= EF_COLOR_SHELL;
  641. ent->s.renderfx |= RF_SHELL_GREEN;
  642. }
  643. }
  644. //ZOID
  645. CTFEffects(ent);
  646. //ZOID
  647. if (ent->client->quad_framenum > level.framenum
  648. //ZOID
  649. && (level.framenum & 8)
  650. //ZOID
  651. )
  652. {
  653. remaining = ent->client->quad_framenum - level.framenum;
  654. if (remaining > 30 || (remaining & 4) )
  655. ent->s.effects |= EF_QUAD;
  656. }
  657. if (ent->client->invincible_framenum > level.framenum
  658. //ZOID
  659. && (level.framenum & 8)
  660. //ZOID
  661. )
  662. {
  663. remaining = ent->client->invincible_framenum - level.framenum;
  664. if (remaining > 30 || (remaining & 4) )
  665. ent->s.effects |= EF_PENT;
  666. }
  667. // show cheaters!!!
  668. if (ent->flags & FL_GODMODE)
  669. {
  670. ent->s.effects |= EF_COLOR_SHELL;
  671. ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
  672. }
  673. }
  674. /*
  675. ===============
  676. G_SetClientEvent
  677. ===============
  678. */
  679. void G_SetClientEvent (edict_t *ent)
  680. {
  681. if (ent->s.event)
  682. return;
  683. if ( ent->groundentity && xyspeed > 225)
  684. {
  685. if ( (int)(current_client->bobtime+bobmove) != bobcycle )
  686. ent->s.event = EV_FOOTSTEP;
  687. }
  688. }
  689. /*
  690. ===============
  691. G_SetClientSound
  692. ===============
  693. */
  694. void G_SetClientSound (edict_t *ent)
  695. {
  696. char *weap;
  697. if (ent->client->resp.game_helpchanged != game.helpchanged)
  698. {
  699. ent->client->resp.game_helpchanged = game.helpchanged;
  700. ent->client->resp.helpchanged = 1;
  701. }
  702. // help beep (no more than three times)
  703. if (ent->client->resp.helpchanged && ent->client->resp.helpchanged <= 3 && !(level.framenum&63) )
  704. {
  705. ent->client->resp.helpchanged++;
  706. gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0);
  707. }
  708. if (ent->client->pers.weapon)
  709. weap = ent->client->pers.weapon->classname;
  710. else
  711. weap = "";
  712. if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
  713. ent->s.sound = snd_fry;
  714. else if (strcmp(weap, "weapon_railgun") == 0)
  715. ent->s.sound = gi.soundindex("weapons/rg_hum.wav");
  716. else if (strcmp(weap, "weapon_bfg") == 0)
  717. ent->s.sound = gi.soundindex("weapons/bfg_hum.wav");
  718. else if (ent->client->weapon_sound)
  719. ent->s.sound = ent->client->weapon_sound;
  720. else
  721. ent->s.sound = 0;
  722. }
  723. /*
  724. ===============
  725. G_SetClientFrame
  726. ===============
  727. */
  728. void G_SetClientFrame (edict_t *ent)
  729. {
  730. gclient_t *client;
  731. qboolean duck, run;
  732. if (ent->s.modelindex != 255)
  733. return; // not in the player model
  734. client = ent->client;
  735. if (client->ps.pmove.pm_flags & PMF_DUCKED)
  736. duck = true;
  737. else
  738. duck = false;
  739. if (xyspeed)
  740. run = true;
  741. else
  742. run = false;
  743. // check for stand/duck and stop/go transitions
  744. if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH)
  745. goto newanim;
  746. if (run != client->anim_run && client->anim_priority == ANIM_BASIC)
  747. goto newanim;
  748. if (!ent->groundentity && client->anim_priority <= ANIM_WAVE)
  749. goto newanim;
  750. if(client->anim_priority == ANIM_REVERSE)
  751. {
  752. if(ent->s.frame > client->anim_end)
  753. {
  754. ent->s.frame--;
  755. return;
  756. }
  757. }
  758. else if (ent->s.frame < client->anim_end)
  759. { // continue an animation
  760. ent->s.frame++;
  761. return;
  762. }
  763. if (client->anim_priority == ANIM_DEATH)
  764. return; // stay there
  765. if (client->anim_priority == ANIM_JUMP)
  766. {
  767. if (!ent->groundentity)
  768. return; // stay there
  769. ent->client->anim_priority = ANIM_WAVE;
  770. ent->s.frame = FRAME_jump3;
  771. ent->client->anim_end = FRAME_jump6;
  772. return;
  773. }
  774. newanim:
  775. // return to either a running or standing frame
  776. client->anim_priority = ANIM_BASIC;
  777. client->anim_duck = duck;
  778. client->anim_run = run;
  779. if (!ent->groundentity)
  780. {
  781. //ZOID: if on grapple, don't go into jump frame, go into standing
  782. //frame
  783. if (client->ctf_grapple) {
  784. ent->s.frame = FRAME_stand01;
  785. client->anim_end = FRAME_stand40;
  786. } else {
  787. //ZOID
  788. client->anim_priority = ANIM_JUMP;
  789. if (ent->s.frame != FRAME_jump2)
  790. ent->s.frame = FRAME_jump1;
  791. client->anim_end = FRAME_jump2;
  792. }
  793. }
  794. else if (run)
  795. { // running
  796. if (duck)
  797. {
  798. ent->s.frame = FRAME_crwalk1;
  799. client->anim_end = FRAME_crwalk6;
  800. }
  801. else
  802. {
  803. ent->s.frame = FRAME_run1;
  804. client->anim_end = FRAME_run6;
  805. }
  806. }
  807. else
  808. { // standing
  809. if (duck)
  810. {
  811. ent->s.frame = FRAME_crstnd01;
  812. client->anim_end = FRAME_crstnd19;
  813. }
  814. else
  815. {
  816. ent->s.frame = FRAME_stand01;
  817. client->anim_end = FRAME_stand40;
  818. }
  819. }
  820. }
  821. /*
  822. =================
  823. ClientEndServerFrame
  824. Called for each player at the end of the server frame
  825. and right after spawning
  826. =================
  827. */
  828. void ClientEndServerFrame (edict_t *ent)
  829. {
  830. float bobtime;
  831. int i;
  832. current_player = ent;
  833. current_client = ent->client;
  834. //
  835. // If the origin or velocity have changed since ClientThink(),
  836. // update the pmove values. This will happen when the client
  837. // is pushed by a bmodel or kicked by an explosion.
  838. //
  839. // If it wasn't updated here, the view position would lag a frame
  840. // behind the body position when pushed -- "sinking into plats"
  841. //
  842. for (i=0 ; i<3 ; i++)
  843. {
  844. current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0;
  845. current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0;
  846. }
  847. //
  848. // If the end of unit layout is displayed, don't give
  849. // the player any normal movement attributes
  850. //
  851. if (level.intermissiontime)
  852. {
  853. // FIXME: add view drifting here?
  854. current_client->ps.blend[3] = 0;
  855. current_client->ps.fov = 90;
  856. G_SetStats (ent);
  857. return;
  858. }
  859. AngleVectors (ent->client->v_angle, forward, right, up);
  860. // burn from lava, etc
  861. P_WorldEffects ();
  862. //
  863. // set model angles from view angles so other things in
  864. // the world can tell which direction you are looking
  865. //
  866. if (ent->client->v_angle[PITCH] > 180)
  867. ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3;
  868. else
  869. ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3;
  870. ent->s.angles[YAW] = ent->client->v_angle[YAW];
  871. ent->s.angles[ROLL] = 0;
  872. ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4;
  873. //
  874. // calculate speed and cycle to be used for
  875. // all cyclic walking effects
  876. //
  877. xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]);
  878. if (xyspeed < 5)
  879. {
  880. bobmove = 0;
  881. current_client->bobtime = 0; // start at beginning of cycle again
  882. }
  883. else if (ent->groundentity)
  884. { // so bobbing only cycles when on ground
  885. if (xyspeed > 210)
  886. bobmove = 0.25;
  887. else if (xyspeed > 100)
  888. bobmove = 0.125;
  889. else
  890. bobmove = 0.0625;
  891. }
  892. bobtime = (current_client->bobtime += bobmove);
  893. if (current_client->ps.pmove.pm_flags & PMF_DUCKED)
  894. bobtime *= 4;
  895. bobcycle = (int)bobtime;
  896. bobfracsin = fabs(sin(bobtime*M_PI));
  897. // detect hitting the floor
  898. P_FallingDamage (ent);
  899. // apply all the damage taken this frame
  900. P_DamageFeedback (ent);
  901. // determine the view offsets
  902. SV_CalcViewOffset (ent);
  903. // determine the gun offsets
  904. SV_CalcGunOffset (ent);
  905. // determine the full screen color blend
  906. // must be after viewoffset, so eye contents can be
  907. // accurately determined
  908. // FIXME: with client prediction, the contents
  909. // should be determined by the client
  910. SV_CalcBlend (ent);
  911. //ZOID
  912. if (!ent->client->chase_target)
  913. //ZOID
  914. G_SetStats (ent);
  915. //ZOID
  916. //update chasecam follower stats
  917. for (i = 1; i <= maxclients->value; i++) {
  918. edict_t *e = g_edicts + i;
  919. if (!e->inuse || e->client->chase_target != ent)
  920. continue;
  921. memcpy(e->client->ps.stats,
  922. ent->client->ps.stats,
  923. sizeof(ent->client->ps.stats));
  924. e->client->ps.stats[STAT_LAYOUTS] = 1;
  925. break;
  926. }
  927. //ZOID
  928. G_SetClientEvent (ent);
  929. G_SetClientEffects (ent);
  930. G_SetClientSound (ent);
  931. G_SetClientFrame (ent);
  932. VectorCopy (ent->velocity, ent->client->oldvelocity);
  933. VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles);
  934. // clear weapon kicks
  935. VectorClear (ent->client->kick_origin);
  936. VectorClear (ent->client->kick_angles);
  937. // if the scoreboard is up, update it
  938. if (ent->client->showscores && !(level.framenum & 31) )
  939. {
  940. //ZOID
  941. if (ent->client->menu) {
  942. PMenu_Do_Update(ent);
  943. ent->client->menudirty = false;
  944. ent->client->menutime = level.time;
  945. } else
  946. //ZOID
  947. DeathmatchScoreboardMessage (ent, ent->enemy);
  948. gi.unicast (ent, false);
  949. }
  950. }