p_view.c 26 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088
  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; // always 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 always 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. // never take falling damage if completely underwater
  425. if (ent->waterlevel == 3)
  426. return;
  427. if (ent->waterlevel == 2)
  428. delta *= 0.25;
  429. if (ent->waterlevel == 1)
  430. delta *= 0.5;
  431. if (delta < 1)
  432. return;
  433. if (delta < 15)
  434. {
  435. ent->s.event = EV_FOOTSTEP;
  436. return;
  437. }
  438. ent->client->fall_value = delta*0.5;
  439. if (ent->client->fall_value > 40)
  440. ent->client->fall_value = 40;
  441. ent->client->fall_time = level.time + FALL_TIME;
  442. if (delta > 30)
  443. {
  444. if (ent->health > 0)
  445. {
  446. if (delta >= 55)
  447. ent->s.event = EV_FALLFAR;
  448. else
  449. ent->s.event = EV_FALL;
  450. }
  451. ent->pain_debounce_time = level.time; // no normal pain sound
  452. damage = (delta-30)/2;
  453. if (damage < 1)
  454. damage = 1;
  455. VectorSet (dir, 0, 0, 1);
  456. if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) )
  457. T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
  458. }
  459. else
  460. {
  461. ent->s.event = EV_FALLSHORT;
  462. return;
  463. }
  464. }
  465. /*
  466. =============
  467. P_WorldEffects
  468. =============
  469. */
  470. void P_WorldEffects (void)
  471. {
  472. qboolean breather;
  473. qboolean envirosuit;
  474. int waterlevel, old_waterlevel;
  475. if (current_player->movetype == MOVETYPE_NOCLIP)
  476. {
  477. current_player->air_finished = level.time + 12; // don't need air
  478. return;
  479. }
  480. waterlevel = current_player->waterlevel;
  481. old_waterlevel = current_client->old_waterlevel;
  482. current_client->old_waterlevel = waterlevel;
  483. breather = current_client->breather_framenum > level.framenum;
  484. envirosuit = current_client->enviro_framenum > level.framenum;
  485. //
  486. // if just entered a water volume, play a sound
  487. //
  488. if (!old_waterlevel && waterlevel)
  489. {
  490. PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  491. if (current_player->watertype & CONTENTS_LAVA)
  492. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
  493. else if (current_player->watertype & CONTENTS_SLIME)
  494. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  495. else if (current_player->watertype & CONTENTS_WATER)
  496. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
  497. current_player->flags |= FL_INWATER;
  498. // clear damage_debounce, so the pain sound will play immediately
  499. current_player->damage_debounce_time = level.time - 1;
  500. }
  501. //
  502. // if just completely exited a water volume, play a sound
  503. //
  504. if (old_waterlevel && ! waterlevel)
  505. {
  506. PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  507. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
  508. current_player->flags &= ~FL_INWATER;
  509. }
  510. //
  511. // check for head just going under water
  512. //
  513. if (old_waterlevel != 3 && waterlevel == 3)
  514. {
  515. gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
  516. }
  517. //
  518. // check for head just coming out of water
  519. //
  520. if (old_waterlevel == 3 && waterlevel != 3)
  521. {
  522. if (current_player->air_finished < level.time)
  523. { // gasp for air
  524. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
  525. PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  526. }
  527. else if (current_player->air_finished < level.time + 11)
  528. { // just break surface
  529. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
  530. }
  531. }
  532. //
  533. // check for drowning
  534. //
  535. if (waterlevel == 3)
  536. {
  537. // breather or envirosuit give air
  538. if (breather || envirosuit)
  539. {
  540. current_player->air_finished = level.time + 10;
  541. if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0)
  542. {
  543. if (!current_client->breather_sound)
  544. gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
  545. else
  546. gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
  547. current_client->breather_sound ^= 1;
  548. PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
  549. //FIXME: release a bubble?
  550. }
  551. }
  552. // if out of air, start drowning
  553. if (current_player->air_finished < level.time)
  554. { // drown!
  555. if (current_player->client->next_drown_time < level.time
  556. && current_player->health > 0)
  557. {
  558. current_player->client->next_drown_time = level.time + 1;
  559. // take more damage the longer underwater
  560. current_player->dmg += 2;
  561. if (current_player->dmg > 15)
  562. current_player->dmg = 15;
  563. // play a gurp sound instead of a normal pain sound
  564. if (current_player->health <= current_player->dmg)
  565. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
  566. else if (rand()&1)
  567. gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
  568. else
  569. gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
  570. current_player->pain_debounce_time = level.time;
  571. T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
  572. }
  573. }
  574. }
  575. else
  576. {
  577. current_player->air_finished = level.time + 12;
  578. current_player->dmg = 2;
  579. }
  580. //
  581. // check for sizzle damage
  582. //
  583. if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
  584. {
  585. if (current_player->watertype & CONTENTS_LAVA)
  586. {
  587. if (current_player->health > 0
  588. && current_player->pain_debounce_time <= level.time
  589. && current_client->invincible_framenum < level.framenum)
  590. {
  591. if (rand()&1)
  592. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
  593. else
  594. gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
  595. current_player->pain_debounce_time = level.time + 1;
  596. }
  597. if (envirosuit) // take 1/3 damage with envirosuit
  598. T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA);
  599. else
  600. T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA);
  601. }
  602. if (current_player->watertype & CONTENTS_SLIME)
  603. {
  604. if (!envirosuit)
  605. { // no damage from slime with envirosuit
  606. T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME);
  607. }
  608. }
  609. }
  610. }
  611. /*
  612. ===============
  613. G_SetClientEffects
  614. ===============
  615. */
  616. void G_SetClientEffects (edict_t *ent)
  617. {
  618. int pa_type;
  619. int remaining;
  620. ent->s.effects = 0;
  621. ent->s.renderfx = 0;
  622. if (ent->health <= 0 || level.intermissiontime)
  623. return;
  624. if (ent->powerarmor_time > level.time)
  625. {
  626. pa_type = PowerArmorType (ent);
  627. if (pa_type == POWER_ARMOR_SCREEN)
  628. {
  629. ent->s.effects |= EF_POWERSCREEN;
  630. }
  631. else if (pa_type == POWER_ARMOR_SHIELD)
  632. {
  633. ent->s.effects |= EF_COLOR_SHELL;
  634. ent->s.renderfx |= RF_SHELL_GREEN;
  635. }
  636. }
  637. if (ent->client->quad_framenum > level.framenum)
  638. {
  639. remaining = ent->client->quad_framenum - level.framenum;
  640. if (remaining > 30 || (remaining & 4) )
  641. ent->s.effects |= EF_QUAD;
  642. }
  643. if (ent->client->invincible_framenum > level.framenum)
  644. {
  645. remaining = ent->client->invincible_framenum - level.framenum;
  646. if (remaining > 30 || (remaining & 4) )
  647. ent->s.effects |= EF_PENT;
  648. }
  649. // show cheaters!!!
  650. if (ent->flags & FL_GODMODE)
  651. {
  652. ent->s.effects |= EF_COLOR_SHELL;
  653. ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
  654. }
  655. }
  656. /*
  657. ===============
  658. G_SetClientEvent
  659. ===============
  660. */
  661. void G_SetClientEvent (edict_t *ent)
  662. {
  663. if (ent->s.event)
  664. return;
  665. if ( ent->groundentity && xyspeed > 225)
  666. {
  667. if ( (int)(current_client->bobtime+bobmove) != bobcycle )
  668. ent->s.event = EV_FOOTSTEP;
  669. }
  670. }
  671. /*
  672. ===============
  673. G_SetClientSound
  674. ===============
  675. */
  676. void G_SetClientSound (edict_t *ent)
  677. {
  678. char *weap;
  679. if (ent->client->pers.game_helpchanged != game.helpchanged)
  680. {
  681. ent->client->pers.game_helpchanged = game.helpchanged;
  682. ent->client->pers.helpchanged = 1;
  683. }
  684. // help beep (no more than three times)
  685. if (ent->client->pers.helpchanged && ent->client->pers.helpchanged <= 3 && !(level.framenum&63) )
  686. {
  687. ent->client->pers.helpchanged++;
  688. gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0);
  689. }
  690. if (ent->client->pers.weapon)
  691. weap = ent->client->pers.weapon->classname;
  692. else
  693. weap = "";
  694. if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
  695. ent->s.sound = snd_fry;
  696. else if (strcmp(weap, "weapon_railgun") == 0)
  697. ent->s.sound = gi.soundindex("weapons/rg_hum.wav");
  698. else if (strcmp(weap, "weapon_bfg") == 0)
  699. ent->s.sound = gi.soundindex("weapons/bfg_hum.wav");
  700. else if (ent->client->weapon_sound)
  701. ent->s.sound = ent->client->weapon_sound;
  702. else
  703. ent->s.sound = 0;
  704. }
  705. /*
  706. ===============
  707. G_SetClientFrame
  708. ===============
  709. */
  710. void G_SetClientFrame (edict_t *ent)
  711. {
  712. gclient_t *client;
  713. qboolean duck, run;
  714. if (ent->s.modelindex != 255)
  715. return; // not in the player model
  716. client = ent->client;
  717. if (client->ps.pmove.pm_flags & PMF_DUCKED)
  718. duck = true;
  719. else
  720. duck = false;
  721. if (xyspeed)
  722. run = true;
  723. else
  724. run = false;
  725. // check for stand/duck and stop/go transitions
  726. if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH)
  727. goto newanim;
  728. if (run != client->anim_run && client->anim_priority == ANIM_BASIC)
  729. goto newanim;
  730. if (!ent->groundentity && client->anim_priority <= ANIM_WAVE)
  731. goto newanim;
  732. if(client->anim_priority == ANIM_REVERSE)
  733. {
  734. if(ent->s.frame > client->anim_end)
  735. {
  736. ent->s.frame--;
  737. return;
  738. }
  739. }
  740. else if (ent->s.frame < client->anim_end)
  741. { // continue an animation
  742. ent->s.frame++;
  743. return;
  744. }
  745. if (client->anim_priority == ANIM_DEATH)
  746. return; // stay there
  747. if (client->anim_priority == ANIM_JUMP)
  748. {
  749. if (!ent->groundentity)
  750. return; // stay there
  751. ent->client->anim_priority = ANIM_WAVE;
  752. ent->s.frame = FRAME_jump3;
  753. ent->client->anim_end = FRAME_jump6;
  754. return;
  755. }
  756. newanim:
  757. // return to either a running or standing frame
  758. client->anim_priority = ANIM_BASIC;
  759. client->anim_duck = duck;
  760. client->anim_run = run;
  761. if (!ent->groundentity)
  762. {
  763. client->anim_priority = ANIM_JUMP;
  764. if (ent->s.frame != FRAME_jump2)
  765. ent->s.frame = FRAME_jump1;
  766. client->anim_end = FRAME_jump2;
  767. }
  768. else if (run)
  769. { // running
  770. if (duck)
  771. {
  772. ent->s.frame = FRAME_crwalk1;
  773. client->anim_end = FRAME_crwalk6;
  774. }
  775. else
  776. {
  777. ent->s.frame = FRAME_run1;
  778. client->anim_end = FRAME_run6;
  779. }
  780. }
  781. else
  782. { // standing
  783. if (duck)
  784. {
  785. ent->s.frame = FRAME_crstnd01;
  786. client->anim_end = FRAME_crstnd19;
  787. }
  788. else
  789. {
  790. ent->s.frame = FRAME_stand01;
  791. client->anim_end = FRAME_stand40;
  792. }
  793. }
  794. }
  795. /*
  796. =================
  797. ClientEndServerFrame
  798. Called for each player at the end of the server frame
  799. and right after spawning
  800. =================
  801. */
  802. void ClientEndServerFrame (edict_t *ent)
  803. {
  804. float bobtime;
  805. int i;
  806. current_player = ent;
  807. current_client = ent->client;
  808. //
  809. // If the origin or velocity have changed since ClientThink(),
  810. // update the pmove values. This will happen when the client
  811. // is pushed by a bmodel or kicked by an explosion.
  812. //
  813. // If it wasn't updated here, the view position would lag a frame
  814. // behind the body position when pushed -- "sinking into plats"
  815. //
  816. for (i=0 ; i<3 ; i++)
  817. {
  818. current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0;
  819. current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0;
  820. }
  821. //
  822. // If the end of unit layout is displayed, don't give
  823. // the player any normal movement attributes
  824. //
  825. if (level.intermissiontime)
  826. {
  827. // FIXME: add view drifting here?
  828. current_client->ps.blend[3] = 0;
  829. current_client->ps.fov = 90;
  830. G_SetStats (ent);
  831. return;
  832. }
  833. AngleVectors (ent->client->v_angle, forward, right, up);
  834. // burn from lava, etc
  835. P_WorldEffects ();
  836. //
  837. // set model angles from view angles so other things in
  838. // the world can tell which direction you are looking
  839. //
  840. if (ent->client->v_angle[PITCH] > 180)
  841. ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3;
  842. else
  843. ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3;
  844. ent->s.angles[YAW] = ent->client->v_angle[YAW];
  845. ent->s.angles[ROLL] = 0;
  846. ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4;
  847. //
  848. // calculate speed and cycle to be used for
  849. // all cyclic walking effects
  850. //
  851. xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]);
  852. if (xyspeed < 5)
  853. {
  854. bobmove = 0;
  855. current_client->bobtime = 0; // start at beginning of cycle again
  856. }
  857. else if (ent->groundentity)
  858. { // so bobbing only cycles when on ground
  859. if (xyspeed > 210)
  860. bobmove = 0.25;
  861. else if (xyspeed > 100)
  862. bobmove = 0.125;
  863. else
  864. bobmove = 0.0625;
  865. }
  866. bobtime = (current_client->bobtime += bobmove);
  867. if (current_client->ps.pmove.pm_flags & PMF_DUCKED)
  868. bobtime *= 4;
  869. bobcycle = (int)bobtime;
  870. bobfracsin = fabs(sin(bobtime*M_PI));
  871. // detect hitting the floor
  872. P_FallingDamage (ent);
  873. // apply all the damage taken this frame
  874. P_DamageFeedback (ent);
  875. // determine the view offsets
  876. SV_CalcViewOffset (ent);
  877. // determine the gun offsets
  878. SV_CalcGunOffset (ent);
  879. // determine the full screen color blend
  880. // must be after viewoffset, so eye contents can be
  881. // accurately determined
  882. // FIXME: with client prediction, the contents
  883. // should be determined by the client
  884. SV_CalcBlend (ent);
  885. // chase cam stuff
  886. if (ent->client->resp.spectator)
  887. G_SetSpectatorStats(ent);
  888. else
  889. G_SetStats (ent);
  890. G_CheckChaseStats(ent);
  891. G_SetClientEvent (ent);
  892. G_SetClientEffects (ent);
  893. G_SetClientSound (ent);
  894. G_SetClientFrame (ent);
  895. VectorCopy (ent->velocity, ent->client->oldvelocity);
  896. VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles);
  897. // clear weapon kicks
  898. VectorClear (ent->client->kick_origin);
  899. VectorClear (ent->client->kick_angles);
  900. // if the scoreboard is up, update it
  901. if (ent->client->showscores && !(level.framenum & 31) )
  902. {
  903. DeathmatchScoreboardMessage (ent, ent->enemy);
  904. gi.unicast (ent, false);
  905. }
  906. }