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
= sinf(angleval
);
67 cosval
= cosf(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
= sqrtf(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
);
236 len
-= 25*host_frametime
;
238 len
-= 10*host_frametime
;
242 VectorScale (sv_player
->v
.punchangle
, len
, sv_player
->v
.punchangle
);
251 void SV_WaterMove (void)
255 float speed
, newspeed
, wishspeed
, addspeed
, accelspeed
;
260 AngleVectors (sv_player
->v
.v_angle
, forward
, right
, up
);
262 for (i
=0 ; i
<3 ; i
++)
263 wishvel
[i
] = forward
[i
]*cmd
.forwardmove
+ right
[i
]*cmd
.sidemove
;
265 if (!cmd
.forwardmove
&& !cmd
.sidemove
&& !cmd
.upmove
)
268 wishvel
[2] -= 60; // drift towards bottom
271 wishvel
[2] += cmd
.upmove
;
273 wishspeed
= Length(wishvel
);
274 if (wishspeed
> sv_maxspeed
.value
)
276 VectorScale (wishvel
, sv_maxspeed
.value
/wishspeed
, wishvel
);
277 wishspeed
= sv_maxspeed
.value
;
284 speed
= Length (velocity
);
287 newspeed
= speed
- host_frametime
* speed
* sv_friction
.value
;
290 VectorScale (velocity
, newspeed
/speed
, velocity
);
296 // water acceleration
301 addspeed
= wishspeed
- newspeed
;
305 VectorNormalize (wishvel
);
306 accelspeed
= sv_accelerate
.value
* wishspeed
* host_frametime
;
307 if (accelspeed
> addspeed
)
308 accelspeed
= addspeed
;
310 for (i
=0 ; i
<3 ; i
++)
311 velocity
[i
] += accelspeed
* wishvel
[i
];
314 void SV_WaterJump (void)
316 if (sv
.time
> sv_player
->v
.teleport_time
317 || !sv_player
->v
.waterlevel
)
319 sv_player
->v
.flags
= (int)sv_player
->v
.flags
& ~FL_WATERJUMP
;
320 sv_player
->v
.teleport_time
= 0;
322 sv_player
->v
.velocity
[0] = sv_player
->v
.movedir
[0];
323 sv_player
->v
.velocity
[1] = sv_player
->v
.movedir
[1];
333 void SV_AirMove (void)
339 AngleVectors (sv_player
->v
.angles
, forward
, right
, up
);
341 fmove
= cmd
.forwardmove
;
342 smove
= cmd
.sidemove
;
344 // hack to not let you back into teleporter
345 if (sv
.time
< sv_player
->v
.teleport_time
&& fmove
< 0)
348 for (i
=0 ; i
<3 ; i
++)
349 wishvel
[i
] = forward
[i
]*fmove
+ right
[i
]*smove
;
351 if ( (int)sv_player
->v
.movetype
!= MOVETYPE_WALK
)
352 wishvel
[2] = cmd
.upmove
;
356 VectorCopy (wishvel
, wishdir
);
357 wishspeed
= VectorNormalize(wishdir
);
358 if (wishspeed
> sv_maxspeed
.value
)
360 VectorScale (wishvel
, sv_maxspeed
.value
/wishspeed
, wishvel
);
361 wishspeed
= sv_maxspeed
.value
;
364 if ( sv_player
->v
.movetype
== MOVETYPE_NOCLIP
)
366 VectorCopy (wishvel
, velocity
);
374 { // not on ground, so little effect on velocity
375 SV_AirAccelerate (wishvel
);
383 the move fields specify an intended velocity in pix/sec
384 the angle fields specify an exact angular motion in degrees
387 void SV_ClientThink (void)
391 if (sv_player
->v
.movetype
== MOVETYPE_NONE
)
394 onground
= (int)sv_player
->v
.flags
& FL_ONGROUND
;
396 origin
= sv_player
->v
.origin
;
397 velocity
= sv_player
->v
.velocity
;
402 // if dead, behave differently
404 if (sv_player
->v
.health
<= 0)
409 // show 1/3 the pitch angle and all the roll angle
410 cmd
= host_client
->cmd
;
411 angles
= sv_player
->v
.angles
;
413 VectorAdd (sv_player
->v
.v_angle
, sv_player
->v
.punchangle
, v_angle
);
414 angles
[ROLL
] = V_CalcRoll (sv_player
->v
.angles
, sv_player
->v
.velocity
)*4;
415 if (!sv_player
->v
.fixangle
)
417 angles
[PITCH
] = -v_angle
[PITCH
]/3;
418 angles
[YAW
] = v_angle
[YAW
];
421 if ( (int)sv_player
->v
.flags
& FL_WATERJUMP
)
429 if ( (sv_player
->v
.waterlevel
>= 2)
430 && (sv_player
->v
.movetype
!= MOVETYPE_NOCLIP
) )
445 void SV_ReadClientMove (usercmd_t
*move
)
452 host_client
->ping_times
[host_client
->num_pings
%NUM_PING_TIMES
]
453 = sv
.time
- MSG_ReadFloat ();
454 host_client
->num_pings
++;
456 // read current angles
457 // JPG - precise aim for ProQuake!!
458 for (i
=0 ; i
<3 ; i
++)
459 angle
[i
] = MSG_ReadPreciseAngle ();
461 // read current angles
462 // for (i=0 ; i<3 ; i++)
463 // angle[i] = MSG_ReadAngle ();
465 VectorCopy (angle
, host_client
->edict
->v
.v_angle
);
468 move
->forwardmove
= MSG_ReadShort ();
469 move
->sidemove
= MSG_ReadShort ();
470 move
->upmove
= MSG_ReadShort ();
473 bits
= MSG_ReadByte ();
474 host_client
->edict
->v
.button0
= bits
& 1;
475 host_client
->edict
->v
.button2
= (bits
& 2)>>1;
479 host_client
->edict
->v
.impulse
= i
;
483 host_client
->edict
->v
.light_level
= MSG_ReadByte ();
491 Returns false if the client should be killed
494 qboolean
SV_ReadClientMessage (void)
503 ret
= NET_GetMessage (host_client
->netconnection
);
506 Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n");
516 if (!host_client
->active
)
517 return false; // a command caused an error
521 Sys_Printf ("SV_ReadClientMessage: badread\n");
525 cmd
= MSG_ReadChar ();
530 goto nextmsg
; // end of message
533 Sys_Printf ("SV_ReadClientMessage: unknown command char\n");
537 // Sys_Printf ("clc_nop\n");
541 s
= MSG_ReadString ();
542 if (host_client
->privileged
)
546 if (Q_strncasecmp(s
, "status", 6) == 0)
548 else if (Q_strncasecmp(s
, "god", 3) == 0)
550 else if (Q_strncasecmp(s
, "notarget", 8) == 0)
552 else if (Q_strncasecmp(s
, "fly", 3) == 0)
554 else if (Q_strncasecmp(s
, "name", 4) == 0)
556 else if (Q_strncasecmp(s
, "noclip", 6) == 0)
558 else if (Q_strncasecmp(s
, "say", 3) == 0)
560 else if (Q_strncasecmp(s
, "say_team", 8) == 0)
562 else if (Q_strncasecmp(s
, "tell", 4) == 0)
564 else if (Q_strncasecmp(s
, "color", 5) == 0)
566 else if (Q_strncasecmp(s
, "kill", 4) == 0)
568 else if (Q_strncasecmp(s
, "pause", 5) == 0)
570 else if (Q_strncasecmp(s
, "spawn", 5) == 0)
572 else if (Q_strncasecmp(s
, "begin", 5) == 0)
574 else if (Q_strncasecmp(s
, "prespawn", 8) == 0)
576 else if (Q_strncasecmp(s
, "kick", 4) == 0)
578 else if (Q_strncasecmp(s
, "ping", 4) == 0)
580 else if (Q_strncasecmp(s
, "give", 4) == 0)
582 else if (Q_strncasecmp(s
, "ban", 3) == 0)
587 Cmd_ExecuteString (s
, src_client
);
589 Con_DPrintf("%s tried to %s\n", host_client
->name
, s
);
593 // Sys_Printf ("SV_ReadClientMessage: client disconnected\n");
597 SV_ReadClientMove (&host_client
->cmd
);
606 extern qboolean bmg_type_changed
;
612 void SV_RunClients (void)
616 for (i
=0, host_client
= svs
.clients
; i
<svs
.maxclients
; i
++, host_client
++)
618 if (!host_client
->active
)
621 sv_player
= host_client
->edict
;
623 if (!SV_ReadClientMessage ())
625 SV_DropClient (false); // client misbehaved...
629 if (!host_client
->spawned
)
631 // clear client movement until a new packet is received
632 memset (&host_client
->cmd
, 0, sizeof(host_client
->cmd
));
636 // always pause in single player if in console or menus
637 if (!sv
.paused
&& (svs
.maxclients
> 1 || key_dest
== key_game
) )
642 Cvar_Set("bgmtype","cd");
643 bmg_type_changed
= true;
650 Cvar_Set("bgmtype","none");
651 bmg_type_changed
= true;