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