1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, 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// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All 23// rights reserved. 24 25#include "quakedef.h" 26 27/* 28=============================================================================== 29 30KEY BUTTONS 31 32Continuous button event tracking is complicated by the fact that two different 33input sources (say, mouse button 1 and the control key) can both press the 34same button, but the button should only be released when both of the 35pressing key have been released. 36 37When a key event issues a button command (+forward, +attack, etc), it appends 38its key number as a parameter to the command so it can be matched up with 39the release. 40 41state bit 0 is the current state of the key 42state bit 1 is edge triggered on the up to down transition 43state bit 2 is edge triggered on the down to up transition 44 45=============================================================================== 46*/ 47 48 49kbutton_t in_mlook, in_klook; 50kbutton_t in_left, in_right, in_forward, in_back; 51kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright; 52kbutton_t in_strafe, in_speed, in_use, in_jump, in_attack; 53kbutton_t in_up, in_down; 54 55int in_impulse; 56 57 58void KeyDown (kbutton_t *b) 59{ 60 int k; 61 const char *c; 62 63 c = Cmd_Argv(1); 64 if (c[0]) 65 k = atoi(c); 66 else 67 k = -1; // typed manually at the console for continuous down 68 69 if (k == b->down[0] || k == b->down[1]) 70 return; // repeating key 71 72 if (!b->down[0]) 73 b->down[0] = k; 74 else if (!b->down[1]) 75 b->down[1] = k; 76 else 77 { 78 Con_Printf ("Three keys down for a button!\n"); 79 return; 80 } 81 82 if (b->state & 1) 83 return; // still down 84 b->state |= 1 + 2; // down + impulse down 85} 86 87void KeyUp (kbutton_t *b) 88{ 89 int k; 90 const char *c; 91 92 c = Cmd_Argv(1); 93 if (c[0]) 94 k = atoi(c); 95 else 96 { // typed manually at the console, assume for unsticking, so clear all 97 b->down[0] = b->down[1] = 0; 98 b->state = 4; // impulse up 99 return; 100 } 101 102 if (b->down[0] == k) 103 b->down[0] = 0; 104 else if (b->down[1] == k) 105 b->down[1] = 0; 106 else 107 return; // key up without coresponding down (menu pass through) 108 if (b->down[0] || b->down[1]) 109 return; // some other key is still holding it down 110 111 if (!(b->state & 1)) 112 return; // still up (this should not happen) 113 b->state &= ~1; // now up 114 b->state |= 4; // impulse up 115} 116 117void IN_KLookDown (void) {KeyDown(&in_klook);} 118void IN_KLookUp (void) {KeyUp(&in_klook);} 119void IN_MLookDown (void) {KeyDown(&in_mlook);} 120void IN_MLookUp (void) { 121KeyUp(&in_mlook); 122if ( !(in_mlook.state&1) && lookspring.value) 123 V_StartPitchDrift(); 124} 125void IN_UpDown(void) {KeyDown(&in_up);} 126void IN_UpUp(void) {KeyUp(&in_up);} 127void IN_DownDown(void) {KeyDown(&in_down);} 128void IN_DownUp(void) {KeyUp(&in_down);} 129void IN_LeftDown(void) {KeyDown(&in_left);} 130void IN_LeftUp(void) {KeyUp(&in_left);} 131void IN_RightDown(void) {KeyDown(&in_right);} 132void IN_RightUp(void) {KeyUp(&in_right);} 133void IN_ForwardDown(void) {KeyDown(&in_forward);} 134void IN_ForwardUp(void) {KeyUp(&in_forward);} 135void IN_BackDown(void) {KeyDown(&in_back);} 136void IN_BackUp(void) {KeyUp(&in_back);} 137void IN_LookupDown(void) {KeyDown(&in_lookup);} 138void IN_LookupUp(void) {KeyUp(&in_lookup);} 139void IN_LookdownDown(void) {KeyDown(&in_lookdown);} 140void IN_LookdownUp(void) {KeyUp(&in_lookdown);} 141void IN_MoveleftDown(void) {KeyDown(&in_moveleft);} 142void IN_MoveleftUp(void) {KeyUp(&in_moveleft);} 143void IN_MoverightDown(void) {KeyDown(&in_moveright);} 144void IN_MoverightUp(void) {KeyUp(&in_moveright);} 145 146void IN_SpeedDown(void) {KeyDown(&in_speed);} 147void IN_SpeedUp(void) {KeyUp(&in_speed);} 148void IN_StrafeDown(void) {KeyDown(&in_strafe);} 149void IN_StrafeUp(void) {KeyUp(&in_strafe);} 150 151void IN_AttackDown(void) {KeyDown(&in_attack);} 152void IN_AttackUp(void) {KeyUp(&in_attack);} 153 154void IN_UseDown (void) {KeyDown(&in_use);} 155void IN_UseUp (void) {KeyUp(&in_use);} 156void IN_JumpDown (void) {KeyDown(&in_jump);} 157void IN_JumpUp (void) {KeyUp(&in_jump);} 158 159void IN_Impulse (void) {in_impulse=Q_atoi(Cmd_Argv(1));} 160 161/* 162=============== 163CL_KeyState 164 165Returns 0.25 if a key was pressed and released during the frame, 1660.5 if it was pressed and held 1670 if held then released, and 1681.0 if held for the entire time 169=============== 170*/ 171float CL_KeyState (kbutton_t *key) 172{ 173 float val; 174 qboolean impulsedown, impulseup, down; 175 176 impulsedown = key->state & 2; 177 impulseup = key->state & 4; 178 down = key->state & 1; 179 val = 0; 180 181 if (impulsedown && !impulseup) 182 { 183 if (down) 184 val = 0.5; // pressed and held this frame 185 else 186 val = 0; // I_Error (); 187 } 188 189 if (impulseup && !impulsedown) 190 { 191 if (down) 192 val = 0; // I_Error (); 193 else 194 val = 0; // released this frame 195 } 196 197 if (!impulsedown && !impulseup) 198 { 199 if (down) 200 val = 1.0; // held the entire frame 201 else 202 val = 0; // up the entire frame 203 } 204 205 if (impulsedown && impulseup) 206 { 207 if (down) 208 val = 0.75; // released and re-pressed this frame 209 else 210 val = 0.25; // pressed and released this frame 211 } 212 213 key->state &= 1; // clear impulses 214 215 return val; 216} 217 218 219 220 221//========================================================================== 222 223cvar_t cl_upspeed = CVAR2("cl_upspeed","200"); 224cvar_t cl_forwardspeed = CVAR3("cl_forwardspeed","200", true); 225cvar_t cl_backspeed = CVAR3("cl_backspeed","200", true); 226cvar_t cl_sidespeed = CVAR2("cl_sidespeed","350"); 227 228cvar_t cl_movespeedkey = CVAR2("cl_movespeedkey","2.0"); 229 230cvar_t cl_yawspeed = CVAR2("cl_yawspeed","140"); 231cvar_t cl_pitchspeed = CVAR2("cl_pitchspeed","150"); 232 233cvar_t cl_anglespeedkey = CVAR2("cl_anglespeedkey","1.5"); 234 235 236/* 237================ 238CL_AdjustAngles 239 240Moves the local angle positions 241================ 242*/ 243void CL_AdjustAngles (void) 244{ 245 float speed; 246 float up, down; 247 248 if (in_speed.state & 1) 249 speed = host_frametime * cl_anglespeedkey.value; 250 else 251 speed = host_frametime; 252 253 if (!(in_strafe.state & 1)) 254 { 255 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right); 256 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left); 257 cl.viewangles[YAW] = anglemod(cl.viewangles[YAW]); 258 } 259 if (in_klook.state & 1) 260 { 261 V_StopPitchDrift (); 262 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward); 263 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back); 264 } 265 266 up = CL_KeyState (&in_lookup); 267 down = CL_KeyState(&in_lookdown); 268 269 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up; 270 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down; 271 272 if (up || down) 273 V_StopPitchDrift (); 274 275 if (cl.viewangles[PITCH] > 80) 276 cl.viewangles[PITCH] = 80; 277 if (cl.viewangles[PITCH] < -70) 278 cl.viewangles[PITCH] = -70; 279 280 if (cl.viewangles[ROLL] > 50) 281 cl.viewangles[ROLL] = 50; 282 if (cl.viewangles[ROLL] < -50) 283 cl.viewangles[ROLL] = -50; 284 285} 286 287/* 288================ 289CL_BaseMove 290 291Send the intended movement message to the server 292================ 293*/ 294void CL_BaseMove (usercmd_t *cmd) 295{ 296 if (cls.signon != SIGNONS) 297 return; 298 299 CL_AdjustAngles (); 300 301 Q_memset (cmd, 0, sizeof(*cmd)); 302 303 if (in_strafe.state & 1) 304 { 305 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right); 306 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left); 307 } 308 309 cmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright); 310 cmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft); 311 312 cmd->upmove += cl_upspeed.value * CL_KeyState (&in_up); 313 cmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down); 314 315 if (! (in_klook.state & 1) ) 316 { 317 cmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward); 318 cmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back); 319 } 320 321// 322// adjust for speed key 323// 324 if (in_speed.state & 1) 325 { 326 cmd->forwardmove *= cl_movespeedkey.value; 327 cmd->sidemove *= cl_movespeedkey.value; 328 cmd->upmove *= cl_movespeedkey.value; 329 } 330 331#ifdef QUAKE2 332 cmd->lightlevel = cl.light_level; 333#endif 334} 335 336 337 338/* 339============== 340CL_SendMove 341============== 342*/ 343void CL_SendMove (usercmd_t *cmd) 344{ 345 int i; 346 int bits; 347 sizebuf_t buf; 348 byte data[128]; 349 350 buf.maxsize = 128; 351 buf.cursize = 0; 352 buf.data = data; 353 354 cl.cmd = *cmd; 355 356// 357// send the movement message 358// 359 MSG_WriteByte (&buf, clc_move); 360 361 MSG_WriteFloat (&buf, cl.mtime[0]); // so server can get ping times 362 363 for (i=0 ; i<3 ; i++) 364 MSG_WriteAngle (&buf, cl.viewangles[i]); 365 366 MSG_WriteShort (&buf, (short) cmd->forwardmove); 367 MSG_WriteShort (&buf, (short) cmd->sidemove); 368 MSG_WriteShort (&buf, (short) cmd->upmove); 369 370// 371// send button bits 372// 373 bits = 0; 374 375 if ( in_attack.state & 3 ) 376 bits |= 1; 377 in_attack.state &= ~2; 378 379 if (in_jump.state & 3) 380 bits |= 2; 381 in_jump.state &= ~2; 382 383 MSG_WriteByte (&buf, bits); 384 385 MSG_WriteByte (&buf, in_impulse); 386 in_impulse = 0; 387 388#ifdef QUAKE2 389// 390// light level 391// 392 MSG_WriteByte (&buf, cmd->lightlevel); 393#endif 394 395// 396// deliver the message 397// 398 if (cls.demoplayback) 399 return; 400 401// 402// allways dump the first two message, because it may contain leftover inputs 403// from the last level 404// 405 if (++cl.movemessages <= 2) 406 return; 407 408 if (NET_SendUnreliableMessage (cls.netcon, &buf) == -1) 409 { 410 Con_Printf ("CL_SendMove: lost server connection\n"); 411 CL_Disconnect (); 412 } 413} 414 415/* 416============ 417CL_InitInput 418============ 419*/ 420void CL_InitInput (void) 421{ 422 Cmd_AddCommand ("+moveup",IN_UpDown); 423 Cmd_AddCommand ("-moveup",IN_UpUp); 424 Cmd_AddCommand ("+movedown",IN_DownDown); 425 Cmd_AddCommand ("-movedown",IN_DownUp); 426 Cmd_AddCommand ("+left",IN_LeftDown); 427 Cmd_AddCommand ("-left",IN_LeftUp); 428 Cmd_AddCommand ("+right",IN_RightDown); 429 Cmd_AddCommand ("-right",IN_RightUp); 430 Cmd_AddCommand ("+forward",IN_ForwardDown); 431 Cmd_AddCommand ("-forward",IN_ForwardUp); 432 Cmd_AddCommand ("+back",IN_BackDown); 433 Cmd_AddCommand ("-back",IN_BackUp); 434 Cmd_AddCommand ("+lookup", IN_LookupDown); 435 Cmd_AddCommand ("-lookup", IN_LookupUp); 436 Cmd_AddCommand ("+lookdown", IN_LookdownDown); 437 Cmd_AddCommand ("-lookdown", IN_LookdownUp); 438 Cmd_AddCommand ("+strafe", IN_StrafeDown); 439 Cmd_AddCommand ("-strafe", IN_StrafeUp); 440 Cmd_AddCommand ("+moveleft", IN_MoveleftDown); 441 Cmd_AddCommand ("-moveleft", IN_MoveleftUp); 442 Cmd_AddCommand ("+moveright", IN_MoverightDown); 443 Cmd_AddCommand ("-moveright", IN_MoverightUp); 444 Cmd_AddCommand ("+speed", IN_SpeedDown); 445 Cmd_AddCommand ("-speed", IN_SpeedUp); 446 Cmd_AddCommand ("+attack", IN_AttackDown); 447 Cmd_AddCommand ("-attack", IN_AttackUp); 448 Cmd_AddCommand ("+use", IN_UseDown); 449 Cmd_AddCommand ("-use", IN_UseUp); 450 Cmd_AddCommand ("+jump", IN_JumpDown); 451 Cmd_AddCommand ("-jump", IN_JumpUp); 452 Cmd_AddCommand ("impulse", IN_Impulse); 453 Cmd_AddCommand ("+klook", IN_KLookDown); 454 Cmd_AddCommand ("-klook", IN_KLookUp); 455 Cmd_AddCommand ("+mlook", IN_MLookDown); 456 Cmd_AddCommand ("-mlook", IN_MLookUp); 457 458} 459 460