static void Mod_Sprite_SharedSetup(const unsigned char *datapointer, int version, const unsigned int *palette, qboolean additive) { int i, j, groupframes, realframes, x, y, origin[2], width, height; qboolean fullbright; dspriteframetype_t *pinframetype; dspriteframe_t *pinframe; dspritegroup_t *pingroup; dspriteinterval_t *pinintervals; skinframe_t *skinframe; float modelradius, interval; char name[MAX_QPATH], fogname[MAX_QPATH]; const void *startframes; int texflags = (r_mipsprites.integer ? TEXF_MIPMAP : 0) | TEXF_ISSPRITE | TEXF_PICMIP | TEXF_ALPHA | TEXF_CLAMP; modelradius = 0; if (loadmodel->numframes < 1) Host_Error ("Mod_Sprite_SharedSetup: Invalid # of frames: %d", loadmodel->numframes); // LordHavoc: hack to allow sprites to be non-fullbright fullbright = true; for (i = 0;i < MAX_QPATH && loadmodel->name[i];i++) if (loadmodel->name[i] == '!') fullbright = false; // // load the frames // startframes = datapointer; realframes = 0; for (i = 0;i < loadmodel->numframes;i++) { pinframetype = (dspriteframetype_t *)datapointer; datapointer += sizeof(dspriteframetype_t); if (LittleLong (pinframetype->type) == SPR_SINGLE) groupframes = 1; else { pingroup = (dspritegroup_t *)datapointer; datapointer += sizeof(dspritegroup_t); groupframes = LittleLong(pingroup->numframes); datapointer += sizeof(dspriteinterval_t) * groupframes; } for (j = 0;j < groupframes;j++) { pinframe = (dspriteframe_t *)datapointer; if (version == SPRITE32_VERSION) datapointer += sizeof(dspriteframe_t) + LittleLong(pinframe->width) * LittleLong(pinframe->height) * 4; else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION) datapointer += sizeof(dspriteframe_t) + LittleLong(pinframe->width) * LittleLong(pinframe->height); } realframes += groupframes; } loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); loadmodel->sprite.sprdata_frames = (mspriteframe_t *)Mem_Alloc(loadmodel->mempool, sizeof(mspriteframe_t) * realframes); loadmodel->num_textures = realframes; loadmodel->num_texturesperskin = 1; loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, sizeof(texture_t) * loadmodel->num_textures); datapointer = (unsigned char *)startframes; realframes = 0; for (i = 0;i < loadmodel->numframes;i++) { pinframetype = (dspriteframetype_t *)datapointer; datapointer += sizeof(dspriteframetype_t); if (LittleLong (pinframetype->type) == SPR_SINGLE) { groupframes = 1; interval = 0.1f; } else { pingroup = (dspritegroup_t *)datapointer; datapointer += sizeof(dspritegroup_t); groupframes = LittleLong(pingroup->numframes); pinintervals = (dspriteinterval_t *)datapointer; datapointer += sizeof(dspriteinterval_t) * groupframes; interval = LittleFloat(pinintervals[0].interval); if (interval < 0.01f) Host_Error("Mod_Sprite_SharedSetup: invalid interval"); } dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "frame %i", i); loadmodel->animscenes[i].firstframe = realframes; loadmodel->animscenes[i].framecount = groupframes; loadmodel->animscenes[i].framerate = 1.0f / interval; loadmodel->animscenes[i].loop = true; for (j = 0;j < groupframes;j++) { pinframe = (dspriteframe_t *)datapointer; datapointer += sizeof(dspriteframe_t); origin[0] = LittleLong (pinframe->origin[0]); origin[1] = LittleLong (pinframe->origin[1]); width = LittleLong (pinframe->width); height = LittleLong (pinframe->height); loadmodel->sprite.sprdata_frames[realframes].left = origin[0]; loadmodel->sprite.sprdata_frames[realframes].right = origin[0] + width; loadmodel->sprite.sprdata_frames[realframes].up = origin[1]; loadmodel->sprite.sprdata_frames[realframes].down = origin[1] - height; x = (int)max(loadmodel->sprite.sprdata_frames[realframes].left * loadmodel->sprite.sprdata_frames[realframes].left, loadmodel->sprite.sprdata_frames[realframes].right * loadmodel->sprite.sprdata_frames[realframes].right); y = (int)max(loadmodel->sprite.sprdata_frames[realframes].up * loadmodel->sprite.sprdata_frames[realframes].up, loadmodel->sprite.sprdata_frames[realframes].down * loadmodel->sprite.sprdata_frames[realframes].down); if (modelradius < x + y) modelradius = x + y; if (cls.state != ca_dedicated) { skinframe = NULL; // note: Nehahra's null.spr has width == 0 and height == 0 if (width > 0 && height > 0) { if (groupframes > 1) { dpsnprintf (name, sizeof(name), "%s_%i_%i", loadmodel->name, i, j); dpsnprintf (fogname, sizeof(fogname), "%s_%i_%ifog", loadmodel->name, i, j); } else { dpsnprintf (name, sizeof(name), "%s_%i", loadmodel->name, i); dpsnprintf (fogname, sizeof(fogname), "%s_%ifog", loadmodel->name, i); } if (!(skinframe = R_SkinFrame_LoadExternal(name, texflags | TEXF_COMPRESS, false))) { unsigned char *pixels = (unsigned char *) Mem_Alloc(loadmodel->mempool, width*height*4); if (version == SPRITE32_VERSION) { for (x = 0;x < width*height;x++) { pixels[x*4+2] = datapointer[x*4+0]; pixels[x*4+1] = datapointer[x*4+1]; pixels[x*4+0] = datapointer[x*4+2]; pixels[x*4+3] = datapointer[x*4+3]; } } else //if (version == SPRITEHL_VERSION || version == SPRITE_VERSION) Image_Copy8bitBGRA(datapointer, pixels, width*height, palette ? palette : palette_bgra_transparent); skinframe = R_SkinFrame_LoadInternalBGRA(name, texflags, pixels, width, height); Mem_Free(pixels); } } if (skinframe == NULL) skinframe = R_SkinFrame_LoadMissing(); Mod_SpriteSetupTexture(&loadmodel->data_textures[realframes], skinframe, fullbright, additive); } if (version == SPRITE32_VERSION) datapointer += width * height * 4; else //if (version == SPRITE_VERSION || version == SPRITEHL_VERSION) datapointer += width * height; realframes++; } } modelradius = sqrt(modelradius); for (i = 0;i < 3;i++) { loadmodel->normalmins[i] = loadmodel->yawmins[i] = loadmodel->rotatedmins[i] = -modelradius; loadmodel->normalmaxs[i] = loadmodel->yawmaxs[i] = loadmodel->rotatedmaxs[i] = modelradius; } loadmodel->radius = modelradius; loadmodel->radius2 = modelradius * modelradius; }
/* =============== PR_LoadProgs =============== */ void PR_LoadProgs (void) { int i; char num[32]; static int lumpsize[6] = { sizeof(dstatement_t), sizeof(ddef_t), sizeof(ddef_t), sizeof(dfunction_t), 4, 4 }; int filesize = 0; const char *progsname; progs = NULL; // decide whether to load qwprogs.dat, progs.dat or spprogs.dat #ifdef WITH_NQPROGS if (Cvar_Value("sv_forcenqprogs")) goto use_progs; #endif if (!deathmatch.value) { if (Q_stricmp(com_gamedirfile, "qw") && strcmp(com_gamedirfile, "")) { // if we're using a custom mod, anything // in gamedir is preferred to stock *progs.dat qbool check; check = FS_FindFile ("spprogs.dat"); if (check && file_from_gamedir) goto use_spprogs; #ifdef WITH_NQPROGS check = FS_FindFile ("progs.dat"); if (check && file_from_gamedir) goto use_progs; #endif check = FS_FindFile ("qwprogs.dat"); if (check && file_from_gamedir) goto use_qwprogs; } use_spprogs: progs = (dprograms_t *) FS_LoadHunkFile ("spprogs.dat"); progsname = "spprogs.dat"; pr_nqprogs = false; if (!progs) { #ifdef WITH_NQPROGS use_progs: progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat"); progsname = "progs.dat"; pr_nqprogs = true; } #endif if (!progs) { use_qwprogs: progs = (dprograms_t *)FS_LoadHunkFile ("qwprogs.dat"); progsname = "qwprogs.dat"; pr_nqprogs = false; } } else // deathmatch { if (Q_stricmp(com_gamedirfile, "qw") && strcmp(com_gamedirfile, "")) { qbool check; check = FS_FindFile ("qwprogs.dat"); if (check && file_from_gamedir) goto dm_use_qwprogs; #ifdef WITH_NQPROGS check = FS_FindFile ("progs.dat"); if (check && file_from_gamedir) goto dm_use_progs; #endif } dm_use_qwprogs: progs = (dprograms_t *) FS_LoadHunkFile ("qwprogs.dat"); progsname = "qwprogs.dat"; pr_nqprogs = false; if (!progs) { #ifdef WITH_NQPROGS dm_use_progs: progs = (dprograms_t *)FS_LoadHunkFile ("progs.dat"); progsname = "progs.dat"; pr_nqprogs = true; } #endif } if (!progs) Host_Error ("PR_LoadProgs: couldn't load progs.dat"); filesize = fs_filesize; if (filesize < (int)sizeof(*progs)) Host_Error("%s is corrupt", progsname); Com_DPrintf ("Using %s (%i bytes).\n", progsname, filesize); // add prog crc to the serverinfo sprintf (num, "%i", CRC_Block ((byte *)progs, filesize)); svs.info.set("*progs", num); // byte swap the header for (i = 0; i < sizeof(*progs)/4; i++) ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] ); if (progs->version != PROG_VERSION) Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); if (progs->crc != (pr_nqprogs ? NQ_PROGHEADER_CRC : PROGHEADER_CRC)) Host_Error ("You must have the qwprogs.dat from QuakeWorld installed"); // check lump offsets and sizes for (i = 0; i < 6; i ++) { if (((int *)progs)[i*2 + 2] < sizeof(*progs) || ((int *)progs)[i*2 + 2] + ((int *)progs)[i*2 + 3]*lumpsize[i] > filesize) Host_Error("progs.dat is corrupt"); } pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_strings = (char *)progs + progs->ofs_strings; pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); pr_globals = (float *)pr_global_struct; PR_InitStrings (); pr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t); // byte swap the lumps for (i=0 ; i<progs->numstatements ; i++) { pr_statements[i].op = LittleShort(pr_statements[i].op); pr_statements[i].a = LittleShort(pr_statements[i].a); pr_statements[i].b = LittleShort(pr_statements[i].b); pr_statements[i].c = LittleShort(pr_statements[i].c); } for (i=0 ; i<progs->numfunctions; i++) { pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); pr_functions[i].locals = LittleLong (pr_functions[i].locals); } for (i=0 ; i<progs->numglobaldefs ; i++) { pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); } for (i=0 ; i<progs->numfielddefs ; i++) { pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); } for (i=0 ; i<progs->numglobals ; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); #ifdef WITH_NQPROGS if (pr_nqprogs) { memcpy (pr_globaloffsetpatch, pr_globaloffsetpatch_nq, sizeof(pr_globaloffsetpatch)); for (i = 0; i < 106; i++) { pr_fieldoffsetpatch[i] = (i < 8) ? i : (i < 25) ? i + 1 : (i < 28) ? i + (102 - 25) : (i < 73) ? i - 2 : (i < 74) ? i + (105 - 73) : (i < 105) ? i - 3 : /* (i == 105) */ 8; } for (i=0 ; i<progs->numfielddefs ; i++) pr_fielddefs[i].ofs = PR_FIELDOFS(pr_fielddefs[i].ofs); } else { memset (pr_globaloffsetpatch, 0, sizeof(pr_globaloffsetpatch)); for (i = 0; i < 106; i++) pr_fieldoffsetpatch[i] = i; } #endif // find optional QC-exported functions SpectatorConnect = ED_FindFunctionOffset ("SpectatorConnect"); SpectatorThink = ED_FindFunctionOffset ("SpectatorThink"); SpectatorDisconnect = ED_FindFunctionOffset ("SpectatorDisconnect"); GE_ClientCommand = ED_FindFunctionOffset ("GE_ClientCommand"); GE_ConsoleCommand = ED_FindFunctionOffset ("GE_ConsoleCommand"); GE_PausedTic = ED_FindFunctionOffset ("GE_PausedTic"); GE_ShouldPause = ED_FindFunctionOffset ("GE_ShouldPause"); // find optional QC-exported fields fofs_maxspeed = ED_FindFieldOffset ("maxspeed"); fofs_gravity = ED_FindFieldOffset ("gravity"); fofs_items2 = ED_FindFieldOffset ("items2"); fofs_movement = ED_FindFieldOffset ("movement"); fofs_vw_index = ED_FindFieldOffset ("vw_index"); for (i = 3; i < 8; i++) fofs_buttonX[i-3] = ED_FindFieldOffset(va("button%i", i)); // reset stuff like ZQ_CLIENTCOMMAND, progs must enable it explicitly memset (&pr_ext_enabled, sizeof(pr_ext_enabled), 0); PR_Exec_Init (); }
/* ================== CL_ParseServerInfo ================== */ static void CL_ParseServerInfo (void) { const char *str; int i; int nummodels, numsounds; char model_precache[MAX_MODELS][MAX_QPATH]; char sound_precache[MAX_SOUNDS][MAX_QPATH]; // rjr edict_t *ent; Con_DPrintf ("Serverinfo packet received.\n"); // // wipe the client_state_t struct // CL_ClearState (); // parse protocol version number cl_protocol = MSG_ReadLong (); switch (cl_protocol) { case PROTOCOL_RAVEN_111: case PROTOCOL_RAVEN_112: case PROTOCOL_UQE_113: Con_Printf ("\nServer using protocol %i\n", cl_protocol); break; default: Con_Printf ("\nServer returned version %i, not %i or %i\n", cl_protocol, PROTOCOL_RAVEN_112, PROTOCOL_UQE_113); return; } // parse maxclients cl.maxclients = MSG_ReadByte (); if (cl.maxclients < 1 || cl.maxclients > MAX_CLIENTS) { Con_Printf("Bad maxclients (%d) from server\n", cl.maxclients); return; } cl.scores = (scoreboard_t *) Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores"); // parse gametype cl.gametype = MSG_ReadByte (); if (cl.gametype == GAME_DEATHMATCH && cl_protocol > PROTOCOL_RAVEN_111) sv_kingofhill = MSG_ReadShort (); // parse signon message str = MSG_ReadString (); q_strlcpy (cl.levelname, str, sizeof(cl.levelname)); // 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; } q_strlcpy (model_precache[nummodels], str, MAX_QPATH); 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; } q_strlcpy (sound_precache[numsounds], str, MAX_QPATH); S_TouchSound (str); } // // now we try to load everything else until a cache allocation fails // if (precache.integer) { total_loading_size = nummodels + numsounds; current_loading_size = 1; loading_stage = 2; } // copy the naked name of the map file to the cl structure COM_StripExtension (COM_SkipPath(model_precache[1]), cl.mapname, sizeof(cl.mapname)); //always precache the world!!! cl.model_precache[1] = Mod_ForName (model_precache[1], false); for (i = 2; i < nummodels; i++) { if (precache.integer) { cl.model_precache[i] = Mod_ForName (model_precache[i], false); current_loading_size++; D_ShowLoadingSize(); } else cl.model_precache[i] = (model_t *)Mod_FindName (model_precache[i]); if (cl.model_precache[i] == NULL) { Host_Error("Model %s not found", model_precache[i]); return; } CL_KeepaliveMessage (); } player_models[0] = (model_t *)Mod_FindName ("models/paladin.mdl"); // Note: old demo doesnt have necro and crusader classes. add // a GAME_OLD_DEMO flag check ? player_models[1] = (model_t *)Mod_FindName ("models/crusader.mdl"); player_models[2] = (model_t *)Mod_FindName ("models/necro.mdl"); player_models[3] = (model_t *)Mod_FindName ("models/assassin.mdl"); if (gameflags & GAME_PORTALS) player_models[4] = (model_t *)Mod_FindName ("models/succubus.mdl"); S_BeginPrecaching (); for (i = 1; i < numsounds; i++) { cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]); if (precache.integer) { current_loading_size++; D_ShowLoadingSize(); } CL_KeepaliveMessage (); } S_EndPrecaching (); total_loading_size = 0; loading_stage = 0; // local state cl_entities[0].model = cl.worldmodel = cl.model_precache[1]; R_NewMap (); if (!sv.active) { PR_LoadStrings(); } PR_LoadPuzzleStrings(); // mission pack, objectives strings if (gameflags & GAME_PORTALS) PR_LoadInfoStrings(); Hunk_Check (); // make sure nothing is hurt // we connected to the server, make sure the mouse is going - S.A. menu_disabled_mouse = false; IN_ActivateMouse(); }
void CL_Disconnect_f( void ) { Host_Error( "Disconnected from server\n" ); }
/* ==================== ED_ParseEdict Parses an edict out of the given string, returning the new position ed should be a properly initialized empty edict. Used for initial level load and for savegames. ==================== */ char *ED_ParseEdict (char *data, edict_t *ent) { ddef_t *key; qbool anglehack, skyhack; qbool init; char keyname[256]; init = false; // clear it if (ent != sv.edicts) // hack memset (&ent->v, 0, progs->entityfields * 4); // go through all the dictionary pairs while (1) { // parse key data = COM_Parse (data); if (com_token[0] == '}') break; if (!data) Host_Error ("ED_ParseEntity: EOF without closing brace"); // anglehack is to allow QuakeEd to write single scalar angles // and allow them to be turned into vectors. (FIXME...) if (!strcmp(com_token, "angle")) { strcpy (com_token, "angles"); anglehack = true; } else anglehack = false; // FIXME: change light to _light to get rid of this hack if (!strcmp(com_token, "light")) strcpy (com_token, "light_lev"); // hack for single light def strlcpy (keyname, com_token, sizeof(keyname)); // parse value data = COM_Parse (data); if (!data) Host_Error ("ED_ParseEntity: EOF without closing brace"); if (com_token[0] == '}') Host_Error ("ED_ParseEntity: closing brace without data"); init = true; skyhack = false; if (ent == sv.edicts && (!strcmp(keyname, "sky") || !strcmp(keyname, "skyname"))) { skyhack = true; sv.sky = com_token; if (sv.sky.find("..") != string::npos) sv.sky = ""; } // keynames with a leading underscore are used for utility comments, // and are immediately discarded by quake if (keyname[0] == '_') continue; key = ED_FindField (keyname); if (!key) { if (!skyhack) Com_Printf ("%s is not a field\n", keyname); continue; } if (anglehack) { char temp[32]; strlcpy (temp, com_token, sizeof(temp)); sprintf (com_token, "0 %s 0", temp); } if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) Host_Error ("ED_ParseEdict: parse error"); } if (!init) ent->inuse = false; return data; }
/* ===================== 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\n"); 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 (); if (i != PROTOCOL_VERSION) Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); 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: for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); cl_lightstyle[i].length = Q_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"); Q_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) { CDAudio_Pause (); } else { CDAudio_Resume (); } } 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]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) CDAudio_Play ((byte)cls.forcetrack, true); else CDAudio_Play ((byte)cl.cdtrack, true); break; 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_sellscreen: Cmd_ExecuteString ("help", src_command); break; } } }
/* =============== CL_ChangeGame This is experiment. Use with precaution =============== */ qboolean CL_ChangeGame( const char *gamefolder, qboolean bReset ) { if( host.type == HOST_DEDICATED ) return false; if( Q_stricmp( host.gamefolder, gamefolder )) { kbutton_t *mlook, *jlook; qboolean mlook_active = false, jlook_active = false; string mapname, maptitle; int maxEntities; mlook = (kbutton_t *)clgame.dllFuncs.KB_Find( "in_mlook" ); jlook = (kbutton_t *)clgame.dllFuncs.KB_Find( "in_jlook" ); if( mlook && ( mlook->state & 1 )) mlook_active = true; if( jlook && ( jlook->state & 1 )) jlook_active = true; // so reload all images (remote connect) Mod_ClearAll( true ); R_ShutdownImages(); FS_LoadGameInfo( (bReset) ? host.gamefolder : gamefolder ); R_InitImages(); // save parms maxEntities = clgame.maxEntities; Q_strncpy( mapname, clgame.mapname, MAX_STRING ); Q_strncpy( maptitle, clgame.maptitle, MAX_STRING ); if( !CL_LoadProgs( va( "%s/client.dll", GI->dll_path ))) Host_Error( "can't initialize client.dll\n" ); // restore parms clgame.maxEntities = maxEntities; Q_strncpy( clgame.mapname, mapname, MAX_STRING ); Q_strncpy( clgame.maptitle, maptitle, MAX_STRING ); // invalidate fonts so we can reloading them again Q_memset( &cls.creditsFont, 0, sizeof( cls.creditsFont )); SCR_InstallParticlePalette(); SCR_LoadCreditsFont(); Con_InvalidateFonts(); SCR_RegisterTextures (); CL_FreeEdicts (); SCR_VidInit (); if( cls.key_dest == key_game ) // restore mouse state clgame.dllFuncs.IN_ActivateMouse(); // restore mlook state if( mlook_active ) Cmd_ExecuteString( "+mlook\n", src_command ); if( jlook_active ) Cmd_ExecuteString( "+jlook\n", src_command ); return true; } return false; }
static void Host_Loadgame_f (void) { dstring_t *name = 0; QFile *f; char *mapname = 0; script_t *script = 0; plitem_t *game = 0; plitem_t *list; plitem_t *item; char *script_data = 0; int i; int entnum; int count; int version; float spawn_parms[NUM_SPAWN_PARMS]; if (cmd_source != src_command) goto end; if (Cmd_Argc () != 2) { Sys_Printf ("load <savename> : load a game\n"); goto end; } cls.demonum = -1; // stop demo loop in case this fails name = dstring_newstr (); dsprintf (name, "%s/%s", qfs_gamedir->dir.def, Cmd_Argv (1)); QFS_DefaultExtension (name, ".sav"); cl.loading = true; CL_UpdateScreen (cl.time); Sys_Printf ("Loading game from %s...\n", name->str); f = QFS_Open (name->str, "rz"); if (!f) { Sys_Printf ("ERROR: couldn't open.\n"); goto end; } script_data = malloc (Qfilesize (f) + 1); i = Qread (f, script_data, Qfilesize (f)); script_data[i] = 0; Qclose (f); script = Script_New (); script->single = ""; // disable {}()': lexing Script_Start (script, name->str, script_data); Script_GetToken (script, 1); if (strequal (script->token->str, PACKAGE_NAME)) { if (!Script_TokenAvailable (script, 1)) { Sys_Printf ("Unexpected EOF reading %s\n", name->str); goto end; } game = PL_GetPropertyList (script->p); } else { sscanf (script->token->str, "%i", &version); if (version != SAVEGAME_VERSION) { Sys_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); goto end; } game = convert_to_game_dict (script); } item = PL_ObjectForKey (game, "spawn_parms"); for (i = 0; i < NUM_SPAWN_PARMS; i++) { if (i >= PL_A_NumObjects (item)) break; spawn_parms[i] = atof (PL_String (PL_ObjectAtIndex (item, i))); } current_skill = atoi (PL_String (PL_ObjectForKey (game, "current_skill"))); Cvar_SetValue (skill, current_skill); mapname = strdup (PL_String (PL_ObjectForKey (game, "name"))); CL_Disconnect_f (); SV_SpawnServer (mapname); if (!sv.active) { Sys_Printf ("Couldn't load map %s\n", mapname); goto end; } sv.paused = true; // pause until all clients connect sv.loadgame = true; list = PL_ObjectForKey (game, "lightstyles"); for (i = 0; i < MAX_LIGHTSTYLES; i++) { const char *style; char *str; if (i >= PL_A_NumObjects (list)) break; item = PL_ObjectAtIndex (list, i); style = PL_String (item); sv.lightstyles[i] = str = Hunk_Alloc (strlen (style) + 1); strcpy (str, style); } ED_InitGlobals (&sv_pr_state, PL_ObjectForKey (game, "globals")); list = PL_ObjectForKey (game, "entities"); entnum = 0; count = PL_A_NumObjects (list); if (count > sv.max_edicts) Host_Error ("too many entities in saved game. adjust max_edicts\n"); for (entnum = 0; entnum < count; entnum++) { plitem_t *entity = PL_ObjectAtIndex (list, entnum); edict_t *ent = EDICT_NUM (&sv_pr_state, entnum); memset (&ent->v, 0, sv_pr_state.progs->entityfields * 4); ent->free = false; ED_InitEntity (&sv_pr_state, entity, ent); // link it into the bsp tree if (!ent->free) SV_LinkEdict (ent, false); } sv.num_edicts = entnum; sv.time = atof (PL_String (PL_ObjectForKey (game, "time"))); for (i = 0; i < NUM_SPAWN_PARMS; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; if (cls.state != ca_dedicated) { CL_EstablishConnection ("local"); Host_Reconnect_f (); } end: if (game) PL_Free (game); if (mapname) free (mapname); if (script) Script_Delete (script); if (script_data) free (script_data); if (name) dstring_delete (name); }
/* ==================== CL_GetDemoMessage FIXME... ==================== */ qboolean CL_GetDemoMessage (void) { int r, i, j; float f; float demotime; byte c; usercmd_t *pcmd; // read the time from the packet fread(&demotime, sizeof(demotime), 1, cls.demofile); demotime = LittleFloat(demotime); // decide if it is time to grab the next message if (cls.timedemo) { if (cls.td_lastframe < 0) cls.td_lastframe = demotime; else if (demotime > cls.td_lastframe) { cls.td_lastframe = demotime; // rewind back to time fseek(cls.demofile, ftell(cls.demofile) - sizeof(demotime), SEEK_SET); return 0; // allready read this frame's message } if (!cls.td_starttime && cls.state == ca_active) { cls.td_starttime = Sys_DoubleTime(); cls.td_startframe = host_framecount; } realtime = demotime; // warp } else if (!cl.paused && cls.state >= ca_onserver) { // allways grab until fully connected if (realtime + 1.0 < demotime) { // too far back realtime = demotime - 1.0; // rewind back to time fseek(cls.demofile, ftell(cls.demofile) - sizeof(demotime), SEEK_SET); return 0; } else if (realtime < demotime) { // rewind back to time fseek(cls.demofile, ftell(cls.demofile) - sizeof(demotime), SEEK_SET); return 0; // don't need another message yet } } else realtime = demotime; // we're warping if (cls.state < ca_demostart) Host_Error ("CL_GetDemoMessage: cls.state != ca_active"); // get the msg type fread (&c, sizeof(c), 1, cls.demofile); switch (c) { case dem_cmd : // user sent input i = cls.netchan.outgoing_sequence & UPDATE_MASK; pcmd = &cl.frames[i].cmd; r = (int) fread (pcmd, sizeof(*pcmd), 1, cls.demofile); if (r != 1) { CL_StopPlayback (); return 0; } // byte order stuff for (j = 0; j < 3; j++) pcmd->angles[j] = LittleFloat(pcmd->angles[j]); pcmd->forwardmove = LittleShort(pcmd->forwardmove); pcmd->sidemove = LittleShort(pcmd->sidemove); pcmd->upmove = LittleShort(pcmd->upmove); cl.frames[i].senttime = demotime; cl.frames[i].receivedtime = -1; // we haven't gotten a reply yet cls.netchan.outgoing_sequence++; for (i=0 ; i<3 ; i++) { r = (int) fread (&f, 4, 1, cls.demofile); cl.viewangles[i] = LittleFloat (f); } break; case dem_read: // get the next message fread (&net_message.cursize, 4, 1, cls.demofile); net_message.cursize = LittleLong (net_message.cursize); //Con_Printf("read: %ld bytes\n", net_message.cursize); if (net_message.cursize > MAX_MSGLEN) Sys_Error ("Demo message > MAX_MSGLEN"); r = (int) fread (net_message.data, net_message.cursize, 1, cls.demofile); if (r != 1) { CL_StopPlayback (); return 0; } break; case dem_set : fread (&i, 4, 1, cls.demofile); cls.netchan.outgoing_sequence = LittleLong(i); fread (&i, 4, 1, cls.demofile); cls.netchan.incoming_sequence = LittleLong(i); break; default : Con_Printf("Corrupted demo.\n"); CL_StopPlayback (); return 0; } return 1; }
/* ================== CL_ParseServerData ================== */ void CL_ParseServerData( sizebuf_t *msg ) { string gamefolder; qboolean background; int i; MsgDev( D_NOTE, "Serverdata packet received.\n" ); cls.demowaiting = false; // server is changed clgame.load_sequence++; // now all hud sprites are invalid // wipe the client_t struct if( !cls.changelevel && !cls.changedemo ) CL_ClearState (); cls.state = ca_connected; // parse protocol version number i = BF_ReadLong( msg ); cls.serverProtocol = i; if( i != PROTOCOL_VERSION ) Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION ); cl.servercount = BF_ReadLong( msg ); cl.checksum = BF_ReadLong( msg ); cl.playernum = BF_ReadByte( msg ); cl.maxclients = BF_ReadByte( msg ); clgame.maxEntities = BF_ReadWord( msg ); clgame.maxEntities = bound( 600, clgame.maxEntities, 4096 ); Q_strncpy( clgame.mapname, BF_ReadString( msg ), MAX_STRING ); Q_strncpy( clgame.maptitle, BF_ReadString( msg ), MAX_STRING ); background = BF_ReadOneBit( msg ); Q_strncpy( gamefolder, BF_ReadString( msg ), MAX_STRING ); host.features = (uint)BF_ReadLong( msg ); if( cl.maxclients > 1 && host.developer < 1 ) host.developer++; // set the background state if( cls.demoplayback && ( cls.demonum != -1 )) { // re-init mouse host.mouse_visible = false; cl.background = true; } else cl.background = background; if( cl.background ) // tell the game parts about background state Cvar_FullSet( "cl_background", "1", CVAR_READ_ONLY ); else Cvar_FullSet( "cl_background", "0", CVAR_READ_ONLY ); if( !cls.changelevel ) { // continue playing if we are changing level S_StopBackgroundTrack (); } #if 0 // NOTE: this is not tested as well. Use with precaution CL_ChangeGame( gamefolder, false ); #endif if( !cls.changedemo ) UI_SetActiveMenu( cl.background ); else if( !cls.demoplayback ) Key_SetKeyDest( key_menu ); cl.refdef.viewentity = cl.playernum + 1; // always keep viewent an actual menu.globals->maxClients = cl.maxclients; Q_strncpy( menu.globals->maptitle, clgame.maptitle, sizeof( menu.globals->maptitle )); if( !cls.changelevel && !cls.changedemo ) CL_InitEdicts (); // re-arrange edicts // get splash name if( cls.demoplayback && ( cls.demonum != -1 )) Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", cls.demoname, glState.wideScreen ? "16x9" : "4x3" )); else Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", clgame.mapname, glState.wideScreen ? "16x9" : "4x3" )); Cvar_SetFloat( "scr_loading", 0.0f ); // reset progress bar if(( cl_allow_levelshots->integer && !cls.changelevel ) || cl.background ) { if( !FS_FileExists( va( "%s.bmp", cl_levelshot_name->string ), true )) Cvar_Set( "cl_levelshot_name", "*black" ); // render a black screen cls.scrshot_request = scrshot_plaque; // request levelshot even if exist (check filetime) } if( scr_dark->integer ) { screenfade_t *sf = &clgame.fade; client_textmessage_t *title; title = CL_TextMessageGet( "GAMETITLE" ); if( title ) { // get settings from titles.txt sf->fadeEnd = title->holdtime + title->fadeout; sf->fadeReset = title->fadeout; } else sf->fadeEnd = sf->fadeReset = 4.0f; sf->fadeFlags = FFADE_IN; sf->fader = sf->fadeg = sf->fadeb = 0; sf->fadealpha = 255; sf->fadeSpeed = (float)sf->fadealpha / sf->fadeReset; sf->fadeReset += cl.time; sf->fadeEnd += sf->fadeReset; Cvar_SetFloat( "v_dark", 0.0f ); } // need to prep refresh at next oportunity cl.video_prepped = false; cl.audio_prepped = false; Q_memset( &clgame.movevars, 0, sizeof( clgame.movevars )); Q_memset( &clgame.oldmovevars, 0, sizeof( clgame.oldmovevars )); }
bool CClientState::ProcessServerInfo( SVC_ServerInfo *msg ) { // Reset client state CL_ClearState(); if ( !CBaseClientState::ProcessServerInfo( msg ) ) { Disconnect(true); return false; } #ifndef _XBOX if ( demoplayer->IsPlayingBack() ) { // Because a server doesn't run during // demoplayback, but the decal system relies on this... m_nServerCount = gHostSpawnCount; } else { // tell demo recorder that new map is loaded and we are receiving // it's signon data (will be written into extra demo header file) demorecorder->SetSignonState( SIGNONSTATE_NEW ); } #endif // is server a HLTV proxy ? ishltv = msg->m_bIsHLTV; // The CRC of the server map must match the CRC of the client map. or else // the client is probably cheating. serverCRC = msg->m_nMapCRC; // The client side DLL CRC check. serverClientSideDllCRC = msg->m_nClientCRC; // Multiplayer game? if ( m_nMaxClients > 1 ) { if ( mp_decals.GetInt() < r_decals.GetInt() ) { r_decals.SetValue( mp_decals.GetInt() ); } } g_ClientGlobalVariables.maxClients = m_nMaxClients; g_ClientGlobalVariables.network_protocol = msg->m_nProtocol; #ifdef SHARED_NET_STRING_TABLES // use same instance of StringTableContainer as the server does m_StringTableContainer = networkStringTableContainerServer; CL_HookClientStringTables(); #else // use own instance of StringTableContainer m_StringTableContainer = networkStringTableContainerClient; #endif CL_ReallocateDynamicData( m_nMaxClients ); if ( sv.IsPaused() ) { if ( msg->m_fTickInterval != host_state.interval_per_tick ) { Host_Error( "Expecting interval_per_tick %f, got %f\n", host_state.interval_per_tick, msg->m_fTickInterval ); return false; } } else { host_state.interval_per_tick = msg->m_fTickInterval; } // Re-init hud video, especially if we changed game directories ClientDLL_HudVidInit(); // Don't verify the map and player .mdl crc's until after any missing resources have // been downloaded. This will still occur before requesting the rest of the signon. gHostSpawnCount = m_nServerCount; videomode->MarkClientViewRectDirty(); // leave intermission full screen return true; }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage( sizebuf_t *msg ) { char *s; int i, j, cmd; int param1, param2; int bufStart; cls_message_debug.parsing = true; // begin parsing starting_count = BF_GetNumBytesRead( msg ); // updates each frame // parse the message while( 1 ) { if( BF_CheckOverflow( msg )) { Host_Error( "CL_ParseServerMessage: overflow!\n" ); return; } // mark start position bufStart = BF_GetNumBytesRead( msg ); // end of message if( BF_GetNumBitsLeft( msg ) < 8 ) break; cmd = BF_ReadByte( msg ); // record command for debugging spew on parse problem CL_Parse_RecordCommand( cmd, bufStart ); // other commands switch( cmd ) { case svc_bad: Host_Error( "svc_bad\n" ); break; case svc_nop: // this does nothing break; case svc_disconnect: CL_Drop (); Host_AbortCurrentFrame (); break; case svc_changing: if( BF_ReadOneBit( msg )) { cls.changelevel = true; S_StopAllSounds(); if( cls.demoplayback ) { SCR_BeginLoadingPlaque( cl.background ); cls.changedemo = true; } } else MsgDev( D_INFO, "Server disconnected, reconnecting\n" ); CL_ClearState (); CL_InitEdicts (); // re-arrange edicts if( cls.demoplayback ) { cl.background = (cls.demonum != -1) ? true : false; cls.state = ca_connected; } else cls.state = ca_connecting; cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately break; case svc_setview: cl.refdef.viewentity = BF_ReadWord( msg ); break; case svc_sound: CL_ParseSoundPacket( msg, false ); break; case svc_time: // shuffle timestamps cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = BF_ReadFloat( msg ); break; case svc_print: i = BF_ReadByte( msg ); MsgDev( D_INFO, "^6%s", BF_ReadString( msg )); if( i == PRINT_CHAT ) S_StartLocalSound( "common/menu2.wav", VOL_NORM, false ); break; case svc_stufftext: s = BF_ReadString( msg ); Cbuf_AddText( s ); break; case svc_lightstyle: CL_ParseLightStyle( msg ); break; case svc_setangle: CL_ParseSetAngle( msg ); break; case svc_serverdata: Cbuf_Execute(); // make sure any stuffed commands are done CL_ParseServerData( msg ); break; case svc_addangle: CL_ParseAddAngle( msg ); break; case svc_clientdata: CL_ParseClientData( msg ); break; case svc_packetentities: CL_ParsePacketEntities( msg, false ); break; case svc_deltapacketentities: CL_ParsePacketEntities( msg, true ); break; case svc_updatepings: CL_UpdateUserPings( msg ); break; case svc_usermessage: CL_RegisterUserMessage( msg ); break; case svc_particle: CL_ParseParticles( msg ); break; case svc_restoresound: CL_ParseRestoreSoundPacket( msg ); break; case svc_spawnstatic: CL_ParseStaticEntity( msg ); break; case svc_ambientsound: CL_ParseSoundPacket( msg, true ); break; case svc_crosshairangle: CL_ParseCrosshairAngle( msg ); break; case svc_spawnbaseline: CL_ParseBaseline( msg ); break; case svc_temp_entity: CL_ParseTempEntity( msg ); break; case svc_setpause: cl.refdef.paused = ( BF_ReadOneBit( msg ) != 0 ); break; case svc_deltamovevars: CL_ParseMovevars( msg ); break; case svc_customization: CL_ParseCustomization( msg ); break; case svc_centerprint: CL_CenterPrint( BF_ReadString( msg ), 0.25f ); break; case svc_event: CL_ParseEvent( msg ); break; case svc_event_reliable: CL_ParseReliableEvent( msg ); break; case svc_updateuserinfo: CL_UpdateUserinfo( msg ); break; case svc_intermission: cl.refdef.intermission = true; break; case svc_modelindex: CL_PrecacheModel( msg ); break; case svc_soundindex: CL_PrecacheSound( msg ); break; case svc_soundfade: CL_ParseSoundFade( msg ); break; case svc_cdtrack: param1 = BF_ReadByte( msg ); param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum param2 = BF_ReadByte( msg ); param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0 ); break; case svc_serverinfo: CL_ServerInfo( msg ); break; case svc_eventindex: CL_PrecacheEvent( msg ); break; case svc_deltatable: Delta_ParseTableField( msg ); break; case svc_weaponanim: param1 = BF_ReadByte( msg ); // iAnim param2 = BF_ReadByte( msg ); // body CL_WeaponAnim( param1, param2 ); break; case svc_bspdecal: CL_ParseStaticDecal( msg ); break; case svc_roomtype: param1 = BF_ReadShort( msg ); Cvar_SetFloat( "room_type", param1 ); break; case svc_chokecount: i = BF_ReadByte( msg ); j = cls.netchan.incoming_acknowledged - 1; for( ; i > 0 && j > cls.netchan.outgoing_sequence - CL_UPDATE_BACKUP; j-- ) { if( cl.frames[j & CL_UPDATE_MASK].receivedtime != -3.0 ) { cl.frames[j & CL_UPDATE_MASK].receivedtime = -2.0; i--; } } break; case svc_resourcelist: CL_ParseResourceList( msg ); break; case svc_director: CL_ParseDirector( msg ); break; case svc_studiodecal: CL_ParseStudioDecal( msg ); break; case svc_querycvarvalue: CL_ParseCvarValue( msg ); break; case svc_querycvarvalue2: CL_ParseCvarValue2( msg ); break; default: CL_ParseUserMessage( msg, cmd ); break; } } cls_message_debug.parsing = false; // done // we don't know if it is ok to save a demo message until // after we have parsed the frame if( !cls.demoplayback ) { if( cls.demorecording && !cls.demowaiting ) { CL_WriteDemoMessage( false, starting_count, msg ); } else if( cls.state != ca_active ) { CL_WriteDemoMessage( true, starting_count, msg ); } } }
/* ============== CL_ParseUserMessage handles all user messages ============== */ void CL_ParseUserMessage( sizebuf_t *msg, int svc_num ) { int i, iSize; byte pbuf[256]; // message can't be larger than 255 bytes // NOTE: any user message parse on engine, not in client.dll if( svc_num < svc_lastmsg || svc_num >= ( MAX_USER_MESSAGES + svc_lastmsg )) { // out or range Host_Error( "CL_ParseUserMessage: illegible server message %d\n", svc_num ); return; } for( i = 0; i < MAX_USER_MESSAGES; i++ ) { // search for user message if( clgame.msg[i].number == svc_num ) break; } if( i == MAX_USER_MESSAGES ) // probably unregistered Host_Error( "CL_ParseUserMessage: illegible server message %d\n", svc_num ); // NOTE: some user messages handled into engine if( !Q_strcmp( clgame.msg[i].name, "ScreenShake" )) { CL_ParseScreenShake( msg ); return; } else if( !Q_strcmp( clgame.msg[i].name, "ScreenFade" )) { CL_ParseScreenFade( msg ); return; } iSize = clgame.msg[i].size; // message with variable sizes receive an actual size as first byte if( iSize == -1 ) iSize = BF_ReadByte( msg ); // parse user message into buffer BF_ReadBytes( msg, pbuf, iSize ); if( clgame.msg[i].func ) { clgame.msg[i].func( clgame.msg[i].name, iSize, pbuf ); // HACKHACK: run final credits for Half-Life // because hl1 doesn't have call END_SECTION if( !Q_stricmp( clgame.msg[i].name, "HudText" ) && !Q_stricmp( GI->gamefolder, "valve" )) { // it's a end, so we should run credits if( !Q_strcmp( (char *)pbuf, "END3" )) Host_Credits(); } } else { MsgDev( D_ERROR, "CL_ParseUserMessage: %s not hooked\n", clgame.msg[i].name ); clgame.msg[i].func = CL_UserMsgStub; // throw warning only once } }
/* ==================== Host_Init ==================== */ void Host_Init (int argc, char **argv, int default_memsize) { COM_InitArgv (argc, argv); #if !defined(CLIENTONLY) && !defined(SERVERONLY) if (COM_CheckParm("-dedicated")) dedicated = true; #endif Host_InitMemory (default_memsize); Cbuf_Init (); Cmd_Init (); Cvar_Init (); COM_Init (); Key_Init (); FS_InitFilesystem (); COM_CheckRegistered (); Con_Init (); if (!dedicated) { Cbuf_AddText ("exec default.cfg\n"); Cbuf_AddText ("exec config.cfg\n"); Cbuf_Execute (); } Cbuf_AddEarlyCommands (); Cbuf_Execute (); NET_Init (); Netchan_Init (); Sys_Init (); CM_Init (); PM_Init (); Host_InitLocal (); SV_Init (); CL_Init (); Cvar_CleanUpTempVars (); Hunk_AllocName (0, "-HOST_HUNKLEVEL-"); host_hunklevel = Hunk_LowMark (); host_initialized = true; Com_Printf ("Exe: "__TIME__" "__DATE__"\n"); Com_Printf ("%4.1f megs RAM used.\n", host_memsize / (1024*1024.0)); Com_Printf ("\n========= " PROGRAM " Initialized =========\n"); if (dedicated) { Cbuf_AddText ("exec server.cfg\n"); Cmd_StuffCmds_f (); // process command line arguments Cbuf_Execute (); // if a map wasn't specified on the command line, spawn start map if (!com_serveractive) Cmd_ExecuteString ("map start"); if (!com_serveractive) Host_Error ("Couldn't spawn a server"); } else { Cbuf_AddText ("exec autoexec.cfg\n"); Cmd_StuffCmds_f (); // process command line arguments Cbuf_AddText ("cl_warncmd 1\n"); } }
/* ==================== ED_ParseEdict Parses an edict out of the given string, returning the new position ed should be a properly initialized empty edict. Used for initial level load and for savegames. ==================== */ const char *ED_ParseEdict (const char *data, edict_t *ent) { ddef_t *key; char keyname[256]; qboolean anglehack, init; int n; init = false; // clear it if (ent != sv.edicts) // hack memset (&ent->v, 0, progs->entityfields * 4); // go through all the dictionary pairs while (1) { // parse key data = COM_Parse (data); if (com_token[0] == '}') break; if (!data) Host_Error ("ED_ParseEntity: EOF without closing brace"); // anglehack is to allow QuakeEd to write single scalar angles // and allow them to be turned into vectors. (FIXME...) if (!strcmp(com_token, "angle")) { strcpy (com_token, "angles"); anglehack = true; } else anglehack = false; // FIXME: change light to _light to get rid of this hack if (!strcmp(com_token, "light")) strcpy (com_token, "light_lev"); // hack for single light def strcpy (keyname, com_token); // another hack to fix keynames with trailing spaces n = strlen(keyname); while (n && keyname[n-1] == ' ') { keyname[n-1] = 0; n--; } // parse value data = COM_Parse (data); if (!data) Host_Error ("ED_ParseEntity: EOF without closing brace"); if (com_token[0] == '}') Host_Error ("ED_ParseEntity: closing brace without data"); init = true; // keynames with a leading underscore are used for utility comments, // and are immediately discarded by quake if (keyname[0] == '_') continue; //johnfitz -- hack to support .alpha even when progs.dat doesn't know about it if (!strcmp(keyname, "alpha")) ent->alpha = ENTALPHA_ENCODE(atof(com_token)); //johnfitz key = ED_FindField (keyname); if (!key) { //johnfitz -- HACK -- suppress error becuase fog/sky/alpha fields might not be mentioned in defs.qc if (strncmp(keyname, "sky", 3) && strcmp(keyname, "fog") && strcmp(keyname, "alpha")) Con_DPrintf ("\"%s\" is not a field\n", keyname); //johnfitz -- was Con_Printf continue; } if (anglehack) { char temp[32]; strcpy (temp, com_token); sprintf (com_token, "0 %s 0", temp); } if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) Host_Error ("ED_ParseEdict: parse error"); } if (!init) ent->free = true; return data; }
void SV_LoadGame_f (void) { extern cvar_t sv_progtype; char name[MAX_OSPATH], mapname[MAX_QPATH], str[32 * 1024], *start; FILE *f; float time, tfloat, spawn_parms[NUM_SPAWN_PARMS]; edict_t *ent; int entnum, version, r; unsigned int i; if (Cmd_Argc() != 2) { Com_Printf ("Usage: %s <savename> : load a game\n", Cmd_Argv(0)); return; } snprintf (name, sizeof (name), "%s/save/%s", com_gamedir, Cmd_Argv(1)); COM_DefaultExtension (name, ".sav"); Com_Printf ("Loading game from %s...\n", name); if (!(f = fopen (name, "rb"))) { Com_Printf ("ERROR: couldn't open.\n"); return; } if (fscanf (f, "%i\n", &version) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } if (version != SAVEGAME_VERSION) { fclose (f); Com_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return; } if (fscanf (f, "%s\n", str) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } for (i = 0; i < NUM_SPAWN_PARMS; i++) { if (fscanf (f, "%f\n", &spawn_parms[i]) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } } // this silliness is so we can load 1.06 save files, which have float skill values if (fscanf (f, "%f\n", &tfloat) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } current_skill = (int)(tfloat + 0.1); Cvar_Set (&skill, va("%i", current_skill)); Cvar_SetValue (&deathmatch, 0); Cvar_SetValue (&coop, 0); Cvar_SetValue (&teamplay, 0); Cvar_SetValue (&maxclients, 1); Cvar_Set (&sv_progsname, "spprogs"); // force progsname #ifdef USE_PR2 Cvar_Set (&sv_progtype, "0"); // force .dat #endif if (fscanf (f, "%s\n", mapname) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } if (fscanf (f, "%f\n", &time) != 1) { fclose (f); Com_Printf ("Error reading savegame data\n"); return; } Host_EndGame(); CL_BeginLocalConnection (); SV_SpawnServer (mapname, false); if (sv.state != ss_active) { Com_Printf ("Couldn't load map\n"); fclose (f); return; } // load the light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { if (fscanf (f, "%s\n", str) != 1) { Com_Printf("Couldn't read lightstyles\n"); fclose (f); return; } sv.lightstyles[i] = (char *) Hunk_Alloc (strlen(str) + 1); strlcpy (sv.lightstyles[i], str, strlen(str) + 1); } // pause until all clients connect if (!(sv.paused & 1)) SV_TogglePause (NULL, 1); sv.loadgame = true; // load the edicts out of the savegame file entnum = -1; // -1 is the globals while (!feof(f)) { for (i = 0; i < sizeof(str) - 1; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '}') { i++; break; } } if (i == sizeof(str)-1) Host_Error ("Loadgame buffer overflow"); str[i] = 0; start = str; start = COM_Parse(str); if (!com_token[0]) break; // end of file if (strcmp(com_token,"{")) Host_Error ("First token isn't a brace"); if (entnum == -1) { // parse the global vars ED_ParseGlobals (start); } else { // parse an edict ent = EDICT_NUM(entnum); memset (&ent->v, 0, progs->entityfields * 4); ent->e->free = false; ED_ParseEdict (start, ent); // link it into the bsp tree if (!ent->e->free) SV_LinkEdict (ent, false); } entnum++; } sv.num_edicts = entnum; sv.time = time; fclose (f); for (i = 0; i < NUM_SPAWN_PARMS; i++) svs.clients->spawn_parms[i] = spawn_parms[i]; }
void CL_ParseUpdate (int bits) { int i; model_t *model; int modnum; qboolean forcelink; entity_t *ent; int num; int skin; 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); } if (bits & U_LONGENTITY) num = MSG_ReadShort (); else num = MSG_ReadByte (); ent = CL_EntityNum (num); for (i=0 ; i<16 ; i++) if (bits&(1<<i)) bitcounts[i]++; if (ent->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) { 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 if (num > 0 && num <= cl.maxclients) R_TranslatePlayerSkin (num - 1); } 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) Sys_Error ("i >= cl.maxclients"); ent->colormap = cl.scores[i-1].translations; } 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); } 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]; if ( bits & U_NOLERP ) ent->forcelink = true; 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; } }
/* ==================== ED_ParseEdict Parses an edict out of the given string, returning the new_ptr position ed should be a properly initialized empty edict. Used for initial level load and for savegames. ==================== */ char *ED_ParseEdict (char *data, edict_t *ent) { ddef_t *key; qboolean anglehack; qboolean init; char keyname[256]; int n; init = false; // clear it if (ent != sv.edicts) // hack memset (&ent->v, 0, progs->entityfields * 4); // go through all the dictionary pairs while (1) { // parse key data = COM_Parse (data); if (com_token[0] == '}') break; if (!data) Sys_Error ("ED_ParseEntity: EOF without closing brace"); // anglehack is to allow QuakeEd to write single scalar angles // and allow them to be turned into vectors. (FIXME...) if (!strcmp(com_token, "angle")) { strcpy (com_token, "angles"); anglehack = true; } else anglehack = false; // FIXME: change light to _light to get rid of this hack if (!strcmp(com_token, "light")) strcpy (com_token, "light_lev"); // hack for single light def strcpy (keyname, com_token); // another hack to fix heynames with trailing spaces n = strlen(keyname); while (n && keyname[n-1] == ' ') { keyname[n-1] = 0; n--; } // parse value data = COM_Parse (data); if (!data) Sys_Error ("ED_ParseEntity: EOF without closing brace"); if (com_token[0] == '}') Sys_Error ("ED_ParseEntity: closing brace without data"); init = true; // keynames with a leading underscore are used for utility comments, // and are immediately discarded by quake if (keyname[0] == '_') continue; key = ED_FindField (keyname); if (!key) { Con_Printf ("'%s' is not a field\n", keyname); continue; } if (anglehack) { char temp[32]; strcpy (temp, com_token); sprintf (com_token, "0 %s 0", temp); } if (!ED_ParseEpair ((void *)&ent->v, key, com_token)) Host_Error ("ED_ParseEdict: parse error"); } if (!init) ent->free = true; return data; }
/* ================= CL_PrepVideo Call before entering a new level, or after changing dlls ================= */ void CL_PrepVideo( void ) { string name, mapname; int i, mdlcount; int map_checksum; // dummy if( !cl.model_precache[1][0] ) return; // no map loaded Cvar_SetFloat( "scr_loading", 0.0f ); // reset progress bar MsgDev( D_NOTE, "CL_PrepVideo: %s\n", clgame.mapname ); // let the render dll load the map Q_strncpy( mapname, cl.model_precache[1], MAX_STRING ); Mod_LoadWorld( mapname, &map_checksum, false ); cl.worldmodel = Mod_Handle( 1 ); // get world pointer Cvar_SetFloat( "scr_loading", 25.0f ); SCR_UpdateScreen(); // make sure what map is valid if( !cls.demoplayback && map_checksum != cl.checksum ) Host_Error( "Local map version differs from server: %i != '%i'\n", map_checksum, cl.checksum ); for( i = 0, mdlcount = 0; i < MAX_MODELS && cl.model_precache[i+1][0]; i++ ) mdlcount++; // total num models for( i = 0; i < MAX_MODELS && cl.model_precache[i+1][0]; i++ ) { Q_strncpy( name, cl.model_precache[i+1], MAX_STRING ); Mod_RegisterModel( name, i+1 ); Cvar_SetFloat( "scr_loading", scr_loading->value + 75.0f / mdlcount ); if( cl_allow_levelshots->integer || host.developer > 3 || cl.background ) SCR_UpdateScreen(); } // update right muzzleflash indexes CL_RegisterMuzzleFlashes (); // invalidate all decal indexes Q_memset( cl.decal_index, 0, sizeof( cl.decal_index )); CL_ClearWorld (); R_NewMap(); // tell the render about new map V_SetupOverviewState(); // set overview bounds // must be called after lightmap loading! clgame.dllFuncs.pfnVidInit(); // release unused SpriteTextures for( i = 1; i < MAX_IMAGES; i++ ) { if( !clgame.sprites[i].name[0] ) continue; // free slot if( clgame.sprites[i].needload != clgame.load_sequence ) Mod_UnloadSpriteModel( &clgame.sprites[i] ); } Mod_FreeUnused (); Cvar_SetFloat( "scr_loading", 100.0f ); // all done if( host.decalList ) { // need to reapply all decals after restarting for( i = 0; i < host.numdecals; i++ ) { decallist_t *entry = &host.decalList[i]; cl_entity_t *pEdict = CL_GetEntityByIndex( entry->entityIndex ); int decalIndex = CL_DecalIndex( CL_DecalIndexFromName( entry->name )); int modelIndex = 0; if( pEdict ) modelIndex = pEdict->curstate.modelindex; CL_DecalShoot( decalIndex, entry->entityIndex, modelIndex, entry->position, entry->flags ); } Z_Free( host.decalList ); } host.decalList = NULL; host.numdecals = 0; if( host.soundList ) { // need to reapply all ambient sounds after restarting for( i = 0; i < host.numsounds; i++ ) { soundlist_t *entry = &host.soundList[i]; if( entry->looping && entry->entnum != -1 ) { MsgDev( D_NOTE, "Restarting sound %s...\n", entry->name ); S_AmbientSound( entry->origin, entry->entnum, S_RegisterSound( entry->name ), entry->volume, entry->attenuation, entry->pitch, 0 ); } } } host.soundList = NULL; host.numsounds = 0; if( host.developer <= 2 ) Con_ClearNotify(); // clear any lines of console text SCR_UpdateScreen (); cl.video_prepped = true; cl.force_refdef = true; }
void PR_ExecuteProgram (func_t fnum) { int i; int s; eval_t *a, *b, *c; eval_t *ptr; dstatement_t *st; dfunction_t *f, *newf; int runaway; edict_t *ed; int exitdepth; int startFrame; int endFrame; float val; int case_type = -1; float switch_float = 0; // shut up compiler if (!fnum || fnum >= progs->numfunctions) { if (PR_GLOBAL_STRUCT(self)) { ED_Print(PROG_TO_EDICT(PR_GLOBAL_STRUCT(self))); } Host_Error("%s: NULL function", __thisfunc__); } f = &pr_functions[fnum]; runaway = 100000; pr_trace = false; exitdepth = pr_depth; s = EnterFunction(f); #ifdef TIMESNAP_ACTIVE ProgsTimer(); // Init #endif while (1) { s++; // Next statement st = &pr_statements[s]; a = (eval_t *)&pr_globals[(unsigned short)st->a]; b = (eval_t *)&pr_globals[(unsigned short)st->b]; c = (eval_t *)&pr_globals[(unsigned short)st->c]; if (!--runaway) { PR_RunError("runaway loop error"); } #ifndef TIMESNAP_ACTIVE pr_xfunction->profile++; #endif pr_xstatement = s; if (pr_trace) { PrintStatement(st); } switch (st->op) { case OP_ADD_F: c->_float = a->_float + b->_float; break; case OP_ADD_V: c->vector[0] = a->vector[0] + b->vector[0]; c->vector[1] = a->vector[1] + b->vector[1]; c->vector[2] = a->vector[2] + b->vector[2]; break; case OP_SUB_F: c->_float = a->_float - b->_float; break; case OP_SUB_V: c->vector[0] = a->vector[0] - b->vector[0]; c->vector[1] = a->vector[1] - b->vector[1]; c->vector[2] = a->vector[2] - b->vector[2]; break; case OP_MUL_F: c->_float = a->_float * b->_float; break; case OP_MUL_V: c->_float = a->vector[0]*b->vector[0] + a->vector[1]*b->vector[1] + a->vector[2]*b->vector[2]; break; case OP_MUL_FV: c->vector[0] = a->_float * b->vector[0]; c->vector[1] = a->_float * b->vector[1]; c->vector[2] = a->_float * b->vector[2]; break; case OP_MUL_VF: c->vector[0] = b->_float * a->vector[0]; c->vector[1] = b->_float * a->vector[1]; c->vector[2] = b->_float * a->vector[2]; break; case OP_DIV_F: c->_float = a->_float / b->_float; break; case OP_BITAND: c->_float = (int)a->_float & (int)b->_float; break; case OP_BITOR: c->_float = (int)a->_float | (int)b->_float; break; case OP_GE: c->_float = a->_float >= b->_float; break; case OP_LE: c->_float = a->_float <= b->_float; break; case OP_GT: c->_float = a->_float > b->_float; break; case OP_LT: c->_float = a->_float < b->_float; break; case OP_AND: c->_float = a->_float && b->_float; break; case OP_OR: c->_float = a->_float || b->_float; break; case OP_NOT_F: c->_float = !a->_float; break; case OP_NOT_V: c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; break; case OP_NOT_S: c->_float = !a->string || !*PR_GetString(a->string); break; case OP_NOT_FNC: c->_float = !a->function; break; case OP_NOT_ENT: c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); break; case OP_EQ_F: c->_float = a->_float == b->_float; break; case OP_EQ_V: c->_float = (a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1]) && (a->vector[2] == b->vector[2]); break; case OP_EQ_S: c->_float = !strcmp(PR_GetString(a->string), PR_GetString(b->string)); break; case OP_EQ_E: c->_float = a->_int == b->_int; break; case OP_EQ_FNC: c->_float = a->function == b->function; break; case OP_NE_F: c->_float = a->_float != b->_float; break; case OP_NE_V: c->_float = (a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1]) || (a->vector[2] != b->vector[2]); break; case OP_NE_S: c->_float = strcmp(PR_GetString(a->string), PR_GetString(b->string)); break; case OP_NE_E: c->_float = a->_int != b->_int; break; case OP_NE_FNC: c->_float = a->function != b->function; break; case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP_STORE_V: b->vector[0] = a->vector[0]; b->vector[1] = a->vector[1]; b->vector[2] = a->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_int = a->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->vector[0] = a->vector[0]; ptr->vector[1] = a->vector[1]; ptr->vector[2] = a->vector[2]; break; case OP_MULSTORE_F: // f *= f b->_float *= a->_float; break; case OP_MULSTORE_V: // v *= f b->vector[0] *= a->_float; b->vector[1] *= a->_float; b->vector[2] *= a->_float; break; case OP_MULSTOREP_F: // e.f *= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float *= a->_float); break; case OP_MULSTOREP_V: // e.v *= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] *= a->_float); c->vector[0] = (ptr->vector[1] *= a->_float); c->vector[0] = (ptr->vector[2] *= a->_float); break; case OP_DIVSTORE_F: // f /= f b->_float /= a->_float; break; case OP_DIVSTOREP_F: // e.f /= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float /= a->_float); break; case OP_ADDSTORE_F: // f += f b->_float += a->_float; break; case OP_ADDSTORE_V: // v += v b->vector[0] += a->vector[0]; b->vector[1] += a->vector[1]; b->vector[2] += a->vector[2]; break; case OP_ADDSTOREP_F: // e.f += f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float += a->_float); break; case OP_ADDSTOREP_V: // e.v += v ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] += a->vector[0]); c->vector[1] = (ptr->vector[1] += a->vector[1]); c->vector[2] = (ptr->vector[2] += a->vector[2]); break; case OP_SUBSTORE_F: // f -= f b->_float -= a->_float; break; case OP_SUBSTORE_V: // v -= v b->vector[0] -= a->vector[0]; b->vector[1] -= a->vector[1]; b->vector[2] -= a->vector[2]; break; case OP_SUBSTOREP_F: // e.f -= f ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->_float = (ptr->_float -= a->_float); break; case OP_SUBSTOREP_V: // e.v -= v ptr = (eval_t *)((byte *)sv.edicts + b->_int); c->vector[0] = (ptr->vector[0] -= a->vector[0]); c->vector[1] = (ptr->vector[1] -= a->vector[1]); c->vector[2] = (ptr->vector[2] -= a->vector[2]); break; case OP_ADDRESS: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) { PR_RunError("assignment to world entity"); } c->_int = (byte *)((int *)&ed->v + b->_int)-(byte *)sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->_int = a->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; case OP_FETCH_GBL_F: case OP_FETCH_GBL_S: case OP_FETCH_GBL_E: case OP_FETCH_GBL_FNC: i = (int)b->_float; if (i < 0 || i > G_INT((unsigned short)st->a - 1)) { PR_RunError("array index out of bounds: %d", i); } a = (eval_t *)&pr_globals[(unsigned short)st->a + i]; c->_int = a->_int; break; case OP_FETCH_GBL_V: i = (int)b->_float; if (i < 0 || i > G_INT((unsigned short)st->a - 1)) { PR_RunError("array index out of bounds: %d", i); } a = (eval_t *)&pr_globals[(unsigned short)st->a + ((int)b->_float)*3]; c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; case OP_IFNOT: if (!a->_int) { s += st->b - 1; // -1 to offset the s++ } break; case OP_IF: if (a->_int) { s += st->b - 1; // -1 to offset the s++ } break; case OP_GOTO: s += st->a - 1; // -1 to offset the s++ break; case OP_CALL8: case OP_CALL7: case OP_CALL6: case OP_CALL5: case OP_CALL4: case OP_CALL3: case OP_CALL2: // Copy second arg to shared space VectorCopy(c->vector, G_VECTOR(OFS_PARM1)); case OP_CALL1: // Copy first arg to shared space VectorCopy(b->vector, G_VECTOR(OFS_PARM0)); case OP_CALL0: pr_argc = st->op-OP_CALL0; if (!a->function) { PR_RunError("NULL function"); } newf = &pr_functions[a->function]; if (newf->first_statement < 0) { // Built-in function i = -newf->first_statement; if (i >= pr_numbuiltins) { PR_RunError("Bad builtin call number"); } pr_builtins[i](); break; } // Normal function #ifdef TIMESNAP_ACTIVE pr_xfunction->profile += ProgsTimer(); #endif s = EnterFunction(newf); break; case OP_DONE: case OP_RETURN: pr_globals[OFS_RETURN] = pr_globals[(unsigned short)st->a]; pr_globals[OFS_RETURN + 1] = pr_globals[(unsigned short)st->a + 1]; pr_globals[OFS_RETURN + 2] = pr_globals[(unsigned short)st->a + 2]; #ifdef TIMESNAP_ACTIVE pr_xfunction->profile += ProgsTimer(); #endif s = LeaveFunction(); if (pr_depth == exitdepth) { // Done return; } break; case OP_STATE: ed = PROG_TO_EDICT(PR_GLOBAL_STRUCT(self)); /* Id 1.07 changes #ifdef FPS_20 ed->v.nextthink = PR_GLOBAL_STRUCT(time) + 0.05; #else ed->v.nextthink = PR_GLOBAL_STRUCT(time) + 0.1; #endif */ ed->v.nextthink = PR_GLOBAL_STRUCT(time) + HX_FRAME_TIME; if (a->_float != ed->v.frame) { ed->v.frame = a->_float; } ed->v.think = b->function; break; case OP_CSTATE: // Cycle state ed = PROG_TO_EDICT(PR_GLOBAL_STRUCT(self)); ed->v.nextthink = PR_GLOBAL_STRUCT(time) + HX_FRAME_TIME; ed->v.think = pr_xfunction - pr_functions; if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = false; else pr_global_struct->cycle_wrapped = false; startFrame = (int)a->_float; endFrame = (int)b->_float; if (startFrame <= endFrame) { // Increment if (ed->v.frame < startFrame || ed->v.frame > endFrame) { ed->v.frame = startFrame; break; } ed->v.frame++; if (ed->v.frame > endFrame) { if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = true; else pr_global_struct->cycle_wrapped = true; ed->v.frame = startFrame; } break; } // Decrement if (ed->v.frame > startFrame || ed->v.frame < endFrame) { ed->v.frame = startFrame; break; } ed->v.frame--; if (ed->v.frame < endFrame) { if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = true; else pr_global_struct->cycle_wrapped = true; ed->v.frame = startFrame; } break; case OP_CWSTATE: // Cycle weapon state ed = PROG_TO_EDICT(PR_GLOBAL_STRUCT(self)); ed->v.nextthink = PR_GLOBAL_STRUCT(time) + HX_FRAME_TIME; ed->v.think = pr_xfunction - pr_functions; if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = false; else pr_global_struct->cycle_wrapped = false; startFrame = (int)a->_float; endFrame = (int)b->_float; if (startFrame <= endFrame) { // Increment if (ed->v.weaponframe < startFrame || ed->v.weaponframe > endFrame) { ed->v.weaponframe = startFrame; break; } ed->v.weaponframe++; if (ed->v.weaponframe > endFrame) { if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = true; else pr_global_struct->cycle_wrapped = true; ed->v.weaponframe = startFrame; } break; } // Decrement if (ed->v.weaponframe > startFrame || ed->v.weaponframe < endFrame) { ed->v.weaponframe = startFrame; break; } ed->v.weaponframe--; if (ed->v.weaponframe < endFrame) { if (is_progdefs111) pr_global_struct_v111->cycle_wrapped = true; else pr_global_struct->cycle_wrapped = true; ed->v.weaponframe = startFrame; } break; case OP_THINKTIME: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // Make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) { PR_RunError("assignment to world entity"); } ed->v.nextthink = PR_GLOBAL_STRUCT(time) + b->_float; break; case OP_BITSET: // f (+) f b->_float = (int)b->_float | (int)a->_float; break; case OP_BITSETP: // e.f (+) f ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_float = (int)ptr->_float | (int)a->_float; break; case OP_BITCLR: // f (-) f b->_float = (int)b->_float & ~((int)a->_float); break; case OP_BITCLRP: // e.f (-) f ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_float = (int)ptr->_float & ~((int)a->_float); break; case OP_RAND0: // val = (rand() & 0x7fff) / ((float)0x7fff); val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN) = val; break; case OP_RAND1: val = rand() * (1.0 / RAND_MAX) * a->_float; G_FLOAT(OFS_RETURN) = val; break; case OP_RAND2: if (a->_float < b->_float) { val = a->_float + (rand() * (1.0 / RAND_MAX) * (b->_float - a->_float)); } else { val = b->_float + (rand() * (1.0 / RAND_MAX) * (a->_float - b->_float)); } G_FLOAT(OFS_RETURN) = val; break; case OP_RANDV0: val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN + 0) = val; val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN + 1) = val; val = rand() * (1.0 / RAND_MAX); G_FLOAT(OFS_RETURN + 2) = val; break; case OP_RANDV1: val = rand() * (1.0 / RAND_MAX) * a->vector[0]; G_FLOAT(OFS_RETURN + 0) = val; val = rand() * (1.0 / RAND_MAX) * a->vector[1]; G_FLOAT(OFS_RETURN + 1) = val; val = rand() * (1.0 / RAND_MAX) * a->vector[2]; G_FLOAT(OFS_RETURN + 2) = val; break; case OP_RANDV2: for (i = 0; i < 3; i++) { if (a->vector[i] < b->vector[i]) { val = a->vector[i] + (rand() * (1.0 / RAND_MAX) * (b->vector[i] - a->vector[i])); } else { val = b->vector[i] + (rand() * (1.0 / RAND_MAX) * (a->vector[i] - b->vector[i])); } G_FLOAT(OFS_RETURN + i) = val; } break; case OP_SWITCH_F: case_type = SWITCH_F; switch_float = a->_float; s += st->b - 1; // -1 to offset the s++ break; case OP_SWITCH_V: PR_RunError("switch v not done yet!"); break; case OP_SWITCH_S: PR_RunError("switch s not done yet!"); break; case OP_SWITCH_E: PR_RunError("switch e not done yet!"); break; case OP_SWITCH_FNC: PR_RunError("switch fnc not done yet!"); break; case OP_CASERANGE: if (case_type != SWITCH_F) PR_RunError("caserange f****d!"); if ((switch_float >= a->_float) && (switch_float <= b->_float)) { s += st->c - 1; // -1 to offset the s++ } break; case OP_CASE: switch (case_type) { case SWITCH_F: if (switch_float == a->_float) { s += st->b - 1; // -1 to offset the s++ } break; case SWITCH_V: case SWITCH_S: case SWITCH_E: case SWITCH_FNC: PR_RunError("case not done yet!"); break; default: PR_RunError("f****d case!"); } break; default: PR_RunError("Bad opcode %i", st->op); } } // end of while(1) loop }
/* =================== CL_WritePacket Create and send the command packet to the server Including both the reliable commands and the usercmds =================== */ void CL_WritePacket( void ) { sizebuf_t buf; qboolean send_command = false; byte data[MAX_CMD_BUFFER]; int i, from, to, key, size; int numbackup = 2; int numcmds; int newcmds; int cmdnumber; // don't send anything if playing back a demo if( cls.demoplayback || cls.state == ca_cinematic ) return; if( cls.state == ca_disconnected || cls.state == ca_connecting ) return; CL_ComputePacketLoss (); #ifndef _DEBUG if( cl_cmdrate->value < MIN_CMD_RATE ) { Cvar_SetFloat( "cl_cmdrate", MIN_CMD_RATE ); } #endif BF_Init( &buf, "ClientData", data, sizeof( data )); // Determine number of backup commands to send along numbackup = bound( 0, cl_cmdbackup->integer, MAX_BACKUP_COMMANDS ); if( cls.state == ca_connected ) numbackup = 0; // Check to see if we can actually send this command // In single player, send commands as fast as possible // Otherwise, only send when ready and when not choking bandwidth if(( cl.maxclients == 1 ) || ( NET_IsLocalAddress( cls.netchan.remote_address ) && !host_limitlocal->integer )) send_command = true; else if(( host.realtime >= cls.nextcmdtime ) && Netchan_CanPacket( &cls.netchan )) send_command = true; if( cl.force_send_usercmd ) { send_command = true; cl.force_send_usercmd = false; } if(( cls.netchan.outgoing_sequence - cls.netchan.incoming_acknowledged ) >= CL_UPDATE_MASK ) { if(( host.realtime - cls.netchan.last_received ) > CONNECTION_PROBLEM_TIME ) { Con_NPrintf( 1, "^3Warning:^1 Connection Problem^7\n" ); cl.validsequence = 0; } } if( cl_nodelta->integer ) { cl.validsequence = 0; } // send a userinfo update if needed if( userinfo->modified ) { BF_WriteByte( &cls.netchan.message, clc_userinfo ); BF_WriteString( &cls.netchan.message, Cvar_Userinfo( )); } if( send_command ) { int outgoing_sequence; if( cl_cmdrate->integer > 0 ) cls.nextcmdtime = host.realtime + ( 1.0f / cl_cmdrate->value ); else cls.nextcmdtime = host.realtime; // always able to send right away if( cls.lastoutgoingcommand == -1 ) { outgoing_sequence = cls.netchan.outgoing_sequence; cls.lastoutgoingcommand = cls.netchan.outgoing_sequence; } else outgoing_sequence = cls.lastoutgoingcommand + 1; // begin a client move command BF_WriteByte( &buf, clc_move ); // save the position for a checksum byte key = BF_GetRealBytesWritten( &buf ); BF_WriteByte( &buf, 0 ); // write packet lossage percentation BF_WriteByte( &buf, cls.packet_loss ); // say how many backups we'll be sending BF_WriteByte( &buf, numbackup ); // how many real commands have queued up newcmds = ( cls.netchan.outgoing_sequence - cls.lastoutgoingcommand ); // put an upper/lower bound on this newcmds = bound( 0, newcmds, MAX_TOTAL_CMDS ); if( cls.state == ca_connected ) newcmds = 0; BF_WriteByte( &buf, newcmds ); numcmds = newcmds + numbackup; from = -1; for( i = numcmds - 1; i >= 0; i-- ) { cmdnumber = ( cls.netchan.outgoing_sequence - i ) & CL_UPDATE_MASK; to = cmdnumber; CL_WriteUsercmd( &buf, from, to ); from = to; if( BF_CheckOverflow( &buf )) Host_Error( "CL_Move, overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER ); } // calculate a checksum over the move commands size = BF_GetRealBytesWritten( &buf ) - key - 1; buf.pData[key] = CRC32_BlockSequence( buf.pData + key + 1, size, cls.netchan.outgoing_sequence ); // message we are constructing. i = cls.netchan.outgoing_sequence & CL_UPDATE_MASK; // determine if we need to ask for a new set of delta's. if( cl.validsequence && (cls.state == ca_active) && !( cls.demorecording && cls.demowaiting )) { cl.delta_sequence = cl.validsequence; BF_WriteByte( &buf, clc_delta ); BF_WriteByte( &buf, cl.validsequence & 0xFF ); } else { // request delta compression of entities cl.delta_sequence = -1; } if( BF_CheckOverflow( &buf )) { Host_Error( "CL_Move, overflowed command buffer (%i bytes)\n", MAX_CMD_BUFFER ); } // remember outgoing command that we are sending cls.lastoutgoingcommand = cls.netchan.outgoing_sequence; // composite the rest of the datagram.. if( BF_GetNumBitsWritten( &cls.datagram ) <= BF_GetNumBitsLeft( &buf )) BF_WriteBits( &buf, BF_GetData( &cls.datagram ), BF_GetNumBitsWritten( &cls.datagram )); BF_Clear( &cls.datagram ); // deliver the message (or update reliable) Netchan_Transmit( &cls.netchan, BF_GetNumBytesWritten( &buf ), BF_GetData( &buf )); } else { // increment sequence number so we can detect that we've held back packets. cls.netchan.outgoing_sequence++; } if( cls.demorecording ) { // Back up one because we've incremented outgoing_sequence each frame by 1 unit cmdnumber = ( cls.netchan.outgoing_sequence - 1 ) & CL_UPDATE_MASK; CL_WriteDemoUserCmd( cmdnumber ); } // update download/upload slider. Netchan_UpdateProgress( &cls.netchan ); }
/* ================== V_AddViewWeapon ================== */ void V_AddViewWeapon (float bob) { vec3_t forward, up; entity_t ent; extern cvar_t scr_fov; // FIXME, move the statics to a structure like cl static int oldweapon, curframe, oldframe; static double start_lerp_time; if (!cl_drawgun.value || (cl_drawgun.value == 2 && scr_fov.value > 90) || view_message.flags & (PF_GIB|PF_DEAD) || !Cam_DrawViewModel()) return; memset (&ent, 0, sizeof(ent)); if ((unsigned int)cl.stats[STAT_WEAPON] >= MAX_MODELS) Host_Error ("STAT_WEAPON >= MAX_MODELS"); ent.model = cl.model_precache[cl.stats[STAT_WEAPON]]; if (!ent.model) return; ent.frame = view_message.weaponframe; ent.colormap = 0; ent.renderfx = RF_WEAPONMODEL; if (cl.stats[STAT_WEAPON] != oldweapon) { oldweapon = cl.stats[STAT_WEAPON]; curframe = -1; start_lerp_time = -1; } if (ent.frame != curframe) { oldframe = curframe; curframe = ent.frame; start_lerp_time = cl.time; } ent.oldframe = oldframe; ent.backlerp = 1 - (cl.time - start_lerp_time)*10; ent.backlerp = bound (0, ent.backlerp, 1); // if (r_lerpmuzzlehack.value && cl.modelinfos[cl.stats[STAT_WEAPON]] != mi_no_lerp_hack) // ent.renderfx |= RF_LIMITLERP; if (cl.stats[STAT_ITEMS] & IT_INVISIBILITY) ent.alpha = 128; ent.angles[YAW] = r_refdef2.viewangles[YAW]; ent.angles[PITCH] = -r_refdef2.viewangles[PITCH]; ent.angles[ROLL] = r_refdef2.viewangles[ROLL]; AngleVectors (r_refdef2.viewangles, forward, NULL, up); VectorCopy (r_refdef2.vieworg, ent.origin); if (cl_bobmodel.value) { // calculate for swinging gun model // the gun bobs when running on the ground, but doesn't bob when you're in the air. // Sajt: I tried to smooth out the transitions between bob and no bob, which works // for the most part, but for some reason when you go through a message trigger or // pick up an item or anything like that it will momentarily jolt the gun. vec3_t forward, right, up; static double lastongroundtime = 0; double xyspeed; float bspeed; float s, t; xyspeed = sqrt(cl.simvel[0] * cl.simvel[0] + cl.simvel[1] * cl.simvel[1]); s = cl.time * cl_bobmodel_speed.value; if (cl.onground) { lastongroundtime = cl.time; if (cl.time - cl.landtime < 0.2) { // just hit the ground, speed the bob back up over the next 0.2 seconds t = cl.time - cl.landtime; t = bound(0, t, 0.2); t *= 5; } else { t = 1; } } else { // recently left the ground, slow the bob down over the next 0.2 seconds t = cl.time - lastongroundtime; t = 0.2 - bound(0, t, 0.2); t *= 5; } bspeed = bound (0, xyspeed, 400) * 0.01f; AngleVectors (r_refdef2.viewangles, forward, right, up); bob = bspeed * cl_bobmodel_side.value * sin (s) * t; VectorMA (ent.origin, bob, right, ent.origin); bob = bspeed * cl_bobmodel_up.value * cos (s * 2) * t; VectorMA (ent.origin, bob, up, ent.origin); } // fudge position around to keep amount of weapon visible // roughly equal with different FOV if (scr_viewsize.value == 110) VectorMA (ent.origin, 1, up, ent.origin); else if (scr_viewsize.value == 100) VectorMA (ent.origin, 2, up, ent.origin); else if (scr_viewsize.value == 90) VectorMA (ent.origin, 1, up, ent.origin); else if (scr_viewsize.value == 80) VectorMA (ent.origin, 0.5, up, ent.origin); V_AddEntity (&ent); }
edict_t *EDICT_NUM(int n) { if (n < 0 || n >= MAX_EDICTS) Host_Error ("EDICT_NUM: bad number %i", n); return (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size); }
/* ============= R_DrawStretchRaw ============= */ void R_DrawStretchRaw( float x, float y, float w, float h, int cols, int rows, const byte *data, qboolean dirty ) { byte *raw = NULL; gltexture_t *tex; if( !GL_Support( GL_ARB_TEXTURE_NPOT_EXT )) { int width = 1, height = 1; // check the dimensions width = NearestPOW( cols, true ); height = NearestPOW( rows, false ); if( cols != width || rows != height ) { raw = GL_ResampleTexture( data, cols, rows, width, height, false ); cols = width; rows = height; } } else { raw = (byte *)data; } if( cols > glConfig.max_2d_texture_size ) Host_Error( "R_DrawStretchRaw: size %i exceeds hardware limits\n", cols ); if( rows > glConfig.max_2d_texture_size ) Host_Error( "R_DrawStretchRaw: size %i exceeds hardware limits\n", rows ); pglDisable( GL_BLEND ); pglDisable( GL_ALPHA_TEST ); pglTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); tex = R_GetTexture( tr.cinTexture ); GL_Bind( XASH_TEXTURE0, tr.cinTexture ); if( cols == tex->width && rows == tex->height ) { if( dirty ) { pglTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, cols, rows, GL_BGRA, GL_UNSIGNED_BYTE, raw ); } } else { tex->width = cols; tex->height = rows; if( dirty ) { pglTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, cols, rows, 0, GL_BGRA, GL_UNSIGNED_BYTE, raw ); } } pglBegin( GL_QUADS ); pglTexCoord2f( 0, 0 ); pglVertex2f( x, y ); pglTexCoord2f( 1, 0 ); pglVertex2f( x + w, y ); pglTexCoord2f( 1, 1 ); pglVertex2f( x + w, y + h ); pglTexCoord2f( 0, 1 ); pglVertex2f( x, y + h ); pglEnd(); }
/* ================ ED_LoadFromFile The entities are directly placed in the array, rather than allocated with ED_Alloc, because otherwise an error loading the map would have entity number references out of order. Creates a server's entity / program execution context by parsing textual entity definitions out of an ent file. Used for both fresh maps and savegame loads. A fresh map would also need to call ED_CallSpawnFunctions () to let the objects initialize themselves. ================ */ void ED_LoadFromFile (char *data) { edict_t *ent; int inhibit; dfunction_t *func; ent = NULL; inhibit = 0; pr_global_struct->time = sv.time; // parse ents while (1) { // parse the opening brace data = COM_Parse (data); if (!data) break; if (com_token[0] != '{') Host_Error ("ED_LoadFromFile: found %s when expecting {",com_token); if (!ent) ent = EDICT_NUM(0); else ent = ED_Alloc (); data = ED_ParseEdict (data, ent); // remove things from different skill levels or deathmatch if (deathmatch.value) { if (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH)) { ED_Free (ent); inhibit++; continue; } } else if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY)) || (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM)) || (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) ) { ED_Free (ent); inhibit++; continue; } // // immediately call spawn function // if (!ent->v.classname) { Com_Printf ("No classname for:\n"); ED_Print (ent); ED_Free (ent); continue; } // look for the spawn function func = ED_FindFunction ( PR_GetString(ent->v.classname) ); if (!func) { Com_Printf ("No spawn function for:\n"); ED_Print (ent); ED_Free (ent); continue; } pr_global_struct->self = EDICT_TO_PROG(ent); PR_ExecuteProgram (func - pr_functions); SV_FlushSignon(); } Com_DPrintf ("%i entities inhibited\n", inhibit); }
/* ==================== PR_ExecuteProgram ==================== */ void PR_ExecuteProgram (func_t fnum) { eval_t *a, *b, *c; int s; dstatement_t *st; dfunction_t *f, *newf; int runaway; int i; edict_t *ed; int exitdepth; eval_t *ptr; if (!fnum || fnum >= progs->numfunctions) { if (pr_global_struct->self) ED_Print (PROG_TO_EDICT(pr_global_struct->self)); Host_Error ("PR_ExecuteProgram: NULL function"); } f = &pr_functions[fnum]; runaway = 100000; pr_trace = false; // make a stack frame exitdepth = pr_depth; s = PR_EnterFunction (f); while (1) { s++; // next statement st = &pr_statements[s]; a = (eval_t *)&pr_globals[st->a]; b = (eval_t *)&pr_globals[st->b]; c = (eval_t *)&pr_globals[st->c]; if (!--runaway) PR_RunError ("runaway loop error"); pr_xfunction->profile++; pr_xstatement = s; if (pr_trace) PR_PrintStatement (st); switch (st->op) { case OP_ADD_F: c->_float = a->_float + b->_float; break; case OP_ADD_V: c->vector[0] = a->vector[0] + b->vector[0]; c->vector[1] = a->vector[1] + b->vector[1]; c->vector[2] = a->vector[2] + b->vector[2]; break; case OP_SUB_F: c->_float = a->_float - b->_float; break; case OP_SUB_V: c->vector[0] = a->vector[0] - b->vector[0]; c->vector[1] = a->vector[1] - b->vector[1]; c->vector[2] = a->vector[2] - b->vector[2]; break; case OP_MUL_F: c->_float = a->_float * b->_float; break; case OP_MUL_V: c->_float = a->vector[0]*b->vector[0] + a->vector[1]*b->vector[1] + a->vector[2]*b->vector[2]; break; case OP_MUL_FV: c->vector[0] = a->_float * b->vector[0]; c->vector[1] = a->_float * b->vector[1]; c->vector[2] = a->_float * b->vector[2]; break; case OP_MUL_VF: c->vector[0] = b->_float * a->vector[0]; c->vector[1] = b->_float * a->vector[1]; c->vector[2] = b->_float * a->vector[2]; break; case OP_DIV_F: c->_float = a->_float / b->_float; break; case OP_BITAND: c->_float = (int)a->_float & (int)b->_float; break; case OP_BITOR: c->_float = (int)a->_float | (int)b->_float; break; case OP_GE: c->_float = a->_float >= b->_float; break; case OP_LE: c->_float = a->_float <= b->_float; break; case OP_GT: c->_float = a->_float > b->_float; break; case OP_LT: c->_float = a->_float < b->_float; break; case OP_AND: c->_float = a->_float && b->_float; break; case OP_OR: c->_float = a->_float || b->_float; break; case OP_NOT_F: c->_float = !a->_float; break; case OP_NOT_V: c->_float = !a->vector[0] && !a->vector[1] && !a->vector[2]; break; case OP_NOT_S: c->_float = !a->string || !pr_strings[a->string]; break; case OP_NOT_FNC: c->_float = !a->function; break; case OP_NOT_ENT: c->_float = (PROG_TO_EDICT(a->edict) == sv.edicts); break; case OP_EQ_F: c->_float = a->_float == b->_float; break; case OP_EQ_V: c->_float = (a->vector[0] == b->vector[0]) && (a->vector[1] == b->vector[1]) && (a->vector[2] == b->vector[2]); break; case OP_EQ_S: c->_float = !strcmp(pr_strings+a->string,pr_strings+b->string); break; case OP_EQ_E: c->_float = a->_int == b->_int; break; case OP_EQ_FNC: c->_float = a->function == b->function; break; case OP_NE_F: c->_float = a->_float != b->_float; break; case OP_NE_V: c->_float = (a->vector[0] != b->vector[0]) || (a->vector[1] != b->vector[1]) || (a->vector[2] != b->vector[2]); break; case OP_NE_S: c->_float = strcmp(pr_strings+a->string,pr_strings+b->string); break; case OP_NE_E: c->_float = a->_int != b->_int; break; case OP_NE_FNC: c->_float = a->function != b->function; break; //================== case OP_STORE_F: case OP_STORE_ENT: case OP_STORE_FLD: // integers case OP_STORE_S: case OP_STORE_FNC: // pointers b->_int = a->_int; break; case OP_STORE_V: b->vector[0] = a->vector[0]; b->vector[1] = a->vector[1]; b->vector[2] = a->vector[2]; break; case OP_STOREP_F: case OP_STOREP_ENT: case OP_STOREP_FLD: // integers case OP_STOREP_S: case OP_STOREP_FNC: // pointers ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->_int = a->_int; break; case OP_STOREP_V: ptr = (eval_t *)((byte *)sv.edicts + b->_int); ptr->vector[0] = a->vector[0]; ptr->vector[1] = a->vector[1]; ptr->vector[2] = a->vector[2]; break; case OP_ADDRESS: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif if (ed == (edict_t *)sv.edicts && sv.state == ss_active) PR_RunError ("assignment to world entity"); c->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts; break; case OP_LOAD_F: case OP_LOAD_FLD: case OP_LOAD_ENT: case OP_LOAD_S: case OP_LOAD_FNC: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->_int = a->_int; break; case OP_LOAD_V: ed = PROG_TO_EDICT(a->edict); #ifdef PARANOID NUM_FOR_EDICT(ed); // make sure it's in range #endif a = (eval_t *)((int *)&ed->v + b->_int); c->vector[0] = a->vector[0]; c->vector[1] = a->vector[1]; c->vector[2] = a->vector[2]; break; //================== case OP_IFNOT: if (!a->_int) s += st->b - 1; // offset the s++ break; case OP_IF: if (a->_int) s += st->b - 1; // offset the s++ break; case OP_GOTO: s += st->a - 1; // offset the s++ break; case OP_CALL0: case OP_CALL1: case OP_CALL2: case OP_CALL3: case OP_CALL4: case OP_CALL5: case OP_CALL6: case OP_CALL7: case OP_CALL8: pr_argc = st->op - OP_CALL0; if (!a->function) PR_RunError ("NULL function"); newf = &pr_functions[a->function]; if (newf->first_statement < 0) { // negative statements are built in functions i = -newf->first_statement; if (i >= pr_numbuiltins) PR_RunError ("Bad builtin call number"); pr_builtins[i] (); break; } s = PR_EnterFunction (newf); break; case OP_DONE: case OP_RETURN: pr_globals[OFS_RETURN] = pr_globals[st->a]; pr_globals[OFS_RETURN+1] = pr_globals[st->a+1]; pr_globals[OFS_RETURN+2] = pr_globals[st->a+2]; s = PR_LeaveFunction (); if (pr_depth == exitdepth) return; // all done break; case OP_STATE: ed = PROG_TO_EDICT(pr_global_struct->self); #ifdef FPS_20 ed->v.nextthink = pr_global_struct->time + 0.05; #else ed->v.nextthink = pr_global_struct->time + 0.1; #endif if (a->_float != ed->v.frame) { ed->v.frame = a->_float; } ed->v.think = b->function; break; default: PR_RunError ("Bad opcode %i", st->op); } } }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i, j, k; int EntityCount = 0; int EntitySize = 0; int before; static double lasttime; static qboolean packet_loss = false; entity_t *ent; short RemovePlace, OrigPlace, NewPlace, AddedIndex; int sc1, sc2; byte test; float compangles[2][3]; vec3_t deltaangles; // // if recording demos, copy the message out // if (net_message.cursize > LastServerMessageSize) { LastServerMessageSize = net_message.cursize; } if (cl_shownet.integer == 1) { Con_Printf ("Time: %2.2f Pck: %i ", realtime - lasttime, net_message.cursize); lasttime = realtime; } else if (cl_shownet.integer == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); while (1) { if (msg_badread) Host_Error ("%s: Bad server message", __thisfunc__); cmd = MSG_ReadByte (); if (cmd == -1) { if (cl_shownet.integer == 1) Con_Printf ("Ent: %i (%i bytes)",EntityCount,EntitySize); 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) { before = msg_readcount; SHOWNET("fast update"); if (packet_loss) CL_ParseUpdate2 (cmd&127); else CL_ParseUpdate (cmd&127); EntityCount++; EntitySize += msg_readcount - before + 1; continue; } if (cmd < NUM_SVC_STRINGS) // else, it'll hit the illegible message below { SHOWNET(svc_strings[cmd]); } // other commands switch (cmd) { default: // CL_DumpPacket (); Host_Error ("%s: Illegible server message %d", __thisfunc__, cmd); 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: cl_protocol = MSG_ReadLong (); switch (cl_protocol) { case PROTOCOL_RAVEN_111: case PROTOCOL_RAVEN_112: case PROTOCOL_UQE_113: Con_Printf ("Server using protocol %i\n", cl_protocol); break; default: Host_Error ("%s: Server is protocol %i instead of %i or %i", __thisfunc__, cl_protocol, PROTOCOL_RAVEN_112, PROTOCOL_UQE_113); } break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); break; case svc_print: if (intro_playing) MSG_ReadString (); else Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: SCR_CenterPrint (MSG_ReadString ()); break; case svc_stufftext: stufftext_frame = host_framecount; // allow full frame update // on stuff messages. Pa3PyX 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: for (i = 0; i < 3; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setangle_interpolate: compangles[0][0] = MSG_ReadAngle(); compangles[0][1] = MSG_ReadAngle(); compangles[0][2] = MSG_ReadAngle(); for (i = 0; i < 3; i++) { compangles[1][i] = cl.viewangles[i]; for (j = 0; j < 2; j++) {//standardize both old and new angles to +-180 if (compangles[j][i] >= 360) compangles[j][i] -= 360*((int)(compangles[j][i]/360)); else if (compangles[j][i] <= 360) compangles[j][i] += 360*(1+(int)(-compangles[j][i]/360)); if (compangles[j][i] > 180) compangles[j][i] = -360 + compangles[j][i]; else if (compangles[j][i] < -180) compangles[j][i] = 360 + compangles[j][i]; } //get delta deltaangles[i] = compangles[0][i] - compangles[1][i]; //cap delta to <=180,>=-180 if (deltaangles[i] > 180) deltaangles[i] += -360; else if (deltaangles[i] < -180) deltaangles[i] += 360; //add the delta cl.viewangles[i]+=(deltaangles[i]/8);//8 step interpolation //cap newangles to +-180 if (cl.viewangles[i] >= 360) cl.viewangles[i] -= 360*((int)(cl.viewangles[i]/360)); else if (cl.viewangles[i] <= 360) cl.viewangles[i] += 360*(1+(int)(-cl.viewangles[i]/360)); if (cl.viewangles[i] > 180) cl.viewangles[i] += -360; else if (cl.viewangles[i] < -180) cl.viewangles[i] += 360; } break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); q_strlcpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING); cl_lightstyle[i].length = strlen(cl_lightstyle[i].map); break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_sound_update_pos: {//FIXME: put a field on the entity that lists the channels //it should update when it moves- if a certain flag //is on the ent, this update_channels field could //be set automatically by each sound and stopSound //called for this ent? vec3_t pos; int channel, ent_num; channel = MSG_ReadShort (); ent_num = channel >> 3; channel &= 7; if (ent_num > MAX_EDICTS) Host_Error ("svc_sound_update_pos: ent = %i", ent_num); for (i = 0; i < 3; i++) pos[i] = MSG_ReadCoord (); S_UpdateSoundPos (ent_num, channel, pos); } 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 ("%s: svc_updatename > MAX_CLIENTS", __thisfunc__); q_strlcpy (cl.scores[i].name, MSG_ReadString(), MAX_SCOREBOARDNAME); break; case svc_updateclass: Sbar_Changed(); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("%s: svc_updateclass > MAX_CLIENTS", __thisfunc__); cl.scores[i].playerclass = (float)MSG_ReadByte(); CL_NewTranslation(i); // update the color break; case svc_updatefrags: Sbar_Changed(); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("%s: svc_updatefrags > MAX_CLIENTS", __thisfunc__); cl.scores[i].frags = MSG_ReadShort (); break; case svc_update_kingofhill: sv_kingofhill = MSG_ReadShort() - 1; break; case svc_updatecolors: Sbar_Changed(); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("%s: svc_updatecolors > MAX_CLIENTS", __thisfunc__); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_particle2: R_ParseParticleEffect2 (); break; case svc_particle3: R_ParseParticleEffect3 (); break; case svc_particle4: R_ParseParticleEffect4 (); 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_raineffect: CL_ParseRainEffect(); break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); VID_HandlePause (true); } else { CDAudio_Resume (); VID_HandlePause (false); } 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]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong (); break; case svc_spawnstaticsound: CL_ParseStaticSound (); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if (q_strcasecmp(bgmtype.string,"cd") == 0) { if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) CDAudio_Play ((byte)cls.forcetrack, true); else CDAudio_Play ((byte)cl.cdtrack, true); } else CDAudio_Stop(); break; case svc_midi_name: q_strlcpy (cl.midi_name, MSG_ReadString(), sizeof(cl.midi_name)); if (q_strcasecmp(bgmtype.string,"midi") == 0) MIDI_Play(cl.midi_name); else MIDI_Stop(); break; case svc_toggle_statbar: break; case svc_intermission: cl.intermission = MSG_ReadByte(); if (oem.integer && cl.intermission == 1) cl.intermission = 9; // skip intermissions while recording demos in single // player games, but stop recording at ending scenes. // skip intermissions when playing demos. if (cls.demorecording) { // 5: finale for the demo version // 6, 7, 8: eidolon end-1 to end-3 // 9: finale for the bundle version // 10: praevus ending if (sv.active && svs.maxclients == 1 && (cl.intermission < 5 || cl.intermission > 10)) { cl.intermission = 0; demohack = true; Cbuf_AddText("+attack\n"); // HACK !.. break; } CL_Stop_f (); } else if (cls.demoplayback) { cl.intermission = 0; break; } 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_sellscreen: Cmd_ExecuteString ("help", src_command); break; */ case svc_set_view_flags: cl.viewent.drawflags |= MSG_ReadByte(); break; case svc_clear_view_flags: cl.viewent.drawflags &= ~MSG_ReadByte(); break; case svc_start_effect: CL_ParseEffect(); break; case svc_end_effect: CL_EndEffect(); break; case svc_plaque: CL_Plaque(); break; case svc_particle_explosion: CL_ParticleExplosion(); break; case svc_set_view_tint: i = MSG_ReadByte(); cl.viewent.colorshade = i; break; case svc_reference: packet_loss = false; cl.last_frame = cl.current_frame; cl.last_sequence = cl.current_sequence; cl.current_frame = MSG_ReadByte(); cl.current_sequence = MSG_ReadByte(); if (cl.need_build == 2) { // Con_Printf("CL: NB2 CL(%d,%d) R(%d)\n", cl.current_sequence, cl.current_frame,cl.reference_frame); cl.frames[0].count = cl.frames[1].count = cl.frames[2].count = 0; cl.need_build = 1; cl.reference_frame = cl.current_frame; } else if (cl.last_sequence != cl.current_sequence) { // Con_Printf("CL: Sequence CL(%d,%d) R(%d)\n", cl.current_sequence, cl.current_frame,cl.reference_frame); if (cl.reference_frame >= 1 && cl.reference_frame <= MAX_FRAMES) { RemovePlace = OrigPlace = NewPlace = AddedIndex = 0; for (i = 0; i < cl.num_entities; i++) { if (RemovePlace >= cl.NumToRemove || cl.RemoveList[RemovePlace] != i) { if (NewPlace < cl.frames[1].count && cl.frames[1].states[NewPlace].index == i) { cl.frames[2].states[AddedIndex] = cl.frames[1].states[NewPlace]; AddedIndex++; cl.frames[2].count++; } else if (OrigPlace < cl.frames[0].count && cl.frames[0].states[OrigPlace].index == i) { cl.frames[2].states[AddedIndex] = cl.frames[0].states[OrigPlace]; AddedIndex++; cl.frames[2].count++; } } else RemovePlace++; if (cl.frames[0].states[OrigPlace].index == i) OrigPlace++; if (cl.frames[1].states[NewPlace].index == i) NewPlace++; } cl.frames[0] = cl.frames[2]; } cl.frames[1].count = cl.frames[2].count = 0; cl.need_build = 1; cl.reference_frame = cl.current_frame; } else { // Con_Printf("CL: Normal CL(%d,%d) R(%d)\n", cl.current_sequence, cl.current_frame,cl.reference_frame); cl.need_build = 0; } for (i = 1, ent = cl_entities+1; i < cl.num_entities; i++, ent++) { ent->baseline.flags &= ~BE_ON; } for (i = 0; i < cl.frames[0].count; i++) { ent = CL_EntityNum (cl.frames[0].states[i].index); ent->model = cl.model_precache[cl.frames[0].states[i].modelindex]; ent->baseline.flags |= BE_ON; } break; case svc_clear_edicts: j = MSG_ReadByte(); if (cl.need_build) { cl.NumToRemove = j; } for (i = 0; i < j; i++) { k = MSG_ReadShort(); if (cl.need_build) cl.RemoveList[i] = k; ent = CL_EntityNum (k); ent->baseline.flags &= ~BE_ON; } break; case svc_update_inv: sc1 = sc2 = 0; test = MSG_ReadByte(); if (test & 1) sc1 |= ((int)MSG_ReadByte()); if (test & 2) sc1 |= ((int)MSG_ReadByte())<<8; if (test & 4) sc1 |= ((int)MSG_ReadByte())<<16; if (test & 8) sc1 |= ((int)MSG_ReadByte())<<24; if (test & 16) sc2 |= ((int)MSG_ReadByte()); if (test & 32) sc2 |= ((int)MSG_ReadByte())<<8; if (test & 64) sc2 |= ((int)MSG_ReadByte())<<16; if (test & 128) sc2 |= ((int)MSG_ReadByte())<<24; if (sc1 & SC1_HEALTH) cl.v.health = MSG_ReadShort(); if (sc1 & SC1_LEVEL) cl.v.level = MSG_ReadByte(); if (sc1 & SC1_INTELLIGENCE) cl.v.intelligence = MSG_ReadByte(); if (sc1 & SC1_WISDOM) cl.v.wisdom = MSG_ReadByte(); if (sc1 & SC1_STRENGTH) cl.v.strength = MSG_ReadByte(); if (sc1 & SC1_DEXTERITY) cl.v.dexterity = MSG_ReadByte(); if (sc1 & SC1_WEAPON) cl.v.weapon = MSG_ReadByte(); if (sc1 & SC1_BLUEMANA) cl.v.bluemana = MSG_ReadByte(); if (sc1 & SC1_GREENMANA) cl.v.greenmana = MSG_ReadByte(); if (sc1 & SC1_EXPERIENCE) cl.v.experience = MSG_ReadLong(); if (sc1 & SC1_CNT_TORCH) cl.v.cnt_torch = MSG_ReadByte(); if (sc1 & SC1_CNT_H_BOOST) cl.v.cnt_h_boost = MSG_ReadByte(); if (sc1 & SC1_CNT_SH_BOOST) cl.v.cnt_sh_boost = MSG_ReadByte(); if (sc1 & SC1_CNT_MANA_BOOST) cl.v.cnt_mana_boost = MSG_ReadByte(); if (sc1 & SC1_CNT_TELEPORT) cl.v.cnt_teleport = MSG_ReadByte(); if (sc1 & SC1_CNT_TOME) cl.v.cnt_tome = MSG_ReadByte(); if (sc1 & SC1_CNT_SUMMON) cl.v.cnt_summon = MSG_ReadByte(); if (sc1 & SC1_CNT_INVISIBILITY) cl.v.cnt_invisibility = MSG_ReadByte(); if (sc1 & SC1_CNT_GLYPH) cl.v.cnt_glyph = MSG_ReadByte(); if (sc1 & SC1_CNT_HASTE) cl.v.cnt_haste = MSG_ReadByte(); if (sc1 & SC1_CNT_BLAST) cl.v.cnt_blast = MSG_ReadByte(); if (sc1 & SC1_CNT_POLYMORPH) cl.v.cnt_polymorph = MSG_ReadByte(); if (sc1 & SC1_CNT_FLIGHT) cl.v.cnt_flight = MSG_ReadByte(); if (sc1 & SC1_CNT_CUBEOFFORCE) cl.v.cnt_cubeofforce = MSG_ReadByte(); if (sc1 & SC1_CNT_INVINCIBILITY) cl.v.cnt_invincibility = MSG_ReadByte(); if (sc1 & SC1_ARTIFACT_ACTIVE) cl.v.artifact_active = MSG_ReadFloat(); if (sc1 & SC1_ARTIFACT_LOW) cl.v.artifact_low = MSG_ReadFloat(); if (sc1 & SC1_MOVETYPE) cl.v.movetype = MSG_ReadByte(); if (sc1 & SC1_CAMERAMODE) cl.v.cameramode = MSG_ReadByte(); if (sc1 & SC1_HASTED) cl.v.hasted = MSG_ReadFloat(); if (sc1 & SC1_INVENTORY) cl.v.inventory = MSG_ReadByte(); if (sc1 & SC1_RINGS_ACTIVE) cl.v.rings_active = MSG_ReadFloat(); if (sc2 & SC2_RINGS_LOW) cl.v.rings_low = MSG_ReadFloat(); if (sc2 & SC2_AMULET) cl.v.armor_amulet = MSG_ReadByte(); if (sc2 & SC2_BRACER) cl.v.armor_bracer = MSG_ReadByte(); if (sc2 & SC2_BREASTPLATE) cl.v.armor_breastplate = MSG_ReadByte(); if (sc2 & SC2_HELMET) cl.v.armor_helmet = MSG_ReadByte(); if (sc2 & SC2_FLIGHT_T) cl.v.ring_flight = MSG_ReadByte(); if (sc2 & SC2_WATER_T) cl.v.ring_water = MSG_ReadByte(); if (sc2 & SC2_TURNING_T) cl.v.ring_turning = MSG_ReadByte(); if (sc2 & SC2_REGEN_T) cl.v.ring_regeneration = MSG_ReadByte(); if (sc2 & SC2_HASTE_T) cl.v.haste_time = MSG_ReadFloat(); if (sc2 & SC2_TOME_T) cl.v.tome_time = MSG_ReadFloat(); if (sc2 & SC2_PUZZLE1) q_snprintf(cl.puzzle_pieces[0], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE2) q_snprintf(cl.puzzle_pieces[1], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE3) q_snprintf(cl.puzzle_pieces[2], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE4) q_snprintf(cl.puzzle_pieces[3], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE5) q_snprintf(cl.puzzle_pieces[4], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE6) q_snprintf(cl.puzzle_pieces[5], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE7) q_snprintf(cl.puzzle_pieces[6], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE8) q_snprintf(cl.puzzle_pieces[7], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_MAXHEALTH) cl.v.max_health = MSG_ReadShort(); if (sc2 & SC2_MAXMANA) cl.v.max_mana = MSG_ReadByte(); if (sc2 & SC2_FLAGS) cl.v.flags = MSG_ReadFloat(); // SC2_OBJ, SC2_OBJ2: mission pack objectives // With protocol 18 (PROTOCOL_RAVEN_111), these // bits get set somehow (?!): let's avoid them. if (cl_protocol > PROTOCOL_RAVEN_111) { if (sc2 & SC2_OBJ) cl.info_mask = MSG_ReadLong(); if (sc2 & SC2_OBJ2) cl.info_mask2 = MSG_ReadLong(); } if ((sc1 & SC1_STAT_BAR) || (sc2 & SC2_STAT_BAR)) Sbar_Changed(); if ((sc1 & SC1_INV) || (sc2 & SC2_INV)) SB_InvChanged(); break; case svc_mod_name: case svc_skybox: MSG_ReadString(); Con_DPrintf ("Ignored server msg %d (%s)\n", cmd, svc_strings[cmd]); break; } } }
/* =============== PR_LoadProgs =============== */ void PR_LoadProgs (void) { int i; // flush the non-C variable lookup cache for (i = 0; i < GEFV_CACHESIZE; i++) gefvCache[i].field[0] = 0; CRC_Init (&pr_crc); progs = (dprograms_t *)COM_LoadHunkFile ("progs.dat", NULL); if (!progs) Host_Error ("PR_LoadProgs: couldn't load progs.dat"); Con_DPrintf ("Programs occupy %iK.\n", com_filesize/1024); for (i = 0; i < com_filesize; i++) CRC_ProcessByte (&pr_crc, ((byte *)progs)[i]); // byte swap the header for (i = 0; i < (int) sizeof(*progs) / 4; i++) ((int *)progs)[i] = LittleLong ( ((int *)progs)[i] ); if (progs->version != PROG_VERSION) Host_Error ("progs.dat has wrong version number (%i should be %i)", progs->version, PROG_VERSION); if (progs->crc != PROGHEADER_CRC) Host_Error ("progs.dat system vars have been modified, progdefs.h is out of date"); pr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions); pr_strings = (char *)progs + progs->ofs_strings; if (progs->ofs_strings + progs->numstrings >= com_filesize) Host_Error ("progs.dat strings go past end of file\n"); // initialize the strings pr_numknownstrings = 0; pr_maxknownstrings = 0; pr_stringssize = progs->numstrings; if (pr_knownstrings) Z_Free ((void *)pr_knownstrings); pr_knownstrings = NULL; PR_SetEngineString(""); pr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs); pr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs); pr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements); pr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals); pr_globals = (float *)pr_global_struct; // byte swap the lumps for (i = 0; i < progs->numstatements; i++) { pr_statements[i].op = LittleShort(pr_statements[i].op); pr_statements[i].a = LittleShort(pr_statements[i].a); pr_statements[i].b = LittleShort(pr_statements[i].b); pr_statements[i].c = LittleShort(pr_statements[i].c); } for (i = 0; i < progs->numfunctions; i++) { pr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement); pr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start); pr_functions[i].s_name = LittleLong (pr_functions[i].s_name); pr_functions[i].s_file = LittleLong (pr_functions[i].s_file); pr_functions[i].numparms = LittleLong (pr_functions[i].numparms); pr_functions[i].locals = LittleLong (pr_functions[i].locals); } for (i = 0; i < progs->numglobaldefs; i++) { pr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type); pr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs); pr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name); } pr_alpha_supported = false; //johnfitz for (i = 0; i < progs->numfielddefs; i++) { pr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type); if (pr_fielddefs[i].type & DEF_SAVEGLOBAL) Host_Error ("PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); pr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs); pr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name); //johnfitz -- detect alpha support in progs.dat if (!strcmp(pr_strings + pr_fielddefs[i].s_name,"alpha")) pr_alpha_supported = true; //johnfitz } for (i = 0; i < progs->numglobals; i++) ((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]); pr_edict_size = progs->entityfields * 4 + sizeof(edict_t) - sizeof(entvars_t); // round off to next highest whole word address (esp for Alpha) // this ensures that pointers in the engine data area are always // properly aligned pr_edict_size += sizeof(void *) - 1; pr_edict_size &= ~(sizeof(void *) - 1); }
/* ================== 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. ================== */ static void CL_ParseUpdate (int bits) { int i; model_t *model; int modnum; qboolean forcelink; entity_t *ent; int num; entity_state2_t *ref_ent,*set_ent,build_ent,dummy; 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); } if (bits & U_MOREBITS2) { i = MSG_ReadByte (); bits |= (i<<16); } if (bits & U_LONGENTITY) num = MSG_ReadShort (); else num = MSG_ReadByte (); ent = CL_EntityNum (num); ent->baseline.flags |= BE_ON; /* if (num == 2) { FH = fopen("c.txt","r+"); fseek(FH,0,SEEK_END); } */ ref_ent = NULL; for (i = 0; i < cl.frames[0].count; i++) if (cl.frames[0].states[i].index == num) { ref_ent = &cl.frames[0].states[i]; // if (num == 2) fprintf(FH,"Found Reference\n"); break; } if (!ref_ent) { ref_ent = &build_ent; build_ent.index = num; build_ent.origin[0] = ent->baseline.origin[0]; build_ent.origin[1] = ent->baseline.origin[1]; build_ent.origin[2] = ent->baseline.origin[2]; build_ent.angles[0] = ent->baseline.angles[0]; build_ent.angles[1] = ent->baseline.angles[1]; build_ent.angles[2] = ent->baseline.angles[2]; build_ent.modelindex = ent->baseline.modelindex; build_ent.frame = ent->baseline.frame; build_ent.colormap = ent->baseline.colormap; build_ent.skin = ent->baseline.skin; build_ent.effects = ent->baseline.effects; build_ent.scale = ent->baseline.scale; build_ent.drawflags = ent->baseline.drawflags; build_ent.abslight = ent->baseline.abslight; } if (cl.need_build) { // new sequence, first valid frame set_ent = &cl.frames[1].states[cl.frames[1].count]; cl.frames[1].count++; } else set_ent = &dummy; if (bits & U_CLEAR_ENT) { memset(ent, 0, sizeof(entity_t)); memset(ref_ent, 0, sizeof(*ref_ent)); ref_ent->index = num; } *set_ent = *ref_ent; if (ent->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_ReadShort (); if (modnum >= MAX_MODELS) Host_Error ("%s: bad modnum", __thisfunc__); } else modnum = ref_ent->modelindex; model = cl.model_precache[modnum]; set_ent->modelindex = modnum; if (model != ent->model) { ent->model = model; // automatic animation (torches, etc) can be either all together // or randomized if (model) { if (model->synctype == ST_RAND) ent->syncbase = rand() * (1.0 / RAND_MAX);//(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) set_ent->frame = ent->frame = MSG_ReadByte (); else ent->frame = ref_ent->frame; if (bits & U_COLORMAP) set_ent->colormap = i = MSG_ReadByte(); else i = ref_ent->colormap; if (num && num <= cl.maxclients) ent->colormap = ent->sourcecolormap = cl.scores[num-1].translations; else ent->sourcecolormap = vid.colormap; #ifdef GLQUAKE // ent->colormap = vid.colormap; #endif if (!i) { ent->colorshade = i; ent->colormap = ent->sourcecolormap; } else { ent->colorshade = i; #ifdef GLQUAKE // ent->colormap = vid.colormap; ent->colormap = globalcolormap; #else ent->colormap = globalcolormap; #endif } if (bits & U_SKIN) { set_ent->skin = ent->skinnum = MSG_ReadByte(); set_ent->drawflags = ent->drawflags = MSG_ReadByte(); } else { ent->skinnum = ref_ent->skin; ent->drawflags = ref_ent->drawflags; } if (bits & U_EFFECTS) { set_ent->effects = ent->effects = MSG_ReadByte(); // if (num == 2) // fprintf(FH,"Read effects %d\n",set_ent->effects); } else { ent->effects = ref_ent->effects; //if (num == 2) // fprintf(FH,"restored effects %d\n",ref_ent->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) { set_ent->origin[0] = ent->msg_origins[0][0] = MSG_ReadCoord (); //if (num == 2) // fprintf(FH,"Read origin[0] %f\n",set_ent->angles[0]); } else { ent->msg_origins[0][0] = ref_ent->origin[0]; //if (num == 2) // fprintf(FH,"Restored origin[0] %f\n",ref_ent->angles[0]); } if (bits & U_ANGLE1) set_ent->angles[0] = ent->msg_angles[0][0] = MSG_ReadAngle(); else ent->msg_angles[0][0] = ref_ent->angles[0]; if (bits & U_ORIGIN2) set_ent->origin[1] = ent->msg_origins[0][1] = MSG_ReadCoord (); else ent->msg_origins[0][1] = ref_ent->origin[1]; if (bits & U_ANGLE2) set_ent->angles[1] = ent->msg_angles[0][1] = MSG_ReadAngle(); else ent->msg_angles[0][1] = ref_ent->angles[1]; if (bits & U_ORIGIN3) set_ent->origin[2] = ent->msg_origins[0][2] = MSG_ReadCoord (); else ent->msg_origins[0][2] = ref_ent->origin[2]; if (bits & U_ANGLE3) set_ent->angles[2] = ent->msg_angles[0][2] = MSG_ReadAngle(); else ent->msg_angles[0][2] = ref_ent->angles[2]; if (bits & U_SCALE) { set_ent->scale = ent->scale = MSG_ReadByte(); set_ent->abslight = ent->abslight = MSG_ReadByte(); } else { ent->scale = ref_ent->scale; ent->abslight = ref_ent->abslight; } if (bits & U_NOLERP) ent->forcelink = true; 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; } // if (sv.active || num != 2) // return; }
void Mod_IDS2_Load(dp_model_t *mod, void *buffer, void *bufferend) { int i, version; qboolean fullbright; const dsprite2_t *pinqsprite; skinframe_t *skinframe; float modelradius; int texflags = (r_mipsprites.integer ? TEXF_MIPMAP : 0) | TEXF_ISSPRITE | TEXF_PICMIP | TEXF_COMPRESS | TEXF_ALPHA | TEXF_CLAMP; loadmodel->modeldatatypestring = "SPR2"; loadmodel->type = mod_sprite; loadmodel->DrawSky = NULL; loadmodel->Draw = R_Model_Sprite_Draw; loadmodel->DrawDepth = NULL; loadmodel->CompileShadowVolume = NULL; loadmodel->DrawShadowVolume = NULL; loadmodel->DrawLight = NULL; loadmodel->DrawAddWaterPlanes = NULL; pinqsprite = (dsprite2_t *)buffer; version = LittleLong(pinqsprite->version); if (version != SPRITE2_VERSION) Host_Error("Mod_IDS2_Load: %s has wrong version number (%i should be 2 (quake 2)", loadmodel->name, version); loadmodel->numframes = LittleLong (pinqsprite->numframes); if (loadmodel->numframes < 1) Host_Error ("Mod_IDS2_Load: Invalid # of frames: %d", loadmodel->numframes); loadmodel->sprite.sprnum_type = SPR_VP_PARALLEL; loadmodel->synctype = ST_SYNC; // LordHavoc: hack to allow sprites to be non-fullbright fullbright = true; for (i = 0;i < MAX_QPATH && loadmodel->name[i];i++) if (loadmodel->name[i] == '!') fullbright = false; loadmodel->animscenes = (animscene_t *)Mem_Alloc(loadmodel->mempool, sizeof(animscene_t) * loadmodel->numframes); loadmodel->sprite.sprdata_frames = (mspriteframe_t *)Mem_Alloc(loadmodel->mempool, sizeof(mspriteframe_t) * loadmodel->numframes); loadmodel->num_textures = loadmodel->numframes; loadmodel->num_texturesperskin = 1; loadmodel->data_textures = (texture_t *)Mem_Alloc(loadmodel->mempool, sizeof(texture_t) * loadmodel->num_textures); modelradius = 0; for (i = 0;i < loadmodel->numframes;i++) { int origin[2], x, y, width, height; const dsprite2frame_t *pinframe; mspriteframe_t *sprframe; dpsnprintf(loadmodel->animscenes[i].name, sizeof(loadmodel->animscenes[i].name), "frame %i", i); loadmodel->animscenes[i].firstframe = i; loadmodel->animscenes[i].framecount = 1; loadmodel->animscenes[i].framerate = 10; loadmodel->animscenes[i].loop = true; pinframe = &pinqsprite->frames[i]; origin[0] = LittleLong (pinframe->origin_x); origin[1] = LittleLong (pinframe->origin_y); width = LittleLong (pinframe->width); height = LittleLong (pinframe->height); sprframe = &loadmodel->sprite.sprdata_frames[i]; // note that sp2 origin[0] is positive, where as it is negative in // spr/spr32/hlspr sprframe->left = -origin[0]; sprframe->right = -origin[0] + width; sprframe->up = origin[1]; sprframe->down = origin[1] - height; x = (int)max(sprframe->left * sprframe->left, sprframe->right * sprframe->right); y = (int)max(sprframe->up * sprframe->up, sprframe->down * sprframe->down); if (modelradius < x + y) modelradius = x + y; } if (cls.state != ca_dedicated) { for (i = 0;i < loadmodel->numframes;i++) { const dsprite2frame_t *pinframe; pinframe = &pinqsprite->frames[i]; if (!(skinframe = R_SkinFrame_LoadExternal(pinframe->name, texflags, false))) { Con_Printf("Mod_IDS2_Load: failed to load %s", pinframe->name); skinframe = R_SkinFrame_LoadMissing(); } Mod_SpriteSetupTexture(&loadmodel->data_textures[i], skinframe, fullbright, false); } } modelradius = sqrt(modelradius); for (i = 0;i < 3;i++) { loadmodel->normalmins[i] = loadmodel->yawmins[i] = loadmodel->rotatedmins[i] = -modelradius; loadmodel->normalmaxs[i] = loadmodel->yawmaxs[i] = loadmodel->rotatedmaxs[i] = modelradius; } loadmodel->radius = modelradius; loadmodel->radius2 = modelradius * modelradius; loadmodel->surfmesh.isanimated = loadmodel->numframes > 1 || loadmodel->animscenes[0].framecount > 1; }