cl_input.c (12968B)
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.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; 319 if (cl.viewangles[PITCH] + pitch > 89) 320 cl.viewangles[PITCH] = 89 - pitch; 321 if (cl.viewangles[PITCH] + pitch < -89) 322 cl.viewangles[PITCH] = -89 - pitch; 323 } 324 325 /* 326 ============== 327 CL_FinishMove 328 ============== 329 */ 330 void CL_FinishMove (usercmd_t *cmd) 331 { 332 int ms; 333 int i; 334 335 // 336 // figure button bits 337 // 338 if ( in_attack.state & 3 ) 339 cmd->buttons |= BUTTON_ATTACK; 340 in_attack.state &= ~2; 341 342 if (in_use.state & 3) 343 cmd->buttons |= BUTTON_USE; 344 in_use.state &= ~2; 345 346 if (anykeydown && cls.key_dest == key_game) 347 cmd->buttons |= BUTTON_ANY; 348 349 // send milliseconds of time to apply the move 350 ms = cls.frametime * 1000; 351 if (ms > 250) 352 ms = 100; // time was unreasonable 353 cmd->msec = ms; 354 355 CL_ClampPitch (); 356 for (i=0 ; i<3 ; i++) 357 cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]); 358 359 cmd->impulse = in_impulse; 360 in_impulse = 0; 361 362 // send the ambient light level at the player's current position 363 cmd->lightlevel = (byte)cl_lightlevel->value; 364 } 365 366 /* 367 ================= 368 CL_CreateCmd 369 ================= 370 */ 371 usercmd_t CL_CreateCmd (void) 372 { 373 usercmd_t cmd; 374 375 frame_msec = sys_frame_time - old_sys_frame_time; 376 if (frame_msec < 1) 377 frame_msec = 1; 378 if (frame_msec > 200) 379 frame_msec = 200; 380 381 // get basic movement from keyboard 382 CL_BaseMove (&cmd); 383 384 // allow mice or other external controllers to add to the move 385 IN_Move (&cmd); 386 387 CL_FinishMove (&cmd); 388 389 old_sys_frame_time = sys_frame_time; 390 391 //cmd.impulse = cls.framecount; 392 393 return cmd; 394 } 395 396 397 void IN_CenterView (void) 398 { 399 cl.viewangles[PITCH] = -SHORT2ANGLE(cl.frame.playerstate.pmove.delta_angles[PITCH]); 400 } 401 402 /* 403 ============ 404 CL_InitInput 405 ============ 406 */ 407 void CL_InitInput (void) 408 { 409 Cmd_AddCommand ("centerview",IN_CenterView); 410 411 Cmd_AddCommand ("+moveup",IN_UpDown); 412 Cmd_AddCommand ("-moveup",IN_UpUp); 413 Cmd_AddCommand ("+movedown",IN_DownDown); 414 Cmd_AddCommand ("-movedown",IN_DownUp); 415 Cmd_AddCommand ("+left",IN_LeftDown); 416 Cmd_AddCommand ("-left",IN_LeftUp); 417 Cmd_AddCommand ("+right",IN_RightDown); 418 Cmd_AddCommand ("-right",IN_RightUp); 419 Cmd_AddCommand ("+forward",IN_ForwardDown); 420 Cmd_AddCommand ("-forward",IN_ForwardUp); 421 Cmd_AddCommand ("+back",IN_BackDown); 422 Cmd_AddCommand ("-back",IN_BackUp); 423 Cmd_AddCommand ("+lookup", IN_LookupDown); 424 Cmd_AddCommand ("-lookup", IN_LookupUp); 425 Cmd_AddCommand ("+lookdown", IN_LookdownDown); 426 Cmd_AddCommand ("-lookdown", IN_LookdownUp); 427 Cmd_AddCommand ("+strafe", IN_StrafeDown); 428 Cmd_AddCommand ("-strafe", IN_StrafeUp); 429 Cmd_AddCommand ("+moveleft", IN_MoveleftDown); 430 Cmd_AddCommand ("-moveleft", IN_MoveleftUp); 431 Cmd_AddCommand ("+moveright", IN_MoverightDown); 432 Cmd_AddCommand ("-moveright", IN_MoverightUp); 433 Cmd_AddCommand ("+speed", IN_SpeedDown); 434 Cmd_AddCommand ("-speed", IN_SpeedUp); 435 Cmd_AddCommand ("+attack", IN_AttackDown); 436 Cmd_AddCommand ("-attack", IN_AttackUp); 437 Cmd_AddCommand ("+use", IN_UseDown); 438 Cmd_AddCommand ("-use", IN_UseUp); 439 Cmd_AddCommand ("impulse", IN_Impulse); 440 Cmd_AddCommand ("+klook", IN_KLookDown); 441 Cmd_AddCommand ("-klook", IN_KLookUp); 442 443 cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0); 444 } 445 446 447 448 /* 449 ================= 450 CL_SendCmd 451 ================= 452 */ 453 void CL_SendCmd (void) 454 { 455 sizebuf_t buf; 456 byte data[128]; 457 int i; 458 usercmd_t *cmd, *oldcmd; 459 usercmd_t nullcmd; 460 int checksumIndex; 461 462 // build a command even if not connected 463 464 // save this command off for prediction 465 i = cls.netchan.outgoing_sequence & (CMD_BACKUP-1); 466 cmd = &cl.cmds[i]; 467 cl.cmd_time[i] = cls.realtime; // for netgraph ping calculation 468 469 *cmd = CL_CreateCmd (); 470 471 cl.cmd = *cmd; 472 473 if (cls.state == ca_disconnected || cls.state == ca_connecting) 474 return; 475 476 if ( cls.state == ca_connected) 477 { 478 if (cls.netchan.message.cursize || curtime - cls.netchan.last_sent > 1000 ) 479 Netchan_Transmit (&cls.netchan, 0, buf.data); 480 return; 481 } 482 483 // send a userinfo update if needed 484 if (userinfo_modified) 485 { 486 CL_FixUpGender(); 487 userinfo_modified = false; 488 MSG_WriteByte (&cls.netchan.message, clc_userinfo); 489 MSG_WriteString (&cls.netchan.message, Cvar_Userinfo() ); 490 } 491 492 SZ_Init (&buf, data, sizeof(data)); 493 494 if (cmd->buttons && cl.cinematictime > 0 && !cl.attractloop 495 && cls.realtime - cl.cinematictime > 1000) 496 { // skip the rest of the cinematic 497 SCR_FinishCinematic (); 498 } 499 500 // begin a client move command 501 MSG_WriteByte (&buf, clc_move); 502 503 // save the position for a checksum byte 504 checksumIndex = buf.cursize; 505 MSG_WriteByte (&buf, 0); 506 507 // let the server know what the last frame we 508 // got was, so the next message can be delta compressed 509 if (cl_nodelta->value || !cl.frame.valid || cls.demowaiting) 510 MSG_WriteLong (&buf, -1); // no compression 511 else 512 MSG_WriteLong (&buf, cl.frame.serverframe); 513 514 // send this and the previous cmds in the message, so 515 // if the last packet was dropped, it can be recovered 516 i = (cls.netchan.outgoing_sequence-2) & (CMD_BACKUP-1); 517 cmd = &cl.cmds[i]; 518 memset (&nullcmd, 0, sizeof(nullcmd)); 519 MSG_WriteDeltaUsercmd (&buf, &nullcmd, cmd); 520 oldcmd = cmd; 521 522 i = (cls.netchan.outgoing_sequence-1) & (CMD_BACKUP-1); 523 cmd = &cl.cmds[i]; 524 MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd); 525 oldcmd = cmd; 526 527 i = (cls.netchan.outgoing_sequence) & (CMD_BACKUP-1); 528 cmd = &cl.cmds[i]; 529 MSG_WriteDeltaUsercmd (&buf, oldcmd, cmd); 530 531 // calculate a checksum over the move commands 532 buf.data[checksumIndex] = COM_BlockSequenceCRCByte( 533 buf.data + checksumIndex + 1, buf.cursize - checksumIndex - 1, 534 cls.netchan.outgoing_sequence); 535 536 // 537 // deliver the message 538 // 539 Netchan_Transmit (&cls.netchan, buf.cursize, buf.data); 540 } 541 542