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 // sv_user.c -- server code for moving users 21 22 #include "quakedef.h" 23 24 edict_t *sv_player; 25 26 extern cvar_t sv_friction; 27 cvar_t sv_edgefriction = CVAR2("edgefriction", "2"); 28 extern cvar_t sv_stopspeed; 29 30 static vec3_t forward, right, up; 31 32 vec3_t wishdir; 33 float wishspeed; 34 35 // world 36 float *angles; 37 float *origin; 38 float *velocity; 39 40 qboolean onground; 41 42 usercmd_t cmd; 43 44 cvar_t sv_idealpitchscale = CVAR2("sv_idealpitchscale","0.8"); 45 46 47 /* 48 =============== 49 SV_SetIdealPitch 50 =============== 51 */ 52 #define MAX_FORWARD 6 53 void SV_SetIdealPitch (void) 54 { 55 float angleval, sinval, cosval; 56 trace_t tr; 57 vec3_t top, bottom; 58 float z[MAX_FORWARD]; 59 int i, j; 60 int step, dir, steps; 61 62 if (!((int)sv_player->u.v.flags & FL_ONGROUND)) 63 return; 64 65 angleval = sv_player->u.v.angles[YAW] * M_PI*2 / 360; 66 sinval = sin(angleval); 67 cosval = cos(angleval); 68 69 for (i=0 ; i<MAX_FORWARD ; i++) 70 { 71 top[0] = sv_player->u.v.origin[0] + cosval*(i+3)*12; 72 top[1] = sv_player->u.v.origin[1] + sinval*(i+3)*12; 73 top[2] = sv_player->u.v.origin[2] + sv_player->u.v.view_ofs[2]; 74 75 bottom[0] = top[0]; 76 bottom[1] = top[1]; 77 bottom[2] = top[2] - 160; 78 79 tr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player); 80 if (tr.allsolid) 81 return; // looking at a wall, leave ideal the way is was 82 83 if (tr.fraction == 1) 84 return; // near a dropoff 85 86 z[i] = top[2] + tr.fraction*(bottom[2]-top[2]); 87 } 88 89 dir = 0; 90 steps = 0; 91 for (j=1 ; j<i ; j++) 92 { 93 step = (int) (z[j] - z[j-1]); 94 if (step > -ON_EPSILON && step < ON_EPSILON) 95 continue; 96 97 if (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) ) 98 return; // mixed changes 99 100 steps++; 101 dir = step; 102 } 103 104 if (!dir) 105 { 106 sv_player->u.v.idealpitch = 0; 107 return; 108 } 109 110 if (steps < 2) 111 return; 112 sv_player->u.v.idealpitch = -dir * sv_idealpitchscale.value; 113 } 114 115 116 /* 117 ================== 118 SV_UserFriction 119 120 ================== 121 */ 122 void SV_UserFriction (void) 123 { 124 float *vel; 125 float speed, newspeed, control; 126 vec3_t start, stop; 127 float friction; 128 trace_t trace; 129 130 vel = velocity; 131 132 speed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]); 133 if (!speed) 134 return; 135 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->u.v.mins[2]; 140 stop[2] = start[2] - 34; 141 142 trace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player); 143 144 if (trace.fraction == 1.0) 145 friction = sv_friction.value*sv_edgefriction.value; 146 else 147 friction = sv_friction.value; 148 149 // apply friction 150 control = speed < sv_stopspeed.value ? sv_stopspeed.value : speed; 151 newspeed = speed - host_frametime*control*friction; 152 153 if (newspeed < 0) 154 newspeed = 0; 155 newspeed /= speed; 156 157 vel[0] = vel[0] * newspeed; 158 vel[1] = vel[1] * newspeed; 159 vel[2] = vel[2] * newspeed; 160 } 161 162 /* 163 ============== 164 SV_Accelerate 165 ============== 166 */ 167 cvar_t sv_maxspeed = CVAR4("sv_maxspeed", "320", false, true); 168 cvar_t sv_accelerate = CVAR2("sv_accelerate", "10"); 169 #if 0 170 void SV_Accelerate (vec3_t wishvel) 171 { 172 int i; 173 float addspeed, accelspeed; 174 vec3_t pushvec; 175 176 if (wishspeed == 0) 177 return; 178 179 VectorSubtract (wishvel, velocity, pushvec); 180 addspeed = VectorNormalize (pushvec); 181 182 accelspeed = sv_accelerate.value*host_frametime*addspeed; 183 if (accelspeed > addspeed) 184 accelspeed = addspeed; 185 186 for (i=0 ; i<3 ; i++) 187 velocity[i] += accelspeed*pushvec[i]; 188 } 189 #endif 190 void SV_Accelerate (void) 191 { 192 int i; 193 float addspeed, accelspeed, currentspeed; 194 195 currentspeed = DotProduct (velocity, wishdir); 196 addspeed = wishspeed - currentspeed; 197 if (addspeed <= 0) 198 return; 199 accelspeed = sv_accelerate.value*host_frametime*wishspeed; 200 if (accelspeed > addspeed) 201 accelspeed = addspeed; 202 203 for (i=0 ; i<3 ; i++) 204 velocity[i] += accelspeed*wishdir[i]; 205 } 206 207 void SV_AirAccelerate (vec3_t wishveloc) 208 { 209 int i; 210 float addspeed, wishspd, accelspeed, currentspeed; 211 212 wishspd = VectorNormalize (wishveloc); 213 if (wishspd > 30) 214 wishspd = 30; 215 currentspeed = DotProduct (velocity, wishveloc); 216 addspeed = wishspd - currentspeed; 217 if (addspeed <= 0) 218 return; 219 // accelspeed = sv_accelerate.value * host_frametime; 220 accelspeed = sv_accelerate.value*wishspeed * host_frametime; 221 if (accelspeed > addspeed) 222 accelspeed = addspeed; 223 224 for (i=0 ; i<3 ; i++) 225 velocity[i] += accelspeed*wishveloc[i]; 226 } 227 228 229 void DropPunchAngle (void) 230 { 231 float len; 232 233 len = VectorNormalize (sv_player->u.v.punchangle); 234 235 len -= 10*host_frametime; 236 if (len < 0) 237 len = 0; 238 VectorScale (sv_player->u.v.punchangle, len, sv_player->u.v.punchangle); 239 } 240 241 /* 242 =================== 243 SV_WaterMove 244 245 =================== 246 */ 247 void SV_WaterMove (void) 248 { 249 int i; 250 vec3_t wishvel; 251 float speed, newspeed, wishspeed, addspeed, accelspeed; 252 253 // 254 // user intentions 255 // 256 AngleVectors (sv_player->u.v.v_angle, forward, right, up); 257 258 for (i=0 ; i<3 ; i++) 259 wishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove; 260 261 if (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove) 262 wishvel[2] -= 60; // drift towards bottom 263 else 264 wishvel[2] += cmd.upmove; 265 266 wishspeed = Length(wishvel); 267 if (wishspeed > sv_maxspeed.value) 268 { 269 VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel); 270 wishspeed = sv_maxspeed.value; 271 } 272 wishspeed *= 0.7; 273 274 // 275 // water friction 276 // 277 speed = Length (velocity); 278 if (speed) 279 { 280 newspeed = speed - host_frametime * speed * sv_friction.value; 281 if (newspeed < 0) 282 newspeed = 0; 283 VectorScale (velocity, newspeed/speed, velocity); 284 } 285 else 286 newspeed = 0; 287 288 // 289 // water acceleration 290 // 291 if (!wishspeed) 292 return; 293 294 addspeed = wishspeed - newspeed; 295 if (addspeed <= 0) 296 return; 297 298 VectorNormalize (wishvel); 299 accelspeed = sv_accelerate.value * wishspeed * host_frametime; 300 if (accelspeed > addspeed) 301 accelspeed = addspeed; 302 303 for (i=0 ; i<3 ; i++) 304 velocity[i] += accelspeed * wishvel[i]; 305 } 306 307 void SV_WaterJump (void) 308 { 309 if (sv.time > sv_player->u.v.teleport_time 310 || !sv_player->u.v.waterlevel) 311 { 312 sv_player->u.v.flags = (int)sv_player->u.v.flags & ~FL_WATERJUMP; 313 sv_player->u.v.teleport_time = 0; 314 } 315 sv_player->u.v.velocity[0] = sv_player->u.v.movedir[0]; 316 sv_player->u.v.velocity[1] = sv_player->u.v.movedir[1]; 317 } 318 319 320 /* 321 =================== 322 SV_AirMove 323 324 =================== 325 */ 326 void SV_AirMove (void) 327 { 328 int i; 329 vec3_t wishvel; 330 float fmove, smove; 331 332 AngleVectors (sv_player->u.v.angles, forward, right, up); 333 334 fmove = cmd.forwardmove; 335 smove = cmd.sidemove; 336 337 // hack to not let you back into teleporter 338 if (sv.time < sv_player->u.v.teleport_time && fmove < 0) 339 fmove = 0; 340 341 for (i=0 ; i<3 ; i++) 342 wishvel[i] = forward[i]*fmove + right[i]*smove; 343 344 if ( (int)sv_player->u.v.movetype != MOVETYPE_WALK) 345 wishvel[2] = cmd.upmove; 346 else 347 wishvel[2] = 0; 348 349 VectorCopy (wishvel, wishdir); 350 wishspeed = VectorNormalize(wishdir); 351 if (wishspeed > sv_maxspeed.value) 352 { 353 VectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel); 354 wishspeed = sv_maxspeed.value; 355 } 356 357 if ( sv_player->u.v.movetype == MOVETYPE_NOCLIP) 358 { // noclip 359 VectorCopy (wishvel, velocity); 360 } 361 else if ( onground ) 362 { 363 SV_UserFriction (); 364 SV_Accelerate (); 365 } 366 else 367 { // not on ground, so little effect on velocity 368 SV_AirAccelerate (wishvel); 369 } 370 } 371 372 /* 373 =================== 374 SV_ClientThink 375 376 the move fields specify an intended velocity in pix/sec 377 the angle fields specify an exact angular motion in degrees 378 =================== 379 */ 380 void SV_ClientThink (void) 381 { 382 vec3_t v_angle; 383 384 if (sv_player->u.v.movetype == MOVETYPE_NONE) 385 return; 386 387 onground = (int)sv_player->u.v.flags & FL_ONGROUND; 388 389 origin = sv_player->u.v.origin; 390 velocity = sv_player->u.v.velocity; 391 392 DropPunchAngle (); 393 394 // 395 // if dead, behave differently 396 // 397 if (sv_player->u.v.health <= 0) 398 return; 399 400 // 401 // angles 402 // show 1/3 the pitch angle and all the roll angle 403 cmd = host_client->cmd; 404 angles = sv_player->u.v.angles; 405 406 VectorAdd (sv_player->u.v.v_angle, sv_player->u.v.punchangle, v_angle); 407 angles[ROLL] = V_CalcRoll (sv_player->u.v.angles, sv_player->u.v.velocity)*4; 408 if (!sv_player->u.v.fixangle) 409 { 410 angles[PITCH] = -v_angle[PITCH]/3; 411 angles[YAW] = v_angle[YAW]; 412 } 413 414 if ( (int)sv_player->u.v.flags & FL_WATERJUMP ) 415 { 416 SV_WaterJump (); 417 return; 418 } 419 // 420 // walk 421 // 422 if ( (sv_player->u.v.waterlevel >= 2) 423 && (sv_player->u.v.movetype != MOVETYPE_NOCLIP) ) 424 { 425 SV_WaterMove (); 426 return; 427 } 428 429 SV_AirMove (); 430 } 431 432 433 /* 434 =================== 435 SV_ReadClientMove 436 =================== 437 */ 438 void SV_ReadClientMove (usercmd_t *move) 439 { 440 int i; 441 vec3_t angle; 442 int bits; 443 444 // read ping time 445 host_client->ping_times[host_client->num_pings%NUM_PING_TIMES] 446 = sv.time - MSG_ReadFloat (); 447 host_client->num_pings++; 448 449 // read current angles 450 for (i=0 ; i<3 ; i++) 451 angle[i] = MSG_ReadAngle (); 452 453 VectorCopy (angle, host_client->edict->u.v.v_angle); 454 455 // read movement 456 move->forwardmove = MSG_ReadShort (); 457 move->sidemove = MSG_ReadShort (); 458 move->upmove = MSG_ReadShort (); 459 460 // read buttons 461 bits = MSG_ReadByte (); 462 host_client->edict->u.v.button0 = bits & 1; 463 host_client->edict->u.v.button2 = (bits & 2)>>1; 464 465 i = MSG_ReadByte (); 466 if (i) 467 host_client->edict->u.v.impulse = i; 468 469 #ifdef QUAKE2 470 // read light level 471 host_client->edict->u.v.light_level = MSG_ReadByte (); 472 #endif 473 } 474 475 /* 476 =================== 477 SV_ReadClientMessage 478 479 Returns false if the client should be killed 480 =================== 481 */ 482 qboolean SV_ReadClientMessage (void) 483 { 484 int ret; 485 int cmd; 486 char *s; 487 488 do 489 { 490 nextmsg: 491 ret = NET_GetMessage (host_client->netconnection); 492 if (ret == -1) 493 { 494 Sys_Printf ("SV_ReadClientMessage: NET_GetMessage failed\n"); 495 return false; 496 } 497 if (!ret) 498 return true; 499 500 MSG_BeginReading (); 501 502 while (1) 503 { 504 if (!host_client->active) 505 return false; // a command caused an error 506 507 if (msg_badread) 508 { 509 Sys_Printf ("SV_ReadClientMessage: badread\n"); 510 return false; 511 } 512 513 cmd = MSG_ReadChar (); 514 515 switch (cmd) 516 { 517 case -1: 518 goto nextmsg; // end of message 519 520 default: 521 Sys_Printf ("SV_ReadClientMessage: unknown command char\n"); 522 return false; 523 524 case clc_nop: 525 // Sys_Printf ("clc_nop\n"); 526 break; 527 528 case clc_stringcmd: 529 s = MSG_ReadString (); 530 if (host_client->privileged) 531 ret = 2; 532 else 533 ret = 0; 534 if (Q_strncasecmp(s, "status", 6) == 0) 535 ret = 1; 536 else if (Q_strncasecmp(s, "god", 3) == 0) 537 ret = 1; 538 else if (Q_strncasecmp(s, "notarget", 8) == 0) 539 ret = 1; 540 else if (Q_strncasecmp(s, "fly", 3) == 0) 541 ret = 1; 542 else if (Q_strncasecmp(s, "name", 4) == 0) 543 ret = 1; 544 else if (Q_strncasecmp(s, "noclip", 6) == 0) 545 ret = 1; 546 else if (Q_strncasecmp(s, "say", 3) == 0) 547 ret = 1; 548 else if (Q_strncasecmp(s, "say_team", 8) == 0) 549 ret = 1; 550 else if (Q_strncasecmp(s, "tell", 4) == 0) 551 ret = 1; 552 else if (Q_strncasecmp(s, "color", 5) == 0) 553 ret = 1; 554 else if (Q_strncasecmp(s, "kill", 4) == 0) 555 ret = 1; 556 else if (Q_strncasecmp(s, "pause", 5) == 0) 557 ret = 1; 558 else if (Q_strncasecmp(s, "spawn", 5) == 0) 559 ret = 1; 560 else if (Q_strncasecmp(s, "begin", 5) == 0) 561 ret = 1; 562 else if (Q_strncasecmp(s, "prespawn", 8) == 0) 563 ret = 1; 564 else if (Q_strncasecmp(s, "kick", 4) == 0) 565 ret = 1; 566 else if (Q_strncasecmp(s, "ping", 4) == 0) 567 ret = 1; 568 else if (Q_strncasecmp(s, "give", 4) == 0) 569 ret = 1; 570 else if (Q_strncasecmp(s, "ban", 3) == 0) 571 ret = 1; 572 if (ret == 2) 573 Cbuf_InsertText (s); 574 else if (ret == 1) 575 Cmd_ExecuteString (s, src_client); 576 else 577 Con_DPrintf("%s tried to %s\n", host_client->name, s); 578 break; 579 580 case clc_disconnect: 581 // Sys_Printf ("SV_ReadClientMessage: client disconnected\n"); 582 return false; 583 584 case clc_move: 585 SV_ReadClientMove (&host_client->cmd); 586 break; 587 } 588 } 589 } while (ret == 1); 590 591 return true; 592 } 593 594 595 /* 596 ================== 597 SV_RunClients 598 ================== 599 */ 600 void SV_RunClients (void) 601 { 602 int i; 603 604 for (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++) 605 { 606 if (!host_client->active) 607 continue; 608 609 sv_player = host_client->edict; 610 611 if (!SV_ReadClientMessage ()) 612 { 613 SV_DropClient (false); // client misbehaved... 614 continue; 615 } 616 617 if (!host_client->spawned) 618 { 619 // clear client movement until a new packet is received 620 memset (&host_client->cmd, 0, sizeof(host_client->cmd)); 621 continue; 622 } 623 624 // always pause in single player if in console or menus 625 if (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) ) 626 SV_ClientThink (); 627 } 628 } 629 630