6cd5315bc2d6f9b6a6254d4ed1424fc70a55ce27
[xonotic/darkplaces.git] / cl_input.c
1 /*
2 Copyright (C) 1996-1997 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 // 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
30 KEY BUTTONS
31
32 Continuous button event tracking is complicated by the fact that two different
33 input sources (say, mouse button 1 and the control key) can both press the
34 same button, but the button should only be released when both of the
35 pressing key have been released.
36
37 When a key event issues a button command (+forward, +attack, etc), it appends
38 its key number as a parameter to the command so it can be matched up with
39 the release.
40
41 state bit 0 is the current state of the key
42 state bit 1 is edge triggered on the up to down transition
43 state bit 2 is edge triggered on the down to up transition
44
45 ===============================================================================
46 */
47
48
49 kbutton_t       in_mlook, in_klook;
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, in_jump, in_attack, in_use;
53 kbutton_t       in_up, in_down;
54 // LordHavoc: added 6 new buttons
55 kbutton_t       in_button3, in_button4, in_button5, in_button6, in_button7, in_button8;
56
57 int                     in_impulse;
58
59
60 void KeyDown (kbutton_t *b)
61 {
62         int k;
63         const char *c;
64
65         c = Cmd_Argv(1);
66         if (c[0])
67                 k = atoi(c);
68         else
69                 k = -1;         // typed manually at the console for continuous down
70
71         if (k == b->down[0] || k == b->down[1])
72                 return;         // repeating key
73
74         if (!b->down[0])
75                 b->down[0] = k;
76         else if (!b->down[1])
77                 b->down[1] = k;
78         else
79         {
80                 Con_Print("Three keys down for a button!\n");
81                 return;
82         }
83
84         if (b->state & 1)
85                 return;         // still down
86         b->state |= 1 + 2;      // down + impulse down
87 }
88
89 void KeyUp (kbutton_t *b)
90 {
91         int k;
92         const char *c;
93
94         c = Cmd_Argv(1);
95         if (c[0])
96                 k = atoi(c);
97         else
98         { // typed manually at the console, assume for unsticking, so clear all
99                 b->down[0] = b->down[1] = 0;
100                 b->state = 4;   // impulse up
101                 return;
102         }
103
104         if (b->down[0] == k)
105                 b->down[0] = 0;
106         else if (b->down[1] == k)
107                 b->down[1] = 0;
108         else
109                 return;         // key up without coresponding down (menu pass through)
110         if (b->down[0] || b->down[1])
111                 return;         // some other key is still holding it down
112
113         if (!(b->state & 1))
114                 return;         // still up (this should not happen)
115         b->state &= ~1;         // now up
116         b->state |= 4;          // impulse up
117 }
118
119 void IN_KLookDown (void) {KeyDown(&in_klook);}
120 void IN_KLookUp (void) {KeyUp(&in_klook);}
121 void IN_MLookDown (void) {KeyDown(&in_mlook);}
122 void IN_MLookUp (void)
123 {
124         KeyUp(&in_mlook);
125         if ( !(in_mlook.state&1) && lookspring.value)
126                 V_StartPitchDrift();
127 }
128 void IN_UpDown(void) {KeyDown(&in_up);}
129 void IN_UpUp(void) {KeyUp(&in_up);}
130 void IN_DownDown(void) {KeyDown(&in_down);}
131 void IN_DownUp(void) {KeyUp(&in_down);}
132 void IN_LeftDown(void) {KeyDown(&in_left);}
133 void IN_LeftUp(void) {KeyUp(&in_left);}
134 void IN_RightDown(void) {KeyDown(&in_right);}
135 void IN_RightUp(void) {KeyUp(&in_right);}
136 void IN_ForwardDown(void) {KeyDown(&in_forward);}
137 void IN_ForwardUp(void) {KeyUp(&in_forward);}
138 void IN_BackDown(void) {KeyDown(&in_back);}
139 void IN_BackUp(void) {KeyUp(&in_back);}
140 void IN_LookupDown(void) {KeyDown(&in_lookup);}
141 void IN_LookupUp(void) {KeyUp(&in_lookup);}
142 void IN_LookdownDown(void) {KeyDown(&in_lookdown);}
143 void IN_LookdownUp(void) {KeyUp(&in_lookdown);}
144 void IN_MoveleftDown(void) {KeyDown(&in_moveleft);}
145 void IN_MoveleftUp(void) {KeyUp(&in_moveleft);}
146 void IN_MoverightDown(void) {KeyDown(&in_moveright);}
147 void IN_MoverightUp(void) {KeyUp(&in_moveright);}
148
149 void IN_SpeedDown(void) {KeyDown(&in_speed);}
150 void IN_SpeedUp(void) {KeyUp(&in_speed);}
151 void IN_StrafeDown(void) {KeyDown(&in_strafe);}
152 void IN_StrafeUp(void) {KeyUp(&in_strafe);}
153
154 void IN_AttackDown(void) {KeyDown(&in_attack);}
155 void IN_AttackUp(void) {KeyUp(&in_attack);}
156
157 void IN_UseDown(void) {KeyDown(&in_use);}
158 void IN_UseUp(void) {KeyUp(&in_use);}
159
160 // LordHavoc: added 6 new buttons
161 void IN_Button3Down(void) {KeyDown(&in_button3);}
162 void IN_Button3Up(void) {KeyUp(&in_button3);}
163 void IN_Button4Down(void) {KeyDown(&in_button4);}
164 void IN_Button4Up(void) {KeyUp(&in_button4);}
165 void IN_Button5Down(void) {KeyDown(&in_button5);}
166 void IN_Button5Up(void) {KeyUp(&in_button5);}
167 void IN_Button6Down(void) {KeyDown(&in_button6);}
168 void IN_Button6Up(void) {KeyUp(&in_button6);}
169 void IN_Button7Down(void) {KeyDown(&in_button7);}
170 void IN_Button7Up(void) {KeyUp(&in_button7);}
171 void IN_Button8Down(void) {KeyDown(&in_button8);}
172 void IN_Button8Up(void) {KeyUp(&in_button8);}
173
174 void IN_JumpDown (void) {KeyDown(&in_jump);}
175 void IN_JumpUp (void) {KeyUp(&in_jump);}
176
177 void IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}
178
179 /*
180 ===============
181 CL_KeyState
182
183 Returns 0.25 if a key was pressed and released during the frame,
184 0.5 if it was pressed and held
185 0 if held then released, and
186 1.0 if held for the entire time
187 ===============
188 */
189 float CL_KeyState (kbutton_t *key)
190 {
191         float           val;
192         qboolean        impulsedown, impulseup, down;
193
194         impulsedown = key->state & 2;
195         impulseup = key->state & 4;
196         down = key->state & 1;
197         val = 0;
198
199         if (impulsedown && !impulseup)
200         {
201                 if (down)
202                         val = 0.5;      // pressed and held this frame
203                 else
204                         val = 0;        //      I_Error ();
205         }
206         if (impulseup && !impulsedown)
207         {
208                 if (down)
209                         val = 0;        //      I_Error ();
210                 else
211                         val = 0;        // released this frame
212         }
213         if (!impulsedown && !impulseup)
214         {
215                 if (down)
216                         val = 1.0;      // held the entire frame
217                 else
218                         val = 0;        // up the entire frame
219         }
220         if (impulsedown && impulseup)
221         {
222                 if (down)
223                         val = 0.75;     // released and re-pressed this frame
224                 else
225                         val = 0.25;     // pressed and released this frame
226         }
227
228         key->state &= 1;                // clear impulses
229
230         return val;
231 }
232
233
234
235
236 //==========================================================================
237
238 cvar_t cl_upspeed = {CVAR_SAVE, "cl_upspeed","400"};
239 cvar_t cl_forwardspeed = {CVAR_SAVE, "cl_forwardspeed","400"};
240 cvar_t cl_backspeed = {CVAR_SAVE, "cl_backspeed","400"};
241 cvar_t cl_sidespeed = {CVAR_SAVE, "cl_sidespeed","350"};
242
243 cvar_t cl_movespeedkey = {CVAR_SAVE, "cl_movespeedkey","2.0"};
244
245 cvar_t cl_yawspeed = {CVAR_SAVE, "cl_yawspeed","140"};
246 cvar_t cl_pitchspeed = {CVAR_SAVE, "cl_pitchspeed","150"};
247
248 cvar_t cl_anglespeedkey = {CVAR_SAVE, "cl_anglespeedkey","1.5"};
249
250 cvar_t cl_movement = {CVAR_SAVE, "cl_movement", "0"};
251 cvar_t cl_movement_latency = {0, "cl_movement_latency", "0"};
252 cvar_t cl_movement_maxspeed = {0, "cl_movement_maxspeed", "320"};
253 cvar_t cl_movement_maxairspeed = {0, "cl_movement_maxairspeed", "30"};
254 cvar_t cl_movement_stopspeed = {0, "cl_movement_stopspeed", "100"};
255 cvar_t cl_movement_friction = {0, "cl_movement_friction", "4"};
256 cvar_t cl_movement_edgefriction = {0, "cl_movement_edgefriction", "2"};
257 cvar_t cl_movement_stepheight = {0, "cl_movement_stepheight", "18"};
258 cvar_t cl_movement_accelerate = {0, "cl_movement_accelerate", "10"};
259 cvar_t cl_movement_jumpvelocity = {0, "cl_movement_jumpvelocity", "270"};
260 cvar_t cl_gravity = {0, "cl_gravity", "800"};
261 cvar_t cl_slowmo = {0, "cl_slowmo", "1"};
262
263 cvar_t in_pitch_min = {0, "in_pitch_min", "-90"}; // quake used -70
264 cvar_t in_pitch_max = {0, "in_pitch_max", "90"}; // quake used 80
265
266 cvar_t m_filter = {CVAR_SAVE, "m_filter","0"};
267
268
269 /*
270 ================
271 CL_AdjustAngles
272
273 Moves the local angle positions
274 ================
275 */
276 void CL_AdjustAngles (void)
277 {
278         float   speed;
279         float   up, down;
280
281         if (in_speed.state & 1)
282                 speed = host_realframetime * cl_anglespeedkey.value;
283         else
284                 speed = host_realframetime;
285
286         if (!(in_strafe.state & 1))
287         {
288                 cl.viewangles[YAW] -= speed*cl_yawspeed.value*CL_KeyState (&in_right);
289                 cl.viewangles[YAW] += speed*cl_yawspeed.value*CL_KeyState (&in_left);
290         }
291         if (in_klook.state & 1)
292         {
293                 V_StopPitchDrift ();
294                 cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);
295                 cl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);
296         }
297
298         up = CL_KeyState (&in_lookup);
299         down = CL_KeyState(&in_lookdown);
300
301         cl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;
302         cl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;
303
304         if (up || down)
305                 V_StopPitchDrift ();
306
307         cl.viewangles[YAW] = ANGLEMOD(cl.viewangles[YAW]);
308         cl.viewangles[PITCH] = ANGLEMOD(cl.viewangles[PITCH]);
309         cl.viewangles[ROLL] = ANGLEMOD(cl.viewangles[ROLL]);
310         if (cl.viewangles[YAW] >= 180)
311                 cl.viewangles[YAW] -= 360;
312         if (cl.viewangles[PITCH] >= 180)
313                 cl.viewangles[PITCH] -= 360;
314         if (cl.viewangles[ROLL] >= 180)
315                 cl.viewangles[ROLL] -= 360;
316
317         cl.viewangles[PITCH] = bound (in_pitch_min.value, cl.viewangles[PITCH], in_pitch_max.value);
318         cl.viewangles[ROLL] = bound(-50, cl.viewangles[ROLL], 50);
319 }
320
321 qboolean cl_ignoremousemove = false;
322
323 /*
324 ================
325 CL_Move
326
327 Send the intended movement message to the server
328 ================
329 */
330 void CL_Move (void)
331 {
332         vec3_t temp;
333         float mx, my;
334         static float old_mouse_x = 0, old_mouse_y = 0;
335
336         // clamp before the move to prevent starting with bad angles
337         CL_AdjustAngles ();
338
339         // get basic movement from keyboard
340         // PRYDON_CLIENTCURSOR needs to survive basemove resets
341         VectorCopy (cl.cmd.cursor_screen, temp);
342         memset (&cl.cmd, 0, sizeof(cl.cmd));
343         VectorCopy (temp, cl.cmd.cursor_screen);
344
345         if (in_strafe.state & 1)
346         {
347                 cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_right);
348                 cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);
349         }
350
351         cl.cmd.sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);
352         cl.cmd.sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);
353
354         cl.cmd.upmove += cl_upspeed.value * CL_KeyState (&in_up);
355         cl.cmd.upmove -= cl_upspeed.value * CL_KeyState (&in_down);
356
357         if (! (in_klook.state & 1) )
358         {
359                 cl.cmd.forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);
360                 cl.cmd.forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);
361         }
362
363         // adjust for speed key
364         if (in_speed.state & 1)
365         {
366                 cl.cmd.forwardmove *= cl_movespeedkey.value;
367                 cl.cmd.sidemove *= cl_movespeedkey.value;
368                 cl.cmd.upmove *= cl_movespeedkey.value;
369         }
370
371         in_mouse_x = 0;
372         in_mouse_y = 0;
373
374         // allow mice or other external controllers to add to the move
375         IN_Move ();
376
377         // ignore a mouse move if mouse was activated/deactivated this frame
378         if (cl_ignoremousemove)
379         {
380                 cl_ignoremousemove = false;
381                 in_mouse_x = 0;
382                 in_mouse_y = 0;
383         }
384
385         // apply m_filter if it is on
386         mx = in_mouse_x;
387         my = in_mouse_y;
388         if (m_filter.integer)
389         {
390                 in_mouse_x = (mx + old_mouse_x) * 0.5;
391                 in_mouse_y = (my + old_mouse_y) * 0.5;
392         }
393         old_mouse_x = mx;
394         old_mouse_y = my;
395
396         // if not in menu, apply mouse move to viewangles/movement
397         if (in_client_mouse)
398         {
399                 if (cl_prydoncursor.integer)
400                 {
401                         // mouse interacting with the scene, mostly stationary view
402                         V_StopPitchDrift();
403                         cl.cmd.cursor_screen[0] += in_mouse_x * sensitivity.value / vid.width;
404                         cl.cmd.cursor_screen[1] += in_mouse_y * sensitivity.value / vid.height;
405                 }
406                 else if (in_strafe.state & 1)
407                 {
408                         // strafing mode, all looking is movement
409                         V_StopPitchDrift();
410                         cl.cmd.sidemove += m_side.value * in_mouse_x * sensitivity.value * cl.viewzoom;
411                         if (noclip_anglehack)
412                                 cl.cmd.upmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
413                         else
414                                 cl.cmd.forwardmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
415                 }
416                 else if ((in_mlook.state & 1) || freelook.integer)
417                 {
418                         // mouselook, lookstrafe causes turning to become strafing
419                         V_StopPitchDrift();
420                         if (lookstrafe.integer)
421                                 cl.cmd.sidemove += m_side.value * in_mouse_x * sensitivity.value * cl.viewzoom;
422                         else
423                                 cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * sensitivity.value * cl.viewzoom;
424                         cl.viewangles[PITCH] += m_pitch.value * in_mouse_y * sensitivity.value * cl.viewzoom;
425                 }
426                 else
427                 {
428                         // non-mouselook, yaw turning and forward/back movement
429                         cl.viewangles[YAW] -= m_yaw.value * in_mouse_x * sensitivity.value * cl.viewzoom;
430                         cl.cmd.forwardmove -= m_forward.value * in_mouse_y * sensitivity.value * cl.viewzoom;
431                 }
432         }
433
434         // clamp after the move to prevent rendering with bad angles
435         CL_AdjustAngles ();
436 }
437
438 #include "cl_collision.h"
439
440 extern void V_CalcRefdef(void);
441 void CL_UpdatePrydonCursor(void)
442 {
443         vec3_t temp, scale;
444
445         if (!cl_prydoncursor.integer)
446                 VectorClear(cl.cmd.cursor_screen);
447
448         /*
449         if (cl.cmd.cursor_screen[0] < -1)
450         {
451                 cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - -1) * vid.width * sensitivity.value * cl.viewzoom;
452                 cl.cmd.cursor_screen[0] = -1;
453         }
454         if (cl.cmd.cursor_screen[0] > 1)
455         {
456                 cl.viewangles[YAW] -= m_yaw.value * (cl.cmd.cursor_screen[0] - 1) * vid.width * sensitivity.value * cl.viewzoom;
457                 cl.cmd.cursor_screen[0] = 1;
458         }
459         if (cl.cmd.cursor_screen[1] < -1)
460         {
461                 cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - -1) * vid.height * sensitivity.value * cl.viewzoom;
462                 cl.cmd.cursor_screen[1] = -1;
463         }
464         if (cl.cmd.cursor_screen[1] > 1)
465         {
466                 cl.viewangles[PITCH] += m_pitch.value * (cl.cmd.cursor_screen[1] - 1) * vid.height * sensitivity.value * cl.viewzoom;
467                 cl.cmd.cursor_screen[1] = 1;
468         }
469         */
470         cl.cmd.cursor_screen[0] = bound(-1, cl.cmd.cursor_screen[0], 1);
471         cl.cmd.cursor_screen[1] = bound(-1, cl.cmd.cursor_screen[1], 1);
472         cl.cmd.cursor_screen[2] = 1;
473
474         scale[0] = -tan(r_refdef.fov_x * M_PI / 360.0);
475         scale[1] = -tan(r_refdef.fov_y * M_PI / 360.0);
476         scale[2] = 1;
477
478         // trace distance
479         VectorScale(scale, 1000000, scale);
480
481         // calculate current view matrix
482         V_CalcRefdef();
483         VectorClear(temp);
484         Matrix4x4_Transform(&r_refdef.viewentitymatrix, temp, cl.cmd.cursor_start);
485         VectorSet(temp, cl.cmd.cursor_screen[2] * scale[2], cl.cmd.cursor_screen[0] * scale[0], cl.cmd.cursor_screen[1] * scale[1]);
486         Matrix4x4_Transform(&r_refdef.viewentitymatrix, temp, cl.cmd.cursor_end);
487         // trace from view origin to the cursor
488         cl.cmd.cursor_fraction = CL_SelectTraceLine(cl.cmd.cursor_start, cl.cmd.cursor_end, cl.cmd.cursor_impact, cl.cmd.cursor_normal, &cl.cmd.cursor_entitynumber, (chase_active.integer || cl.intermission) ? &cl_entities[cl.playerentity].render : NULL);
489         // makes sparks where cursor is
490         //CL_SparkShower(cl.cmd.cursor_impact, cl.cmd.cursor_normal, 5, 0);
491 }
492
493 void CL_ClientMovement_Input(qboolean buttonjump, qboolean buttoncrouch)
494 {
495         int i;
496         int n;
497         // remove stale queue items
498         n = cl.movement_numqueue;
499         cl.movement_numqueue = 0;
500         if (cl.servermovesequence)
501         {
502                 for (i = 0;i < n;i++)
503                         if (cl.movement_queue[i].sequence > cl.servermovesequence)
504                                 cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
505         }
506         else
507         {
508                 double simulatedtime = cl.mtime[0] + cl_movement_latency.value / 1000.0;
509                 for (i = 0;i < n;i++)
510                         if (cl.movement_queue[i].time >= cl.mtime[0] && cl.movement_queue[i].time <= simulatedtime)
511                                 cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
512         }
513         // add to input queue if there is room
514         if (cl_movement.integer && cl.movement_numqueue < (int)(sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0])) && cl.mtime[0] > cl.mtime[1])
515         {
516                 // add to input queue
517                 cl.movement_queue[cl.movement_numqueue].sequence = cl.movesequence;
518                 cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value / 1000.0;
519                 cl.movement_queue[cl.movement_numqueue].frametime = cl.mtime[0] - cl.mtime[1];
520                 VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
521                 cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
522                 cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove;
523                 cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
524                 cl.movement_queue[cl.movement_numqueue].jump = buttonjump;
525                 cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
526                 cl.movement_numqueue++;
527         }
528         cl.movement = cl_movement.integer && cl.stats[STAT_HEALTH] > 0 && !cls.demoplayback && !cl.intermission;
529         // clear queue if client movement is disabled
530         if (!cl.movement)
531                 cl.movement_numqueue = 0;
532         cl.movement_replay = true;
533 }
534
535 void CL_ClientMovement_Replay(void)
536 {
537         int i;
538         int bump;
539         int contents;
540         int crouch;
541         int onground;
542         double edgefriction;
543         double frametime;
544         double t;
545         vec_t wishspeed;
546         vec_t addspeed;
547         vec_t accelspeed;
548         vec_t f;
549         vec_t *playermins;
550         vec_t *playermaxs;
551         vec3_t currentorigin;
552         vec3_t currentvelocity;
553         vec3_t forward;
554         vec3_t right;
555         vec3_t up;
556         vec3_t wishvel;
557         vec3_t wishdir;
558         vec3_t neworigin;
559         vec3_t currentorigin2;
560         vec3_t neworigin2;
561         vec3_t yawangles;
562         trace_t trace;
563         trace_t trace2;
564         trace_t trace3;
565         if (!cl.movement_replay)
566                 return;
567         cl.movement_replay = false;
568
569         // fetch current starting values
570         VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
571         VectorCopy(cl.mvelocity[0], currentvelocity);
572         // FIXME: try minor nudges in various directions if startsolid to find a
573         // safe place to start the walk (due to network compression in some
574         // protocols this starts in solid)
575         //currentorigin[2] += (1.0 / 32.0); // slight nudge to get out of the floor
576         crouch = false; // this will be updated on first move
577
578         // check if onground
579         VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1);
580         VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1);
581         trace = CL_TraceBox(currentorigin2, cl_playercrouchmins, cl_playercrouchmaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
582         onground = trace.fraction < 1 && trace.plane.normal[2] > 0.7;
583         //Con_Printf("%f: ", cl.mtime[0]);
584
585         // replay the input queue to predict current location
586         // note: this relies on the fact there's always one queue item at the end
587
588         for (i = 0;i < cl.movement_numqueue;i++)
589         {
590                 client_movementqueue_t *q = cl.movement_queue + bound(0, i, cl.movement_numqueue - 1);
591                 frametime = q->frametime;
592                 //Con_Printf(" %f", frametime);
593                 //if (frametime > 0)
594                 {
595                         if (q->crouch)
596                         {
597                                 // wants to crouch, this always works...
598                                 if (!crouch)
599                                         crouch = true;
600                         }
601                         else
602                         {
603                                 // wants to stand, if currently crouching we need to check for a
604                                 // low ceiling first
605                                 if (crouch)
606                                 {
607                                         trace = CL_TraceBox(currentorigin, cl_playerstandmins, cl_playerstandmaxs, currentorigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
608                                         if (!trace.startsolid)
609                                                 crouch = false;
610                                 }
611                         }
612                         if (crouch)
613                         {
614                                 playermins = cl_playercrouchmins;
615                                 playermaxs = cl_playercrouchmaxs;
616                         }
617                         else
618                         {
619                                 playermins = cl_playerstandmins;
620                                 playermaxs = cl_playerstandmaxs;
621                         }
622                         // change velocity according to q->viewangles and q->move
623                         contents = CL_PointSuperContents(currentorigin);
624                         if (contents & SUPERCONTENTS_LIQUIDSMASK)
625                         {
626                                 // swim
627                                 AngleVectors(q->viewangles, forward, right, up);
628                                 VectorSet(up, 0, 0, 1);
629                                 VectorMAMAM(q->move[0], forward, q->move[1], right, q->move[2], up, wishvel);
630                                 wishspeed = VectorLength(wishvel);
631                                 if (wishspeed)
632                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
633                                 else
634                                         VectorSet( wishdir, 0.0, 0.0, 0.0 );
635                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
636                                 if (crouch)
637                                         wishspeed *= 0.5;
638                                 wishspeed *= 0.6;
639                                 VectorScale(currentvelocity, (1 - frametime * cl_movement_friction.value), currentvelocity);
640                                 f = wishspeed - DotProduct(currentvelocity, wishdir);
641                                 if (f > 0)
642                                 {
643                                         f = min(f, cl_movement_accelerate.value * frametime * wishspeed);
644                                         VectorMA(currentvelocity, f, wishdir, currentvelocity);
645                                 }
646                                 if (q->jump)
647                                 {
648                                         if (contents & SUPERCONTENTS_LAVA)
649                                                 currentvelocity[2] =  50;
650                                         else if (contents & SUPERCONTENTS_SLIME)
651                                                 currentvelocity[2] =  80;
652                                         else
653                                         {
654                                                 if (gamemode == GAME_NEXUIZ)
655                                                         currentvelocity[2] = 200;
656                                                 else
657                                                         currentvelocity[2] = 100;
658                                         }
659                                 }
660                         }
661                         else
662                         {
663                                 // walk
664                                 if (onground && q->jump)
665                                 {
666                                         currentvelocity[2] += cl_movement_jumpvelocity.value;
667                                         onground = false;
668                                 }
669                                 VectorSet(yawangles, 0, q->viewangles[1], 0);
670                                 AngleVectors(yawangles, forward, right, up);
671                                 VectorMAM(q->move[0], forward, q->move[1], right, wishvel);
672                                 wishspeed = VectorLength(wishvel);
673                                 if (wishspeed)
674                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
675                                 else
676                                         VectorSet( wishdir, 0.0, 0.0, 0.0 );
677                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
678                                 if (crouch)
679                                         wishspeed *= 0.5;
680                                 // check if onground
681                                 if (onground)
682                                 {
683                                         // apply ground friction
684                                         f = sqrt(currentvelocity[0] * currentvelocity[0] + currentvelocity[1] * currentvelocity[1]);
685                                         edgefriction = 1;
686                                         if (f > 0)
687                                         {
688                                                 VectorSet(currentorigin2, currentorigin[0] + currentvelocity[0]*(16/f), currentorigin[1] + currentvelocity[1]*(16/f), currentorigin[2] + playermins[2]);
689                                                 VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34);
690                                                 trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
691                                                 if (trace.fraction == 1)
692                                                         edgefriction = cl_movement_edgefriction.value;
693                                         }
694                                         // apply friction
695                                         f = 1 - frametime * edgefriction * ((f < cl_movement_stopspeed.value) ? (cl_movement_stopspeed.value / f) : 1) * cl_movement_friction.value;
696                                         f = max(f, 0);
697                                         VectorScale(currentvelocity, f, currentvelocity);
698                                 }
699                                 else
700                                 {
701                                         // apply air speed limit
702                                         wishspeed = min(wishspeed, cl_movement_maxairspeed.value);
703                                 }
704                                 if (gamemode == GAME_NEXUIZ)
705                                         addspeed = wishspeed;
706                                 else
707                                         addspeed = wishspeed - DotProduct(currentvelocity, wishdir);
708                                 if (addspeed > 0)
709                                 {
710                                         accelspeed = min(cl_movement_accelerate.value * frametime * wishspeed, addspeed);
711                                         VectorMA(currentvelocity, accelspeed, wishdir, currentvelocity);
712                                 }
713                                 currentvelocity[2] -= cl_gravity.value * frametime;
714                         }
715                 }
716                 //if (i < cl.movement_numqueue - 1 || (cl_movement.integer & 4))
717                 {
718                         if (crouch)
719                         {
720                                 playermins = cl_playercrouchmins;
721                                 playermaxs = cl_playercrouchmaxs;
722                         }
723                         else
724                         {
725                                 playermins = cl_playerstandmins;
726                                 playermaxs = cl_playerstandmaxs;
727                         }
728                         onground = false;
729                         for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
730                         {
731                                 VectorMA(currentorigin, t, currentvelocity, neworigin);
732                                 trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
733                                 if (trace.fraction < 1 && trace.plane.normal[2] == 0)
734                                 {
735                                         // may be a step or wall, try stepping up
736                                         // first move forward at a higher level
737                                         VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
738                                         VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
739                                         trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
740                                         // then move down from there
741                                         VectorCopy(trace2.endpos, currentorigin2);
742                                         VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]);
743                                         trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
744                                         //Con_Printf("%f %f %f %f : %f %f %f %f : %f %f %f %f\n", trace.fraction, trace.endpos[0], trace.endpos[1], trace.endpos[2], trace2.fraction, trace2.endpos[0], trace2.endpos[1], trace2.endpos[2], trace3.fraction, trace3.endpos[0], trace3.endpos[1], trace3.endpos[2]);
745                                         // accept the new trace if it made some progress
746                                         if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
747                                         {
748                                                 trace = trace2;
749                                                 VectorCopy(trace3.endpos, trace.endpos);
750                                         }
751                                 }
752                                 if (trace.fraction == 1)
753                                 {
754                                         VectorCopy(trace.endpos, currentorigin);
755                                         break;
756                                 }
757                                 if (trace.plane.normal[2] > 0.7)
758                                         onground = true;
759                                 t *= 1 - trace.fraction;
760                                 if (trace.fraction >= 0.001)
761                                         VectorCopy(trace.endpos, currentorigin);
762                                 f = DotProduct(currentvelocity, trace.plane.normal);
763                                 VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity);
764                         }
765                 }
766         }
767         // store replay location
768         VectorCopy(cl.movement_origin, cl.movement_oldorigin);
769         VectorCopy(currentorigin, cl.movement_origin);
770         VectorCopy(currentvelocity, cl.movement_velocity);
771         //VectorCopy(currentorigin, cl_entities[cl.playerentity].state_current.origin);
772         //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
773 }
774
775 /*
776 ==============
777 CL_SendMove
778 ==============
779 */
780 void CL_SendMove(void)
781 {
782         int i;
783         int bits;
784         sizebuf_t buf;
785         qbyte data[128];
786 #define MOVEAVERAGING 0
787 #if MOVEAVERAGING
788         static float forwardmove, sidemove, upmove, total; // accumulation
789 #else
790         float forwardmove, sidemove, upmove;
791 #endif
792
793 #if MOVEAVERAGING
794         // accumulate changes between messages
795         forwardmove += cl.cmd.forwardmove;
796         sidemove += cl.cmd.sidemove;
797         upmove += cl.cmd.upmove;
798         total++;
799 #endif
800         if (cls.signon != SIGNONS)
801                 return;
802 #if MOVEAVERAGING
803         // average the accumulated changes
804         total = 1.0f / total;
805         forwardmove *= total;
806         sidemove *= total;
807         upmove *= total;
808         total = 0;
809 #else
810         // use the latest values
811         forwardmove = cl.cmd.forwardmove;
812         sidemove = cl.cmd.sidemove;
813         upmove = cl.cmd.upmove;
814 #endif
815
816         CL_UpdatePrydonCursor();
817
818         buf.maxsize = 128;
819         buf.cursize = 0;
820         buf.data = data;
821
822         // set button bits
823         // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
824         bits = 0;
825         if (in_attack.state   & 3) bits |=   1;in_attack.state  &= ~2;
826         if (in_jump.state     & 3) bits |=   2;in_jump.state    &= ~2;
827         if (in_button3.state  & 3) bits |=   4;in_button3.state &= ~2;
828         if (in_button4.state  & 3) bits |=   8;in_button4.state &= ~2;
829         if (in_button5.state  & 3) bits |=  16;in_button5.state &= ~2;
830         if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
831         if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
832         if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
833         if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
834         if (key_dest != key_game || key_consoleactive) bits |= 512;
835         if (cl_prydoncursor.integer) bits |= 1024;
836         // button bits 11-31 unused currently
837         // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
838         if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
839         if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
840         if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
841         if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
842
843         // always dump the first two messages, because they may contain leftover inputs from the last level
844         if (++cl.movemessages >= 2)
845         {
846                 // send the movement message
847                 // PROTOCOL_QUAKE        clc_move = 16 bytes total
848                 // PROTOCOL_QUAKEDP      clc_move = 16 bytes total
849                 // PROTOCOL_NEHAHRAMOVIE clc_move = 16 bytes total
850                 // PROTOCOL_DARKPLACES1  clc_move = 19 bytes total
851                 // PROTOCOL_DARKPLACES2  clc_move = 25 bytes total
852                 // PROTOCOL_DARKPLACES3  clc_move = 25 bytes total
853                 // PROTOCOL_DARKPLACES4  clc_move = 19 bytes total
854                 // PROTOCOL_DARKPLACES5  clc_move = 19 bytes total
855                 // PROTOCOL_DARKPLACES6  clc_move = 52 bytes total
856                 // PROTOCOL_DARKPLACES7  clc_move = 56 bytes total
857                 if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_QUAKEDP || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
858                 {
859                         // 5 bytes
860                         MSG_WriteByte (&buf, clc_move);
861                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
862                         // 3 bytes
863                         for (i = 0;i < 3;i++)
864                                 MSG_WriteAngle8i (&buf, cl.viewangles[i]);
865                         // 6 bytes
866                         MSG_WriteCoord16i (&buf, forwardmove);
867                         MSG_WriteCoord16i (&buf, sidemove);
868                         MSG_WriteCoord16i (&buf, upmove);
869                         // 2 bytes
870                         MSG_WriteByte (&buf, bits);
871                         MSG_WriteByte (&buf, in_impulse);
872                 }
873                 else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
874                 {
875                         // 5 bytes
876                         MSG_WriteByte (&buf, clc_move);
877                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
878                         // 12 bytes
879                         for (i = 0;i < 3;i++)
880                                 MSG_WriteAngle32f (&buf, cl.viewangles[i]);
881                         // 6 bytes
882                         MSG_WriteCoord16i (&buf, forwardmove);
883                         MSG_WriteCoord16i (&buf, sidemove);
884                         MSG_WriteCoord16i (&buf, upmove);
885                         // 2 bytes
886                         MSG_WriteByte (&buf, bits);
887                         MSG_WriteByte (&buf, in_impulse);
888                 }
889                 else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
890                 {
891                         // 5 bytes
892                         MSG_WriteByte (&buf, clc_move);
893                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
894                         // 6 bytes
895                         for (i = 0;i < 3;i++)
896                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
897                         // 6 bytes
898                         MSG_WriteCoord16i (&buf, forwardmove);
899                         MSG_WriteCoord16i (&buf, sidemove);
900                         MSG_WriteCoord16i (&buf, upmove);
901                         // 2 bytes
902                         MSG_WriteByte (&buf, bits);
903                         MSG_WriteByte (&buf, in_impulse);
904                 }
905                 else
906                 {
907                         // 5 bytes
908                         MSG_WriteByte (&buf, clc_move);
909                         if (cl.protocol != PROTOCOL_DARKPLACES6)
910                         {
911                                 if (cl_movement.integer)
912                                 {
913                                         cl.movesequence++;
914                                         MSG_WriteLong (&buf, cl.movesequence);
915                                 }
916                                 else
917                                         MSG_WriteLong (&buf, 0);
918                         }
919                         MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
920                         // 6 bytes
921                         for (i = 0;i < 3;i++)
922                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
923                         // 6 bytes
924                         MSG_WriteCoord16i (&buf, forwardmove);
925                         MSG_WriteCoord16i (&buf, sidemove);
926                         MSG_WriteCoord16i (&buf, upmove);
927                         // 5 bytes
928                         MSG_WriteLong (&buf, bits);
929                         MSG_WriteByte (&buf, in_impulse);
930                         // PRYDON_CLIENTCURSOR
931                         // 30 bytes
932                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[0] * 32767.0f);
933                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[1] * 32767.0f);
934                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[0]);
935                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[1]);
936                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[2]);
937                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[0]);
938                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
939                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
940                         MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
941                 }
942         }
943
944 #if MOVEAVERAGING
945         forwardmove = sidemove = upmove = 0;
946 #endif
947         in_impulse = 0;
948
949         // ack the last few frame numbers
950         // (redundent to improve handling of client->server packet loss)
951         // for LATESTFRAMENUMS == 3 case this is 15 bytes
952         for (i = 0;i < LATESTFRAMENUMS;i++)
953         {
954                 if (cl.latestframenums[i] > 0)
955                 {
956                         if (developer_networkentities.integer >= 1)
957                                 Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
958                         MSG_WriteByte(&buf, clc_ackframe);
959                         MSG_WriteLong(&buf, cl.latestframenums[i]);
960                 }
961         }
962
963         // PROTOCOL_DARKPLACES6 = 67 bytes per packet
964         // PROTOCOL_DARKPLACES7 = 71 bytes per packet
965
966         // deliver the message
967         if (cls.demoplayback)
968                 return;
969         // nothing to send
970         if (!buf.cursize)
971                 return;
972
973         // FIXME: bits & 16 is +button5, Nexuiz specific
974         CL_ClientMovement_Input((bits & 2) != 0, (bits & 16) != 0);
975
976         if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
977         {
978                 Con_Print("CL_SendMove: lost server connection\n");
979                 CL_Disconnect();
980                 Host_ShutdownServer(false);
981         }
982 }
983
984 /*
985 ============
986 CL_InitInput
987 ============
988 */
989 void CL_InitInput (void)
990 {
991         Cmd_AddCommand ("+moveup",IN_UpDown);
992         Cmd_AddCommand ("-moveup",IN_UpUp);
993         Cmd_AddCommand ("+movedown",IN_DownDown);
994         Cmd_AddCommand ("-movedown",IN_DownUp);
995         Cmd_AddCommand ("+left",IN_LeftDown);
996         Cmd_AddCommand ("-left",IN_LeftUp);
997         Cmd_AddCommand ("+right",IN_RightDown);
998         Cmd_AddCommand ("-right",IN_RightUp);
999         Cmd_AddCommand ("+forward",IN_ForwardDown);
1000         Cmd_AddCommand ("-forward",IN_ForwardUp);
1001         Cmd_AddCommand ("+back",IN_BackDown);
1002         Cmd_AddCommand ("-back",IN_BackUp);
1003         Cmd_AddCommand ("+lookup", IN_LookupDown);
1004         Cmd_AddCommand ("-lookup", IN_LookupUp);
1005         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
1006         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
1007         Cmd_AddCommand ("+strafe", IN_StrafeDown);
1008         Cmd_AddCommand ("-strafe", IN_StrafeUp);
1009         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
1010         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
1011         Cmd_AddCommand ("+moveright", IN_MoverightDown);
1012         Cmd_AddCommand ("-moveright", IN_MoverightUp);
1013         Cmd_AddCommand ("+speed", IN_SpeedDown);
1014         Cmd_AddCommand ("-speed", IN_SpeedUp);
1015         Cmd_AddCommand ("+attack", IN_AttackDown);
1016         Cmd_AddCommand ("-attack", IN_AttackUp);
1017         Cmd_AddCommand ("+jump", IN_JumpDown);
1018         Cmd_AddCommand ("-jump", IN_JumpUp);
1019         Cmd_AddCommand ("impulse", IN_Impulse);
1020         Cmd_AddCommand ("+klook", IN_KLookDown);
1021         Cmd_AddCommand ("-klook", IN_KLookUp);
1022         Cmd_AddCommand ("+mlook", IN_MLookDown);
1023         Cmd_AddCommand ("-mlook", IN_MLookUp);
1024
1025         // LordHavoc: added use button
1026         Cmd_AddCommand ("+use", IN_UseDown);
1027         Cmd_AddCommand ("-use", IN_UseUp);
1028
1029         // LordHavoc: added 6 new buttons
1030         Cmd_AddCommand ("+button3", IN_Button3Down);
1031         Cmd_AddCommand ("-button3", IN_Button3Up);
1032         Cmd_AddCommand ("+button4", IN_Button4Down);
1033         Cmd_AddCommand ("-button4", IN_Button4Up);
1034         Cmd_AddCommand ("+button5", IN_Button5Down);
1035         Cmd_AddCommand ("-button5", IN_Button5Up);
1036         Cmd_AddCommand ("+button6", IN_Button6Down);
1037         Cmd_AddCommand ("-button6", IN_Button6Up);
1038         Cmd_AddCommand ("+button7", IN_Button7Down);
1039         Cmd_AddCommand ("-button7", IN_Button7Up);
1040         Cmd_AddCommand ("+button8", IN_Button8Down);
1041         Cmd_AddCommand ("-button8", IN_Button8Up);
1042
1043         Cvar_RegisterVariable(&cl_movement);
1044         Cvar_RegisterVariable(&cl_movement_latency);
1045         Cvar_RegisterVariable(&cl_movement_maxspeed);
1046         Cvar_RegisterVariable(&cl_movement_maxairspeed);
1047         Cvar_RegisterVariable(&cl_movement_stopspeed);
1048         Cvar_RegisterVariable(&cl_movement_friction);
1049         Cvar_RegisterVariable(&cl_movement_edgefriction);
1050         Cvar_RegisterVariable(&cl_movement_stepheight);
1051         Cvar_RegisterVariable(&cl_movement_accelerate);
1052         Cvar_RegisterVariable(&cl_movement_jumpvelocity);
1053         Cvar_RegisterVariable(&cl_gravity);
1054         Cvar_RegisterVariable(&cl_slowmo);
1055
1056         Cvar_RegisterVariable(&in_pitch_min);
1057         Cvar_RegisterVariable(&in_pitch_max);
1058         Cvar_RegisterVariable(&m_filter);
1059 }
1060