]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_input.c
added developer_texturelogging
[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, n, bump, contents, crouch;
422         //double simulatedtime;
423         double currenttime;
424         double newtime;
425         double frametime;
426         double t;
427         vec_t wishspeed, addspeed, accelspeed, f, *playermins, *playermaxs;
428         client_movementqueue_t *q;
429         vec3_t currentorigin, currentvelocity, forward, right, up, wishvel, wishdir, neworigin, currentorigin2, neworigin2, yawangles;
430         trace_t trace, trace2, trace3;
431         // remove stale queue items
432         n = cl.movement_numqueue;
433         cl.movement_numqueue = 0;
434         for (i = 0;i < n;i++)
435                 if (cl.movement_queue[i].time >= cl.mtime[0])
436                         cl.movement_queue[cl.movement_numqueue++] = cl.movement_queue[i];
437         // add to input queue if there is room
438         if (cl.movement_numqueue < sizeof(cl.movement_queue)/sizeof(cl.movement_queue[0]))
439         {
440                 // add to input queue
441                 cl.movement_queue[cl.movement_numqueue].time = cl.mtime[0] + cl_movement_latency.value;
442                 VectorCopy(cl.viewangles, cl.movement_queue[cl.movement_numqueue].viewangles);
443                 cl.movement_queue[cl.movement_numqueue].move[0] = cl.cmd.forwardmove;
444                 cl.movement_queue[cl.movement_numqueue].move[1] = cl.cmd.sidemove;
445                 cl.movement_queue[cl.movement_numqueue].move[2] = cl.cmd.upmove;
446                 cl.movement_queue[cl.movement_numqueue].jump = buttonjump;
447                 cl.movement_queue[cl.movement_numqueue].crouch = buttoncrouch;
448                 cl.movement_numqueue++;
449         }
450         cl.movement = false;
451         // abort if client movement is disabled
452         if (!cl_movement.integer || cl.stats[STAT_HEALTH] <= 0)
453                 return;
454         // fetch current starting values
455         currenttime = cl.mtime[0];
456         VectorCopy(cl_entities[cl.playerentity].state_current.origin, currentorigin);
457         VectorCopy(cl.mvelocity[0], currentvelocity);
458         // calculate time to execute for
459         //simulatedtime = currenttime + cl_movement_latency.value;
460         // FIXME: try minor nudges in various directions if startsolid to find a
461         // safe place to start the walk (due to network compression in some
462         // protocols this starts in solid)
463         //currentorigin[2] += (1.0 / 32.0); // slight nudge to get out of the floor
464         crouch = false; // this will be updated on first move
465         //Con_Printf("%f: ", currenttime);
466         // replay input queue, and remove any stale queue items
467         // note: this relies on the fact there's always one queue item at the end
468         for (i = 0, q = cl.movement_queue;i < cl.movement_numqueue;i++, q++)
469         {
470                 //newtime = (i == cl.movement_numqueue) ? simulatedtime : q->time;
471                 newtime = q->time;
472                 frametime = newtime - currenttime;
473                 if (frametime < 0)
474                         continue;
475                 //Con_Printf(" %f", frametime);
476                 currenttime = newtime;
477                 if (crouch)
478                 {
479                         playermins = cl_playercrouchmins;
480                         playermaxs = cl_playercrouchmaxs;
481                 }
482                 else
483                 {
484                         playermins = cl_playerstandmins;
485                         playermaxs = cl_playerstandmaxs;
486                 }
487                 for (bump = 0, t = frametime;bump < 8 && VectorLength2(currentvelocity) > 0;bump++)
488                 {
489                         VectorMA(currentorigin, t, currentvelocity, neworigin);
490                         trace = CL_TraceBox(currentorigin, playermins, playermaxs, neworigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
491                         if (trace.fraction < 1 && trace.plane.normal[2] == 0)
492                         {
493                                 // may be a step or wall, try stepping up
494                                 // first move forward at a higher level
495                                 VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + cl_movement_stepheight.value);
496                                 VectorSet(neworigin2, neworigin[0], neworigin[1], currentorigin[2] + cl_movement_stepheight.value);
497                                 trace2 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
498                                 // then move down from there
499                                 VectorCopy(trace2.endpos, currentorigin2);
500                                 VectorSet(neworigin2, trace2.endpos[0], trace2.endpos[1], currentorigin[2]);
501                                 trace3 = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
502                                 //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]);
503                                 // accept the new trace if it made some progress
504                                 if (fabs(trace3.endpos[0] - trace.endpos[0]) >= 0.03125 || fabs(trace3.endpos[1] - trace.endpos[1]) >= 0.03125)
505                                 {
506                                         trace = trace2;
507                                         VectorCopy(trace3.endpos, trace.endpos);
508                                 }
509                         }
510                         if (trace.fraction == 1)
511                         {
512                                 VectorCopy(trace.endpos, currentorigin);
513                                 break;
514                         }
515                         t *= 1 - trace.fraction;
516                         if (trace.fraction >= 0.001)
517                                 VectorCopy(trace.endpos, currentorigin);
518                         f = DotProduct(currentvelocity, trace.plane.normal);
519                         VectorMA(currentvelocity, -f, trace.plane.normal, currentvelocity);
520                 }
521                 if (i < cl.movement_numqueue)
522                 {
523                         if (q->crouch)
524                         {
525                                 // wants to crouch, this always works...
526                                 if (!crouch)
527                                         crouch = true;
528                         }
529                         else
530                         {
531                                 // wants to stand, if currently crouching we need to check for a
532                                 // low ceiling first
533                                 if (crouch)
534                                 {
535                                         trace = CL_TraceBox(currentorigin, cl_playerstandmins, cl_playerstandmaxs, currentorigin, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
536                                         if (!trace.startsolid)
537                                                 crouch = false;
538                                 }
539                         }
540                         // change velocity according to q->viewangles and q->move
541                         contents = CL_PointSuperContents(currentorigin);
542                         if (contents & SUPERCONTENTS_LIQUIDSMASK)
543                         {
544                                 // swim
545                                 AngleVectors(q->viewangles, forward, right, up);
546                                 VectorSet(up, 0, 0, 1);
547                                 VectorMAMAM(q->move[0], forward, q->move[1], right, q->move[2], up, wishvel);
548                                 wishspeed = VectorLength(wishvel);
549                                 if (wishspeed)
550                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
551                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
552                                 if (crouch)
553                                         wishspeed *= 0.5;
554                                 wishspeed *= 0.6;
555                                 VectorScale(currentvelocity, (1 - frametime * cl_movement_friction.value), currentvelocity);
556                                 f = wishspeed - DotProduct(currentvelocity, wishdir);
557                                 if (f > 0)
558                                 {
559                                         f = min(f, cl_movement_accelerate.value * frametime * wishspeed);
560                                         VectorMA(currentvelocity, f, wishdir, currentvelocity);
561                                 }
562                                 if (q->jump)
563                                 {
564                                         if (contents & SUPERCONTENTS_LAVA)
565                                                 currentvelocity[2] =  50;
566                                         else if (contents & SUPERCONTENTS_SLIME)
567                                                 currentvelocity[2] =  80;
568                                         else
569                                         {
570                                                 if (gamemode == GAME_NEXUIZ)
571                                                         currentvelocity[2] = 200;
572                                                 else
573                                                         currentvelocity[2] = 100;
574                                         }
575                                 }
576                         }
577                         else
578                         {
579                                 // walk
580                                 VectorSet(yawangles, 0, cl.viewangles[1], 0);
581                                 AngleVectors(yawangles, forward, right, up);
582                                 VectorMAM(q->move[0], forward, q->move[1], right, wishvel);
583                                 wishspeed = VectorLength(wishvel);
584                                 if (wishspeed)
585                                         VectorScale(wishvel, 1 / wishspeed, wishdir);
586                                 wishspeed = min(wishspeed, cl_movement_maxspeed.value);
587                                 if (crouch)
588                                         wishspeed *= 0.5;
589                                 // check if onground
590                                 VectorSet(currentorigin2, currentorigin[0], currentorigin[1], currentorigin[2] + 1);
591                                 VectorSet(neworigin2, currentorigin[0], currentorigin[1], currentorigin[2] - 1);
592                                 trace = CL_TraceBox(currentorigin2, playermins, playermaxs, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
593                                 if (trace.fraction < 1 && trace.plane.normal[2] > 0.7)
594                                 {
595                                         // apply ground friction
596                                         f = sqrt(currentvelocity[0] * currentvelocity[0] + currentvelocity[1] * currentvelocity[1]);
597                                         VectorSet(currentorigin2, currentorigin[0] + currentvelocity[0]*(16/f), currentorigin[1] + currentvelocity[1]*(16/f), currentorigin[2] + playermins[2]);
598                                         VectorSet(neworigin2, currentorigin2[0], currentorigin2[1], currentorigin2[2] - 34);
599                                         trace = CL_TraceBox(currentorigin2, vec3_origin, vec3_origin, neworigin2, true, NULL, SUPERCONTENTS_SOLID | SUPERCONTENTS_PLAYERCLIP, true);
600                                         // apply friction
601                                         f = 1 - frametime * (trace.fraction == 1 ? cl_movement_edgefriction.value : 1) * ((f < cl_movement_stopspeed.value) ? (cl_movement_stopspeed.value / f) : 1) * cl_movement_friction.value;
602                                         f = max(f, 0);
603                                         VectorScale(currentvelocity, f, currentvelocity);
604                                 }
605                                 else
606                                 {
607                                         // apply air speed limit
608                                         wishspeed = min(wishspeed, cl_movement_maxairspeed.value);
609                                 }
610                                 if (gamemode == GAME_NEXUIZ)
611                                         addspeed = wishspeed;
612                                 else
613                                         addspeed = wishspeed - DotProduct(currentvelocity, wishdir);
614                                 if (addspeed > 0)
615                                 {
616                                         accelspeed = min(cl_movement_accelerate.value * frametime * wishspeed, addspeed);
617                                         VectorMA(currentvelocity, accelspeed, wishdir, currentvelocity);
618                                 }
619                                 currentvelocity[2] -= cl_gravity.value * frametime;
620                         }
621                 }
622         }
623         //Con_Printf(" :%f\n", currenttime);
624         // store replay location
625         cl.movement = true;
626         VectorCopy(cl.movement_origin, cl.movement_oldorigin);
627         VectorCopy(currentorigin, cl.movement_origin);
628         //VectorCopy(currentorigin, cl_entities[cl.playerentity].state_current.origin);
629         //VectorSet(cl_entities[cl.playerentity].state_current.angles, 0, cl.viewangles[1], 0);
630 }
631
632 /*
633 ==============
634 CL_SendMove
635 ==============
636 */
637 void CL_SendMove(void)
638 {
639         int i;
640         int bits;
641         sizebuf_t buf;
642         qbyte data[128];
643 #define MOVEAVERAGING 0
644 #if MOVEAVERAGING
645         static float forwardmove, sidemove, upmove, total; // accumulation
646 #else
647         float forwardmove, sidemove, upmove;
648 #endif
649
650 #if MOVEAVERAGING
651         // accumulate changes between messages
652         forwardmove += cl.cmd.forwardmove;
653         sidemove += cl.cmd.sidemove;
654         upmove += cl.cmd.upmove;
655         total++;
656 #endif
657         if (cls.signon != SIGNONS)
658                 return;
659 #if MOVEAVERAGING
660         // average the accumulated changes
661         total = 1.0f / total;
662         forwardmove *= total;
663         sidemove *= total;
664         upmove *= total;
665         total = 0;
666 #else
667         // use the latest values
668         forwardmove = cl.cmd.forwardmove;
669         sidemove = cl.cmd.sidemove;
670         upmove = cl.cmd.upmove;
671 #endif
672
673         buf.maxsize = 128;
674         buf.cursize = 0;
675         buf.data = data;
676
677         // set button bits
678         // LordHavoc: added 6 new buttons and use and chat buttons, and prydon cursor active button
679         bits = 0;
680         if (in_attack.state   & 3) bits |=   1;in_attack.state  &= ~2;
681         if (in_jump.state     & 3) bits |=   2;in_jump.state    &= ~2;
682         if (in_button3.state  & 3) bits |=   4;in_button3.state &= ~2;
683         if (in_button4.state  & 3) bits |=   8;in_button4.state &= ~2;
684         if (in_button5.state  & 3) bits |=  16;in_button5.state &= ~2;
685         if (in_button6.state  & 3) bits |=  32;in_button6.state &= ~2;
686         if (in_button7.state  & 3) bits |=  64;in_button7.state &= ~2;
687         if (in_button8.state  & 3) bits |= 128;in_button8.state &= ~2;
688         if (in_use.state      & 3) bits |= 256;in_use.state     &= ~2;
689         if (key_dest != key_game || key_consoleactive) bits |= 512;
690         if (cl_prydoncursor.integer) bits |= 1024;
691         // button bits 11-31 unused currently
692         // rotate/zoom view serverside if PRYDON_CLIENTCURSOR cursor is at edge of screen
693         if (cl.cmd.cursor_screen[0] <= -1) bits |= 8;
694         if (cl.cmd.cursor_screen[0] >=  1) bits |= 16;
695         if (cl.cmd.cursor_screen[1] <= -1) bits |= 32;
696         if (cl.cmd.cursor_screen[1] >=  1) bits |= 64;
697
698         // always dump the first two messages, because they may contain leftover inputs from the last level
699         if (++cl.movemessages >= 2)
700         {
701                 // send the movement message
702                 // PROTOCOL_QUAKE       clc_move = 16 bytes total
703                 // PROTOCOL_DARKPLACES1 clc_move = 19 bytes total
704                 // PROTOCOL_DARKPLACES2 clc_move = 25 bytes total
705                 // PROTOCOL_DARKPLACES3 clc_move = 25 bytes total
706                 // PROTOCOL_DARKPLACES4 clc_move = 19 bytes total
707                 // PROTOCOL_DARKPLACES5 clc_move = 19 bytes total
708                 // PROTOCOL_DARKPLACES6 clc_move = 52 bytes total
709                 // 5 bytes
710                 MSG_WriteByte (&buf, clc_move);
711                 MSG_WriteFloat (&buf, cl.mtime[0]);     // so server can get ping times
712                 if (cl.protocol == PROTOCOL_DARKPLACES6)
713                 {
714                         // 6 bytes
715                         for (i = 0;i < 3;i++)
716                                 MSG_WriteAngle16i (&buf, cl.viewangles[i]);
717                         // 6 bytes
718                         MSG_WriteCoord16i (&buf, forwardmove);
719                         MSG_WriteCoord16i (&buf, sidemove);
720                         MSG_WriteCoord16i (&buf, upmove);
721                         // 5 bytes
722                         MSG_WriteLong (&buf, bits);
723                         MSG_WriteByte (&buf, in_impulse);
724                         // PRYDON_CLIENTCURSOR
725                         // 30 bytes
726                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[0] * 32767.0f);
727                         MSG_WriteShort (&buf, cl.cmd.cursor_screen[1] * 32767.0f);
728                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[0]);
729                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[1]);
730                         MSG_WriteFloat (&buf, cl.cmd.cursor_start[2]);
731                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[0]);
732                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[1]);
733                         MSG_WriteFloat (&buf, cl.cmd.cursor_impact[2]);
734                         MSG_WriteShort (&buf, cl.cmd.cursor_entitynumber);
735                 }
736                 else
737                 {
738                         if (cl.protocol == PROTOCOL_QUAKE || cl.protocol == PROTOCOL_NEHAHRAMOVIE)
739                         {
740                                 // 3 bytes
741                                 for (i = 0;i < 3;i++)
742                                         MSG_WriteAngle8i (&buf, cl.viewangles[i]);
743                         }
744                         else if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3)
745                         {
746                                 // 12 bytes
747                                 for (i = 0;i < 3;i++)
748                                         MSG_WriteAngle32f (&buf, cl.viewangles[i]);
749                         }
750                         else if (cl.protocol == PROTOCOL_DARKPLACES1 || cl.protocol == PROTOCOL_DARKPLACES4 || cl.protocol == PROTOCOL_DARKPLACES5)
751                         {
752                                 // 6 bytes
753                                 for (i = 0;i < 3;i++)
754                                         MSG_WriteAngle16i (&buf, cl.viewangles[i]);
755                         }
756                         else
757                                 Host_Error("CL_SendMove: unknown cl.protocol %i\n", cl.protocol);
758                         // 6 bytes
759                         MSG_WriteCoord16i (&buf, forwardmove);
760                         MSG_WriteCoord16i (&buf, sidemove);
761                         MSG_WriteCoord16i (&buf, upmove);
762                         // 2 bytes
763                         MSG_WriteByte (&buf, bits);
764                         MSG_WriteByte (&buf, in_impulse);
765                 }
766         }
767
768 #if MOVEAVERAGING
769         forwardmove = sidemove = upmove = 0;
770 #endif
771         in_impulse = 0;
772
773         // ack the last few frame numbers
774         // (redundent to improve handling of client->server packet loss)
775         // for LATESTFRAMENUMS == 3 case this is 15 bytes
776         for (i = 0;i < LATESTFRAMENUMS;i++)
777         {
778                 if (cl.latestframenums[i] > 0)
779                 {
780                         if (developer_networkentities.integer >= 1)
781                                 Con_Printf("send clc_ackframe %i\n", cl.latestframenums[i]);
782                         MSG_WriteByte(&buf, clc_ackframe);
783                         MSG_WriteLong(&buf, cl.latestframenums[i]);
784                 }
785         }
786
787         // PROTOCOL_DARKPLACES6 = 67 bytes per packet
788
789         // deliver the message
790         if (cls.demoplayback)
791                 return;
792         // nothing to send
793         if (!buf.cursize)
794                 return;
795
796         // FIXME: bits & 64 is +button5, Nexuiz specific
797         CL_ClientMovement((bits & 2) != 0, (bits & 64) != 0);
798
799         if (NetConn_SendUnreliableMessage(cls.netcon, &buf) == -1)
800         {
801                 Con_Print("CL_SendMove: lost server connection\n");
802                 CL_Disconnect();
803                 Host_ShutdownServer(false);
804         }
805 }
806
807 /*
808 ============
809 CL_InitInput
810 ============
811 */
812 void CL_InitInput (void)
813 {
814         Cmd_AddCommand ("+moveup",IN_UpDown);
815         Cmd_AddCommand ("-moveup",IN_UpUp);
816         Cmd_AddCommand ("+movedown",IN_DownDown);
817         Cmd_AddCommand ("-movedown",IN_DownUp);
818         Cmd_AddCommand ("+left",IN_LeftDown);
819         Cmd_AddCommand ("-left",IN_LeftUp);
820         Cmd_AddCommand ("+right",IN_RightDown);
821         Cmd_AddCommand ("-right",IN_RightUp);
822         Cmd_AddCommand ("+forward",IN_ForwardDown);
823         Cmd_AddCommand ("-forward",IN_ForwardUp);
824         Cmd_AddCommand ("+back",IN_BackDown);
825         Cmd_AddCommand ("-back",IN_BackUp);
826         Cmd_AddCommand ("+lookup", IN_LookupDown);
827         Cmd_AddCommand ("-lookup", IN_LookupUp);
828         Cmd_AddCommand ("+lookdown", IN_LookdownDown);
829         Cmd_AddCommand ("-lookdown", IN_LookdownUp);
830         Cmd_AddCommand ("+strafe", IN_StrafeDown);
831         Cmd_AddCommand ("-strafe", IN_StrafeUp);
832         Cmd_AddCommand ("+moveleft", IN_MoveleftDown);
833         Cmd_AddCommand ("-moveleft", IN_MoveleftUp);
834         Cmd_AddCommand ("+moveright", IN_MoverightDown);
835         Cmd_AddCommand ("-moveright", IN_MoverightUp);
836         Cmd_AddCommand ("+speed", IN_SpeedDown);
837         Cmd_AddCommand ("-speed", IN_SpeedUp);
838         Cmd_AddCommand ("+attack", IN_AttackDown);
839         Cmd_AddCommand ("-attack", IN_AttackUp);
840         Cmd_AddCommand ("+jump", IN_JumpDown);
841         Cmd_AddCommand ("-jump", IN_JumpUp);
842         Cmd_AddCommand ("impulse", IN_Impulse);
843         Cmd_AddCommand ("+klook", IN_KLookDown);
844         Cmd_AddCommand ("-klook", IN_KLookUp);
845         Cmd_AddCommand ("+mlook", IN_MLookDown);
846         Cmd_AddCommand ("-mlook", IN_MLookUp);
847
848         // LordHavoc: added use button
849         Cmd_AddCommand ("+use", IN_UseDown);
850         Cmd_AddCommand ("-use", IN_UseUp);
851
852         // LordHavoc: added 6 new buttons
853         Cmd_AddCommand ("+button3", IN_Button3Down);
854         Cmd_AddCommand ("-button3", IN_Button3Up);
855         Cmd_AddCommand ("+button4", IN_Button4Down);
856         Cmd_AddCommand ("-button4", IN_Button4Up);
857         Cmd_AddCommand ("+button5", IN_Button5Down);
858         Cmd_AddCommand ("-button5", IN_Button5Up);
859         Cmd_AddCommand ("+button6", IN_Button6Down);
860         Cmd_AddCommand ("-button6", IN_Button6Up);
861         Cmd_AddCommand ("+button7", IN_Button7Down);
862         Cmd_AddCommand ("-button7", IN_Button7Up);
863         Cmd_AddCommand ("+button8", IN_Button8Down);
864         Cmd_AddCommand ("-button8", IN_Button8Up);
865
866         Cvar_RegisterVariable(&cl_movement);
867         Cvar_RegisterVariable(&cl_movement_latency);
868         Cvar_RegisterVariable(&cl_movement_maxspeed);
869         Cvar_RegisterVariable(&cl_movement_maxairspeed);
870         Cvar_RegisterVariable(&cl_movement_stopspeed);
871         Cvar_RegisterVariable(&cl_movement_friction);
872         Cvar_RegisterVariable(&cl_movement_edgefriction);
873         Cvar_RegisterVariable(&cl_movement_stepheight);
874         Cvar_RegisterVariable(&cl_movement_accelerate);
875         Cvar_RegisterVariable(&cl_gravity);
876         Cvar_RegisterVariable(&cl_slowmo);
877 }
878