1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // cl_ents.c -- entity parsing and management
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "client.h"
27
28 clentity_t *active_clentities, *free_clentities;
29 clentity_t clentities[MAX_CLENTITIES];
30
31 /*
32 =========================================================================
33
34 FRAME PARSING
35
36 =========================================================================
37 */
38
39 /*
40 =================
41 CL_ParseEntityBits
42
43 Returns the entity number and the header bits
44 =================
45 */
46 int bitcounts[32]; /// just for protocol profiling
CL_ParseEntityBits(unsigned * bits)47 int CL_ParseEntityBits (unsigned *bits)
48 {
49 unsigned b, total;
50 int i;
51 int number;
52
53 total = MSG_ReadByte (&net_message);
54 if (total & U_MOREBITS1)
55 {
56 b = MSG_ReadByte (&net_message);
57 total |= b<<8;
58 }
59 if (total & U_MOREBITS2)
60 {
61 b = MSG_ReadByte (&net_message);
62 total |= b<<16;
63 }
64 if (total & U_MOREBITS3)
65 {
66 b = MSG_ReadByte (&net_message);
67 total |= b<<24;
68 }
69
70 // count the bits for net profiling
71 for (i=0 ; i<32 ; i++)
72 if (total&(1<<i))
73 bitcounts[i]++;
74
75 if (total & U_NUMBER16)
76 number = MSG_ReadShort (&net_message);
77 else
78 number = MSG_ReadByte (&net_message);
79
80 *bits = total;
81
82 return number;
83 }
84
85 /*
86 ==================
87 CL_ParseDelta
88
89 Can go from either a baseline or a previous packet_entity
90 ==================
91 */
CL_ParseDelta(entity_state_t * from,entity_state_t * to,int number,int bits)92 void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits)
93 {
94 // set everything to the state we are delta'ing from
95 *to = *from;
96
97 VectorCopy (from->origin, to->old_origin);
98 to->number = number;
99
100 if (bits & U_MODEL)
101 to->modelindex = MSG_ReadByte (&net_message);
102 if (bits & U_MODEL2)
103 to->modelindex2 = MSG_ReadByte (&net_message);
104 if (bits & U_MODEL3)
105 to->modelindex3 = MSG_ReadByte (&net_message);
106 if (bits & U_MODEL4)
107 to->modelindex4 = MSG_ReadByte (&net_message);
108
109 if (bits & U_FRAME8)
110 to->frame = MSG_ReadByte (&net_message);
111 if (bits & U_FRAME16)
112 to->frame = MSG_ReadShort (&net_message);
113
114 if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors
115 to->skinnum = MSG_ReadLong(&net_message);
116 else if (bits & U_SKIN8)
117 to->skinnum = MSG_ReadByte(&net_message);
118 else if (bits & U_SKIN16)
119 to->skinnum = MSG_ReadShort(&net_message);
120
121 if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
122 to->effects = MSG_ReadLong(&net_message);
123 else if (bits & U_EFFECTS8)
124 to->effects = MSG_ReadByte(&net_message);
125 else if (bits & U_EFFECTS16)
126 to->effects = MSG_ReadShort(&net_message);
127
128 if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
129 to->renderfx = MSG_ReadLong(&net_message);
130 else if (bits & U_RENDERFX8)
131 to->renderfx = MSG_ReadByte(&net_message);
132 else if (bits & U_RENDERFX16)
133 to->renderfx = MSG_ReadShort(&net_message);
134
135 if (bits & U_ORIGIN1)
136 to->origin[0] = MSG_ReadCoord (&net_message);
137 if (bits & U_ORIGIN2)
138 to->origin[1] = MSG_ReadCoord (&net_message);
139 if (bits & U_ORIGIN3)
140 to->origin[2] = MSG_ReadCoord (&net_message);
141
142 if (bits & U_ANGLE1)
143 to->angles[0] = MSG_ReadAngle(&net_message);
144 if (bits & U_ANGLE2)
145 to->angles[1] = MSG_ReadAngle(&net_message);
146 if (bits & U_ANGLE3)
147 to->angles[2] = MSG_ReadAngle(&net_message);
148
149 if (bits & U_OLDORIGIN)
150 MSG_ReadPos (&net_message, to->old_origin);
151
152 if (bits & U_SOUND)
153 to->sound = MSG_ReadByte (&net_message);
154
155 if (bits & U_EVENT)
156 to->event = MSG_ReadByte (&net_message);
157 else
158 to->event = 0;
159
160 if (bits & U_SOLID)
161 to->solid = MSG_ReadShort (&net_message);
162 }
163
164 /*
165 ==================
166 CL_DeltaEntity
167
168 Parses deltas from the given base and adds the resulting entity
169 to the current frame
170 ==================
171 */
CL_DeltaEntity(frame_t * frame,int newnum,entity_state_t * old,int bits)172 void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits)
173 {
174 centity_t *ent;
175 entity_state_t *state;
176
177 ent = &cl_entities[newnum];
178
179 state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
180 cl.parse_entities++;
181 frame->num_entities++;
182
183 CL_ParseDelta (old, state, newnum, bits);
184
185 // some data changes will force no lerping
186 if (state->modelindex != ent->current.modelindex
187 || state->modelindex2 != ent->current.modelindex2
188 || state->modelindex3 != ent->current.modelindex3
189 || state->modelindex4 != ent->current.modelindex4
190 || abs(state->origin[0] - ent->current.origin[0]) > 512
191 || abs(state->origin[1] - ent->current.origin[1]) > 512
192 || abs(state->origin[2] - ent->current.origin[2]) > 512
193 || state->event == EV_PLAYER_TELEPORT
194 || state->event == EV_OTHER_TELEPORT
195 )
196 {
197 ent->serverframe = -99;
198 }
199
200 if (ent->serverframe != cl.frame.serverframe - 1)
201 { // wasn't in last update, so initialize some things
202 ent->trailcount = 1024; // for diminishing rocket / grenade trails
203 ent->pr = NULL; // for chained particle trails
204 // duplicate the current state so lerping doesn't hurt anything
205 ent->prev = *state;
206 if (state->event == EV_OTHER_TELEPORT)
207 {
208 VectorCopy (state->origin, ent->prev.origin);
209 VectorCopy (state->origin, ent->lerp_origin);
210 }
211 else
212 {
213 VectorCopy (state->old_origin, ent->prev.origin);
214 VectorCopy (state->old_origin, ent->lerp_origin);
215 }
216 }
217 else
218 { // shuffle the last state to previous
219 ent->prev = ent->current;
220 }
221
222 ent->serverframe = cl.frame.serverframe;
223 ent->current = *state;
224 }
225
226 /*
227 ==================
228 CL_ParsePacketEntities
229
230 An svc_packetentities has just been parsed, deal with the
231 rest of the data stream.
232 ==================
233 */
CL_ParsePacketEntities(frame_t * oldframe,frame_t * newframe)234 void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe)
235 {
236 int newnum;
237 int bits;
238 entity_state_t *oldstate = NULL;
239 int oldindex, oldnum;
240
241 newframe->parse_entities = cl.parse_entities;
242 newframe->num_entities = 0;
243
244 // delta from the entities present in oldframe
245 oldindex = 0;
246 if (!oldframe)
247 oldnum = 99999;
248 else
249 {
250 if (oldindex >= oldframe->num_entities)
251 oldnum = 99999;
252 else
253 {
254 oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
255 oldnum = oldstate->number;
256 }
257 }
258
259 while (1)
260 {
261 newnum = CL_ParseEntityBits ( (unsigned *)&bits );
262 if (newnum >= MAX_EDICTS)
263 Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
264
265 if (net_message.readcount > net_message.cursize)
266 Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
267
268 if (!newnum)
269 break;
270
271 while (oldnum < newnum)
272 { // one or more entities from the old packet are unchanged
273 if (cl_shownet->value == 3)
274 Com_Printf (" unchanged: %i\n", oldnum);
275 CL_DeltaEntity (newframe, oldnum, oldstate, 0);
276
277 oldindex++;
278
279 if (oldindex >= oldframe->num_entities)
280 oldnum = 99999;
281 else
282 {
283 oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
284 oldnum = oldstate->number;
285 }
286 }
287
288 if (bits & U_REMOVE)
289 { // the entity present in oldframe is not in the current frame
290 if (cl_shownet->value == 3)
291 Com_Printf (" remove: %i\n", newnum);
292 if (oldnum != newnum)
293 Com_Printf ("U_REMOVE: oldnum != newnum\n");
294
295 oldindex++;
296
297 if (oldindex >= oldframe->num_entities)
298 oldnum = 99999;
299 else
300 {
301 oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
302 oldnum = oldstate->number;
303 }
304 continue;
305 }
306
307 if (oldnum == newnum)
308 { // delta from previous state
309 if (cl_shownet->value == 3)
310 Com_Printf (" delta: %i\n", newnum);
311 CL_DeltaEntity (newframe, newnum, oldstate, bits);
312
313 oldindex++;
314
315 if (oldindex >= oldframe->num_entities)
316 oldnum = 99999;
317 else
318 {
319 oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
320 oldnum = oldstate->number;
321 }
322 continue;
323 }
324
325 if (oldnum > newnum)
326 { // delta from baseline
327 if (cl_shownet->value == 3)
328 Com_Printf (" baseline: %i\n", newnum);
329 CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
330 continue;
331 }
332
333 }
334
335 // any remaining entities in the old frame are copied over
336 while (oldnum != 99999)
337 { // one or more entities from the old packet are unchanged
338 if (cl_shownet->value == 3)
339 Com_Printf (" unchanged: %i\n", oldnum);
340 CL_DeltaEntity (newframe, oldnum, oldstate, 0);
341
342 oldindex++;
343
344 if (oldindex >= oldframe->num_entities)
345 oldnum = 99999;
346 else
347 {
348 oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
349 oldnum = oldstate->number;
350 }
351 }
352 }
353
354
355
356 /*
357 ===================
358 CL_ParsePlayerstate
359 ===================
360 */
CL_ParsePlayerstate(frame_t * oldframe,frame_t * newframe)361 void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe)
362 {
363 int flags;
364 player_state_t *state;
365 int i;
366 int statbits;
367
368 state = &newframe->playerstate;
369
370 // clear to old value before delta parsing
371 if (oldframe)
372 *state = oldframe->playerstate;
373 else
374 memset (state, 0, sizeof(*state));
375
376 flags = MSG_ReadShort (&net_message);
377
378 //
379 // parse the pmove_state_t
380 //
381 if (flags & PS_M_TYPE)
382 state->pmove.pm_type = MSG_ReadByte (&net_message);
383
384 if (flags & PS_M_ORIGIN)
385 {
386 state->pmove.origin[0] = MSG_ReadSizeInt (&net_message, coord_bytes);
387 state->pmove.origin[1] = MSG_ReadSizeInt (&net_message, coord_bytes);
388 state->pmove.origin[2] = MSG_ReadSizeInt (&net_message, coord_bytes);
389 }
390
391 if (flags & PS_M_VELOCITY)
392 {
393 state->pmove.velocity[0] = MSG_ReadShort (&net_message);
394 state->pmove.velocity[1] = MSG_ReadShort (&net_message);
395 state->pmove.velocity[2] = MSG_ReadShort (&net_message);
396 }
397
398 if (flags & PS_M_TIME)
399 state->pmove.pm_time = MSG_ReadByte (&net_message);
400
401 if (flags & PS_M_FLAGS)
402 state->pmove.pm_flags = MSG_ReadByte (&net_message);
403
404 if (flags & PS_M_GRAVITY)
405 state->pmove.gravity = MSG_ReadShort (&net_message);
406
407 if (flags & PS_M_DELTA_ANGLES)
408 {
409 state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
410 state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
411 state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
412 }
413
414 if (cl.attractloop)
415 state->pmove.pm_type = PM_FREEZE; // demo playback
416
417 //
418 // parse the rest of the player_state_t
419 //
420 if (flags & PS_VIEWOFFSET)
421 {
422 state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25;
423 state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25;
424 state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25;
425 }
426
427 if (flags & PS_VIEWANGLES)
428 {
429 state->viewangles[0] = MSG_ReadAngle16 (&net_message);
430 state->viewangles[1] = MSG_ReadAngle16 (&net_message);
431 state->viewangles[2] = MSG_ReadAngle16 (&net_message);
432 }
433
434 if (flags & PS_KICKANGLES)
435 {
436 state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25;
437 state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25;
438 state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25;
439 }
440
441 if (flags & PS_WEAPONINDEX)
442 {
443 state->gunindex = MSG_ReadByte (&net_message);
444 }
445
446 if (flags & PS_WEAPONFRAME)
447 {
448 state->gunframe = MSG_ReadByte (&net_message);
449 state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25;
450 state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25;
451 state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25;
452 state->gunangles[0] = MSG_ReadChar (&net_message)*0.25;
453 state->gunangles[1] = MSG_ReadChar (&net_message)*0.25;
454 state->gunangles[2] = MSG_ReadChar (&net_message)*0.25;
455 }
456
457 if (flags & PS_BLEND)
458 {
459 state->blend[0] = MSG_ReadByte (&net_message)/255.0;
460 state->blend[1] = MSG_ReadByte (&net_message)/255.0;
461 state->blend[2] = MSG_ReadByte (&net_message)/255.0;
462 state->blend[3] = MSG_ReadByte (&net_message)/255.0;
463 }
464
465 if (flags & PS_FOV)
466 state->fov = MSG_ReadByte (&net_message);
467
468 if (flags & PS_RDFLAGS)
469 state->rdflags = MSG_ReadByte (&net_message);
470
471 // parse stats
472 statbits = MSG_ReadLong (&net_message);
473 for (i=0 ; i<MAX_STATS ; i++)
474 if (statbits & (1<<i) )
475 state->stats[i] = MSG_ReadShort(&net_message);
476 }
477
478
479 /*
480 ==================
481 CL_FireEntityEvents
482
483 ==================
484 */
CL_FireEntityEvents(frame_t * frame)485 void CL_FireEntityEvents (frame_t *frame)
486 {
487 entity_state_t *s1;
488 int pnum, num;
489
490 for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
491 {
492 num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
493 s1 = &cl_parse_entities[num];
494 if (s1->event)
495 CL_EntityEvent (s1);
496
497 // EF_TELEPORTER acts like an event, but is not cleared each frame
498 if (s1->effects & EF_TELEPORTER)
499 CL_BigTeleportParticles(s1->origin);
500 }
501 }
502
503
504 /*
505 ================
506 CL_ParseFrame
507 ================
508 */
CL_ParseFrame(void)509 void CL_ParseFrame (void)
510 {
511 int cmd;
512 int len;
513 frame_t *old;
514 byte new_areabits[MAX_MAP_AREAS/8];
515
516 //HACK: reduce the number of areabit changes detected
517 memcpy (new_areabits, cl.frame.areabits, MAX_MAP_AREAS/8);
518 memset (&cl.frame, 0, sizeof(cl.frame));
519 memcpy (cl.frame.areabits, new_areabits, MAX_MAP_AREAS/8);
520
521 cl.frame.serverframe = MSG_ReadLong (&net_message);
522 cl.frame.deltaframe = MSG_ReadLong (&net_message);
523 cl.frame.servertime = cl.frame.serverframe*100;
524
525 // BIG HACK to let old demos continue to work
526 if (cls.serverProtocol != 26)
527 cl.surpressCount = MSG_ReadByte (&net_message);
528
529 if (cl_shownet->value == 3)
530 Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe,
531 cl.frame.deltaframe);
532
533 // If the frame is delta compressed from data that we
534 // no longer have available, we must suck up the rest of
535 // the frame, but not use it, then ask for a non-compressed
536 // message
537 if (cl.frame.deltaframe <= 0)
538 {
539 cl.frame.valid = true; // uncompressed frame
540 old = NULL;
541 cls.demowaiting = false; // we can start recording now
542 }
543 else
544 {
545 old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
546 if (!old->valid)
547 { // should never happen
548 Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
549 }
550 if (old->serverframe != cl.frame.deltaframe)
551 { // The frame that the server did the delta from
552 // is too old, so we can't reconstruct it properly.
553 Com_Printf ("Delta frame too old.\n");
554 }
555 else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128)
556 {
557 Com_Printf ("Delta parse_entities too old.\n");
558 }
559 else
560 cl.frame.valid = true; // valid delta parse
561 }
562
563 // clamp time
564 if (cl.time > cl.frame.servertime)
565 cl.time = cl.frame.servertime;
566 else if (cl.time < cl.frame.servertime - 100)
567 cl.time = cl.frame.servertime - 100;
568
569 // read areabits
570 len = MSG_ReadByte (&net_message);
571 MSG_ReadData (&net_message, &new_areabits, len);
572 if (memcmp (cl.frame.areabits, new_areabits, len))
573 {
574 memcpy (cl.frame.areabits, new_areabits, len);
575 cl.refdef.areabits_changed = true;
576 }
577
578 // read playerinfo
579 cmd = MSG_ReadByte (&net_message);
580 SHOWNET(svc_strings[cmd]);
581 if (cmd != svc_playerinfo)
582 Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo");
583 CL_ParsePlayerstate (old, &cl.frame);
584
585 // read packet entities
586 cmd = MSG_ReadByte (&net_message);
587 SHOWNET(svc_strings[cmd]);
588 if (cmd != svc_packetentities)
589 Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities");
590 CL_ParsePacketEntities (old, &cl.frame);
591
592 // save the frame off in the backup array for later delta comparisons
593 cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
594
595 if (cl.frame.valid)
596 {
597 // getting a valid frame message ends the connection process
598 if (cls.state != ca_active)
599 {
600 cls.state = ca_active;
601 cl.force_refdef = true;
602 cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125;
603 cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125;
604 cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125;
605 VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
606 if (cls.disable_servercount != cl.servercount
607 && cl.refresh_prepped)
608 SCR_EndLoadingPlaque (); // get rid of loading plaque
609 }
610 cl.sound_prepped = true; // can start mixing ambient sounds
611
612 // fire entity events
613 CL_FireEntityEvents (&cl.frame);
614 CL_CheckPredictionError ();
615 }
616 }
617
618 /*
619 ==========================================================================
620
621 INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS
622
623 ==========================================================================
624 */
625
626 /*
627 ===============
628 CL_AddPacketEntities
629
630 ===============
631 */
632 struct model_s
633 {
634 char name[MAX_QPATH];
635 };
636
CL_AddPacketEntities(frame_t * frame)637 void CL_AddPacketEntities (frame_t *frame)
638 {
639 entity_t ent;
640 entity_state_t *s1;
641 float autorotate;
642 float bob, bob_scale;
643 int i;
644 int pnum;
645 centity_t *cent;
646 int autoanim;
647 clientinfo_t *ci;
648 unsigned int effects, renderfx;
649 qboolean playermodel;
650
651 // bonus items rotate at a fixed rate
652 autorotate = anglemod(cl.time/10);
653
654 // brush models can auto animate their frames
655 autoanim = 2*cl.time/1000;
656
657 memset (&ent, 0, sizeof(ent));
658
659 for (pnum = 0 ; pnum<frame->num_entities ; pnum++)
660 {
661 s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)];
662
663 cent = &cl_entities[s1->number];
664
665 ent.number = s1->number;
666
667 playermodel = false;
668
669 effects = s1->effects;
670 renderfx = s1->renderfx;
671
672 // set frame
673 if (effects & EF_ANIM01)
674 ent.frame = autoanim & 1;
675 else if (effects & EF_ANIM23)
676 ent.frame = 2 + (autoanim & 1);
677 else if (effects & EF_ANIM_ALL)
678 ent.frame = autoanim;
679 else if (effects & EF_ANIM_ALLFAST)
680 ent.frame = cl.time / 100;
681 else
682 ent.frame = s1->frame;
683
684 // quad and pent can do different things on client
685 if (effects & EF_PENT)
686 {
687 effects &= ~EF_PENT;
688 effects |= EF_COLOR_SHELL;
689 renderfx |= RF_SHELL_RED;
690 }
691
692 if (effects & EF_QUAD)
693 {
694 effects &= ~EF_QUAD;
695 effects |= EF_COLOR_SHELL;
696 renderfx |= RF_SHELL_BLUE;
697 }
698
699 ent.oldframe = cent->prev.frame;
700 ent.backlerp = 1.0 - cl.lerpfrac;
701
702 //animation timestamps are set here
703 if(cent->prevframe != s1->frame) {
704 cent->prevframe = s1->frame;
705 cent->frametime = Sys_Milliseconds();
706 }
707 ent.prevframe = cent->prevframe;
708 ent.frametime = cent->frametime;
709
710 // create a new entity
711
712 ent.lod1 = NULL;
713 ent.lod2 = NULL;
714 ent.team = 0;
715
716 // set skin
717 if (s1->modelindex == 255)
718 { // use custom player skin
719 ent.skinnum = 0;
720 ci = &cl.clientinfo[s1->skinnum & 0xff];
721 ent.skin = ci->skin;
722 ent.model = ci->model;
723
724 ent.lod1 = ci->lod1;
725
726 ent.lod2 = ci->lod2;
727
728 if (!ent.skin || !ent.model)
729 {
730 ent.skin = cl.baseclientinfo.skin;
731 ent.model = cl.baseclientinfo.model;
732 }
733 playermodel = true;
734
735 strcpy(ent.name, ci->name);
736
737 }
738 else
739 {
740 ent.skinnum = s1->skinnum;
741 ent.skin = NULL;
742 ent.model = cl.model_draw[s1->modelindex];
743 }
744
745 if (renderfx & (RF_FRAMELERP))
746 { // step origin discretely, because the frames
747 // do the animation properly
748 VectorCopy (cent->current.origin, ent.origin);
749 VectorCopy (cent->current.old_origin, ent.oldorigin);
750 }
751 else if (s1->number == cl.playernum+1)
752 {
753 for (i=0; i<3; i++) {
754 ent.origin[i] = ent.oldorigin[i] = cent->current.origin[i] + cl.lerpfrac *
755 (cent->current.origin[i] - cent->prev.origin[i]);
756 }
757 }
758 else
759 { // interpolate origin
760 for (i=0 ; i<3 ; i++)
761 {
762 ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac *
763 (cent->current.origin[i] - cent->prev.origin[i]);
764 }
765 }
766
767 // calculate angles
768 if (effects & EF_ROTATE)
769 { // some bonus items auto-rotate
770 ent.angles[0] = 0;
771 ent.angles[1] = autorotate;
772 ent.angles[2] = 0;
773 // bobbing items
774 bob_scale = (0.005f + s1->number * 0.00001f) * 0.5;
775 bob = 5 + cos( (cl.time + 1000) * bob_scale ) * 5;
776 ent.oldorigin[2] += bob;
777 ent.origin[2] += bob;
778
779 ent.bob = bob;
780
781 renderfx |= RF_BOBBING;
782 }
783 else
784 { // interpolate angles
785 float a1, a2;
786
787 for (i=0 ; i<3 ; i++)
788 {
789 a1 = cent->current.angles[i];
790 a2 = cent->prev.angles[i];
791 ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac);
792 }
793 }
794
795 // render effects (fullbright, translucent, etc)
796 if ((effects & EF_COLOR_SHELL))
797 ent.flags = 0; // renderfx go on color shell entity
798 else
799 ent.flags = renderfx;
800
801 if (s1->number == cl.playernum+1)
802 {
803 ent.flags |= RF_VIEWERMODEL; // only draw from mirrors
804 // fixed player origin - fixes the "jittery" player shadows too
805 if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))
806 {
807 VectorCopy (cl.predicted_origin, ent.origin);
808 VectorCopy (cl.predicted_origin, ent.oldorigin);
809 }
810
811 }
812
813 // Sigh, this is the reason for the RF_NODRAW workaround.
814 #if 1 // TODO: replace this with an IFDEF for non Alien Arena CRX games
815 // if set to invisible, skip
816 if (!s1->modelindex)
817 continue;
818 #endif
819
820 if (effects & EF_PLASMA)
821 {
822 ent.flags |= RF_TRANSLUCENT;
823 ent.alpha = 0.6;
824 }
825
826 if (effects & EF_BUBBLES)
827 {
828 CL_PoweredEffects (ent.origin);
829 }
830
831 //cool new ctf flag effects
832 if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/flags/flag1.md2"))
833 {
834 CL_FlagEffects(ent.origin, 0);
835 ent.team = 1;
836 }
837 else if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/flags/flag2.md2"))
838 {
839 CL_FlagEffects(ent.origin, 1);
840 ent.team = 2;
841 }
842
843 if (s1->modelindex != 0 && !(renderfx & RF_NODRAW))
844 {
845 // add to refresh list
846 V_AddEntity (&ent);
847
848 // color shells generate a seperate entity for the main model
849 if ((effects & EF_COLOR_SHELL) && !(s1->number == cl.playernum+1))
850 {
851
852 ent.flags = renderfx | RF_TRANSLUCENT;
853 ent.alpha = 0.30;
854 V_AddViewEntity (&ent);
855 }
856 }
857
858 ent.skin = NULL; // never use a custom skin on others
859 ent.skinnum = 0;
860 ent.flags = 0;
861 ent.alpha = 0;
862 ent.lod1 = NULL; // only player models get lods
863 ent.lod2 = NULL;
864 ent.team = 0;
865
866 ci = &cl.clientinfo[s1->skinnum & 0xff];
867
868 if (s1->modelindex != 0 && !(renderfx & RF_NODRAW))
869 {
870 //give health an "aura"
871 if(cl_healthaura->value && !cl_simpleitems->value)
872 {
873 if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/healing/small/tris.md2"))
874 CL_SmallHealthParticles(ent.origin);
875 if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/healing/medium/tris.md2"))
876 CL_MedHealthParticles(ent.origin);
877 if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/items/healing/large/tris.md2"))
878 CL_LargeHealthParticles(ent.origin);
879 }
880
881 if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/weapons/g_rocket/tris.md2"))
882 {
883 //add clear cover
884 if (!cl_simpleitems->integer)
885 {
886 ent.model = R_RegisterModel("models/weapons/g_rocket/cover.md2");
887 ent.flags |= RF_TRANSLUCENT;
888 ent.alpha = 0.30;
889 V_AddEntity (&ent);
890 }
891 }
892 if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex)], "models/weapons/g_hyperb/tris.md2"))
893 {
894 //add clear cover
895 if (!cl_simpleitems->integer)
896 {
897 ent.model = R_RegisterModel("models/weapons/g_hyperb/cover.md2");
898 ent.flags |= RF_TRANSLUCENT;
899 ent.alpha = 0.30;
900 V_AddEntity (&ent);
901 }
902 }
903 }
904
905 if (s1->modelindex2)
906 {
907 if (s1->modelindex2 == 255 || (ci->helmet && playermodel))
908 { // custom weapon
909
910 i = (s1->skinnum >> 8); // 0 is default weapon model
911 if (!cl_vwep->value || i > MAX_CLIENTWEAPONMODELS - 1)
912 i = 0;
913 ent.model = ci->weaponmodel[i];
914 if (!ent.model)
915 {
916 if (i != 0)
917 ent.model = ci->weaponmodel[0];
918 if (!ent.model)
919 ent.model = cl.baseclientinfo.weaponmodel[0];
920 }
921 }
922 else
923 {
924 ent.model = cl.model_draw[s1->modelindex2];
925 }
926
927 //here is where we will set the alpha for certain model parts - would like to eventually
928 //do something a little less uh, hardcoded.
929 if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex2)], "models/items/healing/globe/tris.md2"))
930 {
931 if(cl_simpleitems->value)
932 continue;
933 ent.alpha = 0.4;
934 ent.flags = RF_TRANSLUCENT;
935 }
936 else if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex2)], "models/items/quaddama/unit.md2"))
937 {
938 if(cl_simpleitems->value)
939 continue;
940 ent.alpha = 0.4;
941 ent.flags = RF_TRANSLUCENT;
942 }
943
944 if (s1->number == cl.playernum+1)
945 ent.flags |= RF_VIEWERMODEL;
946
947 V_AddEntity (&ent);
948
949 //PGM - make sure these get reset.
950 ent.flags = 0;
951 ent.alpha = 0;
952 //PGM
953
954 }
955
956 if (s1->modelindex3 || (ci->helmet && playermodel)) //index 3 is only used for clear entities now, no need for all that checking
957 {
958 if(ci->helmet && playermodel)
959 ent.model = ci->helmet;
960 else
961 ent.model = cl.model_draw[s1->modelindex3];
962
963 ent.alpha = 0.4;
964 ent.flags = RF_TRANSLUCENT;
965
966 if (s1->number == cl.playernum+1) {
967 ent.flags |= RF_VIEWERMODEL;
968 }
969 V_AddEntity (&ent);
970 }
971
972 if (s1->number == cl.playernum+1)
973 goto end;
974
975 if (s1->modelindex4)
976 {
977 ent.flags = 0;
978 ent.alpha = 1.0;
979
980 //new ctf flag effects
981 if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex4)], "models/items/flags/flag1.md2"))
982 {
983 CL_FlagEffects(ent.origin, 0);
984 ent.model = 0;
985 }
986 else if (!Q_strcasecmp (cl.configstrings[CS_MODELS+(s1->modelindex4)], "models/items/flags/flag2.md2"))
987 {
988 CL_FlagEffects(ent.origin, 1);
989 ent.model = 0;
990 }
991 else
992 {
993 ent.model = cl.model_draw[s1->modelindex4];
994 V_AddEntity (&ent);
995 }
996 }
997
998 // add automatic particle trails
999 if ( (effects&~EF_ROTATE) )
1000 {
1001 if (effects & EF_ROCKET)
1002 {
1003 CL_RocketTrail (cent->lerp_origin, ent.origin, cent);
1004 V_AddLight (ent.origin, 200, .4, .4, .1);
1005 }
1006 if (effects & EF_SHIPEXHAUST)
1007 {
1008 CL_ShipExhaust (cent->lerp_origin, ent.origin, cent);
1009 }
1010 if (effects & EF_ROCKETEXHAUST)
1011 {
1012 CL_RocketExhaust (cent->lerp_origin, ent.origin, cent);
1013 }
1014 else if (effects & EF_HYPERBLASTER)
1015 {
1016 V_AddLight (ent.origin, 400*crand(), 1, 0, 1);
1017 }
1018 else if (effects & EF_GIB)
1019 {
1020 CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
1021 }
1022 else if (effects & EF_GRENADE)
1023 {
1024 CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
1025 }
1026 else if (effects & EF_TEAM1)
1027 {
1028 vec3_t right;
1029 vec3_t start;
1030 vec3_t up;
1031
1032 AngleVectors (ent.angles, NULL, right, up);
1033 VectorMA (ent.origin, 16, right, start);
1034 VectorMA (start, 32, up, start);
1035 CL_RedTeamLight(start);
1036
1037 VectorMA (ent.origin, -16, right, start);
1038 VectorMA (start, 32, up, start);
1039 CL_RedTeamLight(start);
1040 }
1041 else if (effects & EF_TEAM2)
1042 {
1043
1044 vec3_t right;
1045 vec3_t start;
1046 vec3_t up;
1047
1048 AngleVectors (ent.angles, NULL, right, up);
1049 VectorMA (ent.origin, 16, right, start);
1050 VectorMA (start, 32, up, start);
1051 CL_BlueTeamLight(start);
1052
1053 VectorMA (ent.origin, -16, right, start);
1054 VectorMA (start, 32, up, start);
1055 CL_BlueTeamLight(start);
1056 }
1057
1058 else if (effects & EF_GREENGIB)
1059 {
1060 CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects);
1061 }
1062
1063 else if (effects & EF_PLASMA)
1064 {
1065 CL_BlasterBall (cent->lerp_origin, ent.origin);
1066 V_AddLight (ent.origin, 200, 0, 1, 1);
1067 }
1068 else if (effects & EF_BLASTER)
1069 {
1070 CL_BlasterTrail(cent->lerp_origin, ent.origin, cent);
1071 V_AddLight (ent.origin, 200, 0, .5, .1);
1072 }
1073 }
1074 end:
1075 VectorCopy (ent.origin, cent->lerp_origin);
1076 }
1077 }
1078
1079 /*
1080 =======================
1081 Berserker@quake2 shell
1082 brass effect. No change
1083 =======================
1084 */
1085
CL_BrassShells(vec3_t org,vec3_t dir,int count)1086 void CL_BrassShells(vec3_t org, vec3_t dir, int count)
1087 {
1088 int i, j;
1089 clentity_t *le;
1090 float d;
1091
1092 if (!cl_brass->value || !count)
1093 return;
1094
1095 for (i = 0; i < count; i++) {
1096
1097 if (!free_clentities)
1098 return;
1099
1100 le = free_clentities;
1101 free_clentities = le->next;
1102 le->next = active_clentities;
1103 active_clentities = le;
1104 le->time = cl.time;
1105 d = (192 + rand()) & 63;
1106 VectorClear(le->accel);
1107 VectorClear(le->vel);
1108 le->accel[0] = le->accel[1] = 0;
1109 le->accel[2] = -6 * PARTICLE_GRAVITY;
1110 le->alpha = 1.0;
1111 le->alphavel = -0.1;
1112 le->flags = CLM_BOUNCE | CLM_FRICTION | CLM_ROTATE | CLM_NOSHADOW | CLM_BRASS;
1113 le->model = R_RegisterModel("models/objects/brass/tris.md2");
1114 le->ang = crand() * 360;
1115 le->avel = crand() * 500;
1116
1117 for (j = 0; j < 3; j++) {
1118 le->lastOrg[j] = le->org[j] = org[j];
1119 le->vel[j] = crand() * 24 + d * dir[j];
1120 }
1121 }
1122 }
1123
CL_GlassShards(vec3_t org,vec3_t dir,int count)1124 void CL_GlassShards(vec3_t org, vec3_t dir, int count)
1125 {
1126 int i, j;
1127 clentity_t *le;
1128 float d;
1129
1130 if (!count)
1131 return;
1132
1133 for (i = 0; i < count; i++) {
1134
1135 if (!free_clentities)
1136 return;
1137
1138 le = free_clentities;
1139 free_clentities = le->next;
1140 le->next = active_clentities;
1141 active_clentities = le;
1142 le->time = cl.time;
1143 d = (192 + rand()) & 13;
1144 VectorClear(le->accel);
1145 VectorClear(le->vel);
1146 le->accel[0] = le->accel[1] = 0;
1147 le->accel[2] = -3 * PARTICLE_GRAVITY;
1148 le->alpha = 1.0;
1149 le->alphavel = -0.01;
1150 le->flags = CLM_BOUNCE | CLM_FRICTION | CLM_ROTATE | CLM_NOSHADOW | CLM_GLASS;
1151 le->model = R_RegisterModel("models/objects/debris1/tris.md2");
1152 le->ang = crand() * 360;
1153 le->avel = crand() * 500;
1154
1155 for (j = 0; j < 3; j++) {
1156 le->lastOrg[j] = le->org[j] = org[j];
1157 le->vel[j] = crand() * 12 + d * dir[j];
1158 }
1159 }
1160 }
1161
1162 /*
1163 ==============
1164 CL_AddViewWeapon
1165 ==============
1166 */
1167
CL_AddViewWeapon(player_state_t * ps,player_state_t * ops)1168 void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops)
1169 {
1170 entity_t gun; // view model
1171 int i;
1172 qboolean useFX = false;
1173 vec3_t offset_down;
1174 vec3_t offset_right;
1175
1176 memset (&gun, 0, sizeof(gun));
1177
1178 gun.model = cl.model_draw[ps->gunindex];
1179
1180 gun.lod1 = NULL;
1181 gun.lod2 = NULL;
1182
1183 if (!gun.model)
1184 return;
1185
1186 //if a vehicle console, we want to render as a 2D HUD now, if a player choses to
1187 if(cl_vehicle_huds->value)
1188 {
1189 if(!(strcmp("vehicles/bomber/v_wep.md2", gun.model->name)))
1190 {
1191 vehicle_hud = 1;
1192 return;
1193 }
1194 else if(!(strcmp("vehicles/strafer/v_wep.md2", gun.model->name)))
1195 {
1196 vehicle_hud = 2;
1197 return;
1198 }
1199 else if(!(strcmp("vehicles/hover/v_wep.md2", gun.model->name)))
1200 {
1201 vehicle_hud = 3;
1202 return;
1203 }
1204 else
1205 vehicle_hud = 0;
1206 }
1207 else
1208 vehicle_hud = 0;
1209
1210 // nudge gun down and right if in wide angle view
1211 if(cl.refdef.fov_x > 90)
1212 {
1213 VectorScale(cl.v_up, 0.2 * (cl.refdef.fov_x - 90), offset_down);
1214 VectorScale(cl.v_right, -0.15 * (cl.refdef.fov_x - 90), offset_right);
1215 }
1216 else
1217 offset_down[0] = offset_down[1] = offset_down[2] = offset_right[0] = offset_right[1] = offset_right[2] = 0;
1218
1219 // set up gun position
1220 for (i=0 ; i<3 ; i++)
1221 {
1222 gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i]
1223 + cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]);
1224 gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i],
1225 ps->gunangles[i], cl.lerpfrac);
1226 }
1227
1228 gun.frame = ps->gunframe;
1229 if (gun.frame == 0)
1230 gun.oldframe = 0; // just changed weapons, don't lerp from old
1231 else
1232 gun.oldframe = ops->gunframe;
1233
1234 VectorSubtract(gun.origin, offset_down, gun.origin);
1235 VectorSubtract(gun.origin, offset_right, gun.origin);
1236
1237 gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL;
1238 gun.backlerp = 1.0 - cl.lerpfrac;
1239 VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all
1240
1241 //add an attached muzzleflash for chaingun
1242 if(!(strcmp("models/weapons/v_shotg2/tris.md2", gun.model->name)))
1243 {
1244 if(gun.frame > 4 && gun.frame < 14)
1245 CL_MuzzleFlashParticle(gun.origin, gun.angles, true);
1246 }
1247 else if(!(strcmp("models/weapons/v_hyperb/tris.md2", gun.model->name)))
1248 {
1249 if(gun.frame > 5 && gun.frame < 7) {
1250 CL_PlasmaFlashParticle(gun.origin, gun.angles, true);
1251 useFX = true;
1252 }
1253 }
1254
1255 V_AddViewEntity (&gun);
1256 //add shells for viewweaps (all of em!)
1257 {
1258 int oldeffects = gun.flags, pnum;
1259 entity_state_t *s1;
1260
1261 for (pnum = 0 ; pnum<cl.frame.num_entities ; pnum++)
1262 if ((s1=&cl_parse_entities[(cl.frame.parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)])->number == cl.playernum+1)
1263 {
1264 int effects = s1->renderfx;
1265
1266 if (effects & (RF_SHELL_RED|RF_SHELL_BLUE|RF_SHELL_GREEN) || s1->effects&(EF_PENT|EF_QUAD) || useFX)
1267 {
1268 if (effects & RF_SHELL_RED)
1269 gun.flags |= RF_SHELL_RED;
1270 if (effects & RF_SHELL_BLUE)
1271 gun.flags |= RF_SHELL_BLUE;
1272 if (effects & RF_SHELL_GREEN)
1273 gun.flags |= RF_SHELL_GREEN;
1274
1275 if (useFX)
1276 gun.flags |= RF_SHELL_GREEN;
1277
1278 gun.flags |= RF_TRANSLUCENT;
1279 gun.alpha = 0.30;
1280
1281 if ( ( s1->effects & EF_COLOR_SHELL && gun.flags & (RF_SHELL_RED|RF_SHELL_BLUE|RF_SHELL_GREEN) ) || useFX)
1282 {
1283 V_AddViewEntity (&gun);
1284 }
1285 if (s1->effects & EF_PENT)
1286 {
1287 gun.flags = oldeffects | RF_TRANSLUCENT | RF_SHELL_RED;
1288
1289
1290 V_AddViewEntity (&gun);
1291 }
1292 if (s1->effects & EF_QUAD && cl_gun->value)
1293 {
1294 gun.flags = oldeffects | RF_TRANSLUCENT | RF_SHELL_BLUE;
1295
1296 V_AddViewEntity (&gun);
1297 }
1298 }
1299 }
1300
1301 gun.flags = oldeffects;
1302 }
1303
1304 //add glass pieces
1305
1306 if(!(strcmp("models/weapons/v_rocket/tris.md2", gun.model->name)))
1307 {
1308 gun.model = R_RegisterModel("models/weapons/v_rocket/cover.md2");
1309 gun.flags |= RF_TRANSLUCENT;
1310 gun.alpha = 0.30;
1311 V_AddViewEntity (&gun);
1312 }
1313 if(!(strcmp("models/weapons/v_hyperb/tris.md2", gun.model->name)))
1314 {
1315 gun.model = R_RegisterModel("models/weapons/v_hyperb/cover.md2");
1316 gun.flags |= RF_TRANSLUCENT;
1317 gun.alpha = 0.30;
1318 V_AddViewEntity (&gun);
1319 }
1320 if(!(strcmp("models/weapons/v_blast/tris.md2", gun.model->name)))
1321 {
1322 gun.model = R_RegisterModel("models/weapons/v_blast/cover.md2");
1323 gun.flags |= RF_TRANSLUCENT;
1324 gun.alpha = 0.30;
1325 V_AddViewEntity (&gun);
1326 }
1327 if(!(strcmp("models/weapons/v_alienblast/tris.md2", gun.model->name)))
1328 {
1329 gun.model = R_RegisterModel("models/weapons/v_alienblast/cover.md2");
1330 gun.flags |= RF_TRANSLUCENT;
1331 gun.alpha = 0.30;
1332 V_AddViewEntity (&gun);
1333 }
1334 }
1335
1336
1337 /*
1338 ===============
1339 CL_CalcViewValues
1340
1341 Sets cl.refdef view values
1342 ===============
1343 */
CL_CalcViewValues(void)1344 void CL_CalcViewValues (void)
1345 {
1346 int i;
1347 float lerp, backlerp;
1348 centity_t *ent;
1349 frame_t *oldframe;
1350 player_state_t *ps, *ops;
1351
1352 // find the previous frame to interpolate from
1353 ps = &cl.frame.playerstate;
1354 i = (cl.frame.serverframe - 1) & UPDATE_MASK;
1355 oldframe = &cl.frames[i];
1356 if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid)
1357 oldframe = &cl.frame; // previous frame was dropped or involid
1358 ops = &oldframe->playerstate;
1359
1360 // see if the player entity was teleported this frame
1361 if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8
1362 || abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8
1363 || abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8)
1364 ops = ps; // don't interpolate
1365
1366 ent = &cl_entities[cl.playernum+1];
1367 lerp = cl.lerpfrac;
1368
1369 // calculate the origin
1370 if ( !cl.attractloop && !ps->stats[STAT_CHASE] && cl_predict->value && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION)) //not for demo/chasecam
1371 { // use predicted values
1372 unsigned delta;
1373
1374 backlerp = 1.0 - lerp;
1375 for (i=0 ; i<3 ; i++)
1376 {
1377 cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i]
1378 + cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i])
1379 - backlerp * cl.prediction_error[i];
1380 }
1381
1382 // smooth out stair climbing
1383 delta = cls.realtime - cl.predicted_step_time;
1384 if (delta < 100)
1385 cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01;
1386 }
1387 else
1388 { // just use interpolated values
1389 for (i=0 ; i<3 ; i++)
1390 cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i]
1391 + lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i]
1392 - (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) );
1393 }
1394
1395 // if not running a demo or on a locked frame, add the local angle movement
1396 if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD )
1397 { // use predicted values
1398 for (i=0 ; i<3 ; i++)
1399 cl.refdef.viewangles[i] = cl.predicted_angles[i];
1400 }
1401 else
1402 { // just use interpolated values
1403 for (i=0 ; i<3 ; i++)
1404 cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp);
1405 }
1406
1407 for (i=0 ; i<3 ; i++)
1408 cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp);
1409
1410 AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up);
1411
1412 // interpolate field of view
1413 cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov);
1414
1415 // don't interpolate blend color
1416 for (i=0 ; i<4 ; i++)
1417 cl.refdef.blend[i] = ps->blend[i];
1418
1419 // add the weapon
1420 CL_AddViewWeapon (ps, ops);
1421 }
1422
1423 /*
1424 ===============
1425 CL_AddEntities
1426
1427 Emits all entities, particles, and lights to the refresh
1428 ===============
1429 */
CL_AddEntities(void)1430 void CL_AddEntities (void)
1431 {
1432 if (cls.state != ca_active)
1433 return;
1434
1435 if (cl.time > cl.frame.servertime)
1436 {
1437 if (cl_showclamp->value)
1438 Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime);
1439 cl.time = cl.frame.servertime;
1440 cl.lerpfrac = 1.0;
1441 }
1442 else if (cl.time < cl.frame.servertime - 100)
1443 {
1444 if (cl_showclamp->value)
1445 Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time);
1446 cl.time = cl.frame.servertime - 100;
1447 cl.lerpfrac = 0;
1448 }
1449 else
1450 cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01;
1451
1452 if (cl_timedemo->value)
1453 cl.lerpfrac = 1.0;
1454
1455 CL_CalcViewValues ();
1456
1457 // PMM - moved this here so the heat beam has the right values for the vieworg, and can lock the beam to the gun
1458 CL_AddPacketEntities (&cl.frame);
1459 CL_AddTEnts ();
1460 CL_AddParticles ();
1461 CL_AddDLights ();
1462 CL_AddClEntities();
1463 CL_AddLightStyles ();
1464 }
1465
1466
1467
1468 /*
1469 ===============
1470 CL_GetEntitySoundOrigin
1471
1472 Called to get the sound spatialization origin
1473 ===============
1474 */
CL_GetEntitySoundOrigin(int ent,vec3_t org)1475 void CL_GetEntitySoundOrigin (int ent, vec3_t org)
1476 {
1477 centity_t *old;
1478
1479 if (ent < 0 || ent >= MAX_EDICTS)
1480 Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent");
1481 old = &cl_entities[ent];
1482 VectorCopy (old->lerp_origin, org);
1483
1484 // FIXME: bmodel issues...
1485 }
1486
1487 /*
1488 ================
1489 Client side entities(ejecting brass, etc
1490 ================
1491 */
1492
1493 /*
1494 -----------------------------
1495 ClipMoveEntitiesWorld
1496 -----------------------------
1497 */
CL_ClipMoveToEntitiesWorld(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,trace_t * tr,int mask)1498 void CL_ClipMoveToEntitiesWorld(vec3_t start, vec3_t mins, vec3_t maxs,
1499 vec3_t end, trace_t * tr, int mask)
1500 {
1501 int i;
1502 trace_t trace;
1503 int headnode;
1504 float *angles;
1505 entity_state_t *ent;
1506 int num;
1507 cmodel_t *cmodel;
1508
1509 for (i = 0; i < cl.frame.num_entities; i++) {
1510 num = (cl.frame.parse_entities + i) & (MAX_PARSE_ENTITIES - 1);
1511 ent = &cl_parse_entities[num];
1512
1513 if (!ent->solid)
1514 continue;
1515
1516 if (ent->solid != 31) // special value for bmodel
1517 continue;
1518
1519 cmodel = cl.model_clip[ent->modelindex];
1520 if (!cmodel)
1521 continue;
1522 headnode = cmodel->headnode;
1523 angles = ent->angles;
1524
1525 if (tr->allsolid)
1526 return;
1527
1528 trace =
1529 CM_TransformedBoxTrace(start, end, mins, maxs, headnode, mask,
1530 ent->origin, angles);
1531
1532 if (trace.allsolid || trace.startsolid
1533 || trace.fraction < tr->fraction) {
1534 trace.ent = (struct edict_s *) ent;
1535 if (tr->startsolid) {
1536 *tr = trace;
1537 tr->startsolid = true;
1538 } else
1539 *tr = trace;
1540 } else if (trace.startsolid)
1541 tr->startsolid = true;
1542 }
1543 }
1544
1545
CL_PMTraceWorld(vec3_t start,vec3_t mins,vec3_t maxs,vec3_t end,int mask)1546 trace_t CL_PMTraceWorld(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end,
1547 int mask)
1548 {
1549 trace_t t;
1550
1551 // check against world
1552 t = CM_BoxTrace(start, end, mins, maxs, 0, mask);
1553 if (t.fraction < 1.0)
1554 t.ent = (struct edict_s *) 1;
1555
1556 // check all other solid models
1557 CL_ClipMoveToEntitiesWorld(start, mins, maxs, end, &t, mask);
1558
1559 return t;
1560 }
1561
VectorReflect(const vec3_t v,const vec3_t normal,vec3_t out)1562 void VectorReflect(const vec3_t v, const vec3_t normal, vec3_t out)
1563 {
1564 float d;
1565
1566 d = 2.0 * (v[0] * normal[0] + v[1] * normal[1] + v[2] * normal[2]);
1567
1568 out[0] = v[0] - normal[0] * d;
1569 out[1] = v[1] - normal[1] * d;
1570 out[2] = v[2] - normal[2] * d;
1571 }
1572
1573 extern int CL_PMpointcontents (vec3_t point);
CL_AddClEntities()1574 void CL_AddClEntities()
1575 {
1576 entity_t ent;
1577 clentity_t *le, *next;
1578 clentity_t *active, *tail;
1579 vec3_t org, dir;
1580 float alpha, bak;
1581 int contents;
1582 qboolean onground;
1583 char soundname[64];
1584 float time, time2, grav = Cvar_VariableValue("sv_gravity");
1585 static vec3_t mins = { -2, -2, -2 };
1586 static vec3_t maxs = { 2, 2, 2 };
1587
1588 if (!grav)
1589 grav = 1;
1590 else
1591 grav /= 800;
1592
1593 active = NULL;
1594 tail = NULL;
1595
1596 memset(&ent, 0, sizeof(ent));
1597
1598 for (le = active_clentities; le; le = next) {
1599 next = le->next;
1600
1601 time = (cl.time - le->time) * 0.001;
1602 alpha = le->alpha + time * le->alphavel;
1603
1604 if (alpha <= 0) { // faded out
1605 le->next = free_clentities;
1606 free_clentities = le;
1607 continue;
1608 }
1609
1610 time2 = time * time;
1611 org[0] = le->org[0] + le->vel[0] * time + le->accel[0] * time2;
1612 org[1] = le->org[1] + le->vel[1] * time + le->accel[1] * time2;
1613 bak = le->org[2] + le->vel[2] * time + le->accel[2] * time2 * grav;
1614
1615 org[2] = bak - 1;
1616 contents = CL_PMpointcontents(org);
1617 org[2] = bak;
1618 onground = contents & MASK_SOLID;
1619 if (onground) {
1620 le->flags &= ~CLM_ROTATE;
1621 le->avel = 0;
1622 } else if (le->flags & CLM_STOPPED) {
1623 le->flags &= ~CLM_STOPPED;
1624 le->flags |= CLM_BOUNCE;
1625 le->accel[2] = -15 * PARTICLE_GRAVITY;
1626 // Reset
1627 le->alpha = 1;
1628 le->time = cl.time;
1629 VectorCopy(org, le->org);
1630 }
1631
1632 le->next = NULL;
1633 if (!tail)
1634 active = tail = le;
1635 else {
1636 tail->next = le;
1637 tail = le;
1638 }
1639
1640 if (alpha > 1.0)
1641 alpha = 1;
1642
1643 if(le->flags & CLM_NOSHADOW)
1644 ent.flags |= RF_NOSHADOWS;
1645
1646 if (le->flags & CLM_FRICTION) {
1647 // Water friction affected cl model
1648 if (contents & MASK_WATER) {
1649 if (contents & CONTENTS_LAVA) { // kill entity in lava
1650 VectorSet(dir, 0, 0, 1);
1651 le->alpha = 0;
1652 continue;
1653 } else {
1654 // Add friction
1655 VectorScale(le->vel, 0.25, le->vel);
1656 VectorScale(le->accel, 0.25, le->accel);
1657
1658 // Don't add friction again
1659 le->flags &= ~(CLM_FRICTION | CLM_ROTATE);
1660
1661 // Reset
1662 le->time = cl.time;
1663 VectorCopy(org, le->org);
1664 }
1665 }
1666 }
1667
1668 if (le->flags & CLM_BOUNCE)
1669 {
1670 trace_t trace = CL_PMTraceWorld (le->lastOrg, mins, maxs, org, MASK_SOLID);
1671
1672 if (trace.fraction > 0.0001f && trace.fraction < 0.9999f )
1673 {
1674 vec3_t vel;
1675 // Reflect velocity
1676 float time =
1677 cl.time - (cls.frametime +
1678 cls.frametime * trace.fraction) * 1000;
1679 time = (time - le->time) * 0.001;
1680
1681 VectorSet(vel, le->vel[0], le->vel[1], le->vel[2] + le->accel[2] * time * grav);
1682 VectorReflect(vel, trace.plane.normal, le->vel);
1683
1684 // Check for stop or slide along the plane
1685 if (trace.plane.normal[2] > 0 && le->vel[2] < 1)
1686 {
1687 if (trace.plane.normal[2] > 0.9)
1688 {
1689 VectorClear(le->vel);
1690 VectorClear(le->accel);
1691 le->avel = 0;
1692 le->flags &= ~CLM_BOUNCE;
1693 le->flags |= CLM_STOPPED;
1694 }
1695 else
1696 {
1697 // FIXME: check for new plane or free fall
1698 float dot = DotProduct(le->vel, trace.plane.normal);
1699 VectorMA(le->vel, -dot, trace.plane.normal, le->vel);
1700
1701 dot = DotProduct(le->accel, trace.plane.normal);
1702 VectorMA(le->accel, -dot, trace.plane.normal, le->accel);
1703 }
1704 }
1705
1706 VectorCopy(trace.endpos, org);
1707
1708 // Reset
1709 le->time = cl.time;
1710 VectorCopy(org, le->org);
1711
1712 //play a sound if brass
1713 if ( (le->flags & (CLM_BRASS)) && (le->flags & (CLM_BOUNCE)) ) {
1714 Com_sprintf(soundname, sizeof(soundname), "weapons/clink0%i.wav", (rand() % 2) + 1);
1715 S_StartSound (le->org, 0, CHAN_WEAPON, S_RegisterSound(soundname), 1.0, ATTN_NORM, 0);
1716 }
1717
1718 //play a sound if glass
1719 if ( (le->flags & (CLM_GLASS)) && (le->flags & (CLM_BOUNCE)) ) {
1720 Com_sprintf(soundname, sizeof(soundname), "weapons/clink0%i.wav", (rand() % 2) + 1); //to do - get glass sound
1721 S_StartSound (le->org, 0, CHAN_WEAPON, S_RegisterSound(soundname), 1.0, ATTN_NORM, 0);
1722 }
1723 }
1724 }
1725 // Save current origin if needed
1726 if (le->flags & (CLM_BOUNCE)) {
1727 VectorCopy(le->lastOrg, ent.origin);
1728 VectorCopy(org, le->lastOrg); // FIXME: pause
1729 } else
1730 VectorCopy(org, ent.origin);
1731
1732 if (CL_PMpointcontents(ent.origin) & MASK_SOLID) { // kill entity
1733 // in solid
1734 le->alpha = 0;
1735 continue;
1736 }
1737
1738 ent.model = le->model;
1739 if (!ent.model)
1740 continue;
1741
1742 ent.lod1 = NULL;
1743 ent.lod2 = NULL;
1744
1745 ent.angles[0] = le->ang +
1746 ((le->flags & CLM_ROTATE) ? (time * le->avel) : 0);;
1747 ent.angles[2] = le->ang +
1748 ((le->flags & CLM_ROTATE) ? (time * le->avel) : 0);;
1749 ent.angles[1] =
1750 le->ang +
1751 ((le->flags & CLM_ROTATE) ? (time * le->avel) : 0);
1752
1753 ent.frame = ent.oldframe = 0;
1754
1755 if(le->flags & CLM_GLASS)
1756 ent.flags |= RF_TRANSLUCENT;
1757
1758 V_AddEntity(&ent);
1759
1760 }
1761
1762 active_clentities = active;
1763 }
1764
CL_ClearClEntities()1765 void CL_ClearClEntities()
1766 {
1767 int i;
1768
1769 free_clentities = &clentities[0];
1770 active_clentities = NULL;
1771
1772 for (i = 0; i < MAX_CLENTITIES-1; i++)
1773 clentities[i].next = &clentities[i + 1];
1774 clentities[MAX_CLENTITIES - 1].next = NULL;
1775 }
1776