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