|
|
1.1 ! root 1: // cl_main.c -- client main loop ! 2: ! 3: #include "quakedef.h" ! 4: ! 5: // we need to declare some mouse variables here, because the menu system ! 6: // references them even when on a unix system. ! 7: ! 8: // these two are not intended to be set directly ! 9: cvar_t cl_name = {"_cl_name", "player", true}; ! 10: cvar_t cl_color = {"_cl_color", "0", true}; ! 11: ! 12: cvar_t cl_shownet = {"cl_shownet","0"}; // can be 0, 1, or 2 ! 13: cvar_t cl_nolerp = {"cl_nolerp","0"}; ! 14: ! 15: cvar_t lookspring = {"lookspring","0", true}; ! 16: cvar_t lookstrafe = {"lookstrafe","0", true}; ! 17: cvar_t sensitivity = {"sensitivity","3", true}; ! 18: ! 19: cvar_t m_pitch = {"m_pitch","0.022", true}; ! 20: cvar_t m_yaw = {"m_yaw","0.022"}; ! 21: cvar_t m_forward = {"m_forward","1"}; ! 22: cvar_t m_side = {"m_side","0.8"}; ! 23: ! 24: ! 25: client_static_t cls; ! 26: client_state_t cl; ! 27: // FIXME: put these on hunk? ! 28: efrag_t cl_efrags[MAX_EFRAGS]; ! 29: entity_t cl_entities[MAX_EDICTS]; ! 30: entity_t cl_static_entities[MAX_STATIC_ENTITIES]; ! 31: lightstyle_t cl_lightstyle[MAX_LIGHTSTYLES]; ! 32: dlight_t cl_dlights[MAX_DLIGHTS]; ! 33: ! 34: int cl_numvisedicts; ! 35: entity_t *cl_visedicts[MAX_VISEDICTS]; ! 36: ! 37: /* ! 38: ===================== ! 39: CL_ClearState ! 40: ! 41: ===================== ! 42: */ ! 43: void CL_ClearState (void) ! 44: { ! 45: int i; ! 46: ! 47: if (!sv.active) ! 48: Host_ClearMemory (); ! 49: ! 50: // wipe the entire cl structure ! 51: memset (&cl, 0, sizeof(cl)); ! 52: ! 53: SZ_Clear (&cls.message); ! 54: ! 55: // clear other arrays ! 56: memset (cl_efrags, 0, sizeof(cl_efrags)); ! 57: memset (cl_entities, 0, sizeof(cl_entities)); ! 58: memset (cl_dlights, 0, sizeof(cl_dlights)); ! 59: memset (cl_lightstyle, 0, sizeof(cl_lightstyle)); ! 60: memset (cl_temp_entities, 0, sizeof(cl_temp_entities)); ! 61: memset (cl_beams, 0, sizeof(cl_beams)); ! 62: ! 63: // ! 64: // allocate the efrags and chain together into a free list ! 65: // ! 66: cl.free_efrags = cl_efrags; ! 67: for (i=0 ; i<MAX_EFRAGS-1 ; i++) ! 68: cl.free_efrags[i].entnext = &cl.free_efrags[i+1]; ! 69: cl.free_efrags[i].entnext = NULL; ! 70: } ! 71: ! 72: /* ! 73: ===================== ! 74: CL_Disconnect ! 75: ! 76: Sends a disconnect message to the server ! 77: This is also called on Host_Error, so it shouldn't cause any errors ! 78: ===================== ! 79: */ ! 80: void CL_Disconnect (void) ! 81: { ! 82: // stop sounds (especially looping!) ! 83: S_StopAllSounds (); ! 84: ! 85: // bring the console down and fade the colors back to normal ! 86: // SCR_BringDownConsole (); ! 87: ! 88: // if running a local server, shut it down ! 89: if (cls.demoplayback) ! 90: CL_StopPlayback (); ! 91: else if (cls.state == ca_connected) ! 92: { ! 93: if (cls.demorecording) ! 94: CL_Stop_f (); ! 95: ! 96: Con_DPrintf ("Sending clc_disconnect\n"); ! 97: SZ_Clear (&cls.message); ! 98: MSG_WriteByte (&cls.message, clc_disconnect); ! 99: NET_SendUnreliableMessage (cls.netcon, &cls.message); ! 100: SZ_Clear (&cls.message); ! 101: NET_Close (cls.netcon); ! 102: ! 103: cls.state = ca_disconnected; ! 104: if (sv.active) ! 105: Host_ShutdownServer(false); ! 106: } ! 107: ! 108: cls.demoplayback = cls.demorecording = cls.timedemo = false; ! 109: cls.signon = 0; ! 110: } ! 111: ! 112: void CL_Disconnect_f (void) ! 113: { ! 114: CL_Disconnect (); ! 115: if (sv.active) ! 116: Host_ShutdownServer (false); ! 117: } ! 118: ! 119: ! 120: ! 121: ! 122: /* ! 123: ===================== ! 124: CL_EstablishConnection ! 125: ! 126: Host should be either "local" or a net address to be passed on ! 127: ===================== ! 128: */ ! 129: void CL_EstablishConnection (char *host) ! 130: { ! 131: if (cls.state == ca_dedicated) ! 132: return; ! 133: ! 134: if (cls.demoplayback) ! 135: return; ! 136: ! 137: CL_Disconnect (); ! 138: ! 139: cls.netcon = NET_Connect (host); ! 140: if (!cls.netcon) ! 141: Host_Error ("CL_Connect: connect failed\n"); ! 142: Con_DPrintf ("CL_EstablishConnection: connected to %s\n", host); ! 143: ! 144: cls.demonum = -1; // not in the demo loop now ! 145: cls.state = ca_connected; ! 146: cls.signon = 0; // need all the signon messages before playing ! 147: } ! 148: ! 149: /* ! 150: ===================== ! 151: CL_SignonReply ! 152: ! 153: An svc_signonnum has been received, perform a client side setup ! 154: ===================== ! 155: */ ! 156: void CL_SignonReply (void) ! 157: { ! 158: char str[8192]; ! 159: ! 160: Con_DPrintf ("CL_SignonReply: %i\n", cls.signon); ! 161: ! 162: switch (cls.signon) ! 163: { ! 164: case 1: ! 165: MSG_WriteByte (&cls.message, clc_stringcmd); ! 166: MSG_WriteString (&cls.message, "prespawn"); ! 167: break; ! 168: ! 169: case 2: ! 170: MSG_WriteByte (&cls.message, clc_stringcmd); ! 171: MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string)); ! 172: ! 173: MSG_WriteByte (&cls.message, clc_stringcmd); ! 174: MSG_WriteString (&cls.message, va("color %i %i\n", ((int)cl_color.value)>>4, ((int)cl_color.value)&15)); ! 175: ! 176: MSG_WriteByte (&cls.message, clc_stringcmd); ! 177: sprintf (str, "spawn %s", cls.spawnparms); ! 178: MSG_WriteString (&cls.message, str); ! 179: break; ! 180: ! 181: case 3: ! 182: MSG_WriteByte (&cls.message, clc_stringcmd); ! 183: MSG_WriteString (&cls.message, "begin"); ! 184: Cache_Report (); // print remaining memory ! 185: break; ! 186: ! 187: case 4: ! 188: SCR_EndLoadingPlaque (); // allow normal screen updates ! 189: break; ! 190: } ! 191: } ! 192: ! 193: /* ! 194: ===================== ! 195: CL_NextDemo ! 196: ! 197: Called to play the next demo in the demo loop ! 198: ===================== ! 199: */ ! 200: void CL_NextDemo (void) ! 201: { ! 202: char str[1024]; ! 203: ! 204: if (cls.demonum == -1) ! 205: return; // don't play demos ! 206: ! 207: SCR_BeginLoadingPlaque (); ! 208: ! 209: if (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS) ! 210: { ! 211: cls.demonum = 0; ! 212: if (!cls.demos[cls.demonum][0]) ! 213: { ! 214: Con_Printf ("No demos listed with startdemos\n"); ! 215: cls.demonum = -1; ! 216: return; ! 217: } ! 218: } ! 219: ! 220: sprintf (str,"playdemo %s\n", cls.demos[cls.demonum]); ! 221: Cbuf_InsertText (str); ! 222: cls.demonum++; ! 223: } ! 224: ! 225: /* ! 226: ============== ! 227: CL_PrintEntities_f ! 228: ============== ! 229: */ ! 230: void CL_PrintEntities_f (void) ! 231: { ! 232: entity_t *ent; ! 233: int i; ! 234: ! 235: for (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++) ! 236: { ! 237: Con_Printf ("%3i:",i); ! 238: if (!ent->model) ! 239: { ! 240: Con_Printf ("EMPTY\n"); ! 241: continue; ! 242: } ! 243: Con_Printf ("%s:%2i (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\n" ! 244: ,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]); ! 245: } ! 246: } ! 247: ! 248: ! 249: /* ! 250: =============== ! 251: SetPal ! 252: ! 253: Debugging tool, just flashes the screen ! 254: =============== ! 255: */ ! 256: void SetPal (int i) ! 257: { ! 258: #if 0 ! 259: static int old; ! 260: byte pal[768]; ! 261: int c; ! 262: ! 263: if (i == old) ! 264: return; ! 265: old = i; ! 266: ! 267: if (i==0) ! 268: VID_SetPalette (host_basepal); ! 269: else if (i==1) ! 270: { ! 271: for (c=0 ; c<768 ; c+=3) ! 272: { ! 273: pal[c] = 0; ! 274: pal[c+1] = 255; ! 275: pal[c+2] = 0; ! 276: } ! 277: VID_SetPalette (pal); ! 278: } ! 279: else ! 280: { ! 281: for (c=0 ; c<768 ; c+=3) ! 282: { ! 283: pal[c] = 0; ! 284: pal[c+1] = 0; ! 285: pal[c+2] = 255; ! 286: } ! 287: VID_SetPalette (pal); ! 288: } ! 289: #endif ! 290: } ! 291: ! 292: /* ! 293: =============== ! 294: CL_AllocDlight ! 295: ! 296: =============== ! 297: */ ! 298: dlight_t *CL_AllocDlight (void) ! 299: { ! 300: int i; ! 301: dlight_t *dl; ! 302: ! 303: dl = cl_dlights; ! 304: for (i=0 ; i<MAX_DLIGHTS ; i++, dl++) ! 305: { ! 306: if (dl->die < cl.time) ! 307: { ! 308: memset (dl, 0, sizeof(*dl)); ! 309: return dl; ! 310: } ! 311: } ! 312: ! 313: memset (&cl_dlights[0], 0, sizeof(*dl)); ! 314: return &cl_dlights[0]; ! 315: } ! 316: ! 317: ! 318: /* ! 319: =============== ! 320: CL_DecayLights ! 321: ! 322: =============== ! 323: */ ! 324: void CL_DecayLights (void) ! 325: { ! 326: int i; ! 327: dlight_t *dl; ! 328: float time; ! 329: ! 330: time = cl.time - cl.oldtime; ! 331: ! 332: dl = cl_dlights; ! 333: for (i=0 ; i<MAX_DLIGHTS ; i++, dl++) ! 334: { ! 335: if (dl->die < cl.time || !dl->radius) ! 336: continue; ! 337: ! 338: dl->radius -= time*dl->decay; ! 339: if (dl->radius < 0) ! 340: dl->radius = 0; ! 341: } ! 342: } ! 343: ! 344: ! 345: /* ! 346: =============== ! 347: CL_LerpPoint ! 348: ! 349: Determines the fraction between the last two messages that the objects ! 350: should be put at. ! 351: =============== ! 352: */ ! 353: float CL_LerpPoint (void) ! 354: { ! 355: float f, frac; ! 356: ! 357: f = cl.mtime[0] - cl.mtime[1]; ! 358: ! 359: if (!f || cl_nolerp.value || cls.timedemo || sv.active) ! 360: { ! 361: cl.time = cl.mtime[0]; ! 362: return 1; ! 363: } ! 364: ! 365: if (f > 0.1) ! 366: { // dropped packet, or start of demo ! 367: cl.mtime[1] = cl.mtime[0] - 0.1; ! 368: f = 0.1; ! 369: } ! 370: frac = (cl.time - cl.mtime[1]) / f; ! 371: //Con_Printf ("frac: %f\n",frac); ! 372: if (frac < 0) ! 373: { ! 374: if (frac < -0.01) ! 375: { ! 376: SetPal(1); ! 377: cl.time = cl.mtime[1]; ! 378: // Con_Printf ("low frac\n"); ! 379: } ! 380: frac = 0; ! 381: } ! 382: else if (frac > 1) ! 383: { ! 384: if (frac > 1.01) ! 385: { ! 386: SetPal(2); ! 387: cl.time = cl.mtime[0]; ! 388: // Con_Printf ("high frac\n"); ! 389: } ! 390: frac = 1; ! 391: } ! 392: else ! 393: SetPal(0); ! 394: ! 395: return frac; ! 396: } ! 397: ! 398: ! 399: /* ! 400: =============== ! 401: CL_RelinkEntities ! 402: =============== ! 403: */ ! 404: void CL_RelinkEntities (void) ! 405: { ! 406: entity_t *ent; ! 407: int i, j; ! 408: float frac, f, d; ! 409: vec3_t delta; ! 410: float bobjrotate; ! 411: vec3_t oldorg; ! 412: dlight_t *dl; ! 413: ! 414: // determine partial update time ! 415: frac = CL_LerpPoint (); ! 416: ! 417: cl_numvisedicts = 0; ! 418: ! 419: // ! 420: // interpolate player info ! 421: // ! 422: for (i=0 ; i<3 ; i++) ! 423: cl.velocity[i] = cl.mvelocity[1][i] + ! 424: frac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]); ! 425: ! 426: if (cls.demoplayback) ! 427: { ! 428: // interpolate the angles ! 429: for (j=0 ; j<3 ; j++) ! 430: { ! 431: d = cl.mviewangles[0][j] - cl.mviewangles[1][j]; ! 432: if (d > 180) ! 433: d -= 360; ! 434: else if (d < -180) ! 435: d += 360; ! 436: cl.viewangles[j] = cl.mviewangles[1][j] + frac*d; ! 437: } ! 438: } ! 439: ! 440: bobjrotate = anglemod(100*cl.time); ! 441: ! 442: // start on the entity after the world ! 443: for (i=1,ent=cl_entities+1 ; i<cl.num_entities ; i++,ent++) ! 444: { ! 445: if (!ent->model) ! 446: { // empty slot ! 447: if (ent->forcelink) ! 448: R_RemoveEfrags (ent); // just became empty ! 449: continue; ! 450: } ! 451: ! 452: // if the object wasn't included in the last packet, remove it ! 453: if (ent->msgtime != cl.mtime[0]) ! 454: { ! 455: ent->model = NULL; ! 456: continue; ! 457: } ! 458: ! 459: VectorCopy (ent->origin, oldorg); ! 460: ! 461: if (ent->forcelink) ! 462: { // the entity was not updated in the last message ! 463: // so move to the final spot ! 464: VectorCopy (ent->msg_origins[0], ent->origin); ! 465: VectorCopy (ent->msg_angles[0], ent->angles); ! 466: } ! 467: else ! 468: { // if the delta is large, assume a teleport and don't lerp ! 469: f = frac; ! 470: for (j=0 ; j<3 ; j++) ! 471: { ! 472: delta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j]; ! 473: if (delta[j] > 100 || delta[j] < -100) ! 474: f = 1; // assume a teleportation, not a motion ! 475: } ! 476: ! 477: // interpolate the origin and angles ! 478: for (j=0 ; j<3 ; j++) ! 479: { ! 480: ent->origin[j] = ent->msg_origins[1][j] + f*delta[j]; ! 481: ! 482: d = ent->msg_angles[0][j] - ent->msg_angles[1][j]; ! 483: if (d > 180) ! 484: d -= 360; ! 485: else if (d < -180) ! 486: d += 360; ! 487: ent->angles[j] = ent->msg_angles[1][j] + f*d; ! 488: } ! 489: ! 490: } ! 491: ! 492: // rotate binary objects locally ! 493: if (ent->model->flags & EF_ROTATE) ! 494: ent->angles[1] = bobjrotate; ! 495: ! 496: if (ent->effects & EF_BRIGHTFIELD) ! 497: R_EntityParticles (ent); ! 498: if (ent->effects & EF_MUZZLEFLASH) ! 499: { ! 500: vec3_t fv, rv, uv; ! 501: ! 502: dl = CL_AllocDlight (); ! 503: VectorCopy (ent->origin, dl->origin); ! 504: dl->origin[2] += 16; ! 505: AngleVectors (ent->angles, fv, rv, uv); ! 506: ! 507: VectorMA (dl->origin, 18, fv, dl->origin); ! 508: dl->radius = 200 + (rand()&31); ! 509: dl->minlight = 32; ! 510: dl->die = cl.time + 0.1; ! 511: } ! 512: if (ent->effects & EF_BRIGHTLIGHT) ! 513: { ! 514: dl = CL_AllocDlight (); ! 515: VectorCopy (ent->origin, dl->origin); ! 516: dl->origin[2] += 16; ! 517: dl->radius = 400 + (rand()&31); ! 518: dl->die = cl.time + 0.001; ! 519: } ! 520: if (ent->effects & EF_DIMLIGHT) ! 521: { ! 522: dl = CL_AllocDlight (); ! 523: VectorCopy (ent->origin, dl->origin); ! 524: dl->radius = 200 + (rand()&31); ! 525: dl->die = cl.time + 0.001; ! 526: } ! 527: ! 528: if (ent->model->flags & EF_GIB) ! 529: R_RocketTrail (oldorg, ent->origin, 2); ! 530: else if (ent->model->flags & EF_ZOMGIB) ! 531: R_RocketTrail (oldorg, ent->origin, 4); ! 532: else if (ent->model->flags & EF_TRACER) ! 533: R_RocketTrail (oldorg, ent->origin, 3); ! 534: else if (ent->model->flags & EF_TRACER2) ! 535: R_RocketTrail (oldorg, ent->origin, 5); ! 536: else if (ent->model->flags & EF_ROCKET) ! 537: { ! 538: R_RocketTrail (oldorg, ent->origin, 0); ! 539: dl = CL_AllocDlight (); ! 540: VectorCopy (ent->origin, dl->origin); ! 541: dl->radius = 200; ! 542: dl->die = cl.time + 0.01; ! 543: } ! 544: else if (ent->model->flags & EF_GRENADE) ! 545: R_RocketTrail (oldorg, ent->origin, 1); ! 546: else if (ent->model->flags & EF_TRACER3) ! 547: R_RocketTrail (oldorg, ent->origin, 6); ! 548: ! 549: ent->forcelink = false; ! 550: if (i != cl.viewentity) ! 551: { ! 552: if (cl_numvisedicts < MAX_VISEDICTS) ! 553: { ! 554: cl_visedicts[cl_numvisedicts] = ent; ! 555: cl_numvisedicts++; ! 556: } ! 557: } ! 558: } ! 559: ! 560: } ! 561: ! 562: ! 563: /* ! 564: =============== ! 565: CL_ReadFromServer ! 566: ! 567: Read all incoming data from the server ! 568: =============== ! 569: */ ! 570: int CL_ReadFromServer (void) ! 571: { ! 572: int ret; ! 573: ! 574: cl.oldtime = cl.time; ! 575: cl.time += host_frametime; ! 576: ! 577: do ! 578: { ! 579: ret = CL_GetMessage (); ! 580: if (ret == -1) ! 581: Host_Error ("CL_ReadFromServer: lost server connection"); ! 582: if (!ret) ! 583: break; ! 584: ! 585: cl.last_received_message = realtime; ! 586: CL_ParseServerMessage (); ! 587: } while (ret && cls.state == ca_connected); ! 588: ! 589: if (cl_shownet.value) ! 590: Con_Printf ("\n"); ! 591: ! 592: CL_RelinkEntities (); ! 593: CL_UpdateTEnts (); ! 594: ! 595: // ! 596: // bring the links up to date ! 597: // ! 598: return 0; ! 599: } ! 600: ! 601: /* ! 602: ================= ! 603: CL_SendCmd ! 604: ================= ! 605: */ ! 606: void CL_SendCmd (void) ! 607: { ! 608: usercmd_t cmd; ! 609: ! 610: if (cls.state != ca_connected) ! 611: return; ! 612: ! 613: if (cls.signon == SIGNONS) ! 614: { ! 615: // get basic movement from keyboard ! 616: CL_BaseMove (&cmd); ! 617: ! 618: // allow mice or other external controllers to add to the move ! 619: IN_Move (&cmd); ! 620: ! 621: // send the unreliable message ! 622: CL_SendMove (&cmd); ! 623: ! 624: } ! 625: ! 626: if (cls.demoplayback) ! 627: { ! 628: SZ_Clear (&cls.message); ! 629: return; ! 630: } ! 631: ! 632: // send the reliable message ! 633: if (!cls.message.cursize) ! 634: return; // no message at all ! 635: ! 636: if (!NET_CanSendMessage (cls.netcon)) ! 637: { ! 638: Con_DPrintf ("CL_WriteToServer: can't send\n"); ! 639: return; ! 640: } ! 641: ! 642: if (NET_SendMessage (cls.netcon, &cls.message) == -1) ! 643: Host_Error ("CL_WriteToServer: lost server connection"); ! 644: ! 645: SZ_Clear (&cls.message); ! 646: } ! 647: ! 648: /* ! 649: ================= ! 650: CL_Init ! 651: ================= ! 652: */ ! 653: void CL_Init (void) ! 654: { ! 655: SZ_Alloc (&cls.message, 1024); ! 656: ! 657: CL_InitInput (); ! 658: CL_InitTEnts (); ! 659: ! 660: // ! 661: // register our commands ! 662: // ! 663: Cvar_RegisterVariable (&cl_name); ! 664: Cvar_RegisterVariable (&cl_color); ! 665: Cvar_RegisterVariable (&cl_upspeed); ! 666: Cvar_RegisterVariable (&cl_forwardspeed); ! 667: Cvar_RegisterVariable (&cl_backspeed); ! 668: Cvar_RegisterVariable (&cl_sidespeed); ! 669: Cvar_RegisterVariable (&cl_movespeedkey); ! 670: Cvar_RegisterVariable (&cl_yawspeed); ! 671: Cvar_RegisterVariable (&cl_pitchspeed); ! 672: Cvar_RegisterVariable (&cl_anglespeedkey); ! 673: Cvar_RegisterVariable (&cl_shownet); ! 674: Cvar_RegisterVariable (&cl_nolerp); ! 675: Cvar_RegisterVariable (&lookspring); ! 676: Cvar_RegisterVariable (&lookstrafe); ! 677: Cvar_RegisterVariable (&sensitivity); ! 678: ! 679: Cvar_RegisterVariable (&m_pitch); ! 680: Cvar_RegisterVariable (&m_yaw); ! 681: Cvar_RegisterVariable (&m_forward); ! 682: Cvar_RegisterVariable (&m_side); ! 683: ! 684: // Cvar_RegisterVariable (&cl_autofire); ! 685: ! 686: Cmd_AddCommand ("entities", CL_PrintEntities_f); ! 687: Cmd_AddCommand ("disconnect", CL_Disconnect_f); ! 688: Cmd_AddCommand ("record", CL_Record_f); ! 689: Cmd_AddCommand ("stop", CL_Stop_f); ! 690: Cmd_AddCommand ("playdemo", CL_PlayDemo_f); ! 691: Cmd_AddCommand ("timedemo", CL_TimeDemo_f); ! 692: } ! 693:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.