|
|
1.1 ! root 1: // cl.input.c -- builds an intended movement command to send to the server ! 2: ! 3: #include "client.h" ! 4: ! 5: cvar_t *cl_nodelta; ! 6: ! 7: extern unsigned sys_frame_time; ! 8: unsigned frame_msec; ! 9: unsigned old_sys_frame_time; ! 10: ! 11: /* ! 12: =============================================================================== ! 13: ! 14: KEY BUTTONS ! 15: ! 16: Continuous button event tracking is complicated by the fact that two different ! 17: input sources (say, mouse button 1 and the control key) can both press the ! 18: same button, but the button should only be released when both of the ! 19: pressing key have been released. ! 20: ! 21: When a key event issues a button command (+forward, +attack, etc), it appends ! 22: its key number as a parameter to the command so it can be matched up with ! 23: the release. ! 24: ! 25: state bit 0 is the current state of the key ! 26: state bit 1 is edge triggered on the up to down transition ! 27: state bit 2 is edge triggered on the down to up transition ! 28: ! 29: ! 30: Key_Event (int key, qboolean down, unsigned time); ! 31: ! 32: +mlook src time ! 33: ! 34: =============================================================================== ! 35: */ ! 36: ! 37: ! 38: kbutton_t in_klook; ! 39: kbutton_t in_left, in_right, in_forward, in_back; ! 40: kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; ! 41: kbutton_t in_strafe, in_speed, in_use, in_attack; ! 42: kbutton_t in_up, in_down; ! 43: ! 44: int in_impulse; ! 45: ! 46: ! 47: void KeyDown (kbutton_t *b) ! 48: { ! 49: int k; ! 50: char *c; ! 51: ! 52: c = Cmd_Argv(1); ! 53: if (c[0]) ! 54: k = atoi(c); ! 55: else ! 56: k = -1; // typed manually at the console for continuous down ! 57: ! 58: if (k == b->down[0] || k == b->down[1]) ! 59: return; // repeating key ! 60: ! 61: if (!b->down[0]) ! 62: b->down[0] = k; ! 63: else if (!b->down[1]) ! 64: b->down[1] = k; ! 65: else ! 66: { ! 67: Com_Printf ("Three keys down for a button!\n"); ! 68: return; ! 69: } ! 70: ! 71: if (b->state & 1) ! 72: return; // still down ! 73: ! 74: // save timestamp ! 75: c = Cmd_Argv(2); ! 76: b->downtime = atoi(c); ! 77: if (!b->downtime) ! 78: b->downtime = sys_frame_time - 100; ! 79: ! 80: b->state |= 1 + 2; // down + impulse down ! 81: } ! 82: ! 83: void KeyUp (kbutton_t *b) ! 84: { ! 85: int k; ! 86: char *c; ! 87: unsigned uptime; ! 88: ! 89: c = Cmd_Argv(1); ! 90: if (c[0]) ! 91: k = atoi(c); ! 92: else ! 93: { // typed manually at the console, assume for unsticking, so clear all ! 94: b->down[0] = b->down[1] = 0; ! 95: b->state = 4; // impulse up ! 96: return; ! 97: } ! 98: ! 99: if (b->down[0] == k) ! 100: b->down[0] = 0; ! 101: else if (b->down[1] == k) ! 102: b->down[1] = 0; ! 103: else ! 104: return; // key up without coresponding down (menu pass through) ! 105: if (b->down[0] || b->down[1]) ! 106: return; // some other key is still holding it down ! 107: ! 108: if (!(b->state & 1)) ! 109: return; // still up (this should not happen) ! 110: ! 111: // save timestamp ! 112: c = Cmd_Argv(2); ! 113: uptime = atoi(c); ! 114: if (uptime) ! 115: b->msec += uptime - b->downtime; ! 116: else ! 117: b->msec += 10; ! 118: ! 119: b->state &= ~1; // now up ! 120: b->state |= 4; // impulse up ! 121: } ! 122: ! 123: void IN_KLookDown (void) {KeyDown(&in_klook);} ! 124: void IN_KLookUp (void) {KeyUp(&in_klook);} ! 125: void IN_UpDown(void) {KeyDown(&in_up);} ! 126: void IN_UpUp(void) {KeyUp(&in_up);} ! 127: void IN_DownDown(void) {KeyDown(&in_down);} ! 128: void IN_DownUp(void) {KeyUp(&in_down);} ! 129: void IN_LeftDown(void) {KeyDown(&in_left);} ! 130: void IN_LeftUp(void) {KeyUp(&in_left);} ! 131: void IN_RightDown(void) {KeyDown(&in_right);} ! 132: void IN_RightUp(void) {KeyUp(&in_right);} ! 133: void IN_ForwardDown(void) {KeyDown(&in_forward);} ! 134: void IN_ForwardUp(void) {KeyUp(&in_forward);} ! 135: void IN_BackDown(void) {KeyDown(&in_back);} ! 136: void IN_BackUp(void) {KeyUp(&in_back);} ! 137: void IN_LookupDown(void) {KeyDown(&in_lookup);} ! 138: void IN_LookupUp(void) {KeyUp(&in_lookup);} ! 139: void IN_LookdownDown(void) {KeyDown(&in_lookdown);} ! 140: void IN_LookdownUp(void) {KeyUp(&in_lookdown);} ! 141: void IN_MoveleftDown(void) {KeyDown(&in_moveleft);} ! 142: void IN_MoveleftUp(void) {KeyUp(&in_moveleft);} ! 143: void IN_MoverightDown(void) {KeyDown(&in_moveright);} ! 144: void IN_MoverightUp(void) {KeyUp(&in_moveright);} ! 145: ! 146: void IN_SpeedDown(void) {KeyDown(&in_speed);} ! 147: void IN_SpeedUp(void) {KeyUp(&in_speed);} ! 148: void IN_StrafeDown(void) {KeyDown(&in_strafe);} ! 149: void IN_StrafeUp(void) {KeyUp(&in_strafe);} ! 150: ! 151: void IN_AttackDown(void) {KeyDown(&in_attack);} ! 152: void IN_AttackUp(void) {KeyUp(&in_attack);} ! 153: ! 154: void IN_UseDown (void) {KeyDown(&in_use);} ! 155: void IN_UseUp (void) {KeyUp(&in_use);} ! 156: ! 157: void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));} ! 158: ! 159: /* ! 160: =============== ! 161: CL_KeyState ! 162: ! 163: Returns the fraction of the frame that the key was down ! 164: =============== ! 165: */ ! 166: float CL_KeyState (kbutton_t *key) ! 167: { ! 168: float val; ! 169: int msec; ! 170: ! 171: key->state &= 1; // clear impulses ! 172: ! 173: msec = key->msec; ! 174: key->msec = 0; ! 175: ! 176: if (key->state) ! 177: { // still down ! 178: msec += sys_frame_time - key->downtime; ! 179: key->downtime = sys_frame_time; ! 180: } ! 181: ! 182: #if 0 ! 183: if (msec) ! 184: { ! 185: Com_Printf ("%i ", msec); ! 186: } ! 187: #endif ! 188: ! 189: val = (float)msec / frame_msec; ! 190: if (val < 0) ! 191: val = 0; ! 192: if (val > 1) ! 193: val = 1; ! 194: ! 195: return val; ! 196: } ! 197: ! 198: ! 199: ! 200: ! 201: //========================================================================== ! 202: ! 203: cvar_t *cl_upspeed; ! 204: cvar_t *cl_forwardspeed; ! 205: cvar_t *cl_sidespeed; ! 206: ! 207: cvar_t *cl_yawspeed; ! 208: cvar_t *cl_pitchspeed; ! 209: ! 210: cvar_t *cl_run; ! 211: ! 212: cvar_t *cl_anglespeedkey; ! 213: ! 214: ! 215: /* ! 216: ================ ! 217: CL_AdjustAngles ! 218: ! 219: Moves the local angle positions ! 220: ================ ! 221: */ ! 222: void CL_AdjustAngles (void) ! 223: { ! 224: float speed; ! 225: float up, down; ! 226: ! 227: if (in_speed.state & 1) ! 228: speed = cls.frametime * cl_anglespeedkey->value; ! 229: else ! 230: speed = cls.frametime; ! 231: ! 232: if (!(in_strafe.state & 1)) ! 233: { ! 234: cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right); ! 235: cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left); ! 236: } ! 237: if (in_klook.state & 1) ! 238: { ! 239: cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_forward); ! 240: cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_back); ! 241: } ! 242: ! 243: up = CL_KeyState (&in_lookup); ! 244: down = CL_KeyState(&in_lookdown); ! 245: ! 246: cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * up; ! 247: cl.viewangles[PITCH] += speed*cl_pitchspeed->value * down; ! 248: } ! 249: ! 250: /* ! 251: ================ ! 252: CL_BaseMove ! 253: ! 254: Send the intended movement message to the server ! 255: ================ ! 256: */ ! 257: void CL_BaseMove (usercmd_t *cmd) ! 258: { ! 259: CL_AdjustAngles (); ! 260: ! 261: memset (cmd, 0, sizeof(*cmd)); ! 262: ! 263: VectorCopy (cl.viewangles, cmd->angles); ! 264: if (in_strafe.state & 1) ! 265: { ! 266: cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_right); ! 267: cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_left); ! 268: } ! 269: ! 270: cmd->sidemove += cl_sidespeed->value * CL_KeyState (&in_moveright); ! 271: cmd->sidemove -= cl_sidespeed->value * CL_KeyState (&in_moveleft); ! 272: ! 273: cmd->upmove += cl_upspeed->value * CL_KeyState (&in_up); ! 274: cmd->upmove -= cl_upspeed->value * CL_KeyState (&in_down); ! 275: ! 276: if (! (in_klook.state & 1) ) ! 277: { ! 278: cmd->forwardmove += cl_forwardspeed->value * CL_KeyState (&in_forward); ! 279: cmd->forwardmove -= cl_forwardspeed->value * CL_KeyState (&in_back); ! 280: } ! 281: ! 282: // ! 283: // adjust for speed key / running ! 284: // ! 285: if ( (in_speed.state & 1) ^ (int)(cl_run->value) ) ! 286: { ! 287: cmd->forwardmove *= 2; ! 288: cmd->sidemove *= 2; ! 289: cmd->upmove *= 2; ! 290: } ! 291: } ! 292: ! 293: void CL_ClampPitch (void) ! 294: { ! 295: float pitch; ! 296: ! 297: pitch = SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]); ! 298: if (pitch > 180) ! 299: pitch -= 360; ! 300: if (cl.viewangles[PITCH] + pitch > 89) ! 301: cl.viewangles[PITCH] = 89 - pitch; ! 302: if (cl.viewangles[PITCH] + pitch < -89) ! 303: cl.viewangles[PITCH] = -89 - pitch; ! 304: } ! 305: ! 306: /* ! 307: ============== ! 308: CL_FinishMove ! 309: ============== ! 310: */ ! 311: void CL_FinishMove (usercmd_t *cmd) ! 312: { ! 313: int ms; ! 314: int i; ! 315: ! 316: // ! 317: // figure button bits ! 318: // ! 319: if ( in_attack.state & 3 ) ! 320: cmd->buttons |= BUTTON_ATTACK; ! 321: in_attack.state &= ~2; ! 322: ! 323: if (in_use.state & 3) ! 324: cmd->buttons |= BUTTON_USE; ! 325: in_use.state &= ~2; ! 326: ! 327: if (anykeydown && cls.key_dest == key_game) ! 328: cmd->buttons |= BUTTON_ANY; ! 329: ! 330: // send milliseconds of time to apply the move ! 331: ms = cls.frametime * 1000; ! 332: if (ms > 250) ! 333: ms = 100; // time was unreasonable ! 334: cmd->msec = ms; ! 335: ! 336: CL_ClampPitch (); ! 337: for (i=0 ; i<3 ; i++) ! 338: cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]); ! 339: ! 340: cmd->impulse = in_impulse; ! 341: in_impulse = 0; ! 342: ! 343: // send the ambient light level at the player's current position ! 344: cmd->lightlevel = (byte)cl_lightlevel->value; ! 345: } ! 346: ! 347: /* ! 348: ================= ! 349: CL_CreateCmd ! 350: ================= ! 351: */ ! 352: usercmd_t CL_CreateCmd (void) ! 353: { ! 354: usercmd_t cmd; ! 355: ! 356: frame_msec = sys_frame_time - old_sys_frame_time; ! 357: if (frame_msec < 1) ! 358: frame_msec = 1; ! 359: if (frame_msec > 200) ! 360: frame_msec = 200; ! 361: ! 362: // get basic movement from keyboard ! 363: CL_BaseMove (&cmd); ! 364: ! 365: // allow mice or other external controllers to add to the move ! 366: IN_Move (&cmd); ! 367: ! 368: CL_FinishMove (&cmd); ! 369: ! 370: old_sys_frame_time = sys_frame_time; ! 371: ! 372: //cmd.impulse = cls.framecount; ! 373: ! 374: return cmd; ! 375: } ! 376: ! 377: ! 378: void IN_CenterView (void) ! 379: { ! 380: cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]); ! 381: } ! 382: ! 383: /* ! 384: ============ ! 385: CL_InitInput ! 386: ============ ! 387: */ ! 388: void CL_InitInput (void) ! 389: { ! 390: Cmd_AddCommand ("centerview",IN_CenterView); ! 391: ! 392: Cmd_AddCommand ("+moveup",IN_UpDown); ! 393: Cmd_AddCommand ("-moveup",IN_UpUp); ! 394: Cmd_AddCommand ("+movedown",IN_DownDown); ! 395: Cmd_AddCommand ("-movedown",IN_DownUp); ! 396: Cmd_AddCommand ("+left",IN_LeftDown); ! 397: Cmd_AddCommand ("-left",IN_LeftUp); ! 398: Cmd_AddCommand ("+right",IN_RightDown); ! 399: Cmd_AddCommand ("-right",IN_RightUp); ! 400: Cmd_AddCommand ("+forward",IN_ForwardDown); ! 401: Cmd_AddCommand ("-forward",IN_ForwardUp); ! 402: Cmd_AddCommand ("+back",IN_BackDown); ! 403: Cmd_AddCommand ("-back",IN_BackUp); ! 404: Cmd_AddCommand ("+lookup", IN_LookupDown); ! 405: Cmd_AddCommand ("-lookup", IN_LookupUp); ! 406: Cmd_AddCommand ("+lookdown", IN_LookdownDown); ! 407: Cmd_AddCommand ("-lookdown", IN_LookdownUp); ! 408: Cmd_AddCommand ("+strafe", IN_StrafeDown); ! 409: Cmd_AddCommand ("-strafe", IN_StrafeUp); ! 410: Cmd_AddCommand ("+moveleft", IN_MoveleftDown); ! 411: Cmd_AddCommand ("-moveleft", IN_MoveleftUp); ! 412: Cmd_AddCommand ("+moveright", IN_MoverightDown); ! 413: Cmd_AddCommand ("-moveright", IN_MoverightUp); ! 414: Cmd_AddCommand ("+speed", IN_SpeedDown); ! 415: Cmd_AddCommand ("-speed", IN_SpeedUp); ! 416: Cmd_AddCommand ("+attack", IN_AttackDown); ! 417: Cmd_AddCommand ("-attack", IN_AttackUp); ! 418: Cmd_AddCommand ("+use", IN_UseDown); ! 419: Cmd_AddCommand ("-use", IN_UseUp); ! 420: Cmd_AddCommand ("impulse", IN_Impulse); ! 421: Cmd_AddCommand ("+klook", IN_KLookDown); ! 422: Cmd_AddCommand ("-klook", IN_KLookUp); ! 423: ! 424: cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0); ! 425: } ! 426: ! 427: ! 428: ! 429: /* ! 430: ================= ! 431: CL_SendCmd ! 432: ================= ! 433: */ ! 434: void CL_SendCmd (void) ! 435: { ! 436: sizebuf_t buf; ! 437: byte data[128]; ! 438: int i; ! 439: usercmd_t *cmd, *oldcmd; ! 440: usercmd_t nullcmd; ! 441: int checksumIndex; ! 442: ! 443: // build a command even if not connected ! 444: ! 445: // save this command off for prediction ! 446: i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1); ! 447: cmd = &cl.cmds[i]; ! 448: cl.cmd_time[i] = cls.realtime; // for netgraph ping calculation ! 449: ! 450: *cmd = CL_CreateCmd (); ! 451: ! 452: cl.cmd = *cmd; ! 453: ! 454: if (cls.state == ca_disconnected || cls.state == ca_connecting) ! 455: return; ! 456: ! 457: if ( cls.state == ca_connected) ! 458: { ! 459: if (cls.netchan.message.cursize || curtime - cls.netchan.last_sent > 1000 ) ! 460: Netchan_Transmit (&cls.netchan, 0, buf.data); ! 461: return; ! 462: } ! 463: ! 464: // send a userinfo update if needed ! 465: if (userinfo_modified) ! 466: { ! 467: userinfo_modified = false; ! 468: MSG_WriteByte (&cls.netchan.message, clc_userinfo); ! 469: MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() ); ! 470: } ! 471: ! 472: SZ_Init (&buf, data, sizeof(data)); ! 473: ! 474: if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop ! 475: && cls.realtime - cl.cinematictime > 1000) ! 476: { // skip the rest of the cinematic ! 477: SCR_FinishCinematic (); ! 478: } ! 479: ! 480: // begin a client move command ! 481: MSG_WriteByte (&buf, clc_move); ! 482: ! 483: // save the position for a checksum byte ! 484: checksumIndex = buf.cursize; ! 485: MSG_WriteByte (&buf, 0); ! 486: ! 487: // let the server know what the last frame we ! 488: // got was, so the next message can be delta compressed ! 489: if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting) ! 490: MSG_WriteLong (&buf, -1); // no compression ! 491: else ! 492: MSG_WriteLong (&buf, cl.frame.serverframe); ! 493: ! 494: // send this and the previous cmds in the message, so ! 495: // if the last packet was dropped, it can be recovered ! 496: i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1); ! 497: cmd = &cl.cmds[i]; ! 498: memset (&nullcmd, 0, sizeof(nullcmd)); ! 499: MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd); ! 500: oldcmd = cmd; ! 501: ! 502: i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1); ! 503: cmd = &cl.cmds[i]; ! 504: MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd); ! 505: oldcmd = cmd; ! 506: ! 507: i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1); ! 508: cmd = &cl.cmds[i]; ! 509: MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd); ! 510: ! 511: // calculate a checksum over the move commands ! 512: buf.data[checksumIndex] = COM_BlockSequenceCheckByte( ! 513: buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1, ! 514: cls.netchan.outgoing_sequence); ! 515: ! 516: // ! 517: // deliver the message ! 518: // ! 519: Netchan_Transmit (&cls.netchan, buf.cursize, buf.data); ! 520: } ! 521: ! 522:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.