|
|
1.1 ! root 1: // cl_ents.c -- entity parsing and management ! 2: #include "client.h" ! 3: ! 4: extern struct model_s *cl_mod_powerscreen; ! 5: /* ! 6: ========================================================================= ! 7: FRAME PARSING ! 8: ========================================================================= ! 9: */ ! 10: /* ! 11: ================= ! 12: CL_ParseEntityBits ! 13: ! 14: Returns the entity number and the header bits ! 15: ================= ! 16: */ ! 17: int bitcounts[32]; /// just for protocol profiling ! 18: int CL_ParseEntityBits (unsigned *bits) ! 19: { ! 20: unsigned b, total; ! 21: int i; ! 22: int number; ! 23: ! 24: total = MSG_ReadByte (&net_message); ! 25: if (total & U_MOREBITS1) ! 26: { ! 27: b = MSG_ReadByte (&net_message); ! 28: total |= b<<8; ! 29: } ! 30: if (total & U_MOREBITS2) ! 31: { ! 32: b = MSG_ReadByte (&net_message); ! 33: total |= b<<16; ! 34: } ! 35: if (total & U_MOREBITS3) ! 36: { ! 37: b = MSG_ReadByte (&net_message); ! 38: total |= b<<24; ! 39: } ! 40: ! 41: // count the bits for net profiling ! 42: for (i=0 ; i<32 ; i++) ! 43: if (total&(1<<i)) ! 44: bitcounts[i]++; ! 45: ! 46: if (total & U_NUMBER16) ! 47: number = MSG_ReadShort (&net_message); ! 48: else ! 49: number = MSG_ReadByte (&net_message); ! 50: ! 51: *bits = total; ! 52: ! 53: return number; ! 54: } ! 55: /* ! 56: ================== ! 57: CL_ParseDelta ! 58: Can go from either a baseline or a previous packet_entity ! 59: ================== ! 60: */ ! 61: void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits) ! 62: { ! 63: // set everything to the state we are delta'ing from ! 64: *to = *from; ! 65: // VectorCopy (from->origin, to->old_origin); ! 66: to->number = number; ! 67: if (bits & U_MODEL) ! 68: to->modelindex = MSG_ReadByte (&net_message); ! 69: if (bits & U_MODEL2) ! 70: to->modelindex2 = MSG_ReadByte (&net_message); ! 71: if (bits & U_MODEL3) ! 72: to->modelindex3 = MSG_ReadByte (&net_message); ! 73: if (bits & U_MODEL4) ! 74: to->modelindex4 = MSG_ReadByte (&net_message); ! 75: ! 76: if (bits & U_FRAME8) ! 77: to->frame = MSG_ReadByte (&net_message); ! 78: if (bits & U_FRAME16) ! 79: to->frame = MSG_ReadShort (&net_message); ! 80: if ((bits & U_SKIN8) && (bits & U_SKIN16)) //used for laser colors ! 81: to->skinnum = MSG_ReadLong(&net_message); ! 82: else if (bits & U_SKIN8) ! 83: to->skinnum = MSG_ReadByte(&net_message); ! 84: else if (bits & U_SKIN16) ! 85: to->skinnum = MSG_ReadShort(&net_message); ! 86: ! 87: if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) ) ! 88: to->effects = MSG_ReadLong(&net_message); ! 89: else if (bits & U_EFFECTS8) ! 90: to->effects = MSG_ReadByte(&net_message); ! 91: else if (bits & U_EFFECTS16) ! 92: to->effects = MSG_ReadShort(&net_message); ! 93: if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) ) ! 94: to->renderfx = MSG_ReadLong(&net_message); ! 95: else if (bits & U_RENDERFX8) ! 96: to->renderfx = MSG_ReadByte(&net_message); ! 97: else if (bits & U_RENDERFX16) ! 98: to->renderfx = MSG_ReadShort(&net_message); ! 99: if (bits & U_ORIGIN1) ! 100: to->origin[0] = MSG_ReadCoord (&net_message); ! 101: if (bits & U_ORIGIN2) ! 102: to->origin[1] = MSG_ReadCoord (&net_message); ! 103: if (bits & U_ORIGIN3) ! 104: to->origin[2] = MSG_ReadCoord (&net_message); ! 105: ! 106: if (bits & U_ANGLE1) ! 107: to->angles[0] = MSG_ReadAngle(&net_message); ! 108: if (bits & U_ANGLE2) ! 109: to->angles[1] = MSG_ReadAngle(&net_message); ! 110: if (bits & U_ANGLE3) ! 111: to->angles[2] = MSG_ReadAngle(&net_message); ! 112: if (bits & U_OLDORIGIN) ! 113: MSG_ReadPos (&net_message, to->old_origin); ! 114: if (bits & U_SOUND) ! 115: to->sound = MSG_ReadByte (&net_message); ! 116: ! 117: if (bits & U_EVENT) ! 118: to->event = MSG_ReadByte (&net_message); ! 119: else ! 120: to->event = 0; ! 121: ! 122: if (bits & U_SOLID) ! 123: to->solid = MSG_ReadShort (&net_message); ! 124: } ! 125: ! 126: /* ! 127: ================== ! 128: CL_DeltaEntity ! 129: ! 130: Parses deltas from the given base and adds the resulting entity ! 131: to the current frame ! 132: ================== ! 133: */ ! 134: void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old, int bits) ! 135: { ! 136: centity_t *ent; ! 137: entity_state_t *state; ! 138: ! 139: ent = &cl_entities[newnum]; ! 140: ! 141: state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)]; ! 142: cl.parse_entities++; ! 143: frame->num_entities++; ! 144: ! 145: CL_ParseDelta (old, state, newnum, bits); ! 146: ! 147: // some data changes will force no lerping ! 148: if (state->modelindex != ent->current.modelindex ! 149: || state->modelindex2 != ent->current.modelindex2 ! 150: || state->modelindex3 != ent->current.modelindex3 ! 151: || state->modelindex4 != ent->current.modelindex4 ! 152: || abs(state->origin[0] - ent->current.origin[0]) > 512 ! 153: || abs(state->origin[1] - ent->current.origin[1]) > 512 ! 154: || abs(state->origin[2] - ent->current.origin[2]) > 512 ! 155: || state->event == EV_PLAYER_TELEPORT ! 156: ) ! 157: { ! 158: ent->serverframe = -99; ! 159: } ! 160: ! 161: if (ent->serverframe != cl.frame.serverframe - 1) ! 162: { // wasn't in last update, so initialize some things ! 163: ent->trailcount = 1024; // for diminishing rocket / grenade trails ! 164: // duplicate the current state so lerping doesn't hurt anything ! 165: ent->prev = *state; ! 166: VectorCopy (state->old_origin, ent->prev.origin); ! 167: VectorCopy (state->old_origin, ent->lerp_origin); ! 168: } ! 169: else ! 170: { // shuffle the last state to previous ! 171: ent->prev = ent->current; ! 172: } ! 173: ! 174: ent->serverframe = cl.frame.serverframe; ! 175: ent->current = *state; ! 176: } ! 177: /* ! 178: ================== ! 179: CL_ParsePacketEntities ! 180: An svc_packetentities has just been parsed, deal with the ! 181: rest of the data stream. ! 182: ================== ! 183: */ ! 184: void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe) ! 185: { ! 186: int newnum; ! 187: int bits; ! 188: entity_state_t *oldstate; ! 189: int oldindex, oldnum; ! 190: ! 191: newframe->parse_entities = cl.parse_entities; ! 192: newframe->num_entities = 0; ! 193: ! 194: // delta from the entities present in oldframe ! 195: oldindex = 0; ! 196: if (!oldframe) ! 197: oldnum = 99999; ! 198: else ! 199: { ! 200: if (oldindex >= oldframe->num_entities) ! 201: oldnum = 99999; ! 202: else ! 203: { ! 204: oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; ! 205: oldnum = oldstate->number; ! 206: } ! 207: } ! 208: while (1) ! 209: { ! 210: newnum = CL_ParseEntityBits (&bits); ! 211: if (newnum >= MAX_EDICTS) ! 212: Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum); ! 213: ! 214: if (net_message.readcount > net_message.cursize) ! 215: Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message"); ! 216: ! 217: if (!newnum) ! 218: break; ! 219: ! 220: while (oldnum < newnum) ! 221: { // one or more entities from the old packet are unchanged ! 222: if (cl_shownet->value == 3) ! 223: Com_Printf (" unchanged: %i\n", oldnum); ! 224: CL_DeltaEntity (newframe, oldnum, oldstate, 0); ! 225: ! 226: oldindex++; ! 227: ! 228: if (oldindex >= oldframe->num_entities) ! 229: oldnum = 99999; ! 230: else ! 231: { ! 232: oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; ! 233: oldnum = oldstate->number; ! 234: } ! 235: } ! 236: ! 237: if (bits & U_REMOVE) ! 238: { // the entity present in oldframe is not in the current frame ! 239: if (cl_shownet->value == 3) ! 240: Com_Printf (" remove: %i\n", newnum); ! 241: if (oldnum != newnum) ! 242: Com_Printf ("U_REMOVE: oldnum != newnum\n"); ! 243: ! 244: oldindex++; ! 245: ! 246: if (oldindex >= oldframe->num_entities) ! 247: oldnum = 99999; ! 248: else ! 249: { ! 250: oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; ! 251: oldnum = oldstate->number; ! 252: } ! 253: continue; ! 254: } ! 255: ! 256: if (oldnum == newnum) ! 257: { // delta from previous state ! 258: if (cl_shownet->value == 3) ! 259: Com_Printf (" delta: %i\n", newnum); ! 260: CL_DeltaEntity (newframe, newnum, oldstate, bits); ! 261: ! 262: oldindex++; ! 263: ! 264: if (oldindex >= oldframe->num_entities) ! 265: oldnum = 99999; ! 266: else ! 267: { ! 268: oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; ! 269: oldnum = oldstate->number; ! 270: } ! 271: continue; ! 272: } ! 273: ! 274: if (oldnum > newnum) ! 275: { // delta from baseline ! 276: if (cl_shownet->value == 3) ! 277: Com_Printf (" baseline: %i\n", newnum); ! 278: CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits); ! 279: continue; ! 280: } ! 281: ! 282: } ! 283: ! 284: // any remaining entities in the old frame are copied over ! 285: while (oldnum != 99999) ! 286: { // one or more entities from the old packet are unchanged ! 287: if (cl_shownet->value == 3) ! 288: Com_Printf (" unchanged: %i\n", oldnum); ! 289: CL_DeltaEntity (newframe, oldnum, oldstate, 0); ! 290: ! 291: oldindex++; ! 292: ! 293: if (oldindex >= oldframe->num_entities) ! 294: oldnum = 99999; ! 295: else ! 296: { ! 297: oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)]; ! 298: oldnum = oldstate->number; ! 299: } ! 300: } ! 301: } ! 302: /* ! 303: =================== ! 304: CL_ParsePlayerstate ! 305: =================== ! 306: */ ! 307: void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe) ! 308: { ! 309: int flags; ! 310: player_state_t *state; ! 311: int i; ! 312: int statbits; ! 313: state = &newframe->playerstate; ! 314: ! 315: // clear to old value before delta parsing ! 316: if (oldframe) ! 317: *state = oldframe->playerstate; ! 318: else ! 319: memset (state, 0, sizeof(*state)); ! 320: flags = MSG_ReadShort (&net_message); ! 321: ! 322: // ! 323: // parse the pmove_state_t ! 324: // ! 325: if (flags & PS_M_TYPE) ! 326: state->pmove.pm_type = MSG_ReadByte (&net_message); ! 327: ! 328: if (flags & PS_M_ORIGIN) ! 329: { ! 330: state->pmove.origin[0] = MSG_ReadShort (&net_message); ! 331: state->pmove.origin[1] = MSG_ReadShort (&net_message); ! 332: state->pmove.origin[2] = MSG_ReadShort (&net_message); ! 333: } ! 334: ! 335: if (flags & PS_M_VELOCITY) ! 336: { ! 337: state->pmove.velocity[0] = MSG_ReadShort (&net_message); ! 338: state->pmove.velocity[1] = MSG_ReadShort (&net_message); ! 339: state->pmove.velocity[2] = MSG_ReadShort (&net_message); ! 340: } ! 341: ! 342: if (flags & PS_M_TIME) ! 343: state->pmove.pm_time = MSG_ReadByte (&net_message); ! 344: ! 345: if (flags & PS_M_FLAGS) ! 346: state->pmove.pm_flags = MSG_ReadByte (&net_message); ! 347: ! 348: if (flags & PS_M_GRAVITY) ! 349: state->pmove.gravity = MSG_ReadShort (&net_message); ! 350: ! 351: if (flags & PS_M_DELTA_ANGLES) ! 352: { ! 353: state->pmove.delta_angles[0] = MSG_ReadShort (&net_message); ! 354: state->pmove.delta_angles[1] = MSG_ReadShort (&net_message); ! 355: state->pmove.delta_angles[2] = MSG_ReadShort (&net_message); ! 356: } ! 357: ! 358: if (cl.attractloop) ! 359: state->pmove.pm_type = PM_FREEZE; // demo playback ! 360: ! 361: // ! 362: // parse the rest of the player_state_t ! 363: // ! 364: if (flags & PS_VIEWOFFSET) ! 365: { ! 366: state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25; ! 367: state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25; ! 368: state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25; ! 369: } ! 370: ! 371: if (flags & PS_VIEWANGLES) ! 372: { ! 373: state->viewangles[0] = MSG_ReadAngle16 (&net_message); ! 374: state->viewangles[1] = MSG_ReadAngle16 (&net_message); ! 375: state->viewangles[2] = MSG_ReadAngle16 (&net_message); ! 376: } ! 377: ! 378: if (flags & PS_KICKANGLES) ! 379: { ! 380: state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25; ! 381: state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25; ! 382: state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25; ! 383: } ! 384: if (flags & PS_WEAPONINDEX) ! 385: { ! 386: state->gunindex = MSG_ReadByte (&net_message); ! 387: } ! 388: if (flags & PS_WEAPONFRAME) ! 389: { ! 390: state->gunframe = MSG_ReadByte (&net_message); ! 391: state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25; ! 392: state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25; ! 393: state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25; ! 394: state->gunangles[0] = MSG_ReadChar (&net_message)*0.25; ! 395: state->gunangles[1] = MSG_ReadChar (&net_message)*0.25; ! 396: state->gunangles[2] = MSG_ReadChar (&net_message)*0.25; ! 397: } ! 398: if (flags & PS_BLEND) ! 399: { ! 400: state->blend[0] = MSG_ReadByte (&net_message)/255.0; ! 401: state->blend[1] = MSG_ReadByte (&net_message)/255.0; ! 402: state->blend[2] = MSG_ReadByte (&net_message)/255.0; ! 403: state->blend[3] = MSG_ReadByte (&net_message)/255.0; ! 404: } ! 405: if (flags & PS_FOV) ! 406: state->fov = MSG_ReadByte (&net_message); ! 407: if (flags & PS_RDFLAGS) ! 408: state->rdflags = MSG_ReadByte (&net_message); ! 409: // parse stats ! 410: statbits = MSG_ReadLong (&net_message); ! 411: for (i=0 ; i<MAX_STATS ; i++) ! 412: if (statbits & (1<<i) ) ! 413: state->stats[i] = MSG_ReadShort(&net_message); ! 414: } ! 415: /* ! 416: ================== ! 417: CL_FireEntityEvents ! 418: ! 419: ================== ! 420: */ ! 421: void CL_FireEntityEvents (frame_t *frame) ! 422: { ! 423: entity_state_t *s1; ! 424: int pnum, num; ! 425: ! 426: for (pnum = 0 ; pnum<frame->num_entities ; pnum++) ! 427: { ! 428: num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1); ! 429: s1 = &cl_parse_entities[num]; ! 430: if (s1->event) ! 431: CL_EntityEvent (s1); ! 432: ! 433: // EF_TELEPORTER acts like an event, but is not cleared each frame ! 434: if (s1->effects & EF_TELEPORTER) ! 435: CL_TeleporterParticles (s1); ! 436: } ! 437: } ! 438: ! 439: ! 440: /* ! 441: ================ ! 442: CL_ParseFrame ! 443: ================ ! 444: */ ! 445: void CL_ParseFrame (void) ! 446: { ! 447: int cmd; ! 448: int len; ! 449: frame_t *old; ! 450: memset (&cl.frame, 0, sizeof(cl.frame)); ! 451: cl.frame.serverframe = MSG_ReadLong (&net_message); ! 452: cl.frame.deltaframe = MSG_ReadLong (&net_message); ! 453: cl.frame.servertime = cl.frame.serverframe*100; ! 454: ! 455: // BIG HACK to let old demos continue to work ! 456: if (cls.serverProtocol != 26) ! 457: cl.surpressCount = MSG_ReadByte (&net_message); ! 458: ! 459: if (cl_shownet->value == 3) ! 460: Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe, ! 461: cl.frame.deltaframe); ! 462: ! 463: // If the frame is delta compressed from data that we ! 464: // no longer have available, we must suck up the rest of ! 465: // the frame, but not use it, then ask for a non-compressed ! 466: // message ! 467: if (cl.frame.deltaframe <= 0) ! 468: { ! 469: cl.frame.valid = true; // uncompressed frame ! 470: old = NULL; ! 471: cls.demowaiting = false; // we can start recording now ! 472: } ! 473: else ! 474: { ! 475: old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK]; ! 476: if (!old->valid) ! 477: { // should never happen ! 478: Com_Printf ("Delta from invalid frame (not supposed to happen!).\n"); ! 479: } ! 480: if (old->serverframe != cl.frame.deltaframe) ! 481: { // The frame that the server did the delta from ! 482: // is too old, so we can't reconstruct it properly. ! 483: Com_Printf ("Delta frame too old.\n"); ! 484: } ! 485: else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128) ! 486: { ! 487: Com_Printf ("Delta parse_entities too old.\n"); ! 488: } ! 489: else ! 490: cl.frame.valid = true; // valid delta parse ! 491: } ! 492: // clamp time ! 493: if (cl.time > cl.frame.servertime) ! 494: cl.time = cl.frame.servertime; ! 495: else if (cl.time < cl.frame.servertime - 100) ! 496: cl.time = cl.frame.servertime - 100; ! 497: ! 498: // read areabits ! 499: len = MSG_ReadByte (&net_message); ! 500: MSG_ReadData (&net_message, &cl.frame.areabits, len); ! 501: ! 502: // read playerinfo ! 503: cmd = MSG_ReadByte (&net_message); ! 504: SHOWNET(svc_strings[cmd]); ! 505: if (cmd != svc_playerinfo) ! 506: Com_Error (ERR_DROP, "CL_ParseFrame: not playerinfo"); ! 507: CL_ParsePlayerstate (old, &cl.frame); ! 508: ! 509: // read packet entities ! 510: cmd = MSG_ReadByte (&net_message); ! 511: SHOWNET(svc_strings[cmd]); ! 512: if (cmd != svc_packetentities) ! 513: Com_Error (ERR_DROP, "CL_ParseFrame: not packetentities"); ! 514: CL_ParsePacketEntities (old, &cl.frame); ! 515: ! 516: // save the frame off in the backup array for later delta comparisons ! 517: cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame; ! 518: ! 519: if (cl.frame.valid) ! 520: { ! 521: // getting a valid frame message ends the connection process ! 522: if (cls.state != ca_active) ! 523: { ! 524: cls.state = ca_active; ! 525: cl.force_refdef = true; ! 526: cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125; ! 527: cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125; ! 528: cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125; ! 529: VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles); ! 530: if (cls.disable_servercount != cl.servercount ! 531: && cl.refresh_prepped) ! 532: SCR_EndLoadingPlaque (); // get rid of loading plaque ! 533: } ! 534: cl.sound_prepped = true; // can start mixing ambient sounds ! 535: ! 536: // fire entity events ! 537: CL_FireEntityEvents (&cl.frame); ! 538: CL_CheckPredictionError (); ! 539: } ! 540: } ! 541: /* ! 542: ========================================================================== ! 543: ! 544: INTERPOLATE BETWEEN FRAMES TO GET RENDERING PARMS ! 545: ! 546: ========================================================================== ! 547: */ ! 548: ! 549: /* ! 550: =============== ! 551: CL_AddPacketEntities ! 552: ! 553: =============== ! 554: */ ! 555: void CL_AddPacketEntities (frame_t *frame) ! 556: { ! 557: entity_t ent; ! 558: entity_state_t *s1; ! 559: float autorotate; ! 560: int i; ! 561: int pnum; ! 562: centity_t *cent; ! 563: int autoanim; ! 564: clientinfo_t *ci; ! 565: int effects, renderfx; ! 566: ! 567: // bonus items rotate at a fixed rate ! 568: autorotate = anglemod(cl.time/10); ! 569: ! 570: // brush models can auto animate their frames ! 571: autoanim = 2*cl.time/1000; ! 572: ! 573: memset (&ent, 0, sizeof(ent)); ! 574: ! 575: for (pnum = 0 ; pnum<frame->num_entities ; pnum++) ! 576: { ! 577: s1 = &cl_parse_entities[(frame->parse_entities+pnum)&(MAX_PARSE_ENTITIES-1)]; ! 578: ! 579: cent = &cl_entities[s1->number]; ! 580: ! 581: effects = s1->effects; ! 582: renderfx = s1->renderfx; ! 583: ! 584: // set frame ! 585: if (effects & EF_ANIM01) ! 586: ent.frame = autoanim & 1; ! 587: else if (effects & EF_ANIM23) ! 588: ent.frame = 2 + (autoanim & 1); ! 589: else if (effects & EF_ANIM_ALL) ! 590: ent.frame = autoanim; ! 591: else if (effects & EF_ANIM_ALLFAST) ! 592: ent.frame = cl.time / 100; ! 593: else ! 594: ent.frame = s1->frame; ! 595: ! 596: ! 597: // quad and pent can do different things on client ! 598: if (effects & EF_PENT) ! 599: { ! 600: effects &= ~EF_PENT; ! 601: effects |= EF_COLOR_SHELL; ! 602: renderfx |= RF_SHELL_RED; ! 603: } ! 604: ! 605: if (effects & EF_QUAD) ! 606: { ! 607: effects &= ~EF_QUAD; ! 608: effects |= EF_COLOR_SHELL; ! 609: renderfx |= RF_SHELL_BLUE; ! 610: } ! 611: ! 612: ent.oldframe = cent->prev.frame; ! 613: ent.backlerp = 1.0 - cl.lerpfrac; ! 614: ! 615: if (renderfx & (RF_FRAMELERP|RF_BEAM)) ! 616: { // step origin discretely, because the frames ! 617: // do the animation properly ! 618: VectorCopy (cent->current.origin, ent.origin); ! 619: VectorCopy (cent->current.old_origin, ent.oldorigin); ! 620: } ! 621: else ! 622: { // interpolate origin ! 623: for (i=0 ; i<3 ; i++) ! 624: { ! 625: ent.origin[i] = ent.oldorigin[i] = cent->prev.origin[i] + cl.lerpfrac * ! 626: (cent->current.origin[i] - cent->prev.origin[i]); ! 627: } ! 628: } ! 629: ! 630: // create a new entity ! 631: ! 632: // tweak the color of beams ! 633: if ( renderfx & RF_BEAM ) ! 634: { // the four beam colors are encoded in 32 bits of skinnum (hack) ! 635: ent.alpha = 0.30; ! 636: ent.skinnum = (s1->skinnum >> ((rand() % 4)*8)) & 0xff; ! 637: ent.model = NULL; ! 638: } ! 639: else ! 640: { ! 641: // set skin ! 642: if (s1->modelindex == 255) ! 643: { // use custom player skin ! 644: ent.skinnum = 0; ! 645: ci = &cl.clientinfo[s1->skinnum]; ! 646: ent.skin = ci->skin; ! 647: ent.model = ci->model; ! 648: if (!ent.skin || !ent.model) ! 649: { ! 650: ent.skin = cl.baseclientinfo.skin; ! 651: ent.model = cl.baseclientinfo.model; ! 652: } ! 653: } ! 654: else ! 655: { ! 656: ent.skinnum = s1->skinnum; ! 657: ent.skin = NULL; ! 658: ent.model = cl.model_draw[s1->modelindex]; ! 659: } ! 660: } ! 661: ! 662: // only used for black hole model right now, FIXME: do better ! 663: if (renderfx == RF_TRANSLUCENT) ! 664: ent.alpha = 0.70; ! 665: ! 666: // render effects (fullbright, translucent, etc) ! 667: if ((effects & EF_COLOR_SHELL)) ! 668: ent.flags = 0; // renderfx go on color shell entity ! 669: else ! 670: ent.flags = renderfx; ! 671: ! 672: // calculate angles ! 673: if (effects & EF_ROTATE) ! 674: { // some bonus items auto-rotate ! 675: ent.angles[0] = 0; ! 676: ent.angles[1] = autorotate; ! 677: ent.angles[2] = 0; ! 678: } ! 679: else ! 680: { // interpolate angles ! 681: float a1, a2; ! 682: ! 683: for (i=0 ; i<3 ; i++) ! 684: { ! 685: a1 = cent->current.angles[i]; ! 686: a2 = cent->prev.angles[i]; ! 687: ent.angles[i] = LerpAngle (a2, a1, cl.lerpfrac); ! 688: } ! 689: } ! 690: ! 691: if (s1->number == cl.playernum+1) ! 692: { ! 693: ent.flags |= RF_VIEWERMODEL; // only draw from mirrors ! 694: // FIXME: still pass to refresh ! 695: ! 696: if (effects & EF_FLAG1) ! 697: V_AddLight (ent.origin, 225, 1.0, 0.1, 0.1); ! 698: else if (effects & EF_FLAG2) ! 699: V_AddLight (ent.origin, 225, 0.1, 0.1, 1.0); ! 700: ! 701: continue; ! 702: } ! 703: ! 704: // if set to invisible, skip ! 705: if (!s1->modelindex) ! 706: continue; ! 707: ! 708: if (effects & EF_BFG) ! 709: { ! 710: ent.flags |= RF_TRANSLUCENT; ! 711: ent.alpha = 0.30; ! 712: } ! 713: ! 714: // add to refresh list ! 715: V_AddEntity (&ent); ! 716: ! 717: // color shells generate a seperate entity for the main model ! 718: if (effects & EF_COLOR_SHELL) ! 719: { ! 720: ent.flags = renderfx | RF_TRANSLUCENT; ! 721: ent.alpha = 0.30; ! 722: V_AddEntity (&ent); ! 723: } ! 724: ! 725: ent.skin = NULL; // never use a custom skin on others ! 726: ent.skinnum = 0; ! 727: ent.flags = 0; ! 728: ent.alpha = 0; ! 729: ! 730: // duplicate for linked models ! 731: if (s1->modelindex2) ! 732: { ! 733: if (s1->modelindex2 == 255) ! 734: { // custom weapon ! 735: ci = &cl.clientinfo[s1->skinnum]; ! 736: ent.model = ci->weaponmodel; ! 737: if (!ent.model) ! 738: ent.model = cl.baseclientinfo.weaponmodel; ! 739: } ! 740: else ! 741: ent.model = cl.model_draw[s1->modelindex2]; ! 742: V_AddEntity (&ent); ! 743: } ! 744: if (s1->modelindex3) ! 745: { ! 746: ent.model = cl.model_draw[s1->modelindex3]; ! 747: V_AddEntity (&ent); ! 748: } ! 749: if (s1->modelindex4) ! 750: { ! 751: ent.model = cl.model_draw[s1->modelindex4]; ! 752: V_AddEntity (&ent); ! 753: } ! 754: ! 755: if ( effects & EF_POWERSCREEN ) ! 756: { ! 757: ent.model = cl_mod_powerscreen; ! 758: ent.oldframe = 0; ! 759: ent.frame = 0; ! 760: ent.flags |= (RF_TRANSLUCENT | RF_SHELL_GREEN); ! 761: ent.alpha = 0.30; ! 762: V_AddEntity (&ent); ! 763: } ! 764: ! 765: // add automatic particle trails ! 766: if ( (effects&~EF_ROTATE) ) ! 767: { ! 768: if (effects & EF_ROCKET) ! 769: { ! 770: CL_RocketTrail (cent->lerp_origin, ent.origin, cent); ! 771: V_AddLight (ent.origin, 200, 1, 1, 0); ! 772: } ! 773: else if (effects & EF_BLASTER) ! 774: { ! 775: CL_BlasterTrail (cent->lerp_origin, ent.origin); ! 776: V_AddLight (ent.origin, 200, 1, 1, 0); ! 777: } ! 778: else if (effects & EF_HYPERBLASTER) ! 779: { ! 780: V_AddLight (ent.origin, 200, 1, 1, 0); ! 781: } ! 782: else if (effects & EF_GIB) ! 783: { ! 784: CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects); ! 785: } ! 786: else if (effects & EF_GRENADE) ! 787: { ! 788: CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects); ! 789: } ! 790: else if (effects & EF_FLIES) ! 791: { ! 792: CL_FlyEffect (cent, ent.origin); ! 793: } ! 794: else if (effects & EF_BFG) ! 795: { ! 796: static int bfg_lightramp[6] = {300, 400, 600, 300, 150, 75}; ! 797: ! 798: if (effects & EF_ANIM_ALLFAST) ! 799: { ! 800: CL_BfgParticles (&ent); ! 801: i = 200; ! 802: } ! 803: else ! 804: { ! 805: i = bfg_lightramp[s1->frame]; ! 806: } ! 807: V_AddLight (ent.origin, i, 0, 1, 0); ! 808: } ! 809: else if (effects & EF_FLAG1) ! 810: { ! 811: CL_FlagTrail (cent->lerp_origin, ent.origin, 242); ! 812: V_AddLight (ent.origin, 225, 1, 0.1, 0.1); ! 813: } ! 814: else if (effects & EF_FLAG2) ! 815: { ! 816: CL_FlagTrail (cent->lerp_origin, ent.origin, 115); ! 817: V_AddLight (ent.origin, 225, 0.1, 0.1, 1); ! 818: } ! 819: else if (effects & EF_GREENGIB) ! 820: { ! 821: CL_DiminishingTrail (cent->lerp_origin, ent.origin, cent, effects); ! 822: } ! 823: else if (effects & EF_BOOMER) ! 824: { ! 825: CL_BoomerTrail (cent->lerp_origin, ent.origin); ! 826: V_AddLight (ent.origin, 100, 1, 0.5, 0.5); ! 827: } ! 828: } ! 829: ! 830: VectorCopy (ent.origin, cent->lerp_origin); ! 831: } ! 832: } ! 833: ! 834: ! 835: ! 836: /* ! 837: ============== ! 838: CL_AddViewWeapon ! 839: ============== ! 840: */ ! 841: void CL_AddViewWeapon (player_state_t *ps, player_state_t *ops) ! 842: { ! 843: entity_t gun; // view model ! 844: int i; ! 845: ! 846: // allow the gun to be completely removed ! 847: if (!cl_gun->value) ! 848: return; ! 849: ! 850: // don't draw gun if in wide angle view ! 851: if (ps->fov > 90) ! 852: return; ! 853: ! 854: memset (&gun, 0, sizeof(gun)); ! 855: ! 856: if (gun_model) ! 857: gun.model = gun_model; // development tool ! 858: else ! 859: gun.model = cl.model_draw[ps->gunindex]; ! 860: if (!gun.model) ! 861: return; ! 862: ! 863: // set up gun position ! 864: for (i=0 ; i<3 ; i++) ! 865: { ! 866: gun.origin[i] = cl.refdef.vieworg[i] + ops->gunoffset[i] ! 867: + cl.lerpfrac * (ps->gunoffset[i] - ops->gunoffset[i]); ! 868: gun.angles[i] = cl.refdef.viewangles[i] + LerpAngle (ops->gunangles[i], ! 869: ps->gunangles[i], cl.lerpfrac); ! 870: } ! 871: ! 872: if (gun_frame) ! 873: { ! 874: gun.frame = gun_frame; // development tool ! 875: gun.oldframe = gun_frame; // development tool ! 876: } ! 877: else ! 878: { ! 879: gun.frame = ps->gunframe; ! 880: if (gun.frame == 0) ! 881: gun.oldframe = 0; // just changed weapons, don't lerp from old ! 882: else ! 883: gun.oldframe = ops->gunframe; ! 884: } ! 885: ! 886: gun.flags = RF_MINLIGHT | RF_DEPTHHACK | RF_WEAPONMODEL; ! 887: gun.backlerp = 1.0 - cl.lerpfrac; ! 888: VectorCopy (gun.origin, gun.oldorigin); // don't lerp at all ! 889: V_AddEntity (&gun); ! 890: } ! 891: ! 892: /* ! 893: =============== ! 894: CL_CalcViewValues ! 895: Sets cl.refdef view values ! 896: =============== ! 897: */ ! 898: void CL_CalcViewValues (void) ! 899: { ! 900: int i; ! 901: float lerp, backlerp; ! 902: centity_t *ent; ! 903: frame_t *oldframe; ! 904: player_state_t *ps, *ops; ! 905: ! 906: // find the previous frame to interpolate from ! 907: ps = &cl.frame.playerstate; ! 908: i = (cl.frame.serverframe - 1) & UPDATE_MASK; ! 909: oldframe = &cl.frames[i]; ! 910: if (oldframe->serverframe != cl.frame.serverframe-1 || !oldframe->valid) ! 911: oldframe = &cl.frame; // previous frame was dropped or involid ! 912: ops = &oldframe->playerstate; ! 913: // see if the player entity was teleported this frame ! 914: if ( fabs(ops->pmove.origin[0] - ps->pmove.origin[0]) > 256*8 ! 915: || abs(ops->pmove.origin[1] - ps->pmove.origin[1]) > 256*8 ! 916: || abs(ops->pmove.origin[2] - ps->pmove.origin[2]) > 256*8) ! 917: ops = ps; // don't interpolate ! 918: ! 919: ent = &cl_entities[cl.playernum+1]; ! 920: lerp = cl.lerpfrac; ! 921: ! 922: // calculate the origin ! 923: if ((cl_predict->value) && !(cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION)) ! 924: { // use predicted values ! 925: unsigned delta; ! 926: ! 927: backlerp = 1.0 - lerp; ! 928: for (i=0 ; i<3 ; i++) ! 929: { ! 930: cl.refdef.vieworg[i] = cl.predicted_origin[i] + ops->viewoffset[i] ! 931: + cl.lerpfrac * (ps->viewoffset[i] - ops->viewoffset[i]) ! 932: - backlerp * cl.prediction_error[i]; ! 933: } ! 934: ! 935: // smooth out stair climbing ! 936: delta = cls.realtime - cl.predicted_step_time; ! 937: if (delta < 100) ! 938: cl.refdef.vieworg[2] -= cl.predicted_step * (100 - delta) * 0.01; ! 939: } ! 940: else ! 941: { // just use interpolated values ! 942: for (i=0 ; i<3 ; i++) ! 943: cl.refdef.vieworg[i] = ops->pmove.origin[i]*0.125 + ops->viewoffset[i] ! 944: + lerp * (ps->pmove.origin[i]*0.125 + ps->viewoffset[i] ! 945: - (ops->pmove.origin[i]*0.125 + ops->viewoffset[i]) ); ! 946: } ! 947: ! 948: // if not running a demo or on a locked frame, add the local angle movement ! 949: if ( cl.frame.playerstate.pmove.pm_type < PM_DEAD ) ! 950: { // use predicted values ! 951: for (i=0 ; i<3 ; i++) ! 952: cl.refdef.viewangles[i] = cl.predicted_angles[i]; ! 953: } ! 954: else ! 955: { // just use interpolated values ! 956: for (i=0 ; i<3 ; i++) ! 957: cl.refdef.viewangles[i] = LerpAngle (ops->viewangles[i], ps->viewangles[i], lerp); ! 958: } ! 959: ! 960: for (i=0 ; i<3 ; i++) ! 961: cl.refdef.viewangles[i] += LerpAngle (ops->kick_angles[i], ps->kick_angles[i], lerp); ! 962: AngleVectors (cl.refdef.viewangles, cl.v_forward, cl.v_right, cl.v_up); ! 963: ! 964: // interpolate field of view ! 965: cl.refdef.fov_x = ops->fov + lerp * (ps->fov - ops->fov); ! 966: // don't interpolate blend color ! 967: for (i=0 ; i<4 ; i++) ! 968: cl.refdef.blend[i] = ps->blend[i]; ! 969: ! 970: // add the weapon ! 971: CL_AddViewWeapon (ps, ops); ! 972: } ! 973: /* ! 974: =============== ! 975: CL_AddEntities ! 976: Emits all entities, particles, and lights to the refresh ! 977: =============== ! 978: */ ! 979: void CL_AddEntities (void) ! 980: { ! 981: if (cls.state != ca_active) ! 982: return; ! 983: if (cl.time > cl.frame.servertime) ! 984: { ! 985: if (cl_showclamp->value) ! 986: Com_Printf ("high clamp %i\n", cl.time - cl.frame.servertime); ! 987: cl.time = cl.frame.servertime; ! 988: cl.lerpfrac = 1.0; ! 989: } ! 990: else if (cl.time < cl.frame.servertime - 100) ! 991: { ! 992: if (cl_showclamp->value) ! 993: Com_Printf ("low clamp %i\n", cl.frame.servertime-100 - cl.time); ! 994: cl.time = cl.frame.servertime - 100; ! 995: cl.lerpfrac = 0; ! 996: } ! 997: else ! 998: cl.lerpfrac = 1.0 - (cl.frame.servertime - cl.time) * 0.01; ! 999: ! 1000: if (cl_timedemo->value) ! 1001: cl.lerpfrac = 1.0; ! 1002: ! 1003: CL_AddPacketEntities (&cl.frame); ! 1004: CL_AddTEnts (); ! 1005: CL_AddParticles (); ! 1006: CL_AddDLights (); ! 1007: CL_AddLightStyles (); ! 1008: CL_CalcViewValues (); ! 1009: } ! 1010: /* ! 1011: =============== ! 1012: CL_GetEntitySoundOrigin ! 1013: Called to get the sound spatialization origin ! 1014: =============== ! 1015: */ ! 1016: void CL_GetEntitySoundOrigin (int ent, vec3_t org) ! 1017: { ! 1018: centity_t *old; ! 1019: if (ent < 0 || ent >= MAX_EDICTS) ! 1020: Com_Error (ERR_DROP, "CL_GetEntitySoundOrigin: bad ent"); ! 1021: old = &cl_entities[ent]; ! 1022: VectorCopy (old->lerp_origin, org); ! 1023: // FIXME: bmodel issues... ! 1024: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.