1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4
5 This file is part of Quake III Arena source code.
6
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
21 */
22 // cl.input.c -- builds an intended movement command to send to the server
23
24 #include "client.h"
25
26 unsigned frame_msec;
27 int old_com_frameTime;
28
29 /*
30 ===============================================================================
31
32 KEY BUTTONS
33
34 Continuous button event tracking is complicated by the fact that two different
35 input sources (say, mouse button 1 and the control key) can both press the
36 same button, but the button should only be released when both of the
37 pressing key have been released.
38
39 When a key event issues a button command (+forward, +attack, etc), it appends
40 its key number as argv(1) so it can be matched up with the release.
41
42 argv(2) will be set to the time the event happened, which allows exact
43 control even at low framerates when the down and up events may both get qued
44 at the same time.
45
46 ===============================================================================
47 */
48
49
50 kbutton_t in_left, in_right, in_forward, in_back;
51 kbutton_t in_lookup, in_lookdown, in_moveleft, in_moveright;
52 kbutton_t in_strafe, in_speed;
53 kbutton_t in_up, in_down;
54
55 #ifdef USE_VOIP
56 kbutton_t in_voiprecord;
57 #endif
58
59 kbutton_t in_buttons[16];
60
61
62 qboolean in_mlooking;
63
64
IN_MLookDown(void)65 void IN_MLookDown( void ) {
66 in_mlooking = qtrue;
67 }
68
IN_MLookUp(void)69 void IN_MLookUp( void ) {
70 in_mlooking = qfalse;
71 if ( !cl_freelook->integer ) {
72 IN_CenterView ();
73 }
74 }
75
IN_KeyDown(kbutton_t * b)76 void IN_KeyDown( kbutton_t *b ) {
77 int k;
78 char *c;
79
80 c = Cmd_Argv(1);
81 if ( c[0] ) {
82 k = atoi(c);
83 } else {
84 k = -1; // typed manually at the console for continuous down
85 }
86
87 if ( k == b->down[0] || k == b->down[1] ) {
88 return; // repeating key
89 }
90
91 if ( !b->down[0] ) {
92 b->down[0] = k;
93 } else if ( !b->down[1] ) {
94 b->down[1] = k;
95 } else {
96 Com_Printf ("Three keys down for a button!\n");
97 return;
98 }
99
100 if ( b->active ) {
101 return; // still down
102 }
103
104 // save timestamp for partial frame summing
105 c = Cmd_Argv(2);
106 b->downtime = atoi(c);
107
108 b->active = qtrue;
109 b->wasPressed = qtrue;
110 }
111
IN_KeyUp(kbutton_t * b)112 void IN_KeyUp( kbutton_t *b ) {
113 int k;
114 char *c;
115 unsigned uptime;
116
117 c = Cmd_Argv(1);
118 if ( c[0] ) {
119 k = atoi(c);
120 } else {
121 // typed manually at the console, assume for unsticking, so clear all
122 b->down[0] = b->down[1] = 0;
123 b->active = qfalse;
124 return;
125 }
126
127 if ( b->down[0] == k ) {
128 b->down[0] = 0;
129 } else if ( b->down[1] == k ) {
130 b->down[1] = 0;
131 } else {
132 return; // key up without coresponding down (menu pass through)
133 }
134 if ( b->down[0] || b->down[1] ) {
135 return; // some other key is still holding it down
136 }
137
138 b->active = qfalse;
139
140 // save timestamp for partial frame summing
141 c = Cmd_Argv(2);
142 uptime = atoi(c);
143 if ( uptime ) {
144 b->msec += uptime - b->downtime;
145 } else {
146 b->msec += frame_msec / 2;
147 }
148
149 b->active = qfalse;
150 }
151
152
153
154 /*
155 ===============
156 CL_KeyState
157
158 Returns the fraction of the frame that the key was down
159 ===============
160 */
CL_KeyState(kbutton_t * key)161 float CL_KeyState( kbutton_t *key ) {
162 float val;
163 int msec;
164
165 msec = key->msec;
166 key->msec = 0;
167
168 if ( key->active ) {
169 // still down
170 if ( !key->downtime ) {
171 msec = com_frameTime;
172 } else {
173 msec += com_frameTime - key->downtime;
174 }
175 key->downtime = com_frameTime;
176 }
177
178 #if 0
179 if (msec) {
180 Com_Printf ("%i ", msec);
181 }
182 #endif
183
184 val = (float)msec / frame_msec;
185 if ( val < 0 ) {
186 val = 0;
187 }
188 if ( val > 1 ) {
189 val = 1;
190 }
191
192 return val;
193 }
194
195
196
IN_UpDown(void)197 void IN_UpDown(void) {IN_KeyDown(&in_up);}
IN_UpUp(void)198 void IN_UpUp(void) {IN_KeyUp(&in_up);}
IN_DownDown(void)199 void IN_DownDown(void) {IN_KeyDown(&in_down);}
IN_DownUp(void)200 void IN_DownUp(void) {IN_KeyUp(&in_down);}
IN_LeftDown(void)201 void IN_LeftDown(void) {IN_KeyDown(&in_left);}
IN_LeftUp(void)202 void IN_LeftUp(void) {IN_KeyUp(&in_left);}
IN_RightDown(void)203 void IN_RightDown(void) {IN_KeyDown(&in_right);}
IN_RightUp(void)204 void IN_RightUp(void) {IN_KeyUp(&in_right);}
IN_ForwardDown(void)205 void IN_ForwardDown(void) {IN_KeyDown(&in_forward);}
IN_ForwardUp(void)206 void IN_ForwardUp(void) {IN_KeyUp(&in_forward);}
IN_BackDown(void)207 void IN_BackDown(void) {IN_KeyDown(&in_back);}
IN_BackUp(void)208 void IN_BackUp(void) {IN_KeyUp(&in_back);}
IN_LookupDown(void)209 void IN_LookupDown(void) {IN_KeyDown(&in_lookup);}
IN_LookupUp(void)210 void IN_LookupUp(void) {IN_KeyUp(&in_lookup);}
IN_LookdownDown(void)211 void IN_LookdownDown(void) {IN_KeyDown(&in_lookdown);}
IN_LookdownUp(void)212 void IN_LookdownUp(void) {IN_KeyUp(&in_lookdown);}
IN_MoveleftDown(void)213 void IN_MoveleftDown(void) {IN_KeyDown(&in_moveleft);}
IN_MoveleftUp(void)214 void IN_MoveleftUp(void) {IN_KeyUp(&in_moveleft);}
IN_MoverightDown(void)215 void IN_MoverightDown(void) {IN_KeyDown(&in_moveright);}
IN_MoverightUp(void)216 void IN_MoverightUp(void) {IN_KeyUp(&in_moveright);}
217
IN_SpeedDown(void)218 void IN_SpeedDown(void) {IN_KeyDown(&in_speed);}
IN_SpeedUp(void)219 void IN_SpeedUp(void) {IN_KeyUp(&in_speed);}
IN_StrafeDown(void)220 void IN_StrafeDown(void) {IN_KeyDown(&in_strafe);}
IN_StrafeUp(void)221 void IN_StrafeUp(void) {IN_KeyUp(&in_strafe);}
222
223 #ifdef USE_VOIP
IN_VoipRecordDown(void)224 void IN_VoipRecordDown(void)
225 {
226 IN_KeyDown(&in_voiprecord);
227 Cvar_Set("cl_voipSend", "1");
228 }
229
IN_VoipRecordUp(void)230 void IN_VoipRecordUp(void)
231 {
232 IN_KeyUp(&in_voiprecord);
233 Cvar_Set("cl_voipSend", "0");
234 }
235 #endif
236
IN_Button0Down(void)237 void IN_Button0Down(void) {IN_KeyDown(&in_buttons[0]);}
IN_Button0Up(void)238 void IN_Button0Up(void) {IN_KeyUp(&in_buttons[0]);}
IN_Button1Down(void)239 void IN_Button1Down(void) {IN_KeyDown(&in_buttons[1]);}
IN_Button1Up(void)240 void IN_Button1Up(void) {IN_KeyUp(&in_buttons[1]);}
IN_Button2Down(void)241 void IN_Button2Down(void) {IN_KeyDown(&in_buttons[2]);}
IN_Button2Up(void)242 void IN_Button2Up(void) {IN_KeyUp(&in_buttons[2]);}
IN_Button3Down(void)243 void IN_Button3Down(void) {IN_KeyDown(&in_buttons[3]);}
IN_Button3Up(void)244 void IN_Button3Up(void) {IN_KeyUp(&in_buttons[3]);}
IN_Button4Down(void)245 void IN_Button4Down(void) {IN_KeyDown(&in_buttons[4]);}
IN_Button4Up(void)246 void IN_Button4Up(void) {IN_KeyUp(&in_buttons[4]);}
IN_Button5Down(void)247 void IN_Button5Down(void) {IN_KeyDown(&in_buttons[5]);}
IN_Button5Up(void)248 void IN_Button5Up(void) {IN_KeyUp(&in_buttons[5]);}
IN_Button6Down(void)249 void IN_Button6Down(void) {IN_KeyDown(&in_buttons[6]);}
IN_Button6Up(void)250 void IN_Button6Up(void) {IN_KeyUp(&in_buttons[6]);}
IN_Button7Down(void)251 void IN_Button7Down(void) {IN_KeyDown(&in_buttons[7]);}
IN_Button7Up(void)252 void IN_Button7Up(void) {IN_KeyUp(&in_buttons[7]);}
IN_Button8Down(void)253 void IN_Button8Down(void) {IN_KeyDown(&in_buttons[8]);}
IN_Button8Up(void)254 void IN_Button8Up(void) {IN_KeyUp(&in_buttons[8]);}
IN_Button9Down(void)255 void IN_Button9Down(void) {IN_KeyDown(&in_buttons[9]);}
IN_Button9Up(void)256 void IN_Button9Up(void) {IN_KeyUp(&in_buttons[9]);}
IN_Button10Down(void)257 void IN_Button10Down(void) {IN_KeyDown(&in_buttons[10]);}
IN_Button10Up(void)258 void IN_Button10Up(void) {IN_KeyUp(&in_buttons[10]);}
IN_Button11Down(void)259 void IN_Button11Down(void) {IN_KeyDown(&in_buttons[11]);}
IN_Button11Up(void)260 void IN_Button11Up(void) {IN_KeyUp(&in_buttons[11]);}
IN_Button12Down(void)261 void IN_Button12Down(void) {IN_KeyDown(&in_buttons[12]);}
IN_Button12Up(void)262 void IN_Button12Up(void) {IN_KeyUp(&in_buttons[12]);}
IN_Button13Down(void)263 void IN_Button13Down(void) {IN_KeyDown(&in_buttons[13]);}
IN_Button13Up(void)264 void IN_Button13Up(void) {IN_KeyUp(&in_buttons[13]);}
IN_Button14Down(void)265 void IN_Button14Down(void) {IN_KeyDown(&in_buttons[14]);}
IN_Button14Up(void)266 void IN_Button14Up(void) {IN_KeyUp(&in_buttons[14]);}
IN_Button15Down(void)267 void IN_Button15Down(void) {IN_KeyDown(&in_buttons[15]);}
IN_Button15Up(void)268 void IN_Button15Up(void) {IN_KeyUp(&in_buttons[15]);}
269
IN_ButtonDown(void)270 void IN_ButtonDown (void) {
271 IN_KeyDown(&in_buttons[1]);}
IN_ButtonUp(void)272 void IN_ButtonUp (void) {
273 IN_KeyUp(&in_buttons[1]);}
274
IN_CenterView(void)275 void IN_CenterView (void) {
276 cl.viewangles[PITCH] = -SHORT2ANGLE(cl.snap.ps.delta_angles[PITCH]);
277 }
278
279
280 //==========================================================================
281
282 cvar_t *cl_upspeed;
283 cvar_t *cl_forwardspeed;
284 cvar_t *cl_sidespeed;
285
286 cvar_t *cl_yawspeed;
287 cvar_t *cl_pitchspeed;
288
289 cvar_t *cl_run;
290
291 cvar_t *cl_anglespeedkey;
292
293
294 /*
295 ================
296 CL_AdjustAngles
297
298 Moves the local angle positions
299 ================
300 */
CL_AdjustAngles(void)301 void CL_AdjustAngles( void ) {
302 float speed;
303
304 if ( in_speed.active ) {
305 speed = 0.001 * cls.frametime * cl_anglespeedkey->value;
306 } else {
307 speed = 0.001 * cls.frametime;
308 }
309
310 if ( !in_strafe.active ) {
311 cl.viewangles[YAW] -= speed*cl_yawspeed->value*CL_KeyState (&in_right);
312 cl.viewangles[YAW] += speed*cl_yawspeed->value*CL_KeyState (&in_left);
313 }
314
315 cl.viewangles[PITCH] -= speed*cl_pitchspeed->value * CL_KeyState (&in_lookup);
316 cl.viewangles[PITCH] += speed*cl_pitchspeed->value * CL_KeyState (&in_lookdown);
317 }
318
319 /*
320 ================
321 CL_KeyMove
322
323 Sets the usercmd_t based on key states
324 ================
325 */
CL_KeyMove(usercmd_t * cmd)326 void CL_KeyMove( usercmd_t *cmd ) {
327 int movespeed;
328 int forward, side, up;
329
330 //
331 // adjust for speed key / running
332 // the walking flag is to keep animations consistant
333 // even during acceleration and develeration
334 //
335 if ( in_speed.active ^ cl_run->integer ) {
336 movespeed = 127;
337 cmd->buttons &= ~BUTTON_WALKING;
338 } else {
339 cmd->buttons |= BUTTON_WALKING;
340 movespeed = 64;
341 }
342
343 forward = 0;
344 side = 0;
345 up = 0;
346 if ( in_strafe.active ) {
347 side += movespeed * CL_KeyState (&in_right);
348 side -= movespeed * CL_KeyState (&in_left);
349 }
350
351 side += movespeed * CL_KeyState (&in_moveright);
352 side -= movespeed * CL_KeyState (&in_moveleft);
353
354
355 up += movespeed * CL_KeyState (&in_up);
356 up -= movespeed * CL_KeyState (&in_down);
357
358 forward += movespeed * CL_KeyState (&in_forward);
359 forward -= movespeed * CL_KeyState (&in_back);
360
361 cmd->forwardmove = ClampChar( forward );
362 cmd->rightmove = ClampChar( side );
363 cmd->upmove = ClampChar( up );
364 }
365
366 /*
367 =================
368 CL_MouseEvent
369 =================
370 */
CL_MouseEvent(int dx,int dy,int time)371 void CL_MouseEvent( int dx, int dy, int time ) {
372 if ( Key_GetCatcher( ) & KEYCATCH_UI ) {
373 VM_Call( uivm, UI_MOUSE_EVENT, dx, dy );
374 } else if (Key_GetCatcher( ) & KEYCATCH_CGAME) {
375 VM_Call (cgvm, CG_MOUSE_EVENT, dx, dy);
376 } else {
377 cl.mouseDx[cl.mouseIndex] += dx;
378 cl.mouseDy[cl.mouseIndex] += dy;
379 }
380 }
381
382 /*
383 =================
384 CL_JoystickEvent
385
386 Joystick values stay set until changed
387 =================
388 */
CL_JoystickEvent(int axis,int value,int time)389 void CL_JoystickEvent( int axis, int value, int time ) {
390 if ( axis < 0 || axis >= MAX_JOYSTICK_AXIS ) {
391 Com_Error( ERR_DROP, "CL_JoystickEvent: bad axis %i", axis );
392 }
393 cl.joystickAxis[axis] = value;
394 }
395
396 /*
397 =================
398 CL_JoystickMove
399 =================
400 */
CL_JoystickMove(usercmd_t * cmd)401 void CL_JoystickMove( usercmd_t *cmd ) {
402 int movespeed;
403 float anglespeed;
404
405 if ( in_speed.active ^ cl_run->integer ) {
406 movespeed = 2;
407 } else {
408 movespeed = 1;
409 cmd->buttons |= BUTTON_WALKING;
410 }
411
412 if ( in_speed.active ) {
413 anglespeed = 0.001 * cls.frametime * cl_anglespeedkey->value;
414 } else {
415 anglespeed = 0.001 * cls.frametime;
416 }
417
418 if ( !in_strafe.active ) {
419 cl.viewangles[YAW] += anglespeed * cl_yawspeed->value * cl.joystickAxis[AXIS_SIDE];
420 } else {
421 cmd->rightmove = ClampChar( cmd->rightmove + cl.joystickAxis[AXIS_SIDE] );
422 }
423
424 if ( in_mlooking ) {
425 cl.viewangles[PITCH] += anglespeed * cl_pitchspeed->value * cl.joystickAxis[AXIS_FORWARD];
426 } else {
427 cmd->forwardmove = ClampChar( cmd->forwardmove + cl.joystickAxis[AXIS_FORWARD] );
428 }
429
430 cmd->upmove = ClampChar( cmd->upmove + cl.joystickAxis[AXIS_UP] );
431 }
432
433 /*
434 =================
435 CL_MouseMove
436 =================
437 */
CL_MouseMove(usercmd_t * cmd)438 void CL_MouseMove( usercmd_t *cmd ) {
439 float mx, my;
440 float accelSensitivity;
441 float rate;
442
443 // allow mouse smoothing
444 if ( m_filter->integer ) {
445 mx = ( cl.mouseDx[0] + cl.mouseDx[1] ) * 0.5;
446 my = ( cl.mouseDy[0] + cl.mouseDy[1] ) * 0.5;
447 } else {
448 mx = cl.mouseDx[cl.mouseIndex];
449 my = cl.mouseDy[cl.mouseIndex];
450 }
451 cl.mouseIndex ^= 1;
452 cl.mouseDx[cl.mouseIndex] = 0;
453 cl.mouseDy[cl.mouseIndex] = 0;
454
455 rate = sqrt( mx * mx + my * my ) / (float)frame_msec;
456 accelSensitivity = cl_sensitivity->value + rate * cl_mouseAccel->value;
457
458 // scale by FOV
459 accelSensitivity *= cl.cgameSensitivity;
460
461 if ( rate && cl_showMouseRate->integer ) {
462 Com_Printf( "%f : %f\n", rate, accelSensitivity );
463 }
464
465 mx *= accelSensitivity;
466 my *= accelSensitivity;
467
468 if (!mx && !my) {
469 return;
470 }
471
472 // add mouse X/Y movement to cmd
473 if ( in_strafe.active ) {
474 cmd->rightmove = ClampChar( cmd->rightmove + m_side->value * mx );
475 } else {
476 cl.viewangles[YAW] -= m_yaw->value * mx;
477 }
478
479 if ( (in_mlooking || cl_freelook->integer) && !in_strafe.active ) {
480 cl.viewangles[PITCH] += m_pitch->value * my;
481 } else {
482 cmd->forwardmove = ClampChar( cmd->forwardmove - m_forward->value * my );
483 }
484 }
485
486
487 /*
488 ==============
489 CL_CmdButtons
490 ==============
491 */
CL_CmdButtons(usercmd_t * cmd)492 void CL_CmdButtons( usercmd_t *cmd ) {
493 int i;
494
495 //
496 // figure button bits
497 // send a button bit even if the key was pressed and released in
498 // less than a frame
499 //
500 for (i = 0 ; i < 15 ; i++) {
501 if ( in_buttons[i].active || in_buttons[i].wasPressed ) {
502 cmd->buttons |= 1 << i;
503 }
504 in_buttons[i].wasPressed = qfalse;
505 }
506
507 if ( Key_GetCatcher( ) ) {
508 cmd->buttons |= BUTTON_TALK;
509 }
510
511 // allow the game to know if any key at all is
512 // currently pressed, even if it isn't bound to anything
513 if ( anykeydown && Key_GetCatcher( ) == 0 ) {
514 cmd->buttons |= BUTTON_ANY;
515 }
516 }
517
518
519 /*
520 ==============
521 CL_FinishMove
522 ==============
523 */
CL_FinishMove(usercmd_t * cmd)524 void CL_FinishMove( usercmd_t *cmd ) {
525 int i;
526
527 // copy the state that the cgame is currently sending
528 cmd->weapon = cl.cgameUserCmdValue;
529
530 // send the current server time so the amount of movement
531 // can be determined without allowing cheating
532 cmd->serverTime = cl.serverTime;
533
534 for (i=0 ; i<3 ; i++) {
535 cmd->angles[i] = ANGLE2SHORT(cl.viewangles[i]);
536 }
537 }
538
539
540 /*
541 =================
542 CL_CreateCmd
543 =================
544 */
CL_CreateCmd(void)545 usercmd_t CL_CreateCmd( void ) {
546 usercmd_t cmd;
547 vec3_t oldAngles;
548
549 VectorCopy( cl.viewangles, oldAngles );
550
551 // keyboard angle adjustment
552 CL_AdjustAngles ();
553
554 Com_Memset( &cmd, 0, sizeof( cmd ) );
555
556 CL_CmdButtons( &cmd );
557
558 // get basic movement from keyboard
559 CL_KeyMove( &cmd );
560
561 // get basic movement from mouse
562 CL_MouseMove( &cmd );
563
564 // get basic movement from joystick
565 CL_JoystickMove( &cmd );
566
567 // check to make sure the angles haven't wrapped
568 if ( cl.viewangles[PITCH] - oldAngles[PITCH] > 90 ) {
569 cl.viewangles[PITCH] = oldAngles[PITCH] + 90;
570 } else if ( oldAngles[PITCH] - cl.viewangles[PITCH] > 90 ) {
571 cl.viewangles[PITCH] = oldAngles[PITCH] - 90;
572 }
573
574 // store out the final values
575 CL_FinishMove( &cmd );
576
577 // draw debug graphs of turning for mouse testing
578 if ( cl_debugMove->integer ) {
579 if ( cl_debugMove->integer == 1 ) {
580 SCR_DebugGraph( abs(cl.viewangles[YAW] - oldAngles[YAW]), 0 );
581 }
582 if ( cl_debugMove->integer == 2 ) {
583 SCR_DebugGraph( abs(cl.viewangles[PITCH] - oldAngles[PITCH]), 0 );
584 }
585 }
586
587 return cmd;
588 }
589
590
591 /*
592 =================
593 CL_CreateNewCommands
594
595 Create a new usercmd_t structure for this frame
596 =================
597 */
CL_CreateNewCommands(void)598 void CL_CreateNewCommands( void ) {
599 usercmd_t *cmd;
600 int cmdNum;
601
602 // no need to create usercmds until we have a gamestate
603 if ( cls.state < CA_PRIMED ) {
604 return;
605 }
606
607 frame_msec = com_frameTime - old_com_frameTime;
608
609 // if running less than 5fps, truncate the extra time to prevent
610 // unexpected moves after a hitch
611 if ( frame_msec > 200 ) {
612 frame_msec = 200;
613 }
614 old_com_frameTime = com_frameTime;
615
616
617 // generate a command for this frame
618 cl.cmdNumber++;
619 cmdNum = cl.cmdNumber & CMD_MASK;
620 cl.cmds[cmdNum] = CL_CreateCmd ();
621 cmd = &cl.cmds[cmdNum];
622 }
623
624 /*
625 =================
626 CL_ReadyToSendPacket
627
628 Returns qfalse if we are over the maxpackets limit
629 and should choke back the bandwidth a bit by not sending
630 a packet this frame. All the commands will still get
631 delivered in the next packet, but saving a header and
632 getting more delta compression will reduce total bandwidth.
633 =================
634 */
CL_ReadyToSendPacket(void)635 qboolean CL_ReadyToSendPacket( void ) {
636 int oldPacketNum;
637 int delta;
638
639 // don't send anything if playing back a demo
640 if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
641 return qfalse;
642 }
643
644 // If we are downloading, we send no less than 50ms between packets
645 if ( *clc.downloadTempName &&
646 cls.realtime - clc.lastPacketSentTime < 50 ) {
647 return qfalse;
648 }
649
650 // if we don't have a valid gamestate yet, only send
651 // one packet a second
652 if ( cls.state != CA_ACTIVE &&
653 cls.state != CA_PRIMED &&
654 !*clc.downloadTempName &&
655 cls.realtime - clc.lastPacketSentTime < 1000 ) {
656 return qfalse;
657 }
658
659 // send every frame for loopbacks
660 if ( clc.netchan.remoteAddress.type == NA_LOOPBACK ) {
661 return qtrue;
662 }
663
664 // send every frame for LAN
665 if ( cl_lanForcePackets->integer && Sys_IsLANAddress( clc.netchan.remoteAddress ) ) {
666 return qtrue;
667 }
668
669 // check for exceeding cl_maxpackets
670 if ( cl_maxpackets->integer < 15 ) {
671 Cvar_Set( "cl_maxpackets", "15" );
672 } else if ( cl_maxpackets->integer > 125 ) {
673 Cvar_Set( "cl_maxpackets", "125" );
674 }
675 oldPacketNum = (clc.netchan.outgoingSequence - 1) & PACKET_MASK;
676 delta = cls.realtime - cl.outPackets[ oldPacketNum ].p_realtime;
677 if ( delta < 1000 / cl_maxpackets->integer ) {
678 // the accumulated commands will go out in the next packet
679 return qfalse;
680 }
681
682 return qtrue;
683 }
684
685 /*
686 ===================
687 CL_WritePacket
688
689 Create and send the command packet to the server
690 Including both the reliable commands and the usercmds
691
692 During normal gameplay, a client packet will contain something like:
693
694 4 sequence number
695 2 qport
696 4 serverid
697 4 acknowledged sequence number
698 4 clc.serverCommandSequence
699 <optional reliable commands>
700 1 clc_move or clc_moveNoDelta
701 1 command count
702 <count * usercmds>
703
704 ===================
705 */
CL_WritePacket(void)706 void CL_WritePacket( void ) {
707 msg_t buf;
708 byte data[MAX_MSGLEN];
709 int i, j;
710 usercmd_t *cmd, *oldcmd;
711 usercmd_t nullcmd;
712 int packetNum;
713 int oldPacketNum;
714 int count, key;
715
716 // don't send anything if playing back a demo
717 if ( clc.demoplaying || cls.state == CA_CINEMATIC ) {
718 return;
719 }
720
721 Com_Memset( &nullcmd, 0, sizeof(nullcmd) );
722 oldcmd = &nullcmd;
723
724 MSG_Init( &buf, data, sizeof(data) );
725
726 MSG_Bitstream( &buf );
727 // write the current serverId so the server
728 // can tell if this is from the current gameState
729 MSG_WriteLong( &buf, cl.serverId );
730
731 // write the last message we received, which can
732 // be used for delta compression, and is also used
733 // to tell if we dropped a gamestate
734 MSG_WriteLong( &buf, clc.serverMessageSequence );
735
736 // write the last reliable message we received
737 MSG_WriteLong( &buf, clc.serverCommandSequence );
738
739 // write any unacknowledged clientCommands
740 for ( i = clc.reliableAcknowledge + 1 ; i <= clc.reliableSequence ; i++ ) {
741 MSG_WriteByte( &buf, clc_clientCommand );
742 MSG_WriteLong( &buf, i );
743 MSG_WriteString( &buf, clc.reliableCommands[ i & (MAX_RELIABLE_COMMANDS-1) ] );
744 }
745
746 // we want to send all the usercmds that were generated in the last
747 // few packet, so even if a couple packets are dropped in a row,
748 // all the cmds will make it to the server
749 if ( cl_packetdup->integer < 0 ) {
750 Cvar_Set( "cl_packetdup", "0" );
751 } else if ( cl_packetdup->integer > 5 ) {
752 Cvar_Set( "cl_packetdup", "5" );
753 }
754 oldPacketNum = (clc.netchan.outgoingSequence - 1 - cl_packetdup->integer) & PACKET_MASK;
755 count = cl.cmdNumber - cl.outPackets[ oldPacketNum ].p_cmdNumber;
756 if ( count > MAX_PACKET_USERCMDS ) {
757 count = MAX_PACKET_USERCMDS;
758 Com_Printf("MAX_PACKET_USERCMDS\n");
759 }
760
761 #ifdef USE_VOIP
762 if (clc.voipOutgoingDataSize > 0) { // only send if data.
763 // Move cl_voipSendTarget from a string to the bitmasks if needed.
764 if (cl_voipSendTarget->modified) {
765 char buffer[32];
766 const char *target = cl_voipSendTarget->string;
767
768 if (Q_stricmp(target, "attacker") == 0) {
769 int player = VM_Call( cgvm, CG_LAST_ATTACKER );
770 Com_sprintf(buffer, sizeof (buffer), "%d", player);
771 target = buffer;
772 } else if (Q_stricmp(target, "crosshair") == 0) {
773 int player = VM_Call( cgvm, CG_CROSSHAIR_PLAYER );
774 Com_sprintf(buffer, sizeof (buffer), "%d", player);
775 target = buffer;
776 }
777
778 if ((*target == '\0') || (Q_stricmp(target, "all") == 0)) {
779 const int all = 0x7FFFFFFF;
780 clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = all;
781 } else if (Q_stricmp(target, "none") == 0) {
782 clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
783 } else {
784 const char *ptr = target;
785 clc.voipTarget1 = clc.voipTarget2 = clc.voipTarget3 = 0;
786 do {
787 if ((*ptr == ',') || (*ptr == '\0')) {
788 const int val = atoi(target);
789 target = ptr + 1;
790 if ((val >= 0) && (val < 31)) {
791 clc.voipTarget1 |= (1 << (val-0));
792 } else if ((val >= 31) && (val < 62)) {
793 clc.voipTarget2 |= (1 << (val-31));
794 } else if ((val >= 62) && (val < 93)) {
795 clc.voipTarget3 |= (1 << (val-62));
796 }
797 }
798 } while (*(ptr++));
799 }
800 cl_voipSendTarget->modified = qfalse;
801 }
802
803 MSG_WriteByte (&buf, clc_EOF); // placate legacy servers.
804 MSG_WriteByte (&buf, clc_extension);
805 MSG_WriteByte (&buf, clc_voip);
806 MSG_WriteByte (&buf, clc.voipOutgoingGeneration);
807 MSG_WriteLong (&buf, clc.voipOutgoingSequence);
808 MSG_WriteByte (&buf, clc.voipOutgoingDataFrames);
809 MSG_WriteLong (&buf, clc.voipTarget1);
810 MSG_WriteLong (&buf, clc.voipTarget2);
811 MSG_WriteLong (&buf, clc.voipTarget3);
812 MSG_WriteShort (&buf, clc.voipOutgoingDataSize);
813 MSG_WriteData (&buf, clc.voipOutgoingData, clc.voipOutgoingDataSize);
814
815 // If we're recording a demo, we have to fake a server packet with
816 // this VoIP data so it gets to disk; the server doesn't send it
817 // back to us, and we might as well eliminate concerns about dropped
818 // and misordered packets here.
819 if ( clc.demorecording && !clc.demowaiting ) {
820 const int voipSize = clc.voipOutgoingDataSize;
821 msg_t fakemsg;
822 byte fakedata[MAX_MSGLEN];
823 MSG_Init (&fakemsg, fakedata, sizeof (fakedata));
824 MSG_Bitstream (&fakemsg);
825 MSG_WriteLong (&fakemsg, clc.reliableAcknowledge);
826 MSG_WriteByte (&fakemsg, svc_EOF);
827 MSG_WriteByte (&fakemsg, svc_extension);
828 MSG_WriteByte (&fakemsg, svc_voip);
829 MSG_WriteShort (&fakemsg, clc.clientNum);
830 MSG_WriteByte (&fakemsg, clc.voipOutgoingGeneration);
831 MSG_WriteLong (&fakemsg, clc.voipOutgoingSequence);
832 MSG_WriteByte (&fakemsg, clc.voipOutgoingDataFrames);
833 MSG_WriteShort (&fakemsg, clc.voipOutgoingDataSize );
834 MSG_WriteData (&fakemsg, clc.voipOutgoingData, voipSize);
835 MSG_WriteByte (&fakemsg, svc_EOF);
836 CL_WriteDemoMessage (&fakemsg, 0);
837 }
838
839 clc.voipOutgoingSequence += clc.voipOutgoingDataFrames;
840 clc.voipOutgoingDataSize = 0;
841 clc.voipOutgoingDataFrames = 0;
842 } else
843 #endif
844
845 if ( count >= 1 ) {
846 if ( cl_showSend->integer ) {
847 Com_Printf( "(%i)", count );
848 }
849
850 // begin a client move command
851 if ( cl_nodelta->integer || !cl.snap.valid || clc.demowaiting
852 || clc.serverMessageSequence != cl.snap.messageNum ) {
853 MSG_WriteByte (&buf, clc_moveNoDelta);
854 } else {
855 MSG_WriteByte (&buf, clc_move);
856 }
857
858 // write the command count
859 MSG_WriteByte( &buf, count );
860
861 // use the checksum feed in the key
862 key = clc.checksumFeed;
863 // also use the message acknowledge
864 key ^= clc.serverMessageSequence;
865 // also use the last acknowledged server command in the key
866 key ^= Com_HashKey(clc.serverCommands[ clc.serverCommandSequence & (MAX_RELIABLE_COMMANDS-1) ], 32);
867
868 // write all the commands, including the predicted command
869 for ( i = 0 ; i < count ; i++ ) {
870 j = (cl.cmdNumber - count + i + 1) & CMD_MASK;
871 cmd = &cl.cmds[j];
872 MSG_WriteDeltaUsercmdKey (&buf, key, oldcmd, cmd);
873 oldcmd = cmd;
874 }
875 }
876
877 //
878 // deliver the message
879 //
880 packetNum = clc.netchan.outgoingSequence & PACKET_MASK;
881 cl.outPackets[ packetNum ].p_realtime = cls.realtime;
882 cl.outPackets[ packetNum ].p_serverTime = oldcmd->serverTime;
883 cl.outPackets[ packetNum ].p_cmdNumber = cl.cmdNumber;
884 clc.lastPacketSentTime = cls.realtime;
885
886 if ( cl_showSend->integer ) {
887 Com_Printf( "%i ", buf.cursize );
888 }
889
890 CL_Netchan_Transmit (&clc.netchan, &buf);
891
892 // clients never really should have messages large enough
893 // to fragment, but in case they do, fire them all off
894 // at once
895 // TTimo: this causes a packet burst, which is bad karma for winsock
896 // added a WARNING message, we'll see if there are legit situations where this happens
897 while ( clc.netchan.unsentFragments ) {
898 Com_DPrintf( "WARNING: #462 unsent fragments (not supposed to happen!)\n" );
899 CL_Netchan_TransmitNextFragment( &clc.netchan );
900 }
901 }
902
903 /*
904 =================
905 CL_SendCmd
906
907 Called every frame to builds and sends a command packet to the server.
908 =================
909 */
CL_SendCmd(void)910 void CL_SendCmd( void ) {
911 // don't send any message if not connected
912 if ( cls.state < CA_CONNECTED ) {
913 return;
914 }
915
916 // don't send commands if paused
917 if ( com_sv_running->integer && sv_paused->integer && cl_paused->integer ) {
918 return;
919 }
920
921 // we create commands even if a demo is playing,
922 CL_CreateNewCommands();
923
924 // don't send a packet if the last packet was sent too recently
925 if ( !CL_ReadyToSendPacket() ) {
926 if ( cl_showSend->integer ) {
927 Com_Printf( ". " );
928 }
929 return;
930 }
931
932 CL_WritePacket();
933 }
934
935 /*
936 ============
937 CL_InitInput
938 ============
939 */
CL_InitInput(void)940 void CL_InitInput( void ) {
941 Cmd_AddCommand ("centerview",IN_CenterView);
942
943 Cmd_AddCommand ("+moveup",IN_UpDown);
944 Cmd_AddCommand ("-moveup",IN_UpUp);
945 Cmd_AddCommand ("+movedown",IN_DownDown);
946 Cmd_AddCommand ("-movedown",IN_DownUp);
947 Cmd_AddCommand ("+left",IN_LeftDown);
948 Cmd_AddCommand ("-left",IN_LeftUp);
949 Cmd_AddCommand ("+right",IN_RightDown);
950 Cmd_AddCommand ("-right",IN_RightUp);
951 Cmd_AddCommand ("+forward",IN_ForwardDown);
952 Cmd_AddCommand ("-forward",IN_ForwardUp);
953 Cmd_AddCommand ("+back",IN_BackDown);
954 Cmd_AddCommand ("-back",IN_BackUp);
955 Cmd_AddCommand ("+lookup", IN_LookupDown);
956 Cmd_AddCommand ("-lookup", IN_LookupUp);
957 Cmd_AddCommand ("+lookdown", IN_LookdownDown);
958 Cmd_AddCommand ("-lookdown", IN_LookdownUp);
959 Cmd_AddCommand ("+strafe", IN_StrafeDown);
960 Cmd_AddCommand ("-strafe", IN_StrafeUp);
961 Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
962 Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
963 Cmd_AddCommand ("+moveright", IN_MoverightDown);
964 Cmd_AddCommand ("-moveright", IN_MoverightUp);
965 Cmd_AddCommand ("+speed", IN_SpeedDown);
966 Cmd_AddCommand ("-speed", IN_SpeedUp);
967 Cmd_AddCommand ("+attack", IN_Button0Down);
968 Cmd_AddCommand ("-attack", IN_Button0Up);
969 Cmd_AddCommand ("+button0", IN_Button0Down);
970 Cmd_AddCommand ("-button0", IN_Button0Up);
971 Cmd_AddCommand ("+button1", IN_Button1Down);
972 Cmd_AddCommand ("-button1", IN_Button1Up);
973 Cmd_AddCommand ("+button2", IN_Button2Down);
974 Cmd_AddCommand ("-button2", IN_Button2Up);
975 Cmd_AddCommand ("+button3", IN_Button3Down);
976 Cmd_AddCommand ("-button3", IN_Button3Up);
977 Cmd_AddCommand ("+button4", IN_Button4Down);
978 Cmd_AddCommand ("-button4", IN_Button4Up);
979 Cmd_AddCommand ("+button5", IN_Button5Down);
980 Cmd_AddCommand ("-button5", IN_Button5Up);
981 Cmd_AddCommand ("+button6", IN_Button6Down);
982 Cmd_AddCommand ("-button6", IN_Button6Up);
983 Cmd_AddCommand ("+button7", IN_Button7Down);
984 Cmd_AddCommand ("-button7", IN_Button7Up);
985 Cmd_AddCommand ("+button8", IN_Button8Down);
986 Cmd_AddCommand ("-button8", IN_Button8Up);
987 Cmd_AddCommand ("+button9", IN_Button9Down);
988 Cmd_AddCommand ("-button9", IN_Button9Up);
989 Cmd_AddCommand ("+button10", IN_Button10Down);
990 Cmd_AddCommand ("-button10", IN_Button10Up);
991 Cmd_AddCommand ("+button11", IN_Button11Down);
992 Cmd_AddCommand ("-button11", IN_Button11Up);
993 Cmd_AddCommand ("+button12", IN_Button12Down);
994 Cmd_AddCommand ("-button12", IN_Button12Up);
995 Cmd_AddCommand ("+button13", IN_Button13Down);
996 Cmd_AddCommand ("-button13", IN_Button13Up);
997 Cmd_AddCommand ("+button14", IN_Button14Down);
998 Cmd_AddCommand ("-button14", IN_Button14Up);
999 Cmd_AddCommand ("+mlook", IN_MLookDown);
1000 Cmd_AddCommand ("-mlook", IN_MLookUp);
1001
1002 #ifdef USE_VOIP
1003 Cmd_AddCommand ("+voiprecord", IN_VoipRecordDown);
1004 Cmd_AddCommand ("-voiprecord", IN_VoipRecordUp);
1005 #endif
1006
1007 cl_nodelta = Cvar_Get ("cl_nodelta", "0", 0);
1008 cl_debugMove = Cvar_Get ("cl_debugMove", "0", 0);
1009 }
1010