/* Copyright (C) 1996-1997 Id Software, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // cl_parse.c -- parse a message received from the server #include "globaldef.h" extern int lightingavailable = 0; // leilei - point lighting, determines if our data is made available extern int lightingcantbeavailable = 0; void LoadPointLighting (char *entstring); char *svc_strings[] = { "svc_bad", "svc_nop", "svc_disconnect", "svc_updatestat", "svc_version", // [long] server version "svc_setview", // [short] entity number "svc_sound", // "svc_time", // [float] server time "svc_print", // [string] null terminated string "svc_stufftext", // [string] stuffed into client's console buffer // the string should be \n terminated "svc_setangle", // [vec3] set the view angle to this absolute value "svc_serverinfo", // [long] version // [string] signon string // [string]..[0]model cache [string]...[0]sounds cache // [string]..[0]item cache "svc_lightstyle", // [byte] [string] "svc_updatename", // [byte] [string] "svc_updatefrags", // [byte] [short] "svc_clientdata", // "svc_stopsound", // "svc_updatecolors", // [byte] [byte] "svc_particle", // [vec3] "svc_damage", // [byte] impact [byte] blood [vec3] from "svc_spawnstatic", "OBSOLETE svc_spawnbinary", "svc_spawnbaseline", "svc_temp_entity", // "svc_setpause", "svc_signonnum", "svc_centerprint", "svc_killedmonster", "svc_foundsecret", "svc_spawnstaticsound", "svc_intermission", "svc_finale", // [string] music [string] text "svc_cdtrack", // [byte] track [byte] looptrack "svc_sellscreen", "svc_cutscene", // 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes // added commata // leilei "svc 35", "svc 36", "svc 37", "svc 38", "svc 39", "svc 40", "svc 41", "svc 42", "svc 43", "svc 44", "svc 45", "svc 46", "svc 47", "svc 48", "svc 49", "svc 50", "svc 51", "svc 52", "svc 53", "svc 54", "svc 55", "svc 56", "svc 57", "svc 58", "svc 59", "svc 60", "svc 61", "svc 62", "svc 63", "svc 64", "svc 65", "svc 66", "svc 67", "svc 68", "svc 69", "svc 70", "svc 71", "svc 72", "svc 73", "svc 74", "svc 75", "svc 76", "svc 77", "svc 78", "svc 79", "svc 80", "svc_sound3", "svc 82", "svc 83", "svc 84", "svc 85", "svc 86", "svc 87", "svc 88", "svc 89", "svc 90", "svc 91", "svc 92", "svc 93", "svc 94", "svc 95", "svc 96", "svc 97", "svc 98", "svc 99", "svc 100", "svc 101", "svc 102", "svc 103", "svc 104", "svc 105", "svc 106", "svc 107", "svc 108", "svc 109", "svc 110", "svc 111", "svc 112", "svc 113", "svc 114", "svc 115", "svc 116", "svc 117", "svc 118", "svc 119", "svc 120", "svc 121", "svc 122", "svc 123", "svc 124", "svc 125", "svc_limit", // 2001-09-20 Configurable limits by Maddes // "svc_extra_version", // 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes // [float] SSVC [float] CSVC [float] CCLC }; //============================================================================= /* =============== CL_EntityNum This error checks and tracks the total number of entities =============== */ entity_t *CL_EntityNum (int num) { // 2001-09-20 Configurable entity limits by Maddes start if (!cl_entities) { Cvar_Set(cl_entities_min, cl_entities_min->string); // do rangecheck if (cl.max_edicts < cl_entities_min->value) { cl.max_edicts = cl_entities_min->value; } Con_DPrintf("Allocating memory for %i entities.\n", cl.max_edicts); cl_entities = Hunk_AllocName (cl.max_edicts*sizeof(entity_t), "cl_edicts"); memset (cl_entities, 0, cl.max_edicts*sizeof(entity_t)); cl_entities[0].model = cl.worldmodel; } // 2001-09-20 Configurable entity limits by Maddes end if (num >= cl.num_entities) { // 2001-09-20 Configurable entity limits by Maddes start // if (num >= MAX_EDICTS) if (num >= cl.max_edicts) // 2001-09-20 Configurable entity limits by Maddes end Host_Error ("CL_EntityNum: %i is an invalid number",num); while (cl.num_entities<=num) { cl_entities[cl.num_entities].colormap = vid.colormap; cl.num_entities++; } } return &cl_entities[num]; } /* ================== CL_ParseStartSoundPacket ================== */ void CL_ParseStartSoundPacket(void) { vec3_t pos; int channel, ent; int sound_num; int volume; int field_mask; float attenuation; int i; field_mask = MSG_ReadByte(); if (field_mask & SND_VOLUME) volume = MSG_ReadByte (); else volume = DEFAULT_SOUND_PACKET_VOLUME; if (field_mask & SND_ATTENUATION) attenuation = MSG_ReadByte () / 64.0; else attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; channel = MSG_ReadShort (); sound_num = MSG_ReadByte (); ent = channel >> 3; channel &= 7; // 2001-09-20 Configurable entity limits by Maddes start // if (ent > MAX_EDICTS) if (ent > cl.max_edicts) // 2001-09-20 Configurable entity limits by Maddes end Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent); for (i=0 ; i<3 ; i++) pos[i] = MSG_ReadCoord (); S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation); } /* ================== CL_ParseStartSoundPacket2 ================== */ void CL_ParseStartSoundPacket2(void) { vec3_t pos; int channel, ent; int sound_num; int volume; int field_mask; float attenuation; int pitch; int i; field_mask = MSG_ReadByte(); if (field_mask & SND_VOLUME) volume = MSG_ReadByte (); else volume = DEFAULT_SOUND_PACKET_VOLUME; if (field_mask & SND_ATTENUATION) attenuation = MSG_ReadByte () / 64.0; else attenuation = DEFAULT_SOUND_PACKET_ATTENUATION; channel = MSG_ReadShort (); sound_num = MSG_ReadByte (); ent = channel >> 3; channel &= 7; if (field_mask & SND_PITCH) pitch = MSG_ReadByte (); else pitch = 100; if (pitch < 1) pitch = 1; if (pitch > 255) pitch = 255; if (ent > cl.max_edicts) Host_Error ("CL_ParseStartSoundPacket2: ent = %i", ent); for (i=0 ; i<3 ; i++) pos[i] = MSG_ReadCoord (); S_StartSound2 (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation, pitch); } /* ================== CL_KeepaliveMessage When the client is taking a long time to load stuff, send keepalive messages so the server doesn't disconnect. ================== */ void CL_KeepaliveMessage (void) { float time; static float lastmsg; int ret; sizebuf_t old; byte olddata[8192]; if (sv.active) return; // no need if server is local if (cls.demoplayback) return; // read messages from server, should just be nops old = net_message; memcpy (olddata, net_message.data, net_message.cursize); do { ret = CL_GetMessage (); switch (ret) { default: Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed"); case 0: break; // nothing waiting case 1: Host_Error ("CL_KeepaliveMessage: received a message"); break; case 2: if (MSG_ReadByte() != svc_nop) Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop"); break; } } while (ret); net_message = old; memcpy (net_message.data, olddata, net_message.cursize); // check time time = Sys_FloatTime (); if (time - lastmsg < 5) return; lastmsg = time; // write out a nop Con_Printf ("--> client to server keepalive\n"); MSG_WriteByte (&cls.message, clc_nop); NET_SendMessage (cls.netcon, &cls.message); SZ_Clear (&cls.message); } // Tomaz - Qc Parsing & HL Maps Begin void CL_ParseEntityLump(char *entdata) { char *data; char key[128], value[4096]; char wadname[128]; int i, j, k; // skyname[0] = 0; data = entdata; if (!data) return; data = COM_Parse(data); if (!data) return; // valid exit if (com_token[0] != '{') return; // error while (1) { data = COM_Parse(data); if (!data) return; // error if (com_token[0] == '}') return; // since we're just parsing the first ent (worldspawn), exit strcpy(key, com_token); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; data = COM_Parse(data); if (!data) return; // error strcpy(value, com_token); // if (!strcmp("sky", key)) // R_SetSkyBox(value); // TODO FIXME LATER ADDME skyboxes from tochris // else if (!strcmp("skyname", key)) // R_SetSkyBox(value); if (!strcmp("wad", key)) // for HalfLife maps { j = 0; for (i = 0;i < 4096;i++) if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':') break; if (value[i]) { for (;i < 4096;i++) { // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'... if (value[i] == '\\' || value[i] == '/' || value[i] == ':') j = i+1; else if (value[i] == ';' || value[i] == 0) { k = value[i]; value[i] = 0; strcpy(wadname, "textures/"); strcat(wadname, &value[j]); W_LoadTextureWadFile (wadname, false); j = i+1; if (!k) break; } } } } } } // Tomaz - Qc Parsing & HL Maps End /* ================== CL_ParseServerInfo ================== */ void CL_ParseServerInfo (void) { char *str; int i; int nummodels, numsounds; char model_precache[MAX_MODELS][MAX_QPATH]; char sound_precache[MAX_SOUNDS][MAX_QPATH]; Con_DPrintf ("Serverinfo packet received.\n"); // // wipe the client_state_t struct // CL_ClearState (); #ifdef DPPROTOCOLS i = MSG_ReadLong (); if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250) { Con_Printf ("Server returned version %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION); return; } // Nehahrademcompatibility = false; // if (i == 250) // Nehahrademcompatibility = true; // if (cls.demoplayback && demo_nehahra.value) // Nehahrademcompatibility = true; dpprotocol = i == DPPROTOCOL_VERSION; #else // parse protocol version number i = MSG_ReadLong (); if (i != PROTOCOL_VERSION) { Con_Printf ("Server returned version %i, not %i\n", i, PROTOCOL_VERSION); // 2000-01-08 Missing linefeeds fix by Maddes return; } #endif // parse maxclients cl.maxclients = MSG_ReadByte (); if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD) { Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients); return; } cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); // parse gametype cl.gametype = MSG_ReadByte (); // parse signon message str = MSG_ReadString (); strncpy (cl.levelname, str, sizeof(cl.levelname)-1); // seperate the printfs so the server message can have a color 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"); Con_Printf ("%c%s\n", 2, str); // // first we go through and touch all of the precache data that still // happens to be in the cache, so precaching something else doesn't // needlessly purge it // // precache models memset (cl.model_precache, 0, sizeof(cl.model_precache)); for (nummodels=1 ; ; nummodels++) { str = MSG_ReadString (); if (!str[0]) break; if (nummodels==MAX_MODELS) { Con_Printf ("Server sent too many model precaches\n"); return; } strcpy (model_precache[nummodels], str); Mod_TouchModel (str); } // precache sounds memset (cl.sound_precache, 0, sizeof(cl.sound_precache)); for (numsounds=1 ; ; numsounds++) { str = MSG_ReadString (); if (!str[0]) break; if (numsounds==MAX_SOUNDS) { Con_Printf ("Server sent too many sound precaches\n"); return; } strcpy (sound_precache[numsounds], str); S_TouchSound (str); } // // now we try to load everything else until a cache allocation fails // for (i=1 ; ientities); // doesn't seem to work when called here } /* ================== CL_ParseUpdate Parse an entity update message from the server If an entities model or origin changes from frame to frame, it must be relinked. Other attributes can change without relinking. ================== */ //#ifndef SONOFABITS int bitcounts[16]; //#endif void CL_ParseUpdate (int bits) { int i; model_t *model; int modnum; qboolean forcelink; entity_t *ent; int num; #ifdef GLQUAKE // 2000-07-16 General variable definition for GLQuake-only variable fix int skin; #endif // 2000-07-16 General variable definition for GLQuake-only variable fix if (cls.signon == SIGNONS - 1) { // first update is the final signon stage cls.signon = SIGNONS; CL_SignonReply (); } if (bits & U_MOREBITS) { i = MSG_ReadByte (); bits |= (i<<8); } #ifdef SONOFABITS // Tomaz - QC Control Begin if (bits & U_EXTEND1) { bits |= MSG_ReadByte() << 16; if (bits & U_EXTEND2) bits |= MSG_ReadByte() << 24; } #endif // Tomaz - QC Control End if (bits & U_LONGENTITY) num = MSG_ReadShort (); else num = MSG_ReadByte (); ent = CL_EntityNum (num); //#ifndef SONOFABITS for (i=0 ; i<16 ; i++) if (bits&(1<msgtime != cl.mtime[1]) forcelink = true; // no previous frame to lerp from else forcelink = false; ent->msgtime = cl.mtime[0]; if (bits & U_MODEL) { modnum = MSG_ReadByte (); if (modnum >= MAX_MODELS) Host_Error ("CL_ParseModel: bad modnum"); } else modnum = ent->baseline.modelindex; model = cl.model_precache[modnum]; if (model != ent->model) { #ifdef MHINTERPOL // if the model has changed we must also reset the interpolation data // pose1 and pose2 are critical as they might be pointing to invalid frames in the new model!!! ent->frame_start_time = 0; //ent->frame_interval = 0; ent->lastpose = ent->currpose = 0; //ent->translate_start_time = 0; //ent->origin1[0] = ent->origin1[1] = ent->origin1[2] = 0; //ent->origin2[0] = ent->origin2[1] = ent->origin2[2] = 0; //ent->rotate_start_time = 0; //ent->angles1[0] = ent->angles1[1] = ent->angles1[2] = 0; //ent->angles2[0] = ent->angles2[1] = ent->angles2[2] = 0; #endif ent->model = model; // automatic animation (torches, etc) can be either all together // or randomized if (model) { if (model->synctype == ST_RAND) ent->syncbase = (float)(rand()&0x7fff) / 0x7fff; else ent->syncbase = 0.0; } else forcelink = true; // hack to make null model players work #ifdef GLQUAKE if (num > 0 && num <= cl.maxclients) R_TranslatePlayerSkin (num - 1); #endif } if (bits & U_FRAME) ent->frame = MSG_ReadByte (); else ent->frame = ent->baseline.frame; if (bits & U_COLORMAP) i = MSG_ReadByte(); else i = ent->baseline.colormap; if (!i) ent->colormap = vid.colormap; else { if (i > cl.maxclients) // 2001-12-16 Various crashes changed to host errors by Maddes start // Sys_Error ("i >= cl.maxclients"); { Host_Error ("CL_ParseUpdate: i > cl.maxclients: %i > %i", i, cl.maxclients); return; } // 2001-12-16 Various crashes changed to host errors by Maddes end ent->colormap = cl.scores[i-1].translations; } #ifdef GLQUAKE if (bits & U_SKIN) skin = MSG_ReadByte(); else skin = ent->baseline.skin; if (skin != ent->skinnum) { ent->skinnum = skin; if (num > 0 && num <= cl.maxclients) R_TranslatePlayerSkin (num - 1); } #else if (bits & U_SKIN) ent->skinnum = MSG_ReadByte(); else ent->skinnum = ent->baseline.skin; #endif if (bits & U_EFFECTS) ent->effects = (ent->effects & 0xFF00) | MSG_ReadByte(); // if (bits & U_EFFECTS) // ent->effects = MSG_ReadByte(); else ent->effects = ent->baseline.effects; // shift the known values for interpolation VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); if (bits & U_ORIGIN1) ent->msg_origins[0][0] = MSG_ReadCoord (); else ent->msg_origins[0][0] = ent->baseline.origin[0]; if (bits & U_ANGLE1) ent->msg_angles[0][0] = MSG_ReadAngle(); else ent->msg_angles[0][0] = ent->baseline.angles[0]; if (bits & U_ORIGIN2) ent->msg_origins[0][1] = MSG_ReadCoord (); else ent->msg_origins[0][1] = ent->baseline.origin[1]; if (bits & U_ANGLE2) ent->msg_angles[0][1] = MSG_ReadAngle(); else ent->msg_angles[0][1] = ent->baseline.angles[1]; if (bits & U_ORIGIN3) ent->msg_origins[0][2] = MSG_ReadCoord (); else ent->msg_origins[0][2] = ent->baseline.origin[2]; if (bits & U_ANGLE3) ent->msg_angles[0][2] = MSG_ReadAngle(); else ent->msg_angles[0][2] = ent->baseline.angles[2]; #ifdef SCALEE ent->scale2 = 1.0f; #endif #ifdef ALPHASCALE if(dpprotocol){ if (bits & U_ALPHA) ent->alpha = MSG_ReadFloat (); // else // ent->alpha = 1.0f; #ifdef SCALEE if (bits & U_SCALE) ent->scale2 = MSG_ReadFloat(); else ent->scale2 = 1.0f; #endif if (bits & U_GLOWCOLOR) ent->glowcolor = MSG_ReadFloat (); else ent->glowcolor = 0; if (bits & U_GLOWSIZE) ent->glowsize = MSG_ReadFloat (); else ent->glowsize = 0; } #endif if ( bits & U_NOLERP ) ent->forcelink = true; #ifdef VMTOC if ( bits & U_VIEWMODEL ) ent->viewmodel = true; #endif if ( forcelink ) { // didn't have an update last message VectorCopy (ent->msg_origins[0], ent->msg_origins[1]); VectorCopy (ent->msg_origins[0], ent->origin); VectorCopy (ent->msg_angles[0], ent->msg_angles[1]); VectorCopy (ent->msg_angles[0], ent->angles); ent->forcelink = true; } } /* ================== CL_ParseBaseline ================== */ void CL_ParseBaseline (entity_t *ent) { int i; ent->baseline.modelindex = MSG_ReadByte (); ent->baseline.frame = MSG_ReadByte (); ent->baseline.colormap = MSG_ReadByte(); ent->baseline.skin = MSG_ReadByte(); for (i=0 ; i<3 ; i++) { ent->baseline.origin[i] = MSG_ReadCoord (); ent->baseline.angles[i] = MSG_ReadAngle (); } } /* ================== CL_ParseClientdata Server information pertaining to this client only ================== */ extern int skipbob; void CL_ParseClientdata (int bits) { int i, j; if (bits & SU_VIEWHEIGHT) cl.viewheight = MSG_ReadChar (); else cl.viewheight = DEFAULT_VIEWHEIGHT; if (bits & SU_IDEALPITCH) cl.idealpitch = MSG_ReadChar (); else cl.idealpitch = 0; VectorCopy (cl.mvelocity[0], cl.mvelocity[1]); // leilei - unrolled /* for (i=0 ; i<3 ; i++) { if (bits & (SU_PUNCH1< cl.maxclients) // 2001-12-16 Various crashes changed to host errors by Maddes start // Sys_Error ("CL_NewTranslation: slot > cl.maxclients"); { Host_Error ("CL_NewTranslation: slot > cl.maxclients: %i > %i", slot, cl.maxclients); return; } // 2001-12-16 Various crashes changed to host errors by Maddes end dest = cl.scores[slot].translations; source = vid.colormap; memcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations)); top = cl.scores[slot].colors & 0xf0; bottom = (cl.scores[slot].colors &15)<<4; #ifdef GLQUAKE R_TranslatePlayerSkin (slot); #endif for (i=0 ; istring); // do rangecheck if (cl.max_static_edicts < cl_entities_min_static->value) { cl.max_static_edicts = cl_entities_min_static->value; } Con_DPrintf("Allocating memory for %i static entities.\n", cl.max_static_edicts); cl_static_entities = Hunk_AllocName (cl.max_static_edicts*sizeof(entity_t), "cl_ed_static"); memset (cl_static_entities, 0, cl.max_static_edicts*sizeof(entity_t)); } // 2001-09-20 Configurable entity limits by Maddes end i = cl.num_statics; // 2001-09-20 Configurable entity limits by Maddes start // if (i >= MAX_STATIC_ENTITIES) // Host_Error ("Too many static entities"); if (i >= cl.max_static_edicts) Host_Error ("Too many static entities, max is %i", cl.max_static_edicts); // 2001-09-20 Configurable entity limits by Maddes end ent = &cl_static_entities[i]; cl.num_statics++; CL_ParseBaseline (ent); // copy it to the current state ent->model = cl.model_precache[ent->baseline.modelindex]; ent->frame = ent->baseline.frame; ent->colormap = vid.colormap; ent->skinnum = ent->baseline.skin; ent->effects = ent->baseline.effects; //ent->model->dontshadow = 1; // leilei - shadowhack - prevent torches from shadowing // FIXME: Crashes After The Fall! #ifdef ALPHASCALE // Why did Makaqu need this? // Not like anyone will ever alpha their static entities anyway // This stuff breaks demo playback for some reason // But right now this is not important, we do not need it if(dpprotocol) { int bits; bits = MSG_ReadLong(); if (bits & U_ALPHA) ent->alpha = MSG_ReadFloat (); // else // ent->alpha = 0; #ifdef SCALEE if (bits & U_SCALE) ent->scale2 = MSG_ReadFloat (); #endif if (bits & U_GLOWSIZE) ent->glowsize = MSG_ReadFloat (); else ent->glowsize = 0; if (bits & U_GLOWCOLOR) ent->glowcolor = MSG_ReadFloat (); else ent->glowcolor = 0; ent->effects = MSG_ReadShort(); // ent->glowsize = 0; // ent->glowcolor = 0; // ent->alpha = 1.0f; #ifdef SCALEE ent->scale2 = 1.0f; #endif } #endif VectorCopy (ent->baseline.origin, ent->origin); VectorCopy (ent->baseline.angles, ent->angles); R_AddEfrags (ent); } /* =================== CL_ParseStaticSound =================== */ void CL_ParseStaticSound (void) { vec3_t org; int sound_num, vol, atten; int i; org[0] = MSG_ReadCoord (); org[1] = MSG_ReadCoord (); org[2] = MSG_ReadCoord (); sound_num = MSG_ReadByte (); vol = MSG_ReadByte (); atten = MSG_ReadByte (); S_StaticSound (cl.sound_precache[sound_num], org, vol, atten); } // 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes start /* ================= CL_ParseVersion ================= */ void CL_ParseVersion (void) { int type; float f; type = MSG_ReadByte (); switch (type) { case VERSION_NVS: // read SSVC version f = MSG_ReadFloat (); if (!sv.active) // not necessary on listen server { nvs_current_ssvc->rangecheck = NULL; //deactivate, as server can run with a much higher version Cvar_SetValue (nvs_current_ssvc, f); nvs_current_ssvc->rangecheck = Cvar_RangecheckFloat; //reactivate } // read CSVC version f = MSG_ReadFloat (); Cvar_SetValue (nvs_current_csvc, f); // read CCLC version f = MSG_ReadFloat (); Cvar_SetValue (nvs_current_cclc, f); break; default: Host_Error ("CL_ParseVersion: bad type %i", type); break; } } // 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes end // 2001-09-20 Configurable limits by Maddes start /* ================= CL_ParseLimit ================= */ void CL_ParseLimit (void) { int type; type = MSG_ReadByte (); switch (type) { // 2001-09-20 Configurable entity limits by Maddes start case LIM_ENTITIES: cl.max_edicts = MSG_ReadShort (); cl.max_static_edicts = MSG_ReadShort (); cl.max_temp_edicts = MSG_ReadShort (); Con_DPrintf("Server runs with %i normal, %i static and %i temp edicts.\n", cl.max_edicts, cl.max_static_edicts, cl.max_temp_edicts); // check values: only the normal entities are send with their index number, the others are send without indexes if (cl.max_edicts > MAX_EDICTS) { Host_Error ("CL_ParseLimit: %i entities can not be handled, max is %i", cl.max_edicts, MAX_EDICTS); } break; // 2001-09-20 Configurable entity limits by Maddes end default: Host_Error ("CL_ParseLimit: bad type %i", type); break; } } // 2001-09-20 Configurable limits by Maddes end #define SHOWNET(x) if(cl_shownet->value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x); int whatamiplaying; void MIDIHIJACK(int i, qboolean loop) { // no allegro, no midi. // or is it? #ifdef ASS_MIDI char trackname[512]; loadedfile_t *fileinfo; // Load our MIDI file into memory sprintf(trackname, "sound/cdtracks/track%03i.mid", i); fileinfo = COM_LoadHunkFile(trackname); if (!fileinfo){ Con_SafePrintf ("Can't load MIDI file %s\n", trackname); MUSIC_StopSong(); // stop the dam music whatamiplaying = 666; return;} whatamiplaying = i; MUSIC_PlaySong( fileinfo->data, 1 ); Con_DPrintf ("MIDI system - %s\n", MUSIC_ErrorString( MUSIC_Error ) ); #endif } void Host_Autosavegame_f(void); extern cvar_t *autosaver; /* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i; // // if recording demos, copy the message out // if (cl_shownet->value == 1) Con_Printf ("%i ",net_message.cursize); else if (cl_shownet->value == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { SHOWNET("fast update"); CL_ParseUpdate (cmd&127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("CL_ParseServerMessage: Illegible server message"); break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: i = MSG_ReadShort (); CL_ParseClientdata (i); break; case svc_version: i = MSG_ReadLong (); #ifdef DPPROTOCOLS if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250) Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION); // Nehahrademcompatibility = false; // if (i == 250) // Nehahrademcompatibility = true; // if (cls.demoplayback && demo_nehahra.value) // Nehahrademcompatibility = true; dpprotocol = i == DPPROTOCOL_VERSION; #else if (i != PROTOCOL_VERSION) Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i", i, PROTOCOL_VERSION); #endif break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); case svc_print: Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: SCR_CenterPrint (MSG_ReadString ()); break; case svc_stufftext: Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: // 2000-05-02 NVS SVC_setangle by Maddes start if ((nvs_current_csvc->value >= 0.50) && (cls.signon > 1)) { for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadFloat (); } else { // 2000-05-02 NVS SVC_setangle by Maddes end for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); } // 2000-05-02 NVS SVC_setangle by Maddes break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) // 2001-12-16 Various crashes changed to host errors by Maddes start // Sys_Error ("svc_lightstyle >= MAX_LIGHTSTYLES"); { Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES: %i >= %i", i, MAX_LIGHTSTYLES); break; } // 2001-12-16 Various crashes changed to host errors by Maddes end strcpy (cl_lightstyle[i].map, MSG_ReadString()); cl_lightstyle[i].length = strlen(cl_lightstyle[i].map); break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); strcpy (cl.scores[i].name, MSG_ReadString ()); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); cl.scores[i].frags = MSG_ReadShort (); break; case svc_updatecolors: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i)); break; case svc_spawnstatic: CL_ParseStatic (); break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: { cl.paused = MSG_ReadByte (); if (cl.paused) { Music_Pause(); #ifdef _WIN32 VID_HandlePause (true); #endif } else { Music_Resume(); #ifdef _WIN32 VID_HandlePause (false); #endif } } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; if (autosaver->value){ if (cl.stats[STAT_MONSTERS] > (cl.stats[STAT_TOTALMONSTERS] * 0.5) && !autosaved_monsthalfkilled){ autosaved_monsthalfkilled = 155; Host_Autosavegame_f(); } } break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) // 2001-12-16 Various crashes changed to host errors by Maddes start // Sys_Error ("svc_updatestat: %i is invalid", i); { Host_Error ("svc_updatestat: %i is invalid (0-%i)", i, MAX_CL_STATS); break; } // 2001-12-16 Various crashes changed to host errors by Maddes end cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (); break; #ifdef ASS_MIDI case svc_cdtrack: // todo: cvar this check cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); //if (whatamiplaying != cl.cdtrack) if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) MIDIHIJACK ((byte)cls.forcetrack, true); else MIDIHIJACK ((byte)cl.cdtrack, true); break; #else case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) Music_Play ((byte)cls.forcetrack, true); else Music_Play ((byte)cl.cdtrack, true); break; #endif case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_sound3: CL_ParseStartSoundPacket2(); break; case svc_sellscreen: Cmd_ExecuteString ("help", src_command); break; // 2001-09-20 Configurable limits by Maddes start case svc_limit: CL_ParseLimit(); break; // 2001-09-20 Configurable limits by Maddes end // 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes start case svc_extra_version: CL_ParseVersion(); break; // 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes end } } } /* ============= A crapload of FTEQW lies below for one purpose - getting lights to reflect ============= */ typedef char pbool; typedef struct mentity_s { vec3_t origin; float light; float angle; float cone; int style; vec3_t colour; char classname[64]; char target[64]; char targetname[64]; struct mentity_s *targetent; struct entity_s lighty; // leilei - lightstyles hack } mentity_t; static mentity_t entities[8192]; static int num_entities; static void ParseEpair (mentity_t *mapent, char *key, char *value) { double vec[3]; if (!strcmp(key, "classname")) strcpy(mapent->classname, value); else if (!strcmp(key, "target")) strcpy(mapent->target, value); else if (!strcmp(key, "targetname")) strcpy(mapent->targetname, value); else if (!strcmp(key, "light") || !strcmp(key, "_light") || !strcmp(key, "light_lev")) mapent->light = atoi(value); else if (!strcmp(key, "style") || !strcmp(key, "_style")) mapent->style = atoi(value); else if (!strcmp(key, "angle") || !strcmp(key, "_angle")) mapent->angle = atof(value); else if (!strcmp(key, "cone") || !strcmp(key, "_cone")) mapent->cone = atof(value); else if (!strcmp(key, "origin")) { sscanf (value, "%lf %lf %lf", &vec[0], &vec[1], &vec[2]); mapent->origin[0]=vec[0]; mapent->origin[1]=vec[1]; mapent->origin[2]=vec[2]; } else if (!strcmp(key, "colour") || !strcmp(key, "color") || !strcmp(key, "_colour") || !strcmp(key, "_color")) { sscanf (value, "%lf %lf %lf", &vec[0], &vec[1], &vec[2]); mapent->colour[0]=vec[0]; mapent->colour[1]=vec[1]; mapent->colour[2]=vec[2]; } } extern vec3_t lightcolor; extern cvar_t *temp2; // A botched up FTEQW version just to load realtime point lights for r_shading 3 void LoadPointLighting (char *entstring) { mentity_t *mapent; char key[1024]; int i; int switchedstyle=32; int num_entities = 0; int num_lights = 0; while(1) { entstring = COM_Parse(entstring); if (!entstring || !*com_token) break; if (strcmp(com_token, "{")) { //someone messed up. Stop parsing. Con_Printf("token wasn't an open brace\n"); break; } mapent = &entities[num_entities]; memset(mapent, 0, sizeof(*mapent)); mapent->colour[0] = 1; mapent->colour[1] = 1; mapent->colour[2] = 1; while(1) { entstring = COM_Parse(entstring); if (!strcmp(com_token, "}")) break; strcpy(key, com_token); entstring = COM_Parse(entstring); ParseEpair(mapent, key, com_token); } if (!mapent->light && !strncmp (mapent->classname, "light", 5)) mapent->light = 300; if (*mapent->targetname && !mapent->style && !strcmp(mapent->classname, "light")) { for (i = 0; i <= num_entities; i++) { if (entities[i].style >= 32 && !strcmp(entities[i].targetname, mapent->targetname)) { mapent->style = entities[i].style; break; } } if (i == num_entities) mapent->style = switchedstyle++; } if (mapent->light > 1){ // leilei - try to sample color from the spot if we're in colored lighting mode // for getting lights from lit colored maps that assume colors, like mhcolour if (coloredlights){ R_LightPoint(mapent->origin); mapent->colour[0] = lightcolor[0] / 252; mapent->colour[1] = lightcolor[1] / 252; mapent->colour[2] = lightcolor[2] / 252; // VectorScale(lightcolor, 0.003921568627451, mapent->colour); // VectorScale(lightcolor, 0.014, mapent->colour); // mapent->colour[0] = 0; // mapent->colour[1] = 0; // mapent->colour[2] = 5; //Con_Printf("%f %f %f to %f %f %f\n", lightcolor[0], lightcolor[1], lightcolor[2], mapent->colour[0], mapent->colour[1], mapent->colour[2]); } // Con_Printf("yep %f %f %f %f\n", mapent->origin[0], mapent->origin[1], mapent->origin[2], mapent->light); R_LightsHere(mapent->origin, (int)mapent->light, mapent->colour, num_entities, mapent); // leilei - flare up torches, flames and other carp { vec3_t offsetup; VectorCopy(mapent->origin, offsetup); if (!strncmp(mapent->classname, "light_torch", 11)) { offsetup[2] += 6; R_FlareTest(offsetup,12,32,16,6,0, NULL); } if (!strncmp(mapent->classname, "light_flame_large_yellow", 24)) { offsetup[2] += 3; R_FlareTest(offsetup,12,72,36,6,0, NULL); offsetup[2] += 3; R_FlareTest(offsetup,12,72,36,6,0, NULL); offsetup[2] += 3; R_FlareTest(offsetup,12,32,16,6,0, NULL); offsetup[2] += 3; R_FlareTest(offsetup,12,32,16,6,0, NULL); offsetup[2] += 3; R_FlareTest(offsetup,12,32,16,6,0, NULL); offsetup[2] += 3; R_FlareTest(offsetup,12,32,16,6,0, NULL); } if (!strncmp(mapent->classname, "light_flame_small_yellow", 24)) { offsetup[2] += 1; R_FlareTest(offsetup,12,155,112,22,0, NULL); } if (!strncmp(mapent->classname, "light_flame_small_white", 23)) { offsetup[2] += 1; R_FlareTest(offsetup,12,166,133,100,0, NULL); } if (!strncmp(mapent->classname, "light_globe", 11)) { R_FlareTest(offsetup,12,166,133,46,0, NULL); } } num_lights++; } num_entities++; } for (mapent = entities; mapent < &entities[num_entities]; mapent++) { if (*mapent->target) { for (i = 0; i < num_entities; i++) { if (mapent == &entities[i]) continue; if (!strcmp(mapent->target, entities[i].targetname)) { mapent->targetent = &entities[i]; break; } } } } if (num_lights > 58){ lightingavailable = 1; lightingcantbeavailable = 0; } else { lightingavailable = 0; lightingcantbeavailable = 1; } }