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