2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // sv_user.c -- server code for moving users
26 extern cvar_t sv_friction
;
27 cvar_t sv_edgefriction
= {"edgefriction", "2"};
28 extern cvar_t sv_stopspeed
;
30 static vec3_t forward
, right
, up
;
44 cvar_t sv_idealpitchscale
= {"sv_idealpitchscale","0.8"};
53 void SV_SetIdealPitch (void)
55 float angleval
, sinval
, cosval
;
62 if (!((int)sv_player
->v
.flags
& FL_ONGROUND
))
65 angleval
= sv_player
->v
.angles
[YAW
] * M_PI
*2 / 360;
66 sinval
= sin(angleval
);
67 cosval
= cos(angleval
);
69 for (i
=0 ; i
<MAX_FORWARD
; i
++)
71 top
[0] = sv_player
->v
.origin
[0] + cosval
*(i
+3)*12;
72 top
[1] = sv_player
->v
.origin
[1] + sinval
*(i
+3)*12;
73 top
[2] = sv_player
->v
.origin
[2] + sv_player
->v
.view_ofs
[2];
77 bottom
[2] = top
[2] - 160;
79 tr
= SV_Move (top
, vec3_origin
, vec3_origin
, bottom
, 1, sv_player
);
81 return; // looking at a wall, leave ideal the way is was
84 return; // near a dropoff
86 z
[i
] = top
[2] + tr
.fraction
*(bottom
[2]-top
[2]);
94 if (step
> -ON_EPSILON
&& step
< ON_EPSILON
)
97 if (dir
&& ( step
-dir
> ON_EPSILON
|| step
-dir
< -ON_EPSILON
) )
98 return; // mixed changes
106 sv_player
->v
.idealpitch
= 0;
112 sv_player
->v
.idealpitch
= -dir
* sv_idealpitchscale
.value
;
122 void SV_UserFriction (void)
125 float speed
, newspeed
, control
;
132 speed
= sqrt(vel
[0]*vel
[0] +vel
[1]*vel
[1]);
136 // if the leading edge is over a dropoff, increase friction
137 start
[0] = stop
[0] = origin
[0] + vel
[0]/speed
*16;
138 start
[1] = stop
[1] = origin
[1] + vel
[1]/speed
*16;
139 start
[2] = origin
[2] + sv_player
->v
.mins
[2];
140 stop
[2] = start
[2] - 34;
142 trace
= SV_Move (start
, vec3_origin
, vec3_origin
, stop
, true, sv_player
);
144 if (trace
.fraction
== 1.0)
145 friction
= sv_friction
.value
*sv_edgefriction
.value
;
147 friction
= sv_friction
.value
;
150 control
= speed
< sv_stopspeed
.value
? sv_stopspeed
.value
: speed
;
151 newspeed
= speed
- host_frametime
*control
*friction
;
157 vel
[0] = vel
[0] * newspeed
;
158 vel
[1] = vel
[1] * newspeed
;
159 vel
[2] = vel
[2] * newspeed
;
167 cvar_t sv_maxspeed
= {"sv_maxspeed", "320", false, true};
168 cvar_t sv_accelerate
= {"sv_accelerate", "10"};
170 void SV_Accelerate (vec3_t wishvel
)
173 float addspeed
, accelspeed
;
179 VectorSubtract (wishvel
, velocity
, pushvec
);
180 addspeed
= VectorNormalize (pushvec
);
182 accelspeed
= sv_accelerate
.value
*host_frametime
*addspeed
;
183 if (accelspeed
> addspeed
)
184 accelspeed
= addspeed
;
186 for (i
=0 ; i
<3 ; i
++)
187 velocity
[i
] += accelspeed
*pushvec
[i
];
190 void SV_Accelerate (void)
193 float addspeed
, accelspeed
, currentspeed
;
195 currentspeed
= DotProduct (velocity
, wishdir
);
196 addspeed
= wishspeed
- currentspeed
;
199 accelspeed
= sv_accelerate
.value
*host_frametime
*wishspeed
;
200 if (accelspeed
> addspeed
)
201 accelspeed
= addspeed
;
203 for (i
=0 ; i
<3 ; i
++)
204 velocity
[i
] += accelspeed
*wishdir
[i
];
207 void SV_AirAccelerate (vec3_t wishveloc
)
210 float addspeed
, wishspd
, accelspeed
, currentspeed
;
212 wishspd
= VectorNormalize (wishveloc
);
215 currentspeed
= DotProduct (velocity
, wishveloc
);
216 addspeed
= wishspd
- currentspeed
;
219 // accelspeed = sv_accelerate.value * host_frametime;
220 accelspeed
= sv_accelerate
.value
*wishspeed
* host_frametime
;
221 if (accelspeed
> addspeed
)
222 accelspeed
= addspeed
;
224 for (i
=0 ; i
<3 ; i
++)
225 velocity
[i
] += accelspeed
*wishveloc
[i
];
229 void DropPunchAngle (void)
233 len
= VectorNormalize (sv_player
->v
.punchangle
);
235 len
-= 10*host_frametime
;
238 VectorScale (sv_player
->v
.punchangle
, len
, sv_player
->v
.punchangle
);
247 void SV_WaterMove (void)
251 float speed
, newspeed
, wishspeed
, addspeed
, accelspeed
;
256 AngleVectors (sv_player
->v
.v_angle
, forward
, right
, up
);
258 for (i
=0 ; i
<3 ; i
++)
259 wishvel
[i
] = forward
[i
]*cmd
.forwardmove
+ right
[i
]*cmd
.sidemove
;
261 if (!cmd
.forwardmove
&& !cmd
.sidemove
&& !cmd
.upmove
)
262 wishvel
[2] -= 60; // drift towards bottom
264 wishvel
[2] += cmd
.upmove
;
266 wishspeed
= Length(wishvel
);
267 if (wishspeed
> sv_maxspeed
.value
)
269 VectorScale (wishvel
, sv_maxspeed
.value
/wishspeed
, wishvel
);
270 wishspeed
= sv_maxspeed
.value
;
277 speed
= Length (velocity
);
280 newspeed
= speed
- host_frametime
* speed
* sv_friction
.value
;
283 VectorScale (velocity
, newspeed
/speed
, velocity
);
289 // water acceleration
294 addspeed
= wishspeed
- newspeed
;
298 VectorNormalize (wishvel
);
299 accelspeed
= sv_accelerate
.value
* wishspeed
* host_frametime
;
300 if (accelspeed
> addspeed
)
301 accelspeed
= addspeed
;
303 for (i
=0 ; i
<3 ; i
++)
304 velocity
[i
] += accelspeed
* wishvel
[i
];
307 void SV_WaterJump (void)
309 if (sv
.time
> sv_player
->v
.teleport_time
310 || !sv_player
->v
.waterlevel
)
312 sv_player
->v
.flags
= (int)sv_player
->v
.flags
& ~FL_WATERJUMP
;
313 sv_player
->v
.teleport_time
= 0;
315 sv_player
->v
.velocity
[0] = sv_player
->v
.movedir
[0];
316 sv_player
->v
.velocity
[1] = sv_player
->v
.movedir
[1];
326 void SV_AirMove (void)
332 AngleVectors (sv_player
->v
.angles
, forward
, right
, up
);
334 fmove
= cmd
.forwardmove
;
335 smove
= cmd
.sidemove
;
337 // hack to not let you back into teleporter
338 if (sv
.time
< sv_player
->v
.teleport_time
&& fmove
< 0)
341 for (i
=0 ; i
<3 ; i
++)
342 wishvel
[i
] = forward
[i
]*fmove
+ right
[i
]*smove
;
344 if ( (int)sv_player
->v
.movetype
!= MOVETYPE_WALK
)
345 wishvel
[2] = cmd
.upmove
;
349 VectorCopy (wishvel
, wishdir
);
350 wishspeed
= VectorNormalize(wishdir
);
351 if (wishspeed
> sv_maxspeed
.value
)
353 VectorScale (wishvel
, sv_maxspeed
.value
/wishspeed
, wishvel
);
354 wishspeed
= sv_maxspeed
.value
;
357 if ( sv_player
->v
.movetype
== MOVETYPE_NOCLIP
)
359 VectorCopy (wishvel
, velocity
);
367 { // not on ground, so little effect on velocity
368 SV_AirAccelerate (wishvel
);
376 the move fields specify an intended velocity in pix/sec
377 the angle fields specify an exact angular motion in degrees
380 void SV_ClientThink (void)
384 if (sv_player
->v
.movetype
== MOVETYPE_NONE
)
387 onground
= (int)sv_player
->v
.flags
& FL_ONGROUND
;
389 origin
= sv_player
->v
.origin
;
390 velocity
= sv_player
->v
.velocity
;
395 // if dead, behave differently
397 if (sv_player
->v
.health
<= 0)
402 // show 1/3 the pitch angle and all the roll angle
403 cmd
= host_client
->cmd
;
404 angles
= sv_player
->v
.angles
;
406 VectorAdd (sv_player
->v
.v_angle
, sv_player
->v
.punchangle
, v_angle
);
407 angles
[ROLL
] = V_CalcRoll (sv_player
->v
.angles
, sv_player
->v
.velocity
)*4;
408 if (!sv_player
->v
.fixangle
)
410 angles
[PITCH
] = -v_angle
[PITCH
]/3;
411 angles
[YAW
] = v_angle
[YAW
];
414 if ( (int)sv_player
->v
.flags
& FL_WATERJUMP
)
422 if ( (sv_player
->v
.waterlevel
>= 2)
423 && (sv_player
->v
.movetype
!= MOVETYPE_NOCLIP
) )
438 void SV_ReadClientMove (usercmd_t
*move
)
445 host_client
->ping_times
[host_client
->num_pings
%NUM_PING_TIMES
]
446 = sv
.time
- MSG_ReadFloat ();
447 host_client
->num_pings
++;
449 // read current angles
450 for (i
=0 ; i
<3 ; i
++)
451 angle
[i
] = MSG_ReadAngle ();
453 VectorCopy (angle
, host_client
->edict
->v
.v_angle
);
456 move
->forwardmove
= MSG_ReadShort ();
457 move
->sidemove
= MSG_ReadShort ();
458 move
->upmove
= MSG_ReadShort ();
461 bits
= MSG_ReadByte ();
462 host_client
->edict
->v
.button0
= bits
& 1;
463 host_client
->edict
->v
.button2
= (bits
& 2)>>1;
467 host_client
->edict
->v
.impulse
= i
;
471 host_client
->edict
->v
.light_level
= MSG_ReadByte ();
479 Returns false if the client should be killed
482 qboolean
SV_ReadClientMessage (void)
491 ret
= NET_GetMessage (host_client
->netconnection
);
494 Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");
504 if (!host_client
->active
)
505 return false; // a command caused an error
509 Sys_Printf ("SV_ReadClientMessage: badread\n");
513 cmd
= MSG_ReadChar ();
518 goto nextmsg
; // end of message
521 Sys_Printf ("SV_ReadClientMessage: unknown command char\n");
525 // Sys_Printf ("clc_nop\n");
529 s
= MSG_ReadString ();
530 if (host_client
->privileged
)
534 if (Q_strncasecmp(s
, "status", 6) == 0)
536 else if (Q_strncasecmp(s
, "god", 3) == 0)
538 else if (Q_strncasecmp(s
, "notarget", 8) == 0)
540 else if (Q_strncasecmp(s
, "fly", 3) == 0)
542 else if (Q_strncasecmp(s
, "name", 4) == 0)
544 else if (Q_strncasecmp(s
, "noclip", 6) == 0)
546 else if (Q_strncasecmp(s
, "say", 3) == 0)
548 else if (Q_strncasecmp(s
, "say_team", 8) == 0)
550 else if (Q_strncasecmp(s
, "tell", 4) == 0)
552 else if (Q_strncasecmp(s
, "color", 5) == 0)
554 else if (Q_strncasecmp(s
, "kill", 4) == 0)
556 else if (Q_strncasecmp(s
, "pause", 5) == 0)
558 else if (Q_strncasecmp(s
, "spawn", 5) == 0)
560 else if (Q_strncasecmp(s
, "begin", 5) == 0)
562 else if (Q_strncasecmp(s
, "prespawn", 8) == 0)
564 else if (Q_strncasecmp(s
, "kick", 4) == 0)
566 else if (Q_strncasecmp(s
, "ping", 4) == 0)
568 else if (Q_strncasecmp(s
, "give", 4) == 0)
570 else if (Q_strncasecmp(s
, "ban", 3) == 0)
575 Cmd_ExecuteString (s
, src_client
);
577 Con_DPrintf("%s tried to %s\n", host_client
->name
, s
);
581 // Sys_Printf ("SV_ReadClientMessage: client disconnected\n");
585 SV_ReadClientMove (&host_client
->cmd
);
600 void SV_RunClients (void)
604 for (i
=0, host_client
= svs
.clients
; i
<svs
.maxclients
; i
++, host_client
++)
606 if (!host_client
->active
)
609 sv_player
= host_client
->edict
;
611 if (!SV_ReadClientMessage ())
613 SV_DropClient (false); // client misbehaved...
617 if (!host_client
->spawned
)
619 // clear client movement until a new packet is received
620 memset (&host_client
->cmd
, 0, sizeof(host_client
->cmd
));
624 // always pause in single player if in console or menus
625 if (!sv
.paused
&& (svs
.maxclients
> 1 || key_dest
== key_game
) )