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