Franklin Wei | 5d05b9d | 2018-02-11 15:34:30 -0500 | [diff] [blame] | 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_parse.c -- parse a message received from the server |
| 21 | |
| 22 | #include "quakedef.h" |
| 23 | |
| 24 | char *svc_strings[] = |
| 25 | { |
| 26 | "svc_bad", |
| 27 | "svc_nop", |
| 28 | "svc_disconnect", |
| 29 | "svc_updatestat", |
| 30 | "svc_version", // [long] server version |
| 31 | "svc_setview", // [short] entity number |
| 32 | "svc_sound", // <see code> |
| 33 | "svc_time", // [float] server time |
| 34 | "svc_print", // [string] null terminated string |
| 35 | "svc_stufftext", // [string] stuffed into client's console buffer |
| 36 | // the string should be \n terminated |
| 37 | "svc_setangle", // [vec3] set the view angle to this absolute value |
| 38 | |
| 39 | "svc_serverinfo", // [long] version |
| 40 | // [string] signon string |
| 41 | // [string]..[0]model cache [string]...[0]sounds cache |
| 42 | // [string]..[0]item cache |
| 43 | "svc_lightstyle", // [byte] [string] |
| 44 | "svc_updatename", // [byte] [string] |
| 45 | "svc_updatefrags", // [byte] [short] |
| 46 | "svc_clientdata", // <shortbits + data> |
| 47 | "svc_stopsound", // <see code> |
| 48 | "svc_updatecolors", // [byte] [byte] |
| 49 | "svc_particle", // [vec3] <variable> |
| 50 | "svc_damage", // [byte] impact [byte] blood [vec3] from |
| 51 | |
| 52 | "svc_spawnstatic", |
| 53 | "OBSOLETE svc_spawnbinary", |
| 54 | "svc_spawnbaseline", |
| 55 | |
| 56 | "svc_temp_entity", // <variable> |
| 57 | "svc_setpause", |
| 58 | "svc_signonnum", |
| 59 | "svc_centerprint", |
| 60 | "svc_killedmonster", |
| 61 | "svc_foundsecret", |
| 62 | "svc_spawnstaticsound", |
| 63 | "svc_intermission", |
| 64 | "svc_finale", // [string] music [string] text |
| 65 | "svc_cdtrack", // [byte] track [byte] looptrack |
| 66 | "svc_sellscreen", |
| 67 | "svc_cutscene" |
| 68 | }; |
| 69 | |
| 70 | //============================================================================= |
| 71 | |
| 72 | /* |
| 73 | =============== |
| 74 | CL_EntityNum |
| 75 | |
| 76 | This error checks and tracks the total number of entities |
| 77 | =============== |
| 78 | */ |
| 79 | entity_t *CL_EntityNum (int num) |
| 80 | { |
| 81 | if (num >= cl.num_entities) |
| 82 | { |
| 83 | if (num >= MAX_EDICTS) |
| 84 | Host_Error ("CL_EntityNum: %i is an invalid number",num); |
| 85 | while (cl.num_entities<=num) |
| 86 | { |
| 87 | cl_entities[cl.num_entities].colormap = vid.colormap; |
| 88 | cl.num_entities++; |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | return &cl_entities[num]; |
| 93 | } |
| 94 | |
| 95 | |
| 96 | /* |
| 97 | ================== |
| 98 | CL_ParseStartSoundPacket |
| 99 | ================== |
| 100 | */ |
| 101 | void CL_ParseStartSoundPacket(void) |
| 102 | { |
| 103 | vec3_t pos; |
| 104 | int channel, ent; |
| 105 | int sound_num; |
| 106 | int volume; |
| 107 | int field_mask; |
| 108 | float attenuation; |
| 109 | int i; |
| 110 | |
| 111 | field_mask = MSG_ReadByte(); |
| 112 | |
| 113 | if (field_mask & SND_VOLUME) |
| 114 | volume = MSG_ReadByte (); |
| 115 | else |
| 116 | volume = DEFAULT_SOUND_PACKET_VOLUME; |
| 117 | |
| 118 | if (field_mask & SND_ATTENUATION) |
| 119 | attenuation = MSG_ReadByte () / 64.0; |
| 120 | else |
| 121 | attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; |
| 122 | |
| 123 | channel = MSG_ReadShort (); |
| 124 | sound_num = MSG_ReadByte (); |
| 125 | |
| 126 | ent = channel >> 3; |
| 127 | channel &= 7; |
| 128 | |
| 129 | if (ent > MAX_EDICTS) |
| 130 | Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent); |
| 131 | |
| 132 | for (i=0 ; i<3 ; i++) |
| 133 | pos[i] = MSG_ReadCoord (); |
| 134 | |
| 135 | S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation); |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | ================== |
| 140 | CL_KeepaliveMessage |
| 141 | |
| 142 | When the client is taking a long time to load stuff, send keepalive messages |
| 143 | so the server doesn't disconnect. |
| 144 | ================== |
| 145 | */ |
| 146 | void CL_KeepaliveMessage (void) |
| 147 | { |
| 148 | float time; |
| 149 | static float lastmsg; |
| 150 | int ret; |
| 151 | sizebuf_t old; |
| 152 | byte olddata[8192]; |
| 153 | |
| 154 | if (sv.active) |
| 155 | return; // no need if server is local |
| 156 | if (cls.demoplayback) |
| 157 | return; |
| 158 | |
| 159 | // read messages from server, should just be nops |
| 160 | old = net_message; |
| 161 | memcpy (olddata, net_message.data, net_message.cursize); |
| 162 | |
| 163 | do |
| 164 | { |
| 165 | ret = CL_GetMessage (); |
| 166 | switch (ret) |
| 167 | { |
| 168 | default: |
| 169 | Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed"); |
| 170 | case 0: |
| 171 | break; // nothing waiting |
| 172 | case 1: |
| 173 | Host_Error ("CL_KeepaliveMessage: received a message"); |
| 174 | break; |
| 175 | case 2: |
| 176 | if (MSG_ReadByte() != svc_nop) |
| 177 | Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop"); |
| 178 | break; |
| 179 | } |
| 180 | } while (ret); |
| 181 | |
| 182 | net_message = old; |
| 183 | memcpy (net_message.data, olddata, net_message.cursize); |
| 184 | |
| 185 | // check time |
| 186 | time = Sys_FloatTime (); |
| 187 | if (time - lastmsg < 5) |
| 188 | return; |
| 189 | lastmsg = time; |
| 190 | |
| 191 | // write out a nop |
| 192 | Con_Printf ("--> client to server keepalive\n"); |
| 193 | |
| 194 | MSG_WriteByte (&cls.message, clc_nop); |
| 195 | NET_SendMessage (cls.netcon, &cls.message); |
| 196 | SZ_Clear (&cls.message); |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | ================== |
| 201 | CL_ParseServerInfo |
| 202 | ================== |
| 203 | */ |
| 204 | void CL_ParseServerInfo (void) |
| 205 | { |
| 206 | char *str; |
| 207 | int i; |
| 208 | int nummodels, numsounds; |
| 209 | char model_precache[MAX_MODELS][MAX_QPATH]; |
| 210 | char sound_precache[MAX_SOUNDS][MAX_QPATH]; |
| 211 | |
| 212 | Con_DPrintf ("Serverinfo packet received.\n"); |
| 213 | // |
| 214 | // wipe the client_state_t struct |
| 215 | // |
| 216 | CL_ClearState (); |
| 217 | |
| 218 | // parse protocol version number |
| 219 | i = MSG_ReadLong (); |
| 220 | if (i != PROTOCOL_VERSION) |
| 221 | { |
| 222 | Con_Printf ("Server returned version %i, not %i", i, PROTOCOL_VERSION); |
| 223 | return; |
| 224 | } |
| 225 | |
| 226 | // parse maxclients |
| 227 | cl.maxclients = MSG_ReadByte (); |
| 228 | if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) |
| 229 | { |
| 230 | Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients); |
| 231 | return; |
| 232 | } |
| 233 | cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); |
| 234 | |
| 235 | // parse gametype |
| 236 | cl.gametype = MSG_ReadByte (); |
| 237 | |
| 238 | // parse signon message |
| 239 | str = MSG_ReadString (); |
| 240 | strncpy (cl.levelname, str, sizeof(cl.levelname)-1); |
| 241 | |
| 242 | // seperate the printfs so the server message can have a color |
| 243 | Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n"); |
| 244 | Con_Printf ("%c%s\n", 2, str); |
| 245 | |
| 246 | // |
| 247 | // first we go through and touch all of the precache data that still |
| 248 | // happens to be in the cache, so precaching something else doesn't |
| 249 | // needlessly purge it |
| 250 | // |
| 251 | |
| 252 | // precache models |
| 253 | memset (cl.model_precache, 0, sizeof(cl.model_precache)); |
| 254 | for (nummodels=1 ; ; nummodels++) |
| 255 | { |
| 256 | str = MSG_ReadString (); |
| 257 | if (!str[0]) |
| 258 | break; |
| 259 | if (nummodels==MAX_MODELS) |
| 260 | { |
| 261 | Con_Printf ("Server sent too many model precaches\n"); |
| 262 | return; |
| 263 | } |
| 264 | strcpy (model_precache[nummodels], str); |
| 265 | Mod_TouchModel (str); |
| 266 | } |
| 267 | |
| 268 | // precache sounds |
| 269 | memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); |
| 270 | for (numsounds=1 ; ; numsounds++) |
| 271 | { |
| 272 | str = MSG_ReadString (); |
| 273 | if (!str[0]) |
| 274 | break; |
| 275 | if (numsounds==MAX_SOUNDS) |
| 276 | { |
| 277 | Con_Printf ("Server sent too many sound precaches\n"); |
| 278 | return; |
| 279 | } |
| 280 | strcpy (sound_precache[numsounds], str); |
| 281 | S_TouchSound (str); |
| 282 | } |
| 283 | |
| 284 | // |
| 285 | // now we try to load everything else until a cache allocation fails |
| 286 | // |
| 287 | |
| 288 | for (i=1 ; i<nummodels ; i++) |
| 289 | { |
| 290 | cl.model_precache[i] = Mod_ForName (model_precache[i], false); |
| 291 | if (cl.model_precache[i] == NULL) |
| 292 | { |
| 293 | Con_Printf("Model %s not found\n", model_precache[i]); |
| 294 | return; |
| 295 | } |
| 296 | CL_KeepaliveMessage (); |
| 297 | } |
| 298 | |
| 299 | S_BeginPrecaching (); |
| 300 | for (i=1 ; i<numsounds ; i++) |
| 301 | { |
| 302 | cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]); |
| 303 | CL_KeepaliveMessage (); |
| 304 | } |
| 305 | S_EndPrecaching (); |
| 306 | |
| 307 | |
| 308 | // local state |
| 309 | cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; |
| 310 | |
| 311 | R_NewMap (); |
| 312 | |
| 313 | Hunk_Check (); // make sure nothing is hurt |
| 314 | |
| 315 | noclip_anglehack = false; // noclip is turned off at start |
| 316 | } |
| 317 | |
| 318 | |
| 319 | /* |
| 320 | ================== |
| 321 | CL_ParseUpdate |
| 322 | |
| 323 | Parse an entity update message from the server |
| 324 | If an entities model or origin changes from frame to frame, it must be |
| 325 | relinked. Other attributes can change without relinking. |
| 326 | ================== |
| 327 | */ |
| 328 | int bitcounts[16]; |
| 329 | |
| 330 | void CL_ParseUpdate (int bits) |
| 331 | { |
| 332 | int i; |
| 333 | model_t *model; |
| 334 | int modnum; |
| 335 | qboolean forcelink; |
| 336 | entity_t *ent; |
| 337 | int num; |
| 338 | int skin; |
| 339 | |
| 340 | if (cls.signon == SIGNONS - 1) |
| 341 | { // first update is the final signon stage |
| 342 | cls.signon = SIGNONS; |
| 343 | CL_SignonReply (); |
| 344 | } |
| 345 | |
| 346 | if (bits & U_MOREBITS) |
| 347 | { |
| 348 | i = MSG_ReadByte (); |
| 349 | bits |= (i<<8); |
| 350 | } |
| 351 | |
| 352 | if (bits & U_LONGENTITY) |
| 353 | num = MSG_ReadShort (); |
| 354 | else |
| 355 | num = MSG_ReadByte (); |
| 356 | |
| 357 | ent = CL_EntityNum (num); |
| 358 | |
| 359 | for (i=0 ; i<16 ; i++) |
| 360 | if (bits&(1<<i)) |
| 361 | bitcounts[i]++; |
| 362 | |
| 363 | if (ent->msgtime != cl.mtime[1]) |
| 364 | forcelink = true; // no previous frame to lerp from |
| 365 | else |
| 366 | forcelink = false; |
| 367 | |
| 368 | ent->msgtime = cl.mtime[0]; |
| 369 | |
| 370 | if (bits & U_MODEL) |
| 371 | { |
| 372 | modnum = MSG_ReadByte (); |
| 373 | if (modnum >= MAX_MODELS) |
| 374 | Host_Error ("CL_ParseModel: bad modnum"); |
| 375 | } |
| 376 | else |
| 377 | modnum = ent->baseline.modelindex; |
| 378 | |
| 379 | model = cl.model_precache[modnum]; |
| 380 | if (model != ent->model) |
| 381 | { |
| 382 | ent->model = model; |
| 383 | // automatic animation (torches, etc) can be either all together |
| 384 | // or randomized |
| 385 | if (model) |
| 386 | { |
| 387 | if (model->synctype == ST_RAND) |
| 388 | ent->syncbase = (float)(rand()&0x7fff) / 0x7fff; |
| 389 | else |
| 390 | ent->syncbase = 0.0; |
| 391 | } |
| 392 | else |
| 393 | forcelink = true; // hack to make null model players work |
| 394 | #ifdef GLQUAKE |
| 395 | if (num > 0 && num <= cl.maxclients) |
| 396 | R_TranslatePlayerSkin (num - 1); |
| 397 | #endif |
| 398 | } |
| 399 | |
| 400 | if (bits & U_FRAME) |
| 401 | ent->frame = MSG_ReadByte (); |
| 402 | else |
| 403 | ent->frame = ent->baseline.frame; |
| 404 | |
| 405 | if (bits & U_COLORMAP) |
| 406 | i = MSG_ReadByte(); |
| 407 | else |
| 408 | i = ent->baseline.colormap; |
| 409 | if (!i) |
| 410 | ent->colormap = vid.colormap; |
| 411 | else |
| 412 | { |
| 413 | if (i > cl.maxclients) |
| 414 | Sys_Error ("i >= cl.maxclients"); |
| 415 | ent->colormap = cl.scores[i-1].translations; |
| 416 | } |
| 417 | |
| 418 | #ifdef GLQUAKE |
| 419 | if (bits & U_SKIN) |
| 420 | skin = MSG_ReadByte(); |
| 421 | else |
| 422 | skin = ent->baseline.skin; |
| 423 | if (skin != ent->skinnum) { |
| 424 | ent->skinnum = skin; |
| 425 | if (num > 0 && num <= cl.maxclients) |
| 426 | R_TranslatePlayerSkin (num - 1); |
| 427 | } |
| 428 | |
| 429 | #else |
| 430 | |
| 431 | if (bits & U_SKIN) |
| 432 | ent->skinnum = MSG_ReadByte(); |
| 433 | else |
| 434 | ent->skinnum = ent->baseline.skin; |
| 435 | #endif |
| 436 | |
| 437 | if (bits & U_EFFECTS) |
| 438 | ent->effects = MSG_ReadByte(); |
| 439 | else |
| 440 | ent->effects = ent->baseline.effects; |
| 441 | |
| 442 | // shift the known values for interpolation |
| 443 | VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); |
| 444 | VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); |
| 445 | |
| 446 | if (bits & U_ORIGIN1) |
| 447 | ent->msg_origins[0][0] = MSG_ReadCoord (); |
| 448 | else |
| 449 | ent->msg_origins[0][0] = ent->baseline.origin[0]; |
| 450 | if (bits & U_ANGLE1) |
| 451 | ent->msg_angles[0][0] = MSG_ReadAngle(); |
| 452 | else |
| 453 | ent->msg_angles[0][0] = ent->baseline.angles[0]; |
| 454 | |
| 455 | if (bits & U_ORIGIN2) |
| 456 | ent->msg_origins[0][1] = MSG_ReadCoord (); |
| 457 | else |
| 458 | ent->msg_origins[0][1] = ent->baseline.origin[1]; |
| 459 | if (bits & U_ANGLE2) |
| 460 | ent->msg_angles[0][1] = MSG_ReadAngle(); |
| 461 | else |
| 462 | ent->msg_angles[0][1] = ent->baseline.angles[1]; |
| 463 | |
| 464 | if (bits & U_ORIGIN3) |
| 465 | ent->msg_origins[0][2] = MSG_ReadCoord (); |
| 466 | else |
| 467 | ent->msg_origins[0][2] = ent->baseline.origin[2]; |
| 468 | if (bits & U_ANGLE3) |
| 469 | ent->msg_angles[0][2] = MSG_ReadAngle(); |
| 470 | else |
| 471 | ent->msg_angles[0][2] = ent->baseline.angles[2]; |
| 472 | |
| 473 | if ( bits & U_NOLERP ) |
| 474 | ent->forcelink = true; |
| 475 | |
| 476 | if ( forcelink ) |
| 477 | { // didn't have an update last message |
| 478 | VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); |
| 479 | VectorCopy (ent->msg_origins[0], ent->origin); |
| 480 | VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); |
| 481 | VectorCopy (ent->msg_angles[0], ent->angles); |
| 482 | ent->forcelink = true; |
| 483 | } |
| 484 | } |
| 485 | |
| 486 | /* |
| 487 | ================== |
| 488 | CL_ParseBaseline |
| 489 | ================== |
| 490 | */ |
| 491 | void CL_ParseBaseline (entity_t *ent) |
| 492 | { |
| 493 | int i; |
| 494 | |
| 495 | ent->baseline.modelindex = MSG_ReadByte (); |
| 496 | ent->baseline.frame = MSG_ReadByte (); |
| 497 | ent->baseline.colormap = MSG_ReadByte(); |
| 498 | ent->baseline.skin = MSG_ReadByte(); |
| 499 | for (i=0 ; i<3 ; i++) |
| 500 | { |
| 501 | ent->baseline.origin[i] = MSG_ReadCoord (); |
| 502 | ent->baseline.angles[i] = MSG_ReadAngle (); |
| 503 | } |
| 504 | } |
| 505 | |
| 506 | |
| 507 | /* |
| 508 | ================== |
| 509 | CL_ParseClientdata |
| 510 | |
| 511 | Server information pertaining to this client only |
| 512 | ================== |
| 513 | */ |
| 514 | void CL_ParseClientdata (int bits) |
| 515 | { |
| 516 | int i, j; |
| 517 | |
| 518 | if (bits & SU_VIEWHEIGHT) |
| 519 | cl.viewheight = MSG_ReadChar (); |
| 520 | else |
| 521 | cl.viewheight = DEFAULT_VIEWHEIGHT; |
| 522 | |
| 523 | if (bits & SU_IDEALPITCH) |
| 524 | cl.idealpitch = MSG_ReadChar (); |
| 525 | else |
| 526 | cl.idealpitch = 0; |
| 527 | |
| 528 | VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); |
| 529 | for (i=0 ; i<3 ; i++) |
| 530 | { |
| 531 | if (bits & (SU_PUNCH1<<i) ) |
| 532 | cl.punchangle[i] = MSG_ReadChar(); |
| 533 | else |
| 534 | cl.punchangle[i] = 0; |
| 535 | if (bits & (SU_VELOCITY1<<i) ) |
| 536 | cl.mvelocity[0][i] = MSG_ReadChar()*16; |
| 537 | else |
| 538 | cl.mvelocity[0][i] = 0; |
| 539 | } |
| 540 | |
| 541 | // [always sent] if (bits & SU_ITEMS) |
| 542 | i = MSG_ReadLong (); |
| 543 | |
| 544 | if (cl.items != i) |
| 545 | { // set flash times |
| 546 | Sbar_Changed (); |
| 547 | for (j=0 ; j<32 ; j++) |
| 548 | if ( (i & (1<<j)) && !(cl.items & (1<<j))) |
| 549 | cl.item_gettime[j] = cl.time; |
| 550 | cl.items = i; |
| 551 | } |
| 552 | |
| 553 | cl.onground = (bits & SU_ONGROUND) != 0; |
| 554 | cl.inwater = (bits & SU_INWATER) != 0; |
| 555 | |
| 556 | if (bits & SU_WEAPONFRAME) |
| 557 | cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte (); |
| 558 | else |
| 559 | cl.stats[STAT_WEAPONFRAME] = 0; |
| 560 | |
| 561 | if (bits & SU_ARMOR) |
| 562 | i = MSG_ReadByte (); |
| 563 | else |
| 564 | i = 0; |
| 565 | if (cl.stats[STAT_ARMOR] != i) |
| 566 | { |
| 567 | cl.stats[STAT_ARMOR] = i; |
| 568 | Sbar_Changed (); |
| 569 | } |
| 570 | |
| 571 | if (bits & SU_WEAPON) |
| 572 | i = MSG_ReadByte (); |
| 573 | else |
| 574 | i = 0; |
| 575 | if (cl.stats[STAT_WEAPON] != i) |
| 576 | { |
| 577 | cl.stats[STAT_WEAPON] = i; |
| 578 | Sbar_Changed (); |
| 579 | } |
| 580 | |
| 581 | i = MSG_ReadShort (); |
| 582 | if (cl.stats[STAT_HEALTH] != i) |
| 583 | { |
| 584 | cl.stats[STAT_HEALTH] = i; |
| 585 | Sbar_Changed (); |
| 586 | } |
| 587 | |
| 588 | i = MSG_ReadByte (); |
| 589 | if (cl.stats[STAT_AMMO] != i) |
| 590 | { |
| 591 | cl.stats[STAT_AMMO] = i; |
| 592 | Sbar_Changed (); |
| 593 | } |
| 594 | |
| 595 | for (i=0 ; i<4 ; i++) |
| 596 | { |
| 597 | j = MSG_ReadByte (); |
| 598 | if (cl.stats[STAT_SHELLS+i] != j) |
| 599 | { |
| 600 | cl.stats[STAT_SHELLS+i] = j; |
| 601 | Sbar_Changed (); |
| 602 | } |
| 603 | } |
| 604 | |
| 605 | i = MSG_ReadByte (); |
| 606 | |
| 607 | if (standard_quake) |
| 608 | { |
| 609 | if (cl.stats[STAT_ACTIVEWEAPON] != i) |
| 610 | { |
| 611 | cl.stats[STAT_ACTIVEWEAPON] = i; |
| 612 | Sbar_Changed (); |
| 613 | } |
| 614 | } |
| 615 | else |
| 616 | { |
| 617 | if (cl.stats[STAT_ACTIVEWEAPON] != (1<<i)) |
| 618 | { |
| 619 | cl.stats[STAT_ACTIVEWEAPON] = (1<<i); |
| 620 | Sbar_Changed (); |
| 621 | } |
| 622 | } |
| 623 | } |
| 624 | |
| 625 | /* |
| 626 | ===================== |
| 627 | CL_NewTranslation |
| 628 | ===================== |
| 629 | */ |
| 630 | void CL_NewTranslation (int slot) |
| 631 | { |
| 632 | int i, j; |
| 633 | int top, bottom; |
| 634 | byte *dest, *source; |
| 635 | |
| 636 | if (slot > cl.maxclients) |
| 637 | Sys_Error ("CL_NewTranslation: slot > cl.maxclients"); |
| 638 | dest = cl.scores[slot].translations; |
| 639 | source = vid.colormap; |
| 640 | memcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations)); |
| 641 | top = cl.scores[slot].colors & 0xf0; |
| 642 | bottom = (cl.scores[slot].colors &15)<<4; |
| 643 | #ifdef GLQUAKE |
| 644 | R_TranslatePlayerSkin (slot); |
| 645 | #endif |
| 646 | |
| 647 | for (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256) |
| 648 | { |
| 649 | if (top < 128) // the artists made some backwards ranges. sigh. |
| 650 | memcpy (dest + TOP_RANGE, source + top, 16); |
| 651 | else |
| 652 | for (j=0 ; j<16 ; j++) |
| 653 | dest[TOP_RANGE+j] = source[top+15-j]; |
| 654 | |
| 655 | if (bottom < 128) |
| 656 | memcpy (dest + BOTTOM_RANGE, source + bottom, 16); |
| 657 | else |
| 658 | for (j=0 ; j<16 ; j++) |
| 659 | dest[BOTTOM_RANGE+j] = source[bottom+15-j]; |
| 660 | } |
| 661 | } |
| 662 | |
| 663 | /* |
| 664 | ===================== |
| 665 | CL_ParseStatic |
| 666 | ===================== |
| 667 | */ |
| 668 | void CL_ParseStatic (void) |
| 669 | { |
| 670 | entity_t *ent; |
| 671 | int i; |
| 672 | |
| 673 | i = cl.num_statics; |
| 674 | if (i >= MAX_STATIC_ENTITIES) |
| 675 | Host_Error ("Too many static entities"); |
| 676 | ent = &cl_static_entities[i]; |
| 677 | cl.num_statics++; |
| 678 | CL_ParseBaseline (ent); |
| 679 | |
| 680 | // copy it to the current state |
| 681 | ent->model = cl.model_precache[ent->baseline.modelindex]; |
| 682 | ent->frame = ent->baseline.frame; |
| 683 | ent->colormap = vid.colormap; |
| 684 | ent->skinnum = ent->baseline.skin; |
| 685 | ent->effects = ent->baseline.effects; |
| 686 | |
| 687 | VectorCopy (ent->baseline.origin, ent->origin); |
| 688 | VectorCopy (ent->baseline.angles, ent->angles); |
| 689 | R_AddEfrags (ent); |
| 690 | } |
| 691 | |
| 692 | /* |
| 693 | =================== |
| 694 | CL_ParseStaticSound |
| 695 | =================== |
| 696 | */ |
| 697 | void CL_ParseStaticSound (void) |
| 698 | { |
| 699 | vec3_t org; |
| 700 | int sound_num, vol, atten; |
| 701 | int i; |
| 702 | |
| 703 | for (i=0 ; i<3 ; i++) |
| 704 | org[i] = MSG_ReadCoord (); |
| 705 | sound_num = MSG_ReadByte (); |
| 706 | vol = MSG_ReadByte (); |
| 707 | atten = MSG_ReadByte (); |
| 708 | |
| 709 | S_StaticSound (cl.sound_precache[sound_num], org, vol, atten); |
| 710 | } |
| 711 | |
| 712 | |
| 713 | #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); |
| 714 | |
| 715 | /* |
| 716 | ===================== |
| 717 | CL_ParseServerMessage |
| 718 | ===================== |
| 719 | */ |
| 720 | void CL_ParseServerMessage (void) |
| 721 | { |
| 722 | int cmd; |
| 723 | int i; |
| 724 | |
| 725 | // |
| 726 | // if recording demos, copy the message out |
| 727 | // |
| 728 | if (cl_shownet.value == 1) |
| 729 | Con_Printf ("%i ",net_message.cursize); |
| 730 | else if (cl_shownet.value == 2) |
| 731 | Con_Printf ("------------------\n"); |
| 732 | |
| 733 | cl.onground = false; // unless the server says otherwise |
| 734 | // |
| 735 | // parse the message |
| 736 | // |
| 737 | MSG_BeginReading (); |
| 738 | |
| 739 | while (1) |
| 740 | { |
| 741 | if (msg_badread) |
| 742 | Host_Error ("CL_ParseServerMessage: Bad server message"); |
| 743 | |
| 744 | cmd = MSG_ReadByte (); |
| 745 | |
| 746 | if (cmd == -1) |
| 747 | { |
| 748 | SHOWNET("END OF MESSAGE"); |
| 749 | return; // end of message |
| 750 | } |
| 751 | |
| 752 | // if the high bit of the command byte is set, it is a fast update |
| 753 | if (cmd & 128) |
| 754 | { |
| 755 | SHOWNET("fast update"); |
| 756 | CL_ParseUpdate (cmd&127); |
| 757 | continue; |
| 758 | } |
| 759 | |
| 760 | SHOWNET(svc_strings[cmd]); |
| 761 | |
| 762 | // other commands |
| 763 | switch (cmd) |
| 764 | { |
| 765 | default: |
| 766 | Host_Error ("CL_ParseServerMessage: Illegible server message\n"); |
| 767 | break; |
| 768 | |
| 769 | case svc_nop: |
| 770 | // Con_Printf ("svc_nop\n"); |
| 771 | break; |
| 772 | |
| 773 | case svc_time: |
| 774 | cl.mtime[1] = cl.mtime[0]; |
| 775 | cl.mtime[0] = MSG_ReadFloat (); |
| 776 | break; |
| 777 | |
| 778 | case svc_clientdata: |
| 779 | i = MSG_ReadShort (); |
| 780 | CL_ParseClientdata (i); |
| 781 | break; |
| 782 | |
| 783 | case svc_version: |
| 784 | i = MSG_ReadLong (); |
| 785 | if (i != PROTOCOL_VERSION) |
| 786 | Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); |
| 787 | break; |
| 788 | |
| 789 | case svc_disconnect: |
| 790 | Host_EndGame ("Server disconnected\n"); |
| 791 | |
| 792 | case svc_print: |
| 793 | Con_Printf ("%s", MSG_ReadString ()); |
| 794 | break; |
| 795 | |
| 796 | case svc_centerprint: |
| 797 | SCR_CenterPrint (MSG_ReadString ()); |
| 798 | break; |
| 799 | |
| 800 | case svc_stufftext: |
| 801 | Cbuf_AddText (MSG_ReadString ()); |
| 802 | break; |
| 803 | |
| 804 | case svc_damage: |
| 805 | V_ParseDamage (); |
| 806 | break; |
| 807 | |
| 808 | case svc_serverinfo: |
| 809 | CL_ParseServerInfo (); |
| 810 | vid.recalc_refdef = true; // leave intermission full screen |
| 811 | break; |
| 812 | |
| 813 | case svc_setangle: |
| 814 | for (i=0 ; i<3 ; i++) |
| 815 | cl.viewangles[i] = MSG_ReadAngle (); |
| 816 | break; |
| 817 | |
| 818 | case svc_setview: |
| 819 | cl.viewentity = MSG_ReadShort (); |
| 820 | break; |
| 821 | |
| 822 | case svc_lightstyle: |
| 823 | i = MSG_ReadByte (); |
| 824 | if (i >= MAX_LIGHTSTYLES) |
| 825 | Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); |
| 826 | Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); |
| 827 | cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); |
| 828 | break; |
| 829 | |
| 830 | case svc_sound: |
| 831 | CL_ParseStartSoundPacket(); |
| 832 | break; |
| 833 | |
| 834 | case svc_stopsound: |
| 835 | i = MSG_ReadShort(); |
| 836 | S_StopSound(i>>3, i&7); |
| 837 | break; |
| 838 | |
| 839 | case svc_updatename: |
| 840 | Sbar_Changed (); |
| 841 | i = MSG_ReadByte (); |
| 842 | if (i >= cl.maxclients) |
| 843 | Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); |
| 844 | strcpy (cl.scores[i].name, MSG_ReadString ()); |
| 845 | break; |
| 846 | |
| 847 | case svc_updatefrags: |
| 848 | Sbar_Changed (); |
| 849 | i = MSG_ReadByte (); |
| 850 | if (i >= cl.maxclients) |
| 851 | Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); |
| 852 | cl.scores[i].frags = MSG_ReadShort (); |
| 853 | break; |
| 854 | |
| 855 | case svc_updatecolors: |
| 856 | Sbar_Changed (); |
| 857 | i = MSG_ReadByte (); |
| 858 | if (i >= cl.maxclients) |
| 859 | Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); |
| 860 | cl.scores[i].colors = MSG_ReadByte (); |
| 861 | CL_NewTranslation (i); |
| 862 | break; |
| 863 | |
| 864 | case svc_particle: |
| 865 | R_ParseParticleEffect (); |
| 866 | break; |
| 867 | |
| 868 | case svc_spawnbaseline: |
| 869 | i = MSG_ReadShort (); |
| 870 | // must use CL_EntityNum() to force cl.num_entities up |
| 871 | CL_ParseBaseline (CL_EntityNum(i)); |
| 872 | break; |
| 873 | case svc_spawnstatic: |
| 874 | CL_ParseStatic (); |
| 875 | break; |
| 876 | case svc_temp_entity: |
| 877 | CL_ParseTEnt (); |
| 878 | break; |
| 879 | |
| 880 | case svc_setpause: |
| 881 | { |
| 882 | cl.paused = MSG_ReadByte (); |
| 883 | |
| 884 | if (cl.paused) |
| 885 | { |
| 886 | CDAudio_Pause (); |
Franklin Wei | 5d05b9d | 2018-02-11 15:34:30 -0500 | [diff] [blame] | 887 | } |
| 888 | else |
| 889 | { |
| 890 | CDAudio_Resume (); |
Franklin Wei | 5d05b9d | 2018-02-11 15:34:30 -0500 | [diff] [blame] | 891 | } |
| 892 | } |
| 893 | break; |
| 894 | |
| 895 | case svc_signonnum: |
| 896 | i = MSG_ReadByte (); |
| 897 | if (i <= cls.signon) |
| 898 | Host_Error ("Received signon %i when at %i", i, cls.signon); |
| 899 | cls.signon = i; |
| 900 | CL_SignonReply (); |
| 901 | break; |
| 902 | |
| 903 | case svc_killedmonster: |
| 904 | cl.stats[STAT_MONSTERS]++; |
| 905 | break; |
| 906 | |
| 907 | case svc_foundsecret: |
| 908 | cl.stats[STAT_SECRETS]++; |
| 909 | break; |
| 910 | |
| 911 | case svc_updatestat: |
| 912 | i = MSG_ReadByte (); |
| 913 | if (i < 0 || i >= MAX_CL_STATS) |
| 914 | Sys_Error ("svc_updatestat: %i is invalid", i); |
| 915 | cl.stats[i] = MSG_ReadLong ();; |
| 916 | break; |
| 917 | |
| 918 | case svc_spawnstaticsound: |
| 919 | CL_ParseStaticSound (); |
| 920 | break; |
| 921 | |
| 922 | case svc_cdtrack: |
| 923 | cl.cdtrack = MSG_ReadByte (); |
| 924 | cl.looptrack = MSG_ReadByte (); |
| 925 | if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) |
| 926 | CDAudio_Play ((byte)cls.forcetrack, true); |
| 927 | else |
| 928 | CDAudio_Play ((byte)cl.cdtrack, true); |
| 929 | break; |
| 930 | |
| 931 | case svc_intermission: |
| 932 | cl.intermission = 1; |
| 933 | cl.completed_time = cl.time; |
| 934 | vid.recalc_refdef = true; // go to full screen |
| 935 | break; |
| 936 | |
| 937 | case svc_finale: |
| 938 | cl.intermission = 2; |
| 939 | cl.completed_time = cl.time; |
| 940 | vid.recalc_refdef = true; // go to full screen |
| 941 | SCR_CenterPrint (MSG_ReadString ()); |
| 942 | break; |
| 943 | |
| 944 | case svc_cutscene: |
| 945 | cl.intermission = 3; |
| 946 | cl.completed_time = cl.time; |
| 947 | vid.recalc_refdef = true; // go to full screen |
| 948 | SCR_CenterPrint (MSG_ReadString ()); |
| 949 | break; |
| 950 | |
| 951 | case svc_sellscreen: |
| 952 | Cmd_ExecuteString ("help", src_command); |
| 953 | break; |
| 954 | } |
| 955 | } |
| 956 | } |
| 957 | |