/* ================ SV_CreateBaseline Entity baselines are used to compress the update messages to the clients -- only the fields that differ from the baseline will be transmitted ================ */ void SV_CreateBaseline (void) { int i; edict_t *svent; int entnum; for (entnum = 0; entnum < sv.num_edicts ; entnum++) { svent = EDICT_NUM(entnum); if (svent->free) continue; // create baselines for all player slots, // and any other edict that has a visible model if (entnum > MAX_CLIENTS && !svent->v.modelindex) continue; // // create entity baseline // VectorCopy (svent->v.origin, svent->baseline.origin); VectorCopy (svent->v.angles, svent->baseline.angles); svent->baseline.frame = svent->v.frame; svent->baseline.skinnum = svent->v.skin; if (entnum > 0 && entnum <= MAX_CLIENTS) { svent->baseline.colormap = entnum; svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); } else { svent->baseline.colormap = 0; svent->baseline.modelindex = SV_ModelIndex(PR_GetString(svent->v.model)); } CRITICAL_MESSAGE(sv_signon_lock, SV_SIGNON_LOCK, 0, { // // flush the signon message out to a seperate buffer if // nearly full // SV_FlushSignon (); // // add to the message // MSG_WriteByte (&sv.signon,svc_spawnbaseline); MSG_WriteShort (&sv.signon,entnum); MSG_WriteByte (&sv.signon, svent->baseline.modelindex); MSG_WriteByte (&sv.signon, svent->baseline.frame); MSG_WriteByte (&sv.signon, svent->baseline.colormap); MSG_WriteByte (&sv.signon, svent->baseline.skinnum); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); } });
void Server_MakeStatic(ServerEntity_t *ent) { int i,bits=0; if(ent->alpha == ENTALPHA_ZERO) { ED_Free(ent); return; } if(SV_ModelIndex(ent->v.model) & 0xFF00) bits |= B_LARGEMODEL; if((int)(ent->v.frame) & 0xFF00) bits |= B_LARGEFRAME; if(ent->alpha != ENTALPHA_DEFAULT) bits |= B_ALPHA; if(bits) { MSG_WriteByte(&sv.signon, SVC_SPAWNSTATIC2); MSG_WriteByte(&sv.signon, bits); } else MSG_WriteByte(&sv.signon, svc_spawnstatic); if(bits & B_LARGEMODEL) MSG_WriteShort(&sv.signon, SV_ModelIndex(ent->v.model)); else MSG_WriteByte(&sv.signon, SV_ModelIndex(ent->v.model)); if(bits & B_LARGEFRAME) MSG_WriteShort(&sv.signon,ent->v.frame); else MSG_WriteByte(&sv.signon,ent->v.frame); MSG_WriteByte(&sv.signon,ent->Model.fScale); MSG_WriteByte(&sv.signon,ent->v.colormap); MSG_WriteByte(&sv.signon,ent->Model.iSkin); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&sv.signon, ent->v.origin[i]); MSG_WriteAngle(&sv.signon, ent->v.angles[i]); } if (bits & B_ALPHA) MSG_WriteByte (&sv.signon, ent->alpha); ED_Free (ent); }
/* ================ SV_CreateBaseline Entity baselines are used to compress the update messages to the clients -- only the fields that differ from the baseline will be transmitted ================ */ void SV_CreateBaseline (void) { int i, entnum, max_edicts; edict_t *svent; // because baselines for entnum >= 512 don't make sense // FIXME, translate baselines nums as well as packet entity nums? max_edicts = min (sv.num_edicts, 512); for (entnum = 0; entnum < max_edicts ; entnum++) { svent = EDICT_NUM(entnum); if (svent->free) continue; // create baselines for all player slots, and any other edict that has a visible model if (entnum > MAX_CLIENTS && !svent->v.modelindex) continue; // create entity baseline VectorCopy (svent->v.origin, svent->baseline.origin); VectorCopy (svent->v.angles, svent->baseline.angles); svent->baseline.frame = svent->v.frame; svent->baseline.skinnum = svent->v.skin; if (entnum > 0 && entnum <= MAX_CLIENTS) { svent->baseline.colormap = entnum; svent->baseline.modelindex = SV_ModelIndex("progs/player.mdl"); } else { svent->baseline.colormap = 0; svent->baseline.modelindex = SV_ModelIndex(PR_GetString(svent->v.model)); } // flush the signon message out to a separate buffer if // nearly full SV_FlushSignon (); // add to the message MSG_WriteByte (&sv.signon,svc_spawnbaseline); MSG_WriteShort (&sv.signon,entnum); MSG_WriteByte (&sv.signon, svent->baseline.modelindex); MSG_WriteByte (&sv.signon, svent->baseline.frame); MSG_WriteByte (&sv.signon, svent->baseline.colormap); MSG_WriteByte (&sv.signon, svent->baseline.skinnum); for (i = 0; i < 3; i++) { MSG_WriteCoord(&sv.signon, svent->baseline.origin[i]); MSG_WriteAngle(&sv.signon, svent->baseline.angles[i]); } } }
/* * The old weapon has been dropped all * the way, so make the new one current */ void ChangeWeapon(edict_t *ent) { int i; if (!ent) { return; } if (ent->client->grenade_time) { ent->client->grenade_time = level.time; ent->client->weapon_sound = 0; weapon_grenade_fire(ent, false); ent->client->grenade_time = 0; } ent->client->pers.lastweapon = ent->client->pers.weapon; ent->client->pers.weapon = ent->client->newweapon; ent->client->newweapon = NULL; ent->client->machinegun_shots = 0; /* set visible model */ if (ent->s.modelindex == 255) { if (ent->client->pers.weapon) { i = ((ent->client->pers.weapon->weapmodel & 0xff) << 8); } else { i = 0; } ent->s.skinnum = (ent - g_edicts - 1) | i; } if (ent->client->pers.weapon && ent->client->pers.weapon->ammo) { ent->client->ammo_index = ITEM_INDEX(FindItem(ent->client->pers.weapon->ammo)); } else { ent->client->ammo_index = 0; } if (!ent->client->pers.weapon) { /* dead */ ent->client->ps.gunindex = 0; return; } ent->client->weaponstate = WEAPON_ACTIVATING; ent->client->ps.gunframe = 0; ent->client->ps.gunindex = SV_ModelIndex(ent->client->pers.weapon->view_model); ent->client->anim_priority = ANIM_PAIN; if (ent->client->ps.pmove.pm_flags & PMF_DUCKED) { ent->s.frame = FRAME_crpain1; ent->client->anim_end = FRAME_crpain4; } else { ent->s.frame = FRAME_pain301; ent->client->anim_end = FRAME_pain304; } }
/** * @note Also sets mins and maxs for inline bmodels * @sa CM_InlineModel */ static void SV_SetModel (edict_t * ent, const char *name) { if (!name) Com_Error(ERR_DROP, "SV_SetModel: NULL"); ent->modelindex = SV_ModelIndex(name); /* if it is an inline model, get the size information for it */ if (name[0] == '*') { const cBspModel_t *mod = CM_InlineModel(&sv->mapTiles, name); /* Copy model mins and maxs to entity */ VectorCopy(mod->mins, ent->mins); VectorCopy(mod->maxs, ent->maxs); /* This is to help the entity collision code out */ /* Copy entity origin and angles to model*/ CM_SetInlineModelOrientation(&sv->mapTiles, name, ent->origin, ent->angles); } }
static int LoadGamestate (const char *level, const char *startspot, int ClientsMode) { FILE *f; char mapname[MAX_QPATH]; float playtime, sk; char str[32768]; const char *start; int i, r; edict_t *ent; int entnum; int version; // float spawn_parms[NUM_SPAWN_PARMS]; qboolean auto_correct = false; if (ClientsMode == 1) /* for RestoreClients() only: map must be active */ { if (!sv.active) { Con_Printf ("%s: server not active\n", __thisfunc__); return -1; } FS_MakePath_BUF (FS_USERDIR, &r, savename, sizeof(savename), "clients.gip"); if (r) { Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__); return -1; } } else { FS_MakePath_VABUF (FS_USERDIR, &r, savename, sizeof(savename), "%s.gip", level); if (r) { Host_Error("%s: %d: string buffer overflow!", __thisfunc__, __LINE__); return -1; } if (ClientsMode != 2 && ClientsMode != 3) Con_Printf ("Loading game from %s...\n", savename); } f = fopen (savename, "r"); if (!f) { if (ClientsMode == 2) Con_Printf ("%s: ERROR: couldn't open savefile\n", __thisfunc__); return -1; } fscanf (f, "%i\n", &version); if (version != SAVEGAME_VERSION) { fclose (f); Con_Printf ("Savegame is version %i, not %i\n", version, SAVEGAME_VERSION); return -1; } if (ClientsMode != 1) { fscanf (f, "%s\n", str); // for (i = 0; i < NUM_SPAWN_PARMS; i++) // fscanf (f, "%f\n", &spawn_parms[i]); fscanf (f, "%f\n", &sk); Cvar_SetValue ("skill", sk); fscanf (f, "%s\n", mapname); fscanf (f, "%f\n", &playtime); SV_SpawnServer (mapname, startspot); if (!sv.active) { fclose (f); Con_Printf ("Couldn't load map\n"); return -1; } // load the light styles for (i = 0; i < MAX_LIGHTSTYLES; i++) { fscanf (f, "%s\n", str); sv.lightstyles[i] = (const char *)Hunk_Strdup (str, "lightstyles"); } SV_LoadEffects (f); } // load the edicts out of the savegame file while (!feof(f)) { fscanf (f, "%i\n", &entnum); for (i = 0; i < (int) sizeof(str) - 1; i++) { r = fgetc (f); if (r == EOF || !r) break; str[i] = r; if (r == '}') { i++; break; } } if (i == (int) sizeof(str) - 1) { fclose (f); Host_Error ("%s: Loadgame buffer overflow", __thisfunc__); } str[i] = 0; start = str; start = COM_Parse(str); if (!com_token[0]) break; // end of file if (strcmp(com_token,"{")) { fclose (f); Host_Error ("%s: First token isn't a brace", __thisfunc__); } // parse an edict if (entnum == -1) { ED_ParseGlobals (start); // Need to restore this *sv_globals.startspot = PR_SetEngineString(sv.startspot); } else { ent = EDICT_NUM(entnum); /* default to active edict: ED_ParseEdict() set it * to free if it really is free. cf. ED_Write() */ ent->free = false; /* ED_ParseEdict() will always memset ent->v to 0, * because SaveGamestate() doesn't write entnum 0 */ ED_ParseEdict (start, ent); if (ClientsMode == 1 || ClientsMode == 2 || ClientsMode == 3) ent->v.stats_restored = true; // link it into the bsp tree if (!ent->free) { if (entnum >= sv.num_edicts) { /* This is necessary to restore "generated" edicts which were * not available during the map parsing by ED_LoadFromFile(). * This includes items dropped by monsters, items "dropped" by * an item_spawner such as the "prizes" in the Temple of Mars * (romeric5), a health sphere generated by the Crusader's * Holy Strength ability, or a respawning-candidate killed * monster in the expansion pack's nightmare mode. -- THOMAS */ /* Moved this into the if (!ent->free) construct: less debug * chatter. Even if this skips a free edict in between, the * skipped free edict wasn't parsed by ED_LoadFromFile() and * it will remain as a freed edict. (There is no harm because * we are dealing with extra edicts not originally present in * the map.) -- O.S. */ Con_DPrintf("%s: entnum %d >= sv.num_edicts (%d)\n", __thisfunc__, entnum, sv.num_edicts); sv.num_edicts = entnum + 1; } SV_LinkEdict (ent, false); if (ent->v.modelindex && ent->v.model) { i = SV_ModelIndex(PR_GetString(ent->v.model)); if (i != ent->v.modelindex) { ent->v.modelindex = i; auto_correct = true; } } } } } fclose (f); if (ClientsMode == 0) { sv.time = playtime; sv.paused = true; *sv_globals.serverflags = svs.serverflags; RestoreClients (0); } else if (ClientsMode == 2) { sv.time = playtime; } else if (ClientsMode == 3) { sv.time = playtime; *sv_globals.serverflags = svs.serverflags; RestoreClients (3); } if (ClientsMode != 1 && auto_correct) { Con_DPrintf("*** Auto-corrected model indexes!\n"); } // for (i = 0; i < NUM_SPAWN_PARMS; i++) // svs.clients->spawn_parms[i] = spawn_parms[i]; return 0; }
/*QUAKED worldspawn (0 0 0) ? * * Only used for the world. * "sky" environment map name * "skyaxis" vector axis for rotating sky * "skyrotate" speed of rotation in degrees/second * "sounds" music cd track number * "gravity" 800 is default gravity * "message" text to print at user logon */ void SP_worldspawn(edict_t *ent) { if (!ent) { return; } ent->movetype = MOVETYPE_PUSH; ent->solid = SOLID_BSP; ent->inuse = true; /* since the world doesn't use G_Spawn() */ ent->s.modelindex = 1; /* world model is always index 1 */ /* --------------- */ /* reserve some spots for dead player bodies for coop / deathmatch */ InitBodyQue(); /* set configstrings for items */ SetItemNames(); if (st.nextmap) { strcpy(level.nextmap, st.nextmap); } /* make some data visible to the server */ if (ent->message && ent->message[0]) { PF_Configstring(CS_NAME, ent->message); Q_strlcpy(level.level_name, ent->message, sizeof(level.level_name)); } else { Q_strlcpy(level.level_name, level.mapname, sizeof(level.level_name)); } if (st.sky && st.sky[0]) { PF_Configstring(CS_SKY, st.sky); } else { PF_Configstring(CS_SKY, "unit1_"); } PF_Configstring(CS_SKYROTATE, va("%f", st.skyrotate)); PF_Configstring(CS_SKYAXIS, va("%f %f %f", st.skyaxis[0], st.skyaxis[1], st.skyaxis[2])); PF_Configstring(CS_CDTRACK, va("%i", ent->sounds)); PF_Configstring(CS_MAXCLIENTS, va("%i", (int) (maxclients->value))); /* status bar program */ if (deathmatch->value) { PF_Configstring(CS_STATUSBAR, deathmatch_statusbar); } else { PF_Configstring(CS_STATUSBAR, singleplayer_statusbar); } /* --------------- */ level.pic_health = SV_ImageIndex("icon_health"); SV_ImageIndex("stat_flash"); if (!st.gravity) { Cvar_Set("sv_gravity", "800"); } else { Cvar_Set("sv_gravity", st.gravity); } snd_fry = SV_SoundIndex("player/fry.wav"); /* standing in lava / slime */ PrecacheItem(FindItem("Blaster")); SV_SoundIndex("player/lava1.wav"); SV_SoundIndex("player/lava2.wav"); SV_SoundIndex("misc/pc_up.wav"); SV_SoundIndex("misc/talk1.wav"); SV_SoundIndex("misc/udeath.wav"); /* gibs */ SV_SoundIndex("items/respawn1.wav"); /* sexed sounds */ SV_SoundIndex("*death1.wav"); SV_SoundIndex("*death2.wav"); SV_SoundIndex("*death3.wav"); SV_SoundIndex("*death4.wav"); SV_SoundIndex("*fall1.wav"); SV_SoundIndex("*fall2.wav"); SV_SoundIndex("*gurp1.wav"); /* drowning damage */ SV_SoundIndex("*gurp2.wav"); SV_SoundIndex("*jump1.wav"); /* player jump */ SV_SoundIndex("*pain25_1.wav"); SV_SoundIndex("*pain25_2.wav"); SV_SoundIndex("*pain50_1.wav"); SV_SoundIndex("*pain50_2.wav"); SV_SoundIndex("*pain75_1.wav"); SV_SoundIndex("*pain75_2.wav"); SV_SoundIndex("*pain100_1.wav"); SV_SoundIndex("*pain100_2.wav"); /* sexed models: THIS ORDER MUST MATCH THE DEFINES IN g_local.h you can add more, max 19 (pete change)these models are only loaded in coop or deathmatch. not singleplayer. */ if (coop->value || deathmatch->value) { SV_ModelIndex("#w_blaster.md2"); SV_ModelIndex("#w_shotgun.md2"); SV_ModelIndex("#w_sshotgun.md2"); SV_ModelIndex("#w_machinegun.md2"); SV_ModelIndex("#w_chaingun.md2"); SV_ModelIndex("#a_grenades.md2"); SV_ModelIndex("#w_glauncher.md2"); SV_ModelIndex("#w_rlauncher.md2"); SV_ModelIndex("#w_hyperblaster.md2"); SV_ModelIndex("#w_railgun.md2"); } /* ------------------- */ SV_SoundIndex("player/gasp1.wav"); /* gasping for air */ SV_SoundIndex("player/gasp2.wav"); /* head breaking surface, not gasping */ SV_SoundIndex("player/watr_in.wav"); /* feet hitting water */ SV_SoundIndex("player/watr_out.wav"); /* feet leaving water */ SV_SoundIndex("player/watr_un.wav"); /* head going underwater */ SV_SoundIndex("player/u_breath1.wav"); SV_SoundIndex("player/u_breath2.wav"); SV_SoundIndex("items/pkup.wav"); /* bonus item pickup */ SV_SoundIndex("world/land.wav"); /* landing thud */ SV_SoundIndex("misc/h2ohit1.wav"); /* landing splash */ SV_SoundIndex("items/damage.wav"); SV_SoundIndex("items/protect.wav"); SV_SoundIndex("items/protect4.wav"); SV_SoundIndex("weapons/noammo.wav"); SV_SoundIndex("infantry/inflies1.wav"); sm_meat_index = SV_ModelIndex("models/objects/gibs/sm_meat/tris.md2"); SV_ModelIndex("models/objects/gibs/arm/tris.md2"); SV_ModelIndex("models/objects/gibs/bone/tris.md2"); SV_ModelIndex("models/objects/gibs/bone2/tris.md2"); SV_ModelIndex("models/objects/gibs/chest/tris.md2"); SV_ModelIndex("models/objects/gibs/skull/tris.md2"); SV_ModelIndex("models/objects/gibs/head2/tris.md2"); /* Setup light animation tables. 'a' is total darkness, 'z' is doublebright. */ /* 0 normal */ PF_Configstring(CS_LIGHTS + 0, "m"); /* 1 FLICKER (first variety) */ PF_Configstring(CS_LIGHTS + 1, "mmnmmommommnonmmonqnmmo"); /* 2 SLOW STRONG PULSE */ PF_Configstring(CS_LIGHTS + 2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba"); /* 3 CANDLE (first variety) */ PF_Configstring(CS_LIGHTS + 3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg"); /* 4 FAST STROBE */ PF_Configstring(CS_LIGHTS + 4, "mamamamamama"); /* 5 GENTLE PULSE 1 */ PF_Configstring(CS_LIGHTS + 5, "jklmnopqrstuvwxyzyxwvutsrqponmlkj"); /* 6 FLICKER (second variety) */ PF_Configstring(CS_LIGHTS + 6, "nmonqnmomnmomomno"); /* 7 CANDLE (second variety) */ PF_Configstring(CS_LIGHTS + 7, "mmmaaaabcdefgmmmmaaaammmaamm"); /* 8 CANDLE (third variety) */ PF_Configstring(CS_LIGHTS + 8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa"); /* 9 SLOW STROBE (fourth variety) */ PF_Configstring(CS_LIGHTS + 9, "aaaaaaaazzzzzzzz"); /* 10 FLUORESCENT FLICKER */ PF_Configstring(CS_LIGHTS + 10, "mmamammmmammamamaaamammma"); /* 11 SLOW PULSE NOT FADE TO BLACK */ PF_Configstring(CS_LIGHTS + 11, "abcdefghijklmnopqrrqponmlkjihgfedcba"); /* styles 32-62 are assigned by the light program for switchable lights */ /* 63 testing */ PF_Configstring(CS_LIGHTS + 63, "a"); }