1 
2 #include "g_local.h"
3 #include "m_player.h"
4 
5 
6 
7 static	edict_t		*current_player;
8 static	gclient_t	*current_client;
9 
10 static	vec3_t	forward, right, up;
11 float	xyspeed;
12 
13 float	bobmove;
14 int		bobcycle;		// odd cycles are right foot going forward
15 float	bobfracsin;		// sin(bobfrac*M_PI)
16 
17 /*
18 ===============
19 SV_CalcRoll
20 
21 ===============
22 */
SV_CalcRoll(vec3_t angles,vec3_t velocity)23 float SV_CalcRoll (vec3_t angles, vec3_t velocity)
24 {
25 	float	sign;
26 	float	side;
27 	float	value;
28 
29 	side = DotProduct (velocity, right);
30 	sign = side < 0 ? -1 : 1;
31 	side = fabs(side);
32 
33 	value = sv_rollangle->value;
34 
35 	if (side < sv_rollspeed->value)
36 		side = side * value / sv_rollspeed->value;
37 	else
38 		side = value;
39 
40 	return side*sign;
41 
42 }
43 
44 
45 /*
46 ===============
47 P_DamageFeedback
48 
49 Handles color blends and view kicks
50 ===============
51 */
P_DamageFeedback(edict_t * player)52 void P_DamageFeedback (edict_t *player)
53 {
54 	gclient_t	*client;
55 	float	side;
56 	float	realcount, count, kick;
57 	vec3_t	v;
58 	int		r, l;
59 	static	vec3_t	power_color = {0.0, 1.0, 0.0};
60 	static	vec3_t	acolor = {1.0, 1.0, 1.0};
61 	static	vec3_t	bcolor = {1.0, 0.0, 0.0};
62 
63 	client = player->client;
64 
65 	// flash the backgrounds behind the status numbers
66 	client->ps.stats[STAT_FLASHES] = 0;
67 	if (client->damage_blood)
68 		client->ps.stats[STAT_FLASHES] |= 1;
69 	if (client->damage_armor && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
70 		client->ps.stats[STAT_FLASHES] |= 2;
71 
72 	// total points of damage shot at the player this frame
73 	count = (client->damage_blood + client->damage_armor + client->damage_parmor);
74 	if (count == 0)
75 		return;		// didn't take any damage
76 
77 	// start a pain animation if still in the player model
78 	if (client->anim_priority < ANIM_PAIN && player->s.modelindex == 255)
79 	{
80 		static int		i;
81 
82 		client->anim_priority = ANIM_PAIN;
83 		if (client->ps.pmove.pm_flags & PMF_DUCKED)
84 		{
85 			player->s.frame = FRAME_crpain1-1;
86 			client->anim_end = FRAME_crpain4;
87 		}
88 		else
89 		{
90 			i = (i+1)%3;
91 			switch (i)
92 			{
93 			case 0:
94 				player->s.frame = FRAME_pain101-1;
95 				client->anim_end = FRAME_pain104;
96 				break;
97 			case 1:
98 				player->s.frame = FRAME_pain201-1;
99 				client->anim_end = FRAME_pain204;
100 				break;
101 			case 2:
102 				player->s.frame = FRAME_pain301-1;
103 				client->anim_end = FRAME_pain304;
104 				break;
105 			}
106 		}
107 	}
108 
109 	realcount = count;
110 	if (count < 10)
111 		count = 10;	// always make a visible effect
112 
113 	// play an apropriate pain sound
114 	if ((level.time > player->pain_debounce_time) && !(player->flags & FL_GODMODE) && (client->invincible_framenum <= level.framenum))
115 	{
116 		r = 1 + (rand()&1);
117 		player->pain_debounce_time = level.time + 0.7;
118 		if (player->health < 25)
119 			l = 25;
120 		else if (player->health < 50)
121 			l = 50;
122 		else if (player->health < 75)
123 			l = 75;
124 		else
125 			l = 100;
126 
127 		gi.sound (player, CHAN_VOICE, gi.soundindex(va("*pain%i_%i.wav", l, r)), 1, ATTN_NORM, 0);
128 	}
129 
130 	// the total alpha of the blend is always proportional to count
131 	if (client->damage_alpha < 0)
132 		client->damage_alpha = 0;
133 	client->damage_alpha += count*0.01;
134 	if (client->damage_alpha < 0.2)
135 		client->damage_alpha = 0.2;
136 	if (client->damage_alpha > 0.6)
137 		client->damage_alpha = 0.6;		// don't go too saturated
138 
139 	// the color of the blend will vary based on how much was absorbed
140 	// by different armors
141 	VectorClear (v);
142 	if (client->damage_parmor)
143 		VectorMA (v, (float)client->damage_parmor/realcount, power_color, v);
144 	if (client->damage_armor)
145 		VectorMA (v, (float)client->damage_armor/realcount,  acolor, v);
146 	if (client->damage_blood)
147 		VectorMA (v, (float)client->damage_blood/realcount,  bcolor, v);
148 	VectorCopy (v, client->damage_blend);
149 
150 
151 	//
152 	// calculate view angle kicks
153 	//
154 	kick = abs(client->damage_knockback);
155 	if (kick && player->health > 0)	// kick of 0 means no view adjust at all
156 	{
157 		kick = kick * 100 / player->health;
158 
159 		if (kick < count*0.5)
160 			kick = count*0.5;
161 		if (kick > 50)
162 			kick = 50;
163 
164 		VectorSubtract (client->damage_from, player->s.origin, v);
165 		VectorNormalize (v);
166 
167 		side = DotProduct (v, right);
168 		client->v_dmg_roll = kick*side*0.3;
169 
170 		side = -DotProduct (v, forward);
171 		client->v_dmg_pitch = kick*side*0.3;
172 
173 		client->v_dmg_time = level.time + DAMAGE_TIME;
174 	}
175 
176 	//
177 	// clear totals
178 	//
179 	client->damage_blood = 0;
180 	client->damage_armor = 0;
181 	client->damage_parmor = 0;
182 	client->damage_knockback = 0;
183 }
184 
185 
186 
187 
188 /*
189 ===============
190 SV_CalcViewOffset
191 
192 Auto pitching on slopes?
193 
194   fall from 128: 400 = 160000
195   fall from 256: 580 = 336400
196   fall from 384: 720 = 518400
197   fall from 512: 800 = 640000
198   fall from 640: 960 =
199 
200   damage = deltavelocity*deltavelocity  * 0.0001
201 
202 ===============
203 */
SV_CalcViewOffset(edict_t * ent)204 void SV_CalcViewOffset (edict_t *ent)
205 {
206 	float		*angles;
207 	float		bob, temp;
208 	float		ratio;
209 	float		delta;
210 	vec3_t		v;
211 	qboolean water =  (ent->waterlevel>1||sv_waterlevel->value);
212 
213 //===================================
214 
215 	// base angles
216 	angles = ent->client->ps.kick_angles;
217 
218 	// if dead, fix the angle and don't add any kick
219 
220 	if (ent->deadflag&&!ent->killer)
221 	{
222 		VectorClear (angles);
223 
224 		ent->client->ps.viewangles[ROLL] = 40;
225 		ent->client->ps.viewangles[PITCH] = -15;
226 		ent->client->ps.viewangles[YAW] = ent->client->killer_yaw;
227 
228 	}
229 	else if (!ent->deadflag||ent->killer)
230 	{
231 		// add angles based on weapon kick
232 
233 		VectorCopy (ent->client->kick_angles, angles);
234 
235 		// add angles based on damage kick
236 
237 		ratio = (ent->client->v_dmg_time - level.time) / DAMAGE_TIME;
238 		if (ratio < 0)
239 		{
240 			ratio = 0;
241 			ent->client->v_dmg_pitch = 0;
242 			ent->client->v_dmg_roll = 0;
243 		}
244 		angles[PITCH] += ratio * ent->client->v_dmg_pitch;
245 		angles[ROLL] += ratio * ent->client->v_dmg_roll;
246 
247 		// add pitch based on fall kick
248 
249 		ratio = (ent->client->fall_time - level.time) / FALL_TIME;
250 		if (ratio < 0)
251 			ratio = 0;
252 		angles[PITCH] += ratio * ent->client->fall_value;
253 
254 		// add angles based on velocity
255 
256 		delta = DotProduct (ent->velocity, forward);
257 		angles[PITCH] += delta*run_pitch->value;
258 
259 		delta = DotProduct (ent->velocity, right);
260 		angles[ROLL] += delta*run_roll->value;
261 
262 		// add angles based on bob
263 
264 		delta = bobfracsin * bob_pitch->value * xyspeed;
265 		if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
266 			delta *= 6;		// crouching
267 		angles[PITCH] += delta;
268 		delta = bobfracsin * bob_roll->value * xyspeed;
269 		if (ent->client->ps.pmove.pm_flags & PMF_DUCKED)
270 			delta *= 6;		// crouching
271 		if (bobcycle & 1)
272 			delta = -delta;
273 		angles[ROLL] += delta;
274 	}
275 //===================================
276 
277 	// base origin
278 
279 	VectorClear (v);
280 
281 	// add view height
282 
283 	v[2] += ent->viewheight;
284 
285 	// add fall height
286 
287 	ratio = (ent->client->fall_time - level.time) / FALL_TIME;
288 	if (ratio < 0)
289 		ratio = 0;
290 	v[2] -= ratio * ent->client->fall_value * 0.4;
291 
292 	// add bob height
293 
294 	bob = bobfracsin * xyspeed * bob_up->value;
295 	if (bob > 6)
296 		bob = 6;
297 	//gi.DebugGraph (bob *2, 255);
298 	v[2] += bob;
299 
300 	// add kick offset
301 
302 	VectorAdd (v, ent->client->kick_origin, v);
303 
304 	// absolutely bound offsets
305 	// so the view can never be outside the player box
306 
307         if (!ent->client->chasetoggle)
308         {
309 			if (v[0] < -14)
310 				v[0] = -14;
311 			else if (v[0] > 14)
312 				v[0] = 14;
313 			if (v[1] < -14)
314 				v[1] = -14;
315 			else if (v[1] > 14)
316 				v[1] = 14;
317 			if (v[2] < -22)
318 				v[2] = -22;
319 			else if (v[2] > 30 && !water)
320 				v[2] = 30;
321         }
322         else
323         {
324            VectorSet (v, 0, 0, 0);
325            if (ent->client->chasecam != NULL)
326            {
327 	           ent->client->ps.pmove.origin[0] = ent->client->chasecam->s.origin[0]*8;
328                ent->client->ps.pmove.origin[1] = ent->client->chasecam->s.origin[1]*8;
329                ent->client->ps.pmove.origin[2] = ent->client->chasecam->s.origin[2]*8;
330             }
331         }
332 
333 	VectorCopy (v, ent->client->ps.viewoffset);
334 }
335 
336 /*
337 ==============
338 SV_CalcGunOffset
339 ==============
340 */
SV_CalcGunOffset(edict_t * ent)341 void SV_CalcGunOffset (edict_t *ent)
342 {
343 	int		i;
344 	float	delta;
345 
346 	// gun angles from bobbing
347 	ent->client->ps.gunangles[ROLL] = xyspeed * bobfracsin * 0.005;
348 	ent->client->ps.gunangles[YAW] = xyspeed * bobfracsin * 0.01;
349 	if (bobcycle & 1)
350 	{
351 		ent->client->ps.gunangles[ROLL] = -ent->client->ps.gunangles[ROLL];
352 		ent->client->ps.gunangles[YAW] = -ent->client->ps.gunangles[YAW];
353 	}
354 
355 	ent->client->ps.gunangles[PITCH] = xyspeed * bobfracsin * 0.005;
356 
357 	// gun angles from delta movement
358 	for (i=0 ; i<3 ; i++)
359 	{
360 		delta = ent->client->oldviewangles[i] - ent->client->ps.viewangles[i];
361 		if (delta > 180)
362 			delta -= 360;
363 		if (delta < -180)
364 			delta += 360;
365 		if (delta > 45)
366 			delta = 45;
367 		if (delta < -45)
368 			delta = -45;
369 		if (i == YAW)
370 			ent->client->ps.gunangles[ROLL] += 0.1*delta;
371 		ent->client->ps.gunangles[i] += 0.2 * delta;
372 	}
373 
374 	// gun height
375 	VectorClear (ent->client->ps.gunoffset);
376 //	ent->ps->gunorigin[2] += bob;
377 
378 	// gun_x / gun_y / gun_z are development tools
379 	for (i=0 ; i<3 ; i++)
380 	{
381 		ent->client->ps.gunoffset[i] += forward[i]*(gun_y->value);
382 		ent->client->ps.gunoffset[i] += right[i]*gun_x->value;
383 		ent->client->ps.gunoffset[i] += up[i]* (-gun_z->value);
384 	}
385 }
386 
387 
388 /*
389 =============
390 SV_AddBlend
391 =============
392 */
SV_AddBlend(float r,float g,float b,float a,float * v_blend)393 void SV_AddBlend (float r, float g, float b, float a, float *v_blend)
394 {
395 	float	a2, a3;
396 
397 	if (a <= 0)
398 		return;
399 	a2 = v_blend[3] + (1-v_blend[3])*a;	// new total alpha
400 	a3 = v_blend[3]/a2;		// fraction of color from old
401 
402 	v_blend[0] = v_blend[0]*a3 + r*(1-a3);
403 	v_blend[1] = v_blend[1]*a3 + g*(1-a3);
404 	v_blend[2] = v_blend[2]*a3 + b*(1-a3);
405 	v_blend[3] = a2;
406 }
407 
408 
409 /*
410 =============
411 SV_CalcBlend
412 =============
413 */
SV_CalcBlend(edict_t * ent)414 void SV_CalcBlend (edict_t *ent)
415 {
416 	int		contents;
417 	vec3_t	vieworg;
418 	int		remaining;
419 	float		h_temp;
420 
421 	ent->client->ps.blend[0] = ent->client->ps.blend[1] =
422 		ent->client->ps.blend[2] = ent->client->ps.blend[3] = 0;
423 
424 	// add for contents
425 
426     if (ent->client->chasetoggle)
427 	    VectorCopy (ent->client->chasecam->s.origin, vieworg);
428     else
429         VectorAdd (ent->s.origin, ent->client->ps.viewoffset, vieworg);
430 
431 	contents = gi.pointcontents (vieworg);
432 
433 	if (ent->killer)
434 	{
435 		if (sv_waterlevel->value)
436 		{
437 			contents |= CONTENTS_WATER;
438 			SV_AddBlend (0.2, 0.2, 0.6, 0.3, ent->client->ps.blend);
439 		}
440 		return;
441 	}
442 
443 	//I put this here for the hell of it -psychospaz
444 	if (ent->client->laser_on && !ent->client->resp.spectator)
445 	{
446 		weapon_fire_laser (ent);
447 	}
448 	//this too - psychospaz
449 
450 	if (ent->client->flashlight_on && !ent->client->resp.spectator)
451 	{
452 		weapon_flashlight_fire (ent);
453 	}
454 
455 	if (ent->client->bfg_firing)	//this make bfg laser work!!!
456 	{
457 		weapon_fire_laser_bfg (ent);
458 		AddKick (ent, forward, 3);
459 		ent->client->bfg_firing--;
460 	}
461 
462 	if (sv_waterlevel->value)
463 	{
464 		if (ent->flashbanged)	//for FBed suckas
465 		{
466 			h_temp=(ent->flashbanged>50)?10:ent->flashbanged/50;
467 
468 			SV_AddBlend (1, 1, 1, h_temp, ent->client->ps.blend);
469 			ent->flashbanged--;
470 		}
471 
472 		contents |= CONTENTS_WATER;
473 		SV_AddBlend (0.2, 0.2, 0.6, 0.3, ent->client->ps.blend);
474 		return;
475 	}
476 	else
477 	{
478 
479 		if (contents & (CONTENTS_LAVA|CONTENTS_SLIME|CONTENTS_WATER) )
480 			ent->client->ps.rdflags |= RDF_UNDERWATER;
481 		else
482 			ent->client->ps.rdflags &= ~RDF_UNDERWATER;
483 
484 		if (contents & (CONTENTS_SOLID|CONTENTS_LAVA))
485 			SV_AddBlend (1.0, 0.4, 0.0, 0.85, ent->client->ps.blend); //SV_AddBlend (1.0, 0.3, 0.0, 0.6, ent->client->ps.blend);
486 		else if (contents & CONTENTS_SLIME)
487 			SV_AddBlend (0.0, 0.1, 0.05, 0.6, ent->client->ps.blend);
488 		else if (contents & CONTENTS_WATER)
489 		{
490 			if (ent->client->goggles)
491 				SV_AddBlend (0, 0, 0.5, 0.3, ent->client->ps.blend);
492 			else if (ent->client->aquasuit)
493 				SV_AddBlend (-0.5, -0.5, 0, 0.5, ent->client->ps.blend);
494 			else
495 				SV_AddBlend (0.1, 0.5, 0.7, 0.7, ent->client->ps.blend);
496 		}
497 		else
498 		{
499 			if (ent->client->goggles)
500 				SV_AddBlend (0.5, 0.3, 0.3, 0.3, ent->client->ps.blend);
501 			if (ent->client->aquasuit)
502 				SV_AddBlend (-0.5, -1.0, -1.0, 0.3, ent->client->ps.blend);
503 		}
504 	}
505 
506 	// add for powerups
507 	if (ent->client->quad_framenum > level.framenum)
508 	{
509 		remaining = ent->client->quad_framenum - level.framenum;
510 		if (remaining == 30)	// beginning to fade
511 			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/damage2.wav"), 1, ATTN_NORM, 0);
512 		if (remaining > 30 || (remaining & 4) )
513 			SV_AddBlend (0, 0, 1, 0.08, ent->client->ps.blend);
514 	}
515 	else if (ent->client->invincible_framenum > level.framenum)
516 	{
517 		remaining = ent->client->invincible_framenum - level.framenum;
518 		if (remaining == 30)	// beginning to fade
519 			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/protect2.wav"), 1, ATTN_NORM, 0);
520 		if (remaining > 30 || (remaining & 4) )
521 			SV_AddBlend (1, 0, 1, 0.1, ent->client->ps.blend); //SV_AddBlend (1, 1, 0, 0.08, ent->client->ps.blend);
522 	}
523 	else if (ent->client->enviro_framenum > level.framenum)
524 	{
525 		remaining = ent->client->enviro_framenum - level.framenum;
526 		if (remaining == 30)	// beginning to fade
527 			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
528 		if (remaining > 30 || (remaining & 4) )
529 			SV_AddBlend (0, 1, 0, 0.08, ent->client->ps.blend);
530 	}
531 	else if (ent->client->breather_framenum > level.framenum)
532 	{
533 		remaining = ent->client->breather_framenum - level.framenum;
534 		if (remaining == 30)	// beginning to fade
535 			gi.sound(ent, CHAN_ITEM, gi.soundindex("items/airout.wav"), 1, ATTN_NORM, 0);
536 		if (remaining > 30 || (remaining & 4) )
537 			SV_AddBlend (0.4, 0.4, 0.1, 0.04, ent->client->ps.blend);
538 	}
539 
540 	if (ent->client->aquasuit)//||ent->client->goggles)
541 		ent->client->ps.rdflags |= RDF_IRGOGGLES;
542 	else
543 		ent->client->ps.rdflags &= ~RDF_IRGOGGLES;
544 
545 	//very low health makes view bloody if not in lava
546 	//cause lava makes red purple :)
547 	if (!(contents & (CONTENTS_SOLID|CONTENTS_LAVA))&&!ent->client->aquasuit&&sv_bloodyview->value)
548 		if (ent->health < 75)
549 		{
550 			h_temp = ent->health;
551 			if (h_temp<0)
552 				h_temp = 0;
553 			h_temp = (1.75)*(0.5-(h_temp/100));
554 
555 			if (!ent->client->health_dir)
556 				ent->client->health_dir=1;
557 
558 			if (ent->client->health_view>5)
559 			{
560 				ent->client->health_view=5;
561 				ent->client->health_dir=-1;
562 			}
563 			else if (ent->client->health_view<0)
564 			{
565 				ent->client->health_view=0;
566 				ent->client->health_dir=1;
567 			}
568 
569 			ent->client->health_view += ent->client->health_dir;
570 			//ent->client->health_view *= 0.5;
571 
572 			SV_AddBlend (0.4+(ent->client->health_view*0.1), 0, 0, h_temp, ent->client->ps.blend);
573 			if (ent->health < 30)
574 				ent->client->ps.rdflags |= RDF_UNDERWATER;
575 		}
576 
577 	//oh don't forget this - psychospaz
578 	if (ent->linked_flame)
579 		SV_AddBlend (1.0, 0.4, 0.0, 0.65, ent->client->ps.blend);
580 
581 	if (ent->flashbanged)	//for FBed suckas
582 	{
583 		h_temp=(ent->flashbanged>50)?10:ent->flashbanged/50;
584 
585 		SV_AddBlend (1, 1, 1, h_temp, ent->client->ps.blend);
586 		ent->flashbanged--;
587 	}
588 
589 	// add for damage
590 	if (ent->client->damage_alpha > 0)
591 		SV_AddBlend (ent->client->damage_blend[0],ent->client->damage_blend[1]
592 		,ent->client->damage_blend[2], ent->client->damage_alpha, ent->client->ps.blend);
593 
594 	if (ent->client->bonus_alpha > 0)
595 		SV_AddBlend (0.85, 0.7, 0.3, ent->client->bonus_alpha, ent->client->ps.blend);
596 
597 	// drop the damage value
598 	ent->client->damage_alpha -= 0.06;
599 	if (ent->client->damage_alpha < 0)
600 		ent->client->damage_alpha = 0;
601 
602 	// drop the bonus value
603 	ent->client->bonus_alpha -= 0.1;
604 	if (ent->client->bonus_alpha < 0)
605 		ent->client->bonus_alpha = 0;
606 
607 //	SV_AddBlend (0, 1, 0, -0.5, ent->client->ps.blend);
608 }
609 
610 
611 /*
612 =================
613 P_FallingDamage
614 =================
615 */
P_FallingDamage(edict_t * ent)616 void P_FallingDamage (edict_t *ent)
617 {
618 	float	delta;
619 	int		deltamax;
620 	int		damage;
621 	vec3_t	dir;
622 
623 	if (sv_fall->value>0)
624 		deltamax= 20 * 1/sv_fall->value;
625 	else
626 		deltamax = 10000;
627 
628 	if ((ent->client->aquasuit)||(ent->client->grapple==2)||(ent->Move_up<0))
629 		deltamax *= 3/2;
630 
631 	if (ent->client->grapple || abs(ent->client->wallrunning) || ent->client->climbing)
632 		return;
633 
634 	if ((sv_waterlevel->value||(ent->client->goggles && ent->waterlevel>1)||(ent->client->jets)))
635 		return;
636 
637 	if (ent->movetype == MOVETYPE_NOCLIP)
638 		return;
639 
640 	if ((ent->client->oldvelocity[2] < 0) && (ent->velocity[2] > ent->client->oldvelocity[2]) && (!ent->groundentity))
641 	{
642 		delta = ent->client->oldvelocity[2];
643 	}
644 	else
645 	{
646 		if (!ent->groundentity)
647 			return;
648 		delta = ent->velocity[2] - ent->client->oldvelocity[2];
649 	}
650 	delta = delta*delta * 0.0001;
651 
652 	// never take falling damage if completely underwater
653 	if (ent->waterlevel == 3)
654 		return;
655 	if (ent->waterlevel == 2)
656 		delta *= 0.25;
657 	if (ent->waterlevel == 1)
658 		delta *= 0.5;
659 
660 	if (ent->client)
661 		if ((ent->client->aquasuit)||(ent->client->grapple == 2))
662 			delta *= 0.75;
663 
664 	if (delta < 1)
665 		return;
666 
667 	if (delta < deltamax)	//15)
668 	{
669 		ent->s.event = EV_FOOTSTEP;
670 		return;
671 	}
672 
673 	ent->client->fall_value = delta*0.5;
674 	if (ent->client->fall_value > 40)
675 		ent->client->fall_value = 40;
676 	ent->client->fall_time = level.time + FALL_TIME;
677 
678 	if (delta > deltamax) //20)	//(delta > 30)
679 	{
680 		if (ent->health > 0)
681 		{
682 			if (delta > deltamax*5)
683 				ent->s.event = EV_FALLFAR;
684 			else
685 				ent->s.event = EV_FALL;
686 		}
687 		ent->pain_debounce_time = level.time;	// no normal pain sound
688 		damage = (delta-30); //(delta-30)/2;
689 		if (damage < 1)
690 			damage = 1;
691 		VectorSet (dir, 0, 0, 1);
692 
693 
694 		if (ent->Move_up<0&&!ent->client->stunts)
695 			ent->client->stunts=-70;
696 
697 		damage*= sv_fall->value * 5;
698 
699 		if (!deathmatch->value || !((int)dmflags->value & DF_NO_FALLING) )
700 			T_Damage (ent, world, world, dir, ent->s.origin, vec3_origin, damage, 0, 0, MOD_FALLING);
701 	}
702 	else
703 	{
704 		ent->s.event = EV_FALLSHORT;
705 		return;
706 	}
707 }
708 
709 
710 
711 /*
712 =============
713 P_WorldEffects
714 =============
715 */
716 
bbl_think(edict_t * self)717 void bbl_think (edict_t *self)
718 {
719 	int i=0;
720 	edict_t	*findMark=NULL;
721 
722 	self->timer++;
723 
724 	if (self->timer>100)
725 		BulletMarkThink(self);
726 
727 	if ((!self->waterlevel&&!sv_waterlevel->value)&&self->s.frame==1)
728 	{
729 		self->movetype = MOVETYPE_NONE;
730 		self->s.origin[2]+= 4;
731 		self->s.frame--;
732 		self->s.effects = EF_SPHERETRANS;
733 		self->s.renderfx = 0;
734 
735 	//	self->s.effects = 0;
736 	//	self->s.renderfx = RF_TRANSLUCENT;
737 
738 	}
739 
740 	self->think = bbl_think;
741 	self->nextthink = level.time;
742 }
743 
SP_Bubble(edict_t * ent,vec3_t start)744 void SP_Bubble (edict_t *ent, vec3_t start)
745 {
746 	edict_t *bbl;
747 
748 	if ((int)sv_bulletmarks->value<=0)
749 		return;
750 
751 	if (sv_bulletmarks->value <= bulletmarks)
752 		BulletMarkThink(bulletptr[0]);
753 
754 	bbl = G_Spawn();
755 
756 	VectorCopy (start, bbl->s.origin);
757 	VectorCopy (start, bbl->s.old_origin);
758 
759 	if (sv_serversideonly->value)
760 		gi.setmodel (bbl, "sprites/s_bubble.sp2");
761 	else
762 		gi.setmodel (bbl, "sprites/s_bubble2.sp2");
763 
764 //	bbl->s.effects = EF_SPHERETRANS;
765 //	bbl->s.renderfx = 0;
766 
767 	bbl->s.effects = 0;
768 	bbl->s.renderfx = RF_TRANSLUCENT;
769 
770 	bbl->solid = SOLID_BBOX;
771 	bbl->svflags = SVF_DEADMONSTER;
772 	bbl->clipmask = MASK_SHOT;
773 	bbl->takedamage = DAMAGE_NO;
774 	bbl->floater = 1;
775 	bbl->movetype = MOVETYPE_FLYMISSILE;
776 	bbl->svflags |= SVF_MONSTER;
777 	bbl->velocity[1] = random() * 10 - 5;
778 	bbl->velocity[2] = 20 + random() * 10;
779 	bbl->velocity[3] = random() * 10 - 5;
780 	bbl->owner = ent;
781 	bbl->timer = 0;
782 	bbl->think = bbl_think; //G_FreeEdict;
783 	bbl->nextthink = level.time; // + 2;
784 	bbl->s.frame = 1;
785 	bbl->waterlevel = 1;
786 	gi.linkentity (bbl);
787 
788 	bulletptr[bulletmarks] = bbl;
789 	bulletmarks++;
790 }
791 
P_WorldEffects(void)792 void P_WorldEffects (void)
793 {
794 	vec3_t		bbl_pos;
795 	qboolean	breather;
796 	qboolean	envirosuit;
797 	qboolean	aquasuit;
798 	qboolean	goggles;
799 	int			waterlevel, old_waterlevel;
800 
801 	if (current_player->movetype == MOVETYPE_NOCLIP)
802 	{
803 		current_player->air_finished = level.time + 12;	// don't need air
804 		return;
805 	}
806 
807 	waterlevel = current_player->waterlevel;
808 	old_waterlevel = current_client->old_waterlevel;
809 	current_client->old_waterlevel = waterlevel;
810 
811 	breather   = current_client->breather_framenum > level.framenum;
812 	envirosuit = current_client->enviro_framenum > level.framenum;
813 	aquasuit   = current_client->aquasuit;
814 	goggles    = current_client->goggles;
815 	//
816 	// if just entered a water volume, play a sound
817 	//
818 	if (!old_waterlevel && waterlevel)
819 	{
820 		PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
821 		if (current_player->watertype & CONTENTS_LAVA)
822 			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/lava_in.wav"), 1, ATTN_NORM, 0);
823 		else if (current_player->watertype & CONTENTS_SLIME)
824 			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
825 		else if (current_player->watertype & CONTENTS_WATER)
826 			gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_in.wav"), 1, ATTN_NORM, 0);
827 		current_player->flags |= FL_INWATER;
828 
829 		// clear damage_debounce, so the pain sound will play immediately
830 		current_player->damage_debounce_time = level.time - 1;
831 	}
832 
833 	//
834 	// if just completely exited a water volume, play a sound
835 	//
836 	if (old_waterlevel && ! waterlevel)
837 	{
838 		PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
839 		gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_out.wav"), 1, ATTN_NORM, 0);
840 		current_player->flags &= ~FL_INWATER;
841 	}
842 
843 	//
844 	// check for head just going under water
845 	//
846 	if (old_waterlevel != 3 && waterlevel == 3)
847 	{
848 		gi.sound (current_player, CHAN_BODY, gi.soundindex("player/watr_un.wav"), 1, ATTN_NORM, 0);
849 	}
850 
851 	//
852 	// check for head just coming out of water
853 	//
854 	if (old_waterlevel == 3 && waterlevel != 3)
855 	{
856 		if (current_player->air_finished < level.time)
857 		{	// gasp for air
858 			gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp1.wav"), 1, ATTN_NORM, 0);
859 			PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
860 		}
861 		else  if (current_player->air_finished < level.time + 11)
862 		{	// just break surface
863 			gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/gasp2.wav"), 1, ATTN_NORM, 0);
864 		}
865 	}
866 
867 	//
868 	// check for drowning
869 	//
870 	if ((waterlevel == 3)||sv_waterlevel->value)
871 	{
872 		// breather or envirosuit give air
873 		if (breather || envirosuit || aquasuit ||goggles || sv_waterlevel->value)
874 		{
875 			current_player->air_finished = level.time + 10;
876 
877 			if (((int)(current_client->breather_framenum - level.framenum) % 25) == 0)
878 			{
879 				if (!current_client->breather_sound)
880 					gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath1.wav"), 1, ATTN_NORM, 0);
881 				else
882 					gi.sound (current_player, CHAN_AUTO, gi.soundindex("player/u_breath2.wav"), 1, ATTN_NORM, 0);
883 				current_client->breather_sound ^= 1;
884 				PlayerNoise(current_player, current_player->s.origin, PNOISE_SELF);
885 				//FIXME: release a bubble?
886 					VectorCopy (current_player->s.origin, bbl_pos);
887 					bbl_pos[2]+=current_player->viewheight;
888 					SP_Bubble (current_player, bbl_pos);
889 				//oo oo i can do this !!!!
890 			}
891 		}
892 
893 		// if out of air, start drowning
894 		if (current_player->air_finished < level.time)
895 		{	// drown!
896 			if (current_player->client->next_drown_time < level.time
897 				&& current_player->health > 0)
898 			{
899 				current_player->client->next_drown_time = level.time + 1;
900 
901 				// take more damage the longer underwater
902 				current_player->dmg += 2;
903 				if (current_player->dmg > 15)
904 					current_player->dmg = 15;
905 
906 				// play a gurp sound instead of a normal pain sound
907 				if (current_player->health <= current_player->dmg)
908 					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/drown1.wav"), 1, ATTN_NORM, 0);
909 				else if (rand()&1)
910 					gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp1.wav"), 1, ATTN_NORM, 0);
911 				else
912 					gi.sound (current_player, CHAN_VOICE, gi.soundindex("*gurp2.wav"), 1, ATTN_NORM, 0);
913 				//BUBBLE RELEASE FOR CHOKING
914 					//Set out bbl 1
915 					VectorCopy (current_player->s.origin, bbl_pos);
916 					bbl_pos[2]+=current_player->viewheight-5;
917 					SP_Bubble (current_player, bbl_pos);
918 					//Set out bbl 2
919 					VectorCopy (current_player->s.origin, bbl_pos);
920 					bbl_pos[2]+=current_player->viewheight;
921 					bbl_pos[0]+=10;
922 					SP_Bubble (current_player, bbl_pos);
923 					//Set out bbl 3
924 					VectorCopy (current_player->s.origin, bbl_pos);
925 					bbl_pos[2]+=current_player->viewheight-10;
926 					bbl_pos[1]+=10;
927 					SP_Bubble (current_player, bbl_pos);
928 				//BUBBLE RELEASE FINISHED
929 				current_player->pain_debounce_time = level.time;
930 
931 				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, current_player->dmg, 0, DAMAGE_NO_ARMOR, MOD_WATER);
932 			}
933 		}
934 	}
935 	else
936 	{
937 		current_player->air_finished = level.time + 12;
938 		current_player->dmg = 2;
939 	}
940 
941 	//
942 	// check for sizzle damage
943 	//
944 	if (waterlevel && (current_player->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
945 	{
946 		if (current_player->watertype & CONTENTS_LAVA)
947 		{
948 			if (current_player->health > 0
949 				&& current_player->pain_debounce_time <= level.time
950 				&& current_client->invincible_framenum < level.framenum)
951 			{
952 				if (rand()&1)
953 					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
954 				else
955 					gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
956 				current_player->pain_debounce_time = level.time + 1;
957 			}
958 
959 			if (envirosuit || aquasuit)	// take 1/3 damage with envirosuit
960 				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_LAVA);
961 			else
962 			{
963 				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 3*waterlevel, 0, 0, MOD_LAVA);
964 				if (current_player->health>0 && !current_player->linked_flame)
965 				{
966 					Linked_Flame (current_player, NULL);
967 				}
968 			}
969 		}
970 
971 		if (current_player->watertype & CONTENTS_SLIME)
972 		{
973 			if (!envirosuit && !aquasuit)
974 			{	// no damage from slime with envirosuit
975 				T_Damage (current_player, world, world, vec3_origin, current_player->s.origin, vec3_origin, 1*waterlevel, 0, 0, MOD_SLIME);
976 			}
977 		}
978 	}
979 	//
980 	// check for flame damage
981 	//
982 	else if (current_player->linked_flame)
983 	{
984 		if (current_player->health > 0
985 			&& current_player->pain_debounce_time <= level.time
986 			&& current_client->invincible_framenum < level.framenum)
987 		{
988 			if (rand()&1)
989 				gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn1.wav"), 1, ATTN_NORM, 0);
990 			else
991 				gi.sound (current_player, CHAN_VOICE, gi.soundindex("player/burn2.wav"), 1, ATTN_NORM, 0);
992 			current_player->pain_debounce_time = level.time + 1;
993 		}
994 
995 	}
996 }
997 
998 
999 /*
1000 ===============
1001 G_SetClientEffects
1002 ===============
1003 */
G_SetClientEffects(edict_t * ent)1004 void G_SetClientEffects (edict_t *ent)
1005 {
1006 	int		pa_type;
1007 	int		remaining;
1008 
1009 	ent->s.effects = 0;
1010 	ent->s.renderfx = 0;
1011 
1012 	if (ent->health<=0)
1013 	{
1014 		ent->s.renderfx = RF_BEAM;
1015 		return;
1016 	}
1017 
1018 
1019 	if (ent->health <= 0 || level.intermissiontime)
1020 		return;
1021 
1022 	if (ent->client->kami==666)
1023 	{
1024 		ent->s.effects	=	EF_TELEPORTER;
1025 		ent->s.renderfx	=	RF_SHELL_DOUBLE;
1026 		return;
1027 	}
1028 
1029 	if (sv_teams->value && deathmatch->value)
1030 		if (ent->TeamName>0)
1031 		{
1032 			ent->s.effects = EF_COLOR_SHELL;
1033 			switch (ent->TeamName)
1034 			{
1035 				case 1:
1036 					ent->s.renderfx = RF_SHELL_RED;
1037 					break;
1038 				case 2:
1039 					ent->s.renderfx = RF_SHELL_RED|RF_SHELL_GREEN;
1040 					break;
1041 				case 3:
1042 					ent->s.renderfx = RF_SHELL_RED|RF_SHELL_BLUE;
1043 					break;
1044 				case 4:
1045 					ent->s.renderfx = RF_SHELL_BLUE;
1046 					break;
1047 				case 5:
1048 					ent->s.renderfx = RF_SHELL_BLUE|RF_SHELL_GREEN;
1049 					break;
1050 				case 6:
1051 					ent->s.renderfx = RF_SHELL_GREEN;
1052 					break;
1053 				case 7:
1054 					ent->s.renderfx = RF_SHELL_GREEN|RF_SHELL_RED|RF_SHELL_BLUE;
1055 					break;
1056 			}
1057 			if (ent->client->aquasuit)
1058 				ent->s.effects	=	EF_SPHERETRANS;
1059 
1060 			return;
1061 		}
1062 
1063 	if (ent->client->aquasuit)
1064 	{
1065 		if (VectorLength(ent->velocity)<30)
1066 			ent->s.effects	=	EF_SPHERETRANS;
1067 		else if (VectorLength(ent->velocity)<250)
1068 			ent->s.renderfx	|=	RF_TRANSLUCENT;
1069 		else if (VectorLength(ent->velocity)<500 && (int)(rand()%3)==0 )
1070 			ent->s.renderfx	|=	RF_TRANSLUCENT;
1071 
1072 		//ent->s.renderfx		|=	RF_SHELL_HALF_DAM|RF_SHELL_DOUBLE;
1073 	}
1074 	else if (!ent->linked_flame)
1075 	{
1076 		ent->s.effects=0;
1077 		ent->s.renderfx=0;
1078 		if (ent->powerarmor_time > level.time)
1079 		{
1080 			pa_type = PowerArmorType (ent);
1081 			if (pa_type == POWER_ARMOR_SCREEN)
1082 			{
1083 				ent->s.effects |= EF_POWERSCREEN;
1084 			}
1085 			else if (pa_type == POWER_ARMOR_SHIELD)
1086 			{
1087 				ent->s.effects |= EF_COLOR_SHELL;
1088 				ent->s.renderfx |= RF_SHELL_GREEN;
1089 			}
1090 		}
1091 	}
1092 
1093 	if (ent->client->quad_framenum > level.framenum)
1094 	{
1095 		remaining = ent->client->quad_framenum - level.framenum;
1096 		if (remaining > 30 || (remaining & 4) )
1097 			ent->s.effects |= EF_QUAD;
1098 	}
1099 
1100 	if (ent->client->invincible_framenum > level.framenum)
1101 	{
1102 		remaining = ent->client->invincible_framenum - level.framenum;
1103 		if (remaining > 30 || (remaining & 4) )
1104 			ent->s.effects |= EF_PENT;
1105 
1106 		/*	ent->s.effects |= EF_COLOR_SHELL;
1107 			ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_BLUE);*/
1108 	}
1109 
1110 	// show cheaters!!!
1111 	if (ent->flags & FL_GODMODE)
1112 	{
1113 		ent->s.effects |= EF_COLOR_SHELL;
1114 		ent->s.renderfx |= (RF_SHELL_RED|RF_SHELL_GREEN|RF_SHELL_BLUE);
1115 	}
1116 
1117 	if (!ent->client->aquasuit)
1118 		ent->s.renderfx |= RF_IR_VISIBLE;
1119 }
1120 
1121 /*
1122 EF_ROTATE
1123 EF_GIB
1124 EF_BLASTER
1125 EF_ROCKET
1126 EF_GRENADE
1127 EF_HYPERBLASTER
1128 EF_BFG
1129 EF_COLOR_SHELL
1130 EF_POWERSCREEN
1131 EF_ANIM01
1132 EF_ANIM23
1133 EF_ANIM_ALL
1134 EF_ANIM_ALLFAST
1135 EF_FLIES
1136 EF_QUAD
1137 EF_PENT
1138 EF_TELEPORTER
1139 EF_FLAG1
1140 EF_FLAG2
1141 EF_IONRIPPER
1142 EF_GREENGIB
1143 EF_BLUEHYPERBLASTER
1144 EF_SPINNINGLIGHTS
1145 EF_PLASMA
1146 EF_TRAP
1147 EF_TRACKER
1148 EF_DOUBLE
1149 EF_SPHERETRANS
1150 EF_TAGTRAIL
1151 EF_HALF_DAMAGE
1152 EF_TRACKERTRAIL
1153 
1154 */
1155 
1156 /*
1157 ===============
1158 G_SetClientEvent
1159 ===============
1160 */
1161 
1162 #define SURF_PING 1
1163 #define SURF_GRASS 2
1164 #define SURF_CARPT 3
1165 #define SURF_METAL 4
1166 
strcmpwld(char * give,char * check)1167 qboolean strcmpwld (char *give, char *check)
1168 {
1169 	int i, j, givenlength=0, checklength=0;
1170 
1171 	givenlength = strlen(give);
1172 	checklength = strlen(check);
1173 
1174 	for (i=0; i<givenlength; i++)
1175 	{
1176 		char checked[100];
1177 		checked[0] = 0;
1178 		for (j=i; j<checklength+i; j++)
1179 		{
1180 			Com_sprintf (checked, sizeof(checked), "%s%c", &checked, give[j]);
1181 		}
1182 		if (!strcmp(check, (char *)(&checked)))
1183 			return true;
1184 	}
1185 
1186 	return false;
1187 }
1188 
Surface(char * name,int type)1189 qboolean Surface(char *name, int type)
1190 {
1191 
1192 	switch (type)
1193 	{
1194 	case SURF_PING:
1195 		if (strcmpwld (name, "support"))
1196 			return true;
1197 		break;
1198 	case SURF_GRASS:
1199 		if (strcmpwld (name, "grass"))
1200 			return true;
1201 		break;
1202 	case SURF_CARPT:
1203 		if (strcmpwld (name, "wbox"))
1204 			return true;
1205 		if (strcmpwld (name, "box"))
1206 			return true;
1207 		if (strcmpwld (name, "pip"))
1208 			return true;
1209 		if (strcmpwld (name, "airduc"))
1210 			return true;
1211 		if (strcmpwld (name, "grnx"))
1212 			return true;
1213 		if (strcmpwld (name, "stflr"))
1214 			return true;
1215 		if (strcmpwld (name, "grate"))
1216 			return true;
1217 		if (strcmpwld (name, "ggrat"))
1218 			return true;
1219 		break;
1220 	case SURF_METAL:
1221 		if (strcmpwld (name, "metal"))
1222 			return true;
1223 		if (strcmpwld (name, "bmetal"))
1224 			return true;
1225 		if (strcmpwld (name, "bigmet"))
1226 			return true;
1227 		if (strcmpwld (name, "plate"))
1228 			return true;
1229 		if (strcmpwld (name, "train"))
1230 			return true;
1231 		if (strcmpwld (name, "wmtal"))
1232 			return true;
1233 
1234 		break;
1235 	}
1236 	return false;
1237 }
1238 
1239 void FootPrint (edict_t *ent, vec3_t start, vec3_t dir, int type, edict_t *other);
G_SetClientEvent(edict_t * ent)1240 void G_SetClientEvent (edict_t *ent)
1241 {
1242 	vec3_t end = { 0, 0, -200};
1243 	trace_t tr;
1244 	VectorMA (ent->s.origin, 50, end, end);
1245 	tr = gi.trace (ent->s.origin, NULL, NULL, end, ent, MASK_ALL);
1246 	if (tr.ent)
1247 		if (tr.ent->svflags & SVF_DEADMONSTER)
1248 			ent->client->bootblood=15;
1249 
1250 	if (ent->waterlevel)
1251 		ent->client->bootwater = 10;
1252 
1253 	if (!ent->groundentity || ent->client->isOnTurret)
1254 		return;
1255 
1256 	if (!(sv_waterlevel->value||(ent->client->goggles && ent->waterlevel>1)||(ent->client->jets)))
1257 		if ( (int)(current_client->bobtime+bobmove) != bobcycle)
1258 		{
1259 			int sound, type;
1260 			float volume = 1;
1261 			vec3_t end, down = { 0, 0, -1}, point, start, right;
1262 			trace_t tr;
1263 
1264 			volume = (float)(VectorLength(ent->velocity))/400;
1265 			if (volume>1)
1266 				volume = 1;
1267 			if (ent->client->aquasuit)
1268 				volume/=2;
1269 
1270 			if (ent->client->bootblood)
1271 			{
1272 				if (ent->client->bootwater)
1273 					ent->client->bootwater--;
1274 				ent->client->bootblood--;
1275 				type = 2;
1276 				if (random()>0.5)
1277 					gi.sound (ent, CHAN_VOICE, gi.soundindex("player/wade2.wav"), volume, ATTN_IDLE, 0);
1278 				else
1279 					gi.sound (ent, CHAN_VOICE, gi.soundindex("player/wade3.wav"), volume, ATTN_IDLE, 0);
1280 			}
1281 			else if (ent->client->bootwater)
1282 			{
1283 				type = 1;
1284 				ent->client->bootwater--;
1285 				if (random()>0.5)
1286 					gi.sound (ent, CHAN_VOICE, gi.soundindex("player/wade2.wav"), volume, ATTN_IDLE, 0);
1287 				else
1288 					gi.sound (ent, CHAN_VOICE, gi.soundindex("player/wade3.wav"), volume, ATTN_IDLE, 0);
1289 			}
1290 			else
1291 				type = 0;
1292 
1293 			ent->client->foot = (ent->client->foot==1)? -1 : 1;
1294 
1295 			AngleVectors (ent->s.angles, NULL, right, NULL);
1296 			VectorScale(right, ent->client->foot * 5, right);
1297 			VectorAdd(right,ent->s.old_origin, start);
1298 			VectorMA (start, 50, down, end);
1299 			tr = gi.trace (start, NULL, NULL, end, ent, CONTENTS_SOLID);
1300 			VectorCopy (tr.plane.normal, point);
1301 			AngleVectors (ent->s.angles, end, NULL, NULL);
1302 			VectorCopy(tr.endpos, start);
1303 
1304 			if (tr.ent)
1305 				if ((tr.ent->svflags&SVF_DEADMONSTER) || tr.ent->client)
1306 					return;
1307 
1308 			VectorMA (ent->s.origin, 50, down, end);
1309 			tr = gi.trace (ent->s.origin, ent->mins, ent->maxs, end, ent, CONTENTS_SOLID);
1310 
1311 			FootPrint (ent, start, point, type, tr.ent);
1312 
1313 			if (Surface(tr.surface->name, SURF_PING)) //sharp loud metal
1314 			{
1315 				if (random()<0.5)
1316 					sound = gi.soundindex("gladiator/gldsrch1.wav");
1317 				else
1318 					sound = gi.soundindex("tank/tnkdeth1.wav");
1319 				volume/=3;
1320 			}
1321 			else if (Surface(tr.surface->name, SURF_GRASS)) //grass, snow etc
1322 			{
1323 				if (random()<0.5)
1324 					sound = gi.soundindex("chick/chkfall1.wav");
1325 				else
1326 					sound = gi.soundindex("infantry/melee2.wav");
1327 				volume/=4;
1328 			}
1329 			else if (Surface(tr.surface->name, SURF_CARPT)) //carpet/soft/wood
1330 			{
1331 				if (random()<0.5)
1332 					sound = gi.soundindex("mutant/step1.wav");
1333 				else
1334 					sound = gi.soundindex("mutant/step3.wav");
1335 			}
1336 			else if (Surface(tr.surface->name, SURF_METAL)) //heavy metal
1337 			{
1338 				sound = gi.soundindex("mutant/thud1.wav");
1339 				volume/=3;
1340 			}
1341 			else
1342 			{
1343 				if (random()<0.25)
1344 					sound = gi.soundindex("player/step1.wav");
1345 				else if (random()<0.25)
1346 					sound = gi.soundindex("player/step2.wav");
1347 				else if (random()<0.25)
1348 					sound = gi.soundindex("player/step3.wav");
1349 				else
1350 					sound = gi.soundindex("player/step4.wav");
1351 			}
1352 
1353 			gi.sound (ent, CHAN_AUTO, sound, volume, ATTN_NORM, 0);
1354 			gi.sound (ent, CHAN_AUTO, sound, volume, ATTN_NORM, 0);
1355 		}
1356 }
1357 
1358 /*
1359 ===============
1360 G_SetClientSound
1361 ===============
1362 */
G_SetClientSound(edict_t * ent)1363 void G_SetClientSound (edict_t *ent)
1364 {
1365 	char	*weap;
1366 
1367 	if (ent->client->pers.game_helpchanged != game.helpchanged)
1368 	{
1369 		ent->client->pers.game_helpchanged = game.helpchanged;
1370 		ent->client->pers.helpchanged = 1;
1371 	}
1372 
1373 	// help beep (no more than three times)
1374 	if (ent->client->pers.helpchanged && ent->client->pers.helpchanged <= 3 && !(level.framenum&63) )
1375 	{
1376 		ent->client->pers.helpchanged++;
1377 		gi.sound (ent, CHAN_VOICE, gi.soundindex ("misc/pc_up.wav"), 1, ATTN_STATIC, 0);
1378 	}
1379 
1380 
1381 	if (ent->client->pers.weapon)
1382 		weap = ent->client->pers.weapon->classname;
1383 	else
1384 		weap = "";
1385 
1386 	if (ent->waterlevel && (ent->watertype&(CONTENTS_LAVA|CONTENTS_SLIME)) )
1387 		ent->s.sound = snd_fry;
1388 /*	else if (strcmp(weap, "weapon_railgun") == 0)
1389 		ent->s.sound = gi.soundindex("weapons/rg_hum.wav");*/
1390 	else if (strcmp(weap, "weapon_bfg") == 0)
1391 		ent->s.sound = gi.soundindex("weapons/bfg_hum.wav");
1392 	else if (ent->client->weapon_sound)
1393 		ent->s.sound = ent->client->weapon_sound;
1394 	else
1395 		ent->s.sound = 0;
1396 }
1397 
1398 /*
1399 ===============
1400 G_SetClientFrame
1401 ===============
1402 */
G_SetClientFrame(edict_t * ent)1403 void G_SetClientFrame (edict_t *ent)
1404 {
1405 	vec3_t vec;
1406 	gclient_t	*client;
1407 	trace_t tr;
1408 	qboolean	duck, run;
1409 	edict_t *oldgrountent = ent->groundentity;
1410 
1411 	if (ent->s.modelindex != 255)
1412 		return;		// not in the player model
1413 
1414 	client = ent->client;
1415 
1416 	if (!ent->waterlevel)
1417 	{
1418 		VectorCopy(ent->s.origin, vec);
1419 		vec[2] -= 30;
1420 		tr = gi.trace(ent->s.origin, ent->mins, ent->maxs, vec, ent, MASK_SOLID);
1421 		if (tr.fraction!=1 && !ent->client->jumping)
1422 			ent->groundentity = ent;
1423 	}else if (ent->waterlevel>1)
1424 		ent->groundentity = ent;
1425 
1426 	if (client->ps.pmove.pm_flags & PMF_DUCKED || client->stunts<-5)
1427 		duck = true;
1428 	else
1429 		duck = false;
1430 
1431 	if (xyspeed || abs(ent->client->wallrunning) || (ent->waterlevel>1))
1432 		run = true;
1433 	else
1434 		run = false;
1435 
1436 	if (abs(ent->client->wallrunning))
1437 		ent->groundentity = ent;
1438 
1439 	// check for stand/duck and stop/go transitions
1440 	if (duck != client->anim_duck && client->anim_priority < ANIM_DEATH)
1441 		goto newanim;
1442 	if (run != client->anim_run && (client->anim_priority == ANIM_BASIC || abs(ent->client->wallrunning) || (ent->waterlevel>1)))
1443 		goto newanim;
1444 	if (!ent->groundentity && client->anim_priority <= ANIM_WAVE)
1445 		goto newanim;
1446 
1447 	if(client->anim_priority == ANIM_REVERSE)
1448 	{
1449 		if(ent->s.frame > client->anim_end)
1450 		{
1451 			ent->s.frame--;
1452 			ent->groundentity = oldgrountent;
1453 			return;
1454 		}
1455 	}
1456 	else if (ent->s.frame < client->anim_end)
1457 	{	// continue an animation
1458 		ent->s.frame++;
1459 		ent->groundentity = oldgrountent;
1460 		return;
1461 	}
1462 
1463 	if (client->anim_priority == ANIM_DEATH)
1464 		return;		// stay there
1465 	if (client->anim_priority == ANIM_JUMP)
1466 	{
1467 		if (!ent->groundentity || ent->client->jets)
1468 		{
1469 			ent->groundentity = oldgrountent;
1470 			return;		// stay there
1471 		}
1472 		ent->client->anim_priority = ANIM_WAVE;
1473 		ent->s.frame = FRAME_jump3;
1474 		ent->client->anim_end = FRAME_jump6;
1475 		ent->groundentity = oldgrountent;
1476 		return;
1477 	}
1478 
1479 newanim:
1480 	// return to either a running or standing frame
1481 	client->anim_priority = ANIM_BASIC;
1482 	client->anim_duck = duck;
1483 	client->anim_run = run;
1484 
1485 	if ((!ent->groundentity) && ent->waterlevel!=2)
1486 	{
1487 		client->anim_priority = ANIM_JUMP;
1488 		if (ent->s.frame != FRAME_jump2)
1489 			ent->s.frame = FRAME_jump1;
1490 		client->anim_end = FRAME_jump2;
1491 	}
1492 	else if (run)
1493 	{	// running
1494 		if (duck)
1495 		{
1496 			ent->s.frame = FRAME_crwalk1;
1497 			client->anim_end = FRAME_crwalk6;
1498 		}
1499 		else
1500 		{
1501 			ent->s.frame = FRAME_run1;
1502 			client->anim_end = FRAME_run6;
1503 		}
1504 	}
1505 	else
1506 	{	// standing
1507 		if (duck)
1508 		{
1509 			ent->s.frame = FRAME_crstnd01;
1510 			client->anim_end = FRAME_crstnd19;
1511 		}
1512 		else
1513 		{
1514 			ent->s.frame = FRAME_stand01;
1515 			client->anim_end = FRAME_stand40;
1516 		}
1517 	}
1518 	ent->groundentity = oldgrountent;
1519 }
1520 
WaveThink(edict_t * ent)1521 void WaveThink (edict_t *ent)
1522 {
1523 	ent->nextthink = level.time;
1524 	ent->s.frame = ent->s.skinnum++;
1525 
1526 	if (ent->s.skinnum>4)
1527 		G_FreeEdict(ent);
1528 }
1529 
AddWaves(edict_t * ent)1530 void AddWaves (edict_t *ent)
1531 {
1532 	trace_t tr;
1533 	vec3_t top, bottom, change;
1534 	float randadd[2], originchange;
1535 	int i;
1536 
1537 	if ((int)sv_bulletmarks->value<=0 || sv_serversideonly->value)
1538 		return;
1539 
1540 	VectorSubtract(ent->s.origin, ent->client->old_origin, change);
1541 	originchange = VectorLength(change);
1542 
1543 	VectorCopy(ent->s.origin, top);
1544 	VectorCopy(ent->s.origin, bottom);
1545 
1546 	top[2] += ent->maxs[2];
1547 	bottom[2] += ent->mins[2];
1548 
1549 	if (originchange<10)
1550 		for (i=0;i<2;i++)
1551 		{
1552 			randadd[i] = (10-originchange) - random()*(10-originchange)*2;
1553 			top[i]+=randadd[i];
1554 			bottom[i]+=randadd[i];
1555 		}
1556 
1557 	tr = gi.trace(top, NULL, NULL, bottom, ent, MASK_WATER);
1558 
1559 	if (tr.fraction!=1)
1560 	{
1561 		edict_t *splash;
1562 
1563 		splash = G_Spawn();
1564 
1565 		if (sv_bulletmarks->value <= bulletmarks)
1566 			BulletMarkThink(bulletptr[0]);
1567 
1568 		vectoangles(tr.plane.normal, splash->s.angles);
1569 		VectorCopy(tr.endpos, splash->s.origin);
1570 
1571 		splash->s.effects = 0;
1572 		splash->s.renderfx = RF_TRANSLUCENT;
1573 		splash->solid = SOLID_NOT;
1574 		splash->svflags = SVF_DEADMONSTER;
1575 		splash->clipmask = MASK_SHOT;
1576 		splash->takedamage = DAMAGE_NO;
1577 		splash->movetype = MOVETYPE_NONE;
1578 		splash->svflags = SVF_DEADMONSTER;
1579 		splash->think = WaveThink;
1580 		splash->nextthink = level.time;
1581 		splash->owner = ent;
1582 		if (originchange<2)
1583 			splash->s.frame = 3;
1584 		else if (originchange<5)
1585 			splash->s.frame = 2;
1586 		else if (originchange<10)
1587 			splash->s.frame = 1;
1588 		else
1589 			splash->s.frame = 0;
1590 
1591 		splash->s.skinnum = splash->s.frame;
1592 
1593 		splash->s.modelindex = gi.modelindex("models/objects/splash/tris.md2");
1594 		splash->classname = "clientwave";
1595 
1596 		gi.linkentity (splash);
1597 		bulletptr[bulletmarks] = splash;
1598 		bulletmarks++;
1599 	}
1600 }
1601 
1602 /*
1603 =================
1604 ClientEndServerFrame
1605 
1606 Called for each player at the end of the server frame
1607 and right after spawning
1608 =================
1609 */
ClientEndServerFrame(edict_t * ent)1610 void ClientEndServerFrame (edict_t *ent)
1611 {
1612 	float	bobtime;
1613 	int		i;
1614 	edict_t *other;
1615 
1616 	current_player = ent;
1617 	current_client = ent->client;
1618 
1619 	//THIS IS FOR PING DEPENDANT FUNCTIONS
1620 	ent->client->MOTDrotChange = (float)(ent->client->ping/25);
1621 	if (ent->client->MOTDrotChange<1)
1622 		ent->client->MOTDrotChange=1;
1623 
1624 	if (level.framenum - ent->client->resp.enterframe > 1 && !ent->configed)
1625 	{
1626 		stuffcmd (ent, "exec uservars.cfg");
1627 		ent->configed = true;
1628 	}
1629 
1630 //	if (level.framenum - ent->client->resp.enterframe==2)
1631 //		stuffcmd(ent, "exec uservars.cfg");
1632 
1633 	//
1634 	// If the origin or velocity have changed since ClientThink(),
1635 	// update the pmove values.  This will happen when the client
1636 	// is pushed by a bmodel or kicked by an explosion.
1637 	//
1638 	// If it wasn't updated here, the view position would lag a frame
1639 	// behind the body position when pushed -- "sinking into plats"
1640 	//
1641 	for (i=0 ; i<3 ; i++)
1642 	{
1643 		current_client->ps.pmove.origin[i] = ent->s.origin[i]*8.0;
1644 		current_client->ps.pmove.velocity[i] = ent->velocity[i]*8.0;
1645 	}
1646 
1647 	//
1648 	// If the end of unit layout is displayed, don't give
1649 	// the player any normal movement attributes
1650 	//
1651 	if (level.intermissiontime)
1652 	{
1653 		// FIXME: add view drifting here?
1654 		current_client->ps.blend[3] = 0;
1655 		current_client->ps.fov = 90;
1656 		G_SetStats (ent);
1657 		return;
1658 	}
1659 
1660 	AngleVectors (ent->client->v_angle, forward, right, up);
1661 
1662 	// burn from lava, etc
1663 	P_WorldEffects ();
1664 
1665 	//
1666 	// set model angles from view angles so other things in
1667 	// the world can tell which direction you are looking
1668 	//
1669 	if (!ent->killer && !ent->client->isOnTurret)
1670 	{
1671 		if (ent->client->v_angle[PITCH] > 180)
1672 			ent->s.angles[PITCH] = (-360 + ent->client->v_angle[PITCH])/3;
1673 		else
1674 			ent->s.angles[PITCH] = ent->client->v_angle[PITCH]/3;
1675 	}
1676 
1677 	//this makes for cool looking angles in the air or water...
1678 
1679 	ent->client->climbing = 0;
1680 	ent->client->wallrunning = 0;
1681 	if (ent->groundentity)
1682 	{
1683 		int offsetAmt = 2;
1684 
1685 		if (abs(ent->client->stunts)==1)
1686 		{
1687 			if (ent->client->stunts==1)
1688 				ent->client->stunts=-70-offsetAmt; //-3
1689 			else
1690 				ent->client->stunts=-90-offsetAmt; //-4
1691 		}
1692 		else if (abs(ent->client->stunts)==2)
1693 		{
1694 			if (ent->client->stunts==2)
1695 				ent->client->stunts=-10-offsetAmt;
1696 			else
1697 				ent->client->stunts=-40-offsetAmt;
1698 		}
1699 		else if ((ent->client->stunts==-3 || ent->client->stunts==-4) && ent->Move_up>=0)
1700 			/* DO NOTHING */;
1701 		else if (ent->client->stunts<-5)
1702 			/* DO NOTHING */;
1703 		else
1704 			ent->client->stunts=0;
1705 	}
1706 	else if (ent->waterlevel>1)
1707 		ent->client->stunts=0;
1708 
1709 	if (ent->client->stunt)
1710 		CheckStunt(ent);
1711 
1712 	flight_check  (ent); //does flight and swimming fx
1713 
1714 	if (!ent->killer && !ent->client->isOnTurret)
1715 	{
1716 		ent->s.angles[ROLL] = 0;
1717 		ent->s.angles[ROLL] = SV_CalcRoll (ent->s.angles, ent->velocity)*4;
1718 		ent->s.angles[YAW] = ent->client->v_angle[YAW];
1719 	}
1720 
1721 	//PITCH(forUp/backDown) YAW(leftRot/rightRot) ROLL(leftTilt/rightTilt)
1722 	if (ent->health && !ent->client->isOnTurret)
1723 	{
1724 		if (ent->waterlevel>1)
1725 			ent->s.angles[PITCH] =  90+ent->client->v_angle[PITCH];
1726 		else if (abs(ent->client->wallrunning))
1727 		{
1728 			if (ent->client->wallrunning>0) //right side
1729 			{
1730 				ent->s.angles[ROLL] =  90+ent->client->v_angle[ROLL];
1731 				ent->client->kick_angles[ROLL] += 45;
1732 			}
1733 			else //left side
1734 			{
1735 				ent->s.angles[ROLL] =  -90+ent->client->v_angle[ROLL];
1736 				ent->client->kick_angles[ROLL] -= 45;
1737 			}
1738 		}
1739 		else if (ent->client->stunts!=0)
1740 		{
1741 			if (ent->client->stunts==1) //forward dive
1742 				ent->s.angles[PITCH] =  60+ent->client->v_angle[PITCH];
1743 			else if (ent->client->stunts==-1) //backwards dive
1744 				ent->s.angles[PITCH] =  -60+ent->client->v_angle[PITCH];
1745 			else if (ent->client->stunts==2) //right dive
1746 				ent->s.angles[ROLL] =  -60+ent->client->v_angle[ROLL];
1747 			else if (ent->client->stunts==-2) //left dive
1748 				ent->s.angles[ROLL] =  60+ent->client->v_angle[ROLL];
1749 			else if (ent->client->stunts>=10)
1750 			{
1751 				int RotMax = 10;
1752 				int rot = ent->client->stunts-9;
1753 
1754 				if (rot==RotMax) //when flip is done, stop flip
1755 					ent->client->stunts=0;
1756 				else
1757 				{
1758 					float temp = rot-(RotMax);
1759 					temp = (temp>0)?temp:-temp;
1760 					ent->s.angles[PITCH] = (360 * ( temp /(RotMax)) ) + ent->s.angles[PITCH];
1761 					ent->client->stunts++;
1762 				}
1763 			}
1764 			else if (ent->client->stunts<-2 && !ent->waterlevel)
1765 			{
1766 				int AngleQuot = 6;
1767 				if (ent->client->stunts==-3 && !(ent->Move_up<0)) //forward prone
1768 				{
1769 					if (ent->client->v_angle[PITCH] > 180)
1770 						ent->s.angles[PITCH] = 75 + (-360 + ent->client->v_angle[PITCH])/AngleQuot;
1771 					else
1772 						ent->s.angles[PITCH] = 75 + ent->client->v_angle[PITCH]/AngleQuot;
1773 				}
1774 				else if (ent->client->stunts==-4) //backwards prone
1775 				{
1776 					if (ent->client->v_angle[PITCH] > 180)
1777 						ent->s.angles[PITCH] = -75 + (-360 + ent->client->v_angle[PITCH])/AngleQuot;
1778 					else
1779 						ent->s.angles[PITCH] = -75 + ent->client->v_angle[PITCH]/AngleQuot;
1780 				}
1781 				else
1782 				{
1783 					ent->client->stunts--;
1784 
1785 					if ((ent->client->stunts==-20 || ent->client->stunts==-50) && !ent->client->stunt)
1786 						ent->client->stunts=0;
1787 					else if ((ent->client->stunts==-20 || ent->client->stunts==-50) && ent->groundentity)
1788 					{
1789 						ent->groundentity=NULL;
1790 						ent->velocity[2]=200;
1791 					}
1792 					else if (ent->client->stunts==-30 || ent->client->stunts==-60 || ent->client->stunts==-80
1793 						|| ent->client->stunts==-100)
1794 						ent->client->stunts=0;
1795 
1796 					if (ent->client->stunts>-30&&ent->client->stunts<-10) //right roll
1797 					{
1798 						float rollamt = -(ent->client->stunts+10);
1799 						ent->s.angles[ROLL] = -(360*(rollamt/10)) + ent->client->v_angle[ROLL];
1800 					}
1801 					else if (ent->client->stunts>-60&&ent->client->stunts<-40) //left roll
1802 					{
1803 						float rollamt = -(ent->client->stunts+40);
1804 						ent->s.angles[ROLL] = (360*(rollamt/10)) + ent->client->v_angle[ROLL];
1805 					}
1806 					else if (ent->client->stunts>-80&&ent->client->stunts<-70) //forward roll
1807 					{
1808 						float rollamt = -(ent->client->stunts+70);
1809 						ent->s.angles[PITCH] = (360*(rollamt/10)) + ent->client->v_angle[PITCH];
1810 					}
1811 					else if (ent->client->stunts>-100&&ent->client->stunts<-90) //backward roll
1812 					{
1813 						float rollamt = -(ent->client->stunts+90);
1814 						ent->s.angles[PITCH] = -(360*(rollamt/10)) + ent->client->v_angle[PITCH];
1815 					}
1816 				}
1817 			}
1818 		}
1819 	}
1820 
1821 	//
1822 	// calculate speed and cycle to be used for
1823 	// all cyclic walking effects
1824 	//
1825 	xyspeed = sqrt(ent->velocity[0]*ent->velocity[0] + ent->velocity[1]*ent->velocity[1]);
1826 
1827 	if (xyspeed < 5 || ent->client->isOnTurret)
1828 	{
1829 		bobmove = 0;
1830 		current_client->bobtime = 0;	// start at beginning of cycle again
1831 	}
1832 	else if (ent->groundentity)
1833 	{	// so bobbing only cycles when on ground
1834 		if (xyspeed > 210)
1835 			bobmove = 0.25;
1836 		else if (xyspeed > 100)
1837 			bobmove = 0.125;
1838 		else
1839 			bobmove = 0.0625;
1840 	}
1841 
1842 	bobtime = (current_client->bobtime += bobmove);
1843 
1844 	if (current_client->ps.pmove.pm_flags & PMF_DUCKED)
1845 		bobtime *= 4;
1846 
1847 	bobcycle = (int)bobtime;
1848 	bobfracsin = fabs(sin(bobtime*M_PI));
1849 
1850 	// detect hitting the floor
1851 	P_FallingDamage (ent);
1852 
1853 	// apply all the damage taken this frame
1854 	P_DamageFeedback (ent);
1855 
1856 	// determine the view offsets
1857 	SV_CalcViewOffset (ent);
1858 
1859 	// determine the gun offsets
1860 	SV_CalcGunOffset (ent);
1861 
1862 	// determine the full screen color blend
1863 	// must be after viewoffset, so eye contents can be
1864 	// accurately determined
1865 	// FIXME: with client prediction, the contents
1866 	// should be determined by the client
1867 	SV_CalcBlend (ent);
1868 
1869 	// chase cam stuff
1870 	if (ent->client->resp.spectator)
1871 		G_SetSpectatorStats(ent);
1872 	else
1873 		G_SetStats (ent);
1874 	G_CheckChaseStats(ent);
1875 
1876 	G_SetClientFrame (ent);
1877 
1878 	G_SetClientEvent (ent);
1879 
1880 	G_SetClientEffects (ent);
1881 
1882 	G_SetClientSound (ent);
1883 
1884 	if (ent->groundentity)
1885 		ent->client->jumping = false;
1886 
1887 	VectorCopy (ent->velocity, ent->client->oldvelocity);
1888 	VectorCopy (ent->client->ps.viewangles, ent->client->oldviewangles);
1889 
1890 	// clear weapon kicks
1891 	VectorClear (ent->client->kick_origin);
1892 	VectorClear (ent->client->kick_angles);
1893 
1894 	// if the scoreboard is up, update it
1895 	if (!(deathmatch->value||coop->value))
1896 		MakeSlowMo (ent);
1897 
1898 	if (ent->client->showscores && !(level.framenum%ent->client->MOTDrotChange) )
1899 	{
1900 		DeathmatchScoreboardMessage (ent, ent->enemy);
1901 		gi.unicast (ent, false);
1902 	}
1903 
1904 	if (ent->deadflag)
1905 		ent->s.frame=0;
1906 
1907 	if (ent->client->aquasuit)
1908 	{
1909 		ent->healthtimer++;
1910 		if (ent->healthtimer==3)
1911 		{
1912 			ent->healthtimer=0;
1913 			if (ent->max_health>ent->health)
1914 				ent->health++;	//and has health regen
1915 		}
1916 	}
1917 
1918 	if (ent->client->kicktime>0)
1919 		ent->client->kicktime--;
1920 	if (ent->client->damage_div>0)
1921 	{
1922 		ent->client->damage_div-=FRAMETIME;
1923 		if (ent->client->damage_div<0)
1924 			ent->client->damage_div=0;
1925 	}
1926 
1927 	if (((int)sv_bulletmarks->value || (!deathmatch->value && !coop->value)))
1928 	{
1929 		if (ent->waterlevel)
1930 			AddWaves(ent);
1931 
1932 		AddShadow(ent);
1933 		AddReflection(ent);
1934 	}
1935 
1936 	VectorCopy (ent->s.origin, ent->client->old_origin);
1937 
1938 	//aligning muzzle flashes etc
1939 	for (i = 1; i <= game.maxentities; i++)
1940 	{
1941 		other = &g_edicts[i];
1942 		if (!other->inuse)
1943 			continue;
1944 		if (other->owner==ent && !strcmp(other->classname, "mzlflash"))
1945 			other->thinklinked(other);
1946 	}
1947 
1948 	if (ent->client->chasetoggle == 1 && !ent->deadflag)
1949 		CheckChasecam_Viewent(ent);
1950 	else if (!deathmatch->value && !coop->value || sv_lowlag->value)
1951 		ent->client->ps.pmove.pm_flags |= PMF_NO_PREDICTION;
1952 	else
1953 		ent->client->ps.pmove.pm_flags &= ~PMF_NO_PREDICTION;
1954 
1955 	VectorCopy(ent->s.origin, ent->client->cl_origin);
1956 }
1957 
1958 
1959 
1960