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