/* ================== SV_StartParticle Make sure the event gets sent to all clients ================== */ void SV_StartParticle(vec3_t org, vec3_t dir, int color, int count) { int i, v; if (sv.datagram.cursize > MAX_DATAGRAM-16) { return; } MSG_WriteByte(&sv.datagram, svc_particle); MSG_WriteCoord(&sv.datagram, org[0]); MSG_WriteCoord(&sv.datagram, org[1]); MSG_WriteCoord(&sv.datagram, org[2]); for (i=0 ; i<3 ; i++) { v = dir[i]*16; if (v > 127) { v = 127; } else if (v < -128) { v = -128; } MSG_WriteChar(&sv.datagram, v); } MSG_WriteByte(&sv.datagram, count); MSG_WriteByte(&sv.datagram, color); }
void ClientReliableWrite_Coord(client_t *cl, float f) { if (cl->num_backbuf) { MSG_WriteCoord(&cl->backbuf, f); ClientReliable_FinishWrite(cl); } else MSG_WriteCoord(&cl->netchan.message, f); }
// 2000-05-02 NVS SVC by Maddes void NVS_WriteCoord (int dest, float f, sizebuf_t *sb) { int i; switch (dest) { case MSG_INIT: if (sv.nvs_msgsignon->conversion_tab[sv.nvs_msgserver->numwrites-sv.nvs_msgwrites]) { if (sb) // special signon { MSG_WriteCoord(sb, f); } else { MSG_WriteCoord (&sv.signon, f); } } break; case MSG_ONE: case MSG_ALL: case MSG_BROADCAST: for (i=0 ; i<svs.maxclients ; i++) { if (NVS_CheckClient(&svs.clients[i])) { if (dest == MSG_BROADCAST) // unreliable { MSG_WriteCoord (&svs.clients[i].datagram, f); } else if (dest == MSG_ONE && sb) // special reliable MSG_ONE { MSG_WriteCoord (sb, f); } else // reliable MSG_ONE, MSG_ALL { MSG_WriteCoord (&svs.clients[i].message, f); } } } break; default: Host_Error ("NVS_WriteCoord: bad destination"); break; } NVS_CheckCounter(); }
void Game_AmbientSound(MathVectorf_t *vPosition,const char *cPath,int iVolume,int iAttenuation) { char **cCheck; int i,iSoundNumber; bool bLarge = false; for(iSoundNumber = 0,cCheck = sv.sound_precache; *cCheck; cCheck++,iSoundNumber++) if(!strcmp(*cCheck,cPath)) break; if(!*cCheck) Console_ErrorMessage(false,(char*)cPath,"Sound was not registered."); if(iSoundNumber > 255) bLarge = true; if(bLarge) MSG_WriteByte(&sv.signon,svc_spawnstaticsound2); else MSG_WriteByte(&sv.signon,svc_spawnstaticsound); for(i = 0; i < 3; i++) MSG_WriteCoord(&sv.signon,vPosition[i]); if(bLarge) MSG_WriteShort(&sv.signon,iSoundNumber); else MSG_WriteByte(&sv.signon,iSoundNumber); MSG_WriteByte(&sv.signon,iVolume); MSG_WriteByte(&sv.signon,iAttenuation*64); }
/* ================ 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 Cam_Pos_Set(float x, float y, float z) { extern qbool clpred_newpos; cl.simorg[0] = x; cl.simorg[1] = y; cl.simorg[2] = z; clpred_newpos = true; VectorCopy (cl.simorg, cl.frames[cl.validsequence & UPDATE_MASK].playerstate[cl.playernum].origin); if (cls.state >= ca_active && !cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, cl.simorg[0]); MSG_WriteCoord (&cls.netchan.message, cl.simorg[1]); MSG_WriteCoord (&cls.netchan.message, cl.simorg[2]); } }
/* ================== SV_StartSound Each entity can have eight independant sound sources, like voice, weapon, feet, etc. Channel 0 is an auto-allocate channel, the others override anything allready running on that entity/channel pair. An attenuation of 0 will play full volume everywhere in the level. Larger attenuations will drop off. (max 4 attenuation) ================== */ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, float attenuation) { int sound_num; int field_mask; int i; int ent; if (volume < 0 || volume > 255) Sys_Error ("SV_StartSound: volume = %i", volume); if (attenuation < 0 || attenuation > 4) Sys_Error ("SV_StartSound: attenuation = %f", attenuation); if (channel < 0 || channel > 7) Sys_Error ("SV_StartSound: channel = %i", channel); if (sv.datagram.cursize > MAX_DATAGRAM-16) return; // find precache number for sound for (sound_num=1 ; sound_num<MAX_SOUNDS && sv.sound_precache[sound_num] ; sound_num++) if (!strcmp(sample, sv.sound_precache[sound_num])) break; if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] ) { Con_Printf ("SV_StartSound: %s not precacheed\n", sample); return; } ent = NUM_FOR_EDICT(entity); channel = (ent<<3) | channel; field_mask = 0; if (volume != DEFAULT_SOUND_PACKET_VOLUME) field_mask |= SND_VOLUME; if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) field_mask |= SND_ATTENUATION; // directed messages go only to the entity the are targeted on MSG_WriteByte (&sv.datagram, svc_sound); MSG_WriteByte (&sv.datagram, field_mask); if (field_mask & SND_VOLUME) MSG_WriteByte (&sv.datagram, volume); if (field_mask & SND_ATTENUATION) MSG_WriteByte (&sv.datagram, attenuation*64); MSG_WriteShort (&sv.datagram, channel); MSG_WriteByte (&sv.datagram, sound_num); for (i=0 ; i<3 ; i++) MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i])); }
static void Cam_Pos_f (void) { extern qbool clpred_newpos; if (Cmd_Argc() == 1) { Com_Printf ("\"%s %s %s\"\n", myftos(cl.simorg[0]), myftos(cl.simorg[1]), myftos(cl.simorg[2])); return; } if (Cmd_Argc() == 2) { // cam_pos "x y z" --> cam_pos x y z Cmd_TokenizeString (va("cam_pos %s", Cmd_Argv(1))); } if (Cmd_Argc() != 4) { Com_Printf("usage:\n" "cam_pos - show current coordinates\n" "cam pos x y z - set new coordinates\n"); return; } if (!cls.demoplayback && !cl.spectator) return; cl.simorg[0] = Q_atof(Cmd_Argv(1)); cl.simorg[1] = Q_atof(Cmd_Argv(2)); cl.simorg[2] = Q_atof(Cmd_Argv(3)); clpred_newpos = true; VectorCopy (cl.simorg, cl.frames[cl.validsequence & UPDATE_MASK].playerstate[cl.playernum].origin); if (cls.state >= ca_active && !cls.demoplayback) { MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, cl.simorg[0]); MSG_WriteCoord (&cls.netchan.message, cl.simorg[1]); MSG_WriteCoord (&cls.netchan.message, cl.simorg[2]); } }
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_StartParticle Make sure the event gets sent to all clients ================== */ void SV_StartParticle (vec3_t org, vec3_t dir, int color, int count) { int i, v; // drop silently if there is no room if (sv.datagram.cursize > ((sv.protocol == PROTOCOL_NETQUAKE) ? 1024 : MAX_DATAGRAM) - 16) return; MSG_WriteByte (&sv.datagram, svc_particle); MSG_WriteCoord (&sv.datagram, org[0], sv.protocolflags); MSG_WriteCoord (&sv.datagram, org[1], sv.protocolflags); MSG_WriteCoord (&sv.datagram, org[2], sv.protocolflags); for (i=0 ; i<3 ; i++) { v = dir[i]*16; if (v > 127) v = 127; else if (v < -128) v = -128; MSG_WriteChar (&sv.datagram, v); } MSG_WriteByte (&sv.datagram, count); MSG_WriteByte (&sv.datagram, color); }
/* ================ 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]); } } }
void Particle(MathVector3f_t org, MathVector3f_t dir,float scale,char *texture,int count) { int i,v; if(sv.datagram.cursize > MAX_DATAGRAM-16) return; MSG_WriteByte(&sv.datagram,SVC_PARTICLE); for(i = 0; i < 3; i++) MSG_WriteCoord(&sv.datagram,org[i]); for(i=0 ; i<3 ; i++) { v = dir[i]*16; if (v > 127) v = 127; else if (v < -128) v = -128; MSG_WriteChar(&sv.datagram,v); } MSG_WriteFloat(&sv.datagram,scale); for(i = 0; i < MAX_EFFECTS; i++) if(gEffectTexture[i]) { if(!strcmp(texture,gEffectTexture[i]->name)) { MSG_WriteByte(&sv.datagram,i); break; } } else { // Otherwise give the texture the initial slot (this points to the notexture). MSG_WriteByte(&sv.datagram,0); break; } MSG_WriteByte(&sv.datagram,count); }
void SV_ParseMultiEffect (sizebuf_t *sb) { int idx, count; byte effect; vec3_t orig, vel; MultiEffectIdCount = 0; effect = G_FLOAT(OFS_PARM0); switch (effect) { case CE_HWRAVENPOWER: // need to set aside 3 effect ids MSG_WriteByte (sb, svc_multieffect); MSG_WriteByte (sb, effect); VectorCopy(G_VECTOR(OFS_PARM1), orig); MSG_WriteCoord(sb, orig[0]); MSG_WriteCoord(sb, orig[1]); MSG_WriteCoord(sb, orig[2]); VectorCopy(G_VECTOR(OFS_PARM2), vel); MSG_WriteCoord(sb, vel[0]); MSG_WriteCoord(sb, vel[1]); MSG_WriteCoord(sb, vel[2]); for (count = 0 ; count < 3 ; count++) { for (idx = 0 ; idx < MAX_EFFECTS ; idx++) { if (!sv.Effects[idx].type || (sv.Effects[idx].expire_time && sv.Effects[idx].expire_time <= sv.time)) break; } if (idx >= MAX_EFFECTS) { PR_RunError ("MAX_EFFECTS reached"); return; } MSG_WriteByte(sb, idx); sv.Effects[idx].type = CE_HWRAVENPOWER; VectorCopy(orig, sv.Effects[idx].ef.Missile.origin); VectorCopy(vel, sv.Effects[idx].ef.Missile.velocity); sv.Effects[idx].expire_time = sv.time + 10; MultiEffectIds[count] = idx; } break; default: PR_RunError ("%s: bad type", __thisfunc__); } }
static void VM_M_WriteCoord (prvm_prog_t *prog) { VM_SAFEPARMCOUNT(1, VM_M_WriteCoord); MSG_WriteCoord (VM_M_WriteDest(prog), PRVM_G_FLOAT(OFS_PARM0), sv.protocol); }
// Take over the user controls and track a player. // We find a nice position to watch the player and move there void Cam_Track(usercmd_t *cmd) { player_state_t *player, *self; frame_t *frame; vec3_t vec; if (!cl.spectator) { return; } // hack: save +movedown command cmddown = cmd->upmove < 0; // cl_hightrack if (cl_hightrack.value && !locked) { Cam_CheckHighTarget(); } if (!autocam || cls.state != ca_active) { return; } if (locked && (!cl.players[spec_track].name[0] || cl.players[spec_track].spectator)) { locked = false; // cl_hightrack if (cl_hightrack.value) { Cam_CheckHighTarget(); } else { Cam_Unlock(); } return; } frame = &cl.frames[cl.validsequence & UPDATE_MASK]; if (autocam && cls.mvdplayback) { if (ideal_track != spec_track && cls.realtime - last_lock > 0.1 && frame->playerstate[ideal_track].messagenum == cl.parsecount) { Cam_Lock(ideal_track); } if (frame->playerstate[spec_track].messagenum != cl.parsecount) { int i; for (i = 0; i < MAX_CLIENTS; i++) { if (frame->playerstate[i].messagenum == cl.parsecount) break; } if (i < MAX_CLIENTS) { Cam_Lock(i); } } } player = frame->playerstate + spec_track; self = frame->playerstate + cl.playernum; if (!locked || !Cam_IsVisible(player, desired_position)) { if (!locked || cls.realtime - cam_lastviewtime > 0.1) { if (!InitFlyby(self, player, true)) InitFlyby(self, player, false); cam_lastviewtime = cls.realtime; } } else { cam_lastviewtime = cls.realtime; } // couldn't track for some reason if (!locked || !autocam) return; if (cl_chasecam.value) { cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; #ifdef JSS_CAM if (!Cvar_Value ("cam_thirdperson")) #endif { VectorCopy(player->viewangles, cl.viewangles); } VectorCopy(player->origin, desired_position); if (memcmp(&desired_position, &self->origin, sizeof(desired_position)) != 0) { MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, desired_position[0]); MSG_WriteCoord (&cls.netchan.message, desired_position[1]); MSG_WriteCoord (&cls.netchan.message, desired_position[2]); // move there locally immediately VectorCopy(desired_position, self->origin); } } else { // Ok, move to our desired position and set our angles to view // the player VectorSubtract(desired_position, self->origin, vec); cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; if (VectorLength(vec) > 16) { // close enough? MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, desired_position[0]); MSG_WriteCoord (&cls.netchan.message, desired_position[1]); MSG_WriteCoord (&cls.netchan.message, desired_position[2]); } // move there locally immediately VectorCopy(desired_position, self->origin); VectorSubtract(player->origin, desired_position, vec); vectoangles(vec, cl.viewangles); cl.viewangles[0] = -cl.viewangles[0]; } }
// ZOID // // Take over the user controls and track a player. // We find a nice position to watch the player and move there void Cam_Track(usercmd_t *cmd) { player_state_t *player, *self; frame_t *frame; vec3_t vec; float len; if (!cl.spectator) return; if (cl_hightrack.value && !locked) Cam_CheckHighTarget(); if (!autocam || cls.state != ca_active) return; if (locked && (!cl.players[spec_track].name[0] || cl.players[spec_track].spectator)) { locked = false; if (cl_hightrack.value) Cam_CheckHighTarget(); else Cam_Unlock(); return; } frame = &cl.frames[cls.netchan.incoming_sequence & UPDATE_MASK]; player = frame->playerstate + spec_track; self = frame->playerstate + cl.playernum; if (!locked || !Cam_IsVisible(player, desired_position)) { if (!locked || realtime - cam_lastviewtime > 0.1) { if (!InitFlyby(self, player, true)) InitFlyby(self, player, false); cam_lastviewtime = realtime; } } else cam_lastviewtime = realtime; // couldn't track for some reason if (!locked || !autocam) return; if (cl_chasecam.value) { cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; VectorCopy(player->viewangles, cl.viewangles); VectorCopy(player->origin, desired_position); if (memcmp(&desired_position, &self->origin, sizeof(desired_position)) != 0) { MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, desired_position[0]); MSG_WriteCoord (&cls.netchan.message, desired_position[1]); MSG_WriteCoord (&cls.netchan.message, desired_position[2]); // move there locally immediately VectorCopy(desired_position, self->origin); } self->weaponframe = player->weaponframe; } else { // Ok, move to our desired position and set our angles to view // the player VectorSubtract(desired_position, self->origin, vec); len = vlen(vec); cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; if (len > 16) { // close enough? MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, desired_position[0]); MSG_WriteCoord (&cls.netchan.message, desired_position[1]); MSG_WriteCoord (&cls.netchan.message, desired_position[2]); } // move there locally immediately VectorCopy(desired_position, self->origin); VectorSubtract(player->origin, desired_position, vec); vectoangles(vec, cl.viewangles); cl.viewangles[0] = -cl.viewangles[0]; } }
/* ================== SV_StartSound Each entity can have eight independant sound sources, like voice, weapon, feet, etc. Channel 0 is an auto-allocate channel, the others override anything already running on that entity/channel pair. An attenuation of 0 will play full volume everywhere in the level. Larger attenuations will drop off. (max 4 attenuation) ================== */ void SV_StartSound (edict_t *entity, int channel, char *sample, int volume, float attenuation) { int sound_num; int field_mask; int i; int ent; static float lastmsg = 0; if (volume < 0 || volume > 255) { Con_Warning ("SV_StartSound: volume = %d, max = %d\n", volume, 255); volume = CLAMP(0, volume, 255); } if (attenuation < 0 || attenuation > 4) { Con_Warning ("SV_StartSound: attenuation = %f, max = %d\n", attenuation, 4); attenuation = CLAMP(0, attenuation, 4); } if (channel < 0 || channel > 7) { Con_Warning ("SV_StartSound: channel = %i, max = %d\n", channel, 7); channel = CLAMP(0, channel, 7); } // drop silently if there is no room if (sv.datagram.cursize > ((sv.protocol == PROTOCOL_NETQUAKE) ? 1024 : MAX_DATAGRAM) - 16) return; // find precache number for sound for (sound_num=1 ; sound_num<MAX_SOUNDS && sv.sound_precache[sound_num] ; sound_num++) if (!strcmp(sample, sv.sound_precache[sound_num])) break; if ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] ) { if (IsTimeout (&lastmsg, 2)) { // let's not upset and annoy the user Con_DPrintf ("SV_StartSound: %s not precacheed\n", sample); } return; } ent = NUM_FOR_EDICT(entity); field_mask = 0; if (volume != DEFAULT_SOUND_PACKET_VOLUME) field_mask |= SND_VOLUME; if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) field_mask |= SND_ATTENUATION; //johnfitz -- PROTOCOL_FITZQUAKE if (ent >= 8192) { if (sv.protocol == PROTOCOL_FITZQUAKE || sv.protocol == PROTOCOL_MARKV || sv.protocol == PROTOCOL_RMQ) field_mask |= SND_LARGEENTITY; else return; // don't send any info protocol can't support } if (sound_num >= 256 || channel >= 8) { if (sv.protocol == PROTOCOL_FITZQUAKE || sv.protocol == PROTOCOL_MARKV || sv.protocol == PROTOCOL_RMQ) field_mask |= SND_LARGESOUND; else return; // don't send any info protocol can't support } //johnfitz // directed messages go only to the entity the are targeted on MSG_WriteByte (&sv.datagram, svc_sound); MSG_WriteByte (&sv.datagram, field_mask); if (field_mask & SND_VOLUME) MSG_WriteByte (&sv.datagram, volume); if (field_mask & SND_ATTENUATION) MSG_WriteByte (&sv.datagram, attenuation*64); //johnfitz -- PROTOCOL_FITZQUAKE if (field_mask & SND_LARGEENTITY) { MSG_WriteShort (&sv.datagram, ent); MSG_WriteByte (&sv.datagram, channel); } else MSG_WriteShort (&sv.datagram, (ent<<3) | channel); if (field_mask & SND_LARGESOUND) MSG_WriteShort (&sv.datagram, sound_num); else MSG_WriteByte (&sv.datagram, sound_num); //johnfitz for (i=0 ; i<3 ; i++) MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]), sv.protocolflags); }
void Server_Sound(ServerEntity_t *ent, int channel, char *sample, int iVolume, float attenuation) { int sound_num, field_mask, i, e; if(!sample) { Con_Warning("Bad sample name (%s)!\n",ent->v.cClassname); return; } else if(iVolume < 0 || iVolume > 255) { Con_Warning("Sound: volume = %i\n", iVolume); return; } else if(attenuation < 0 || attenuation > 4) { Con_Warning("Sound: attenuation = %f\n", attenuation); return; } else if(channel < 0 || channel > 7) { Con_Warning("Sound: channel = %i\n", channel); return; } else if(sv.datagram.cursize > MAX_DATAGRAM-16) return; for(sound_num=1 ; sound_num<MAX_SOUNDS && sv.sound_precache[sound_num] ; sound_num++) if(!strcmp(sample,sv.sound_precache[sound_num])) break; if(sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num]) { // [19/8/2012] Just return a simple warning ~hogsy Con_Warning("%s was not precached!\n",sample); return; } e = NUM_FOR_EDICT(ent); field_mask = 0; if(iVolume != DEFAULT_SOUND_PACKET_VOLUME) field_mask |= SND_VOLUME; if(attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) field_mask |= SND_ATTENUATION; if(e >= 8192) field_mask |= SND_LARGEENTITY; if(sound_num >= 256 || channel >= 8) field_mask |= SND_LARGESOUND; MSG_WriteByte(&sv.datagram,svc_sound); MSG_WriteByte(&sv.datagram,field_mask); if(field_mask & SND_VOLUME) MSG_WriteByte(&sv.datagram, iVolume); if(field_mask & SND_ATTENUATION) MSG_WriteByte(&sv.datagram,attenuation*64); if(field_mask & SND_LARGEENTITY) { MSG_WriteShort(&sv.datagram,e); MSG_WriteByte(&sv.datagram,channel); } else MSG_WriteShort(&sv.datagram,(e<<3)|channel); if(field_mask & SND_LARGESOUND) MSG_WriteShort(&sv.datagram,sound_num); else MSG_WriteByte(&sv.datagram,sound_num); for(i=0 ; i<3 ; i++) MSG_WriteCoord(&sv.datagram,ent->v.origin[i]+0.5*(ent->v.mins[i]+ent->v.maxs[i])); }
qbool SV_MVDWritePackets (int num) { demo_frame_t *frame, *nextframe; demo_client_t *cl, *nextcl = NULL; int i, j, flags; qbool valid; double time1, playertime, nexttime; vec3_t origin, angles; sizebuf_t msg; byte msg_buf[MAX_MSGLEN]; demoinfo_t *demoinfo; if (!sv.mvdrecording) return false; SZ_Init(&msg, msg_buf, sizeof(msg_buf)); if (num > demo.parsecount - demo.lastwritten + 1) num = demo.parsecount - demo.lastwritten + 1; // 'num' frames to write for ( ; num; num--, demo.lastwritten++) { SZ_Clear(&msg); frame = &demo.frames[demo.lastwritten&DEMO_FRAMES_MASK]; time1 = frame->time; nextframe = frame; demo.dbuf = &frame->buf; // find two frames // one before the exact time (time - msec) and one after, // then we can interpolte exact position for current frame for (i = 0, cl = frame->clients, demoinfo = demo.info; i < MAX_CLIENTS; i++, cl++, demoinfo++) { if (cl->parsecount != demo.lastwritten) continue; // not valid nexttime = playertime = time1 - cl->sec; valid = false; for (j = demo.lastwritten+1; nexttime < time1 && j < demo.parsecount; j++) { nextframe = &demo.frames[j&DEMO_FRAMES_MASK]; nextcl = &nextframe->clients[i]; if (nextcl->parsecount != j) break; // disconnected? if (nextcl->fixangle) break; // respawned, or walked into teleport, do not interpolate! if (!(nextcl->flags & DF_DEAD) && (cl->flags & DF_DEAD)) break; // respawned, do not interpolate nexttime = nextframe->time - nextcl->sec; if (nexttime >= time1) { // good, found what we were looking for valid = true; break; } } if (valid) { float f = 0; float z = nexttime - playertime; if ( z ) f = (time1 - nexttime) / z; for (j = 0; j < 3; j++) { angles[j] = adjustangle(cl->info.angles[j], nextcl->info.angles[j], 1.0 + f); origin[j] = nextcl->info.origin[j] + f * (nextcl->info.origin[j] - cl->info.origin[j]); } } else { VectorCopy(cl->info.origin, origin); VectorCopy(cl->info.angles, angles); } // now write it to buf flags = cl->flags; for (j=0; j < 3; j++) if (origin[j] != demoinfo->origin[i]) flags |= DF_ORIGIN << j; for (j=0; j < 3; j++) if (angles[j] != demoinfo->angles[j]) flags |= DF_ANGLES << j; if (cl->info.model != demoinfo->model) flags |= DF_MODEL; if (cl->info.effects != demoinfo->effects) flags |= DF_EFFECTS; if (cl->info.skinnum != demoinfo->skinnum) flags |= DF_SKINNUM; if (cl->info.weaponframe != demoinfo->weaponframe) flags |= DF_WEAPONFRAME; MSG_WriteByte (&msg, svc_playerinfo); MSG_WriteByte (&msg, i); MSG_WriteShort (&msg, flags); MSG_WriteByte (&msg, cl->frame); for (j=0 ; j<3 ; j++) if (flags & (DF_ORIGIN << j)) MSG_WriteCoord (&msg, origin[j]); for (j=0 ; j<3 ; j++) if (flags & (DF_ANGLES << j)) MSG_WriteAngle16 (&msg, angles[j]); if (flags & DF_MODEL) MSG_WriteByte (&msg, cl->info.model); if (flags & DF_SKINNUM) MSG_WriteByte (&msg, cl->info.skinnum); if (flags & DF_EFFECTS) MSG_WriteByte (&msg, cl->info.effects); if (flags & DF_WEAPONFRAME) MSG_WriteByte (&msg, cl->info.weaponframe); VectorCopy(cl->info.origin, demoinfo->origin); VectorCopy(cl->info.angles, demoinfo->angles); demoinfo->skinnum = cl->info.skinnum; demoinfo->effects = cl->info.effects; demoinfo->weaponframe = cl->info.weaponframe; demoinfo->model = cl->info.model; } SV_MVDWriteToDisk(demo.lasttype,demo.lastto, (float)time1); // this goes first to reduce demo size a bit SV_MVDWriteToDisk(0,0, (float)time1); // now goes the rest if (msg.cursize) SV_WriteMVDMessage(&msg, dem_all, 0, (float)time1); if (!sv.mvdrecording) { Com_DPrintf("SV_MVDWritePackets: error: in sv.mvdrecording\n"); return false; // ERROR } } if (!sv.mvdrecording) return false; // ERROR if (demo.lastwritten > demo.parsecount) demo.lastwritten = demo.parsecount; demo.dbuf = &demo.frames[demo.parsecount&DEMO_FRAMES_MASK].buf; demo.dbuf->maxsize = MAXSIZE + demo.dbuf->bufsize; return true; }
void ClientReliableWrite_Coord (float f) { assert (backbuf_write_started); MSG_WriteCoord (&backbuf, f); }
void EXT_FUNC MSG_WriteCoord_api(sizebuf_t *sb, float f) { MSG_WriteCoord(sb, f); }
void Game_WriteCoord(int mode,float f) { MSG_WriteCoord(Game_WriteDest(mode),f); }
/* ================== SV_StartSound Each entity can have eight independant sound sources, like voice, weapon, feet, etc. Channel 0 is an auto-allocate channel, the others override anything allready running on that entity/channel pair. An attenuation of 0 will play full volume everywhere in the level. Larger attenuations will drop off. (max 4 attenuation) ================== */ void SV_StartSound (edict_t *entity, int channel, const char *sample, int volume, float attenuation) { int sound_num, ent; int i, field_mask; if (volume < 0 || volume > 255) Host_Error ("SV_StartSound: volume = %i", volume); if (attenuation < 0 || attenuation > 4) Host_Error ("SV_StartSound: attenuation = %f", attenuation); if (channel < 0 || channel > 7) Host_Error ("SV_StartSound: channel = %i", channel); if (sv.datagram.cursize > MAX_DATAGRAM-16) return; // find precache number for sound for (sound_num = 1; sound_num < MAX_SOUNDS && sv.sound_precache[sound_num]; sound_num++) { if (!strcmp(sample, sv.sound_precache[sound_num])) break; } if (sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num]) { Con_Printf ("SV_StartSound: %s not precacheed\n", sample); return; } ent = NUM_FOR_EDICT(entity); field_mask = 0; if (volume != DEFAULT_SOUND_PACKET_VOLUME) field_mask |= SND_VOLUME; if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) field_mask |= SND_ATTENUATION; //johnfitz -- PROTOCOL_FITZQUAKE if (ent >= 8192) { if (sv.protocol == PROTOCOL_NETQUAKE) return; //don't send any info protocol can't support else field_mask |= SND_LARGEENTITY; } if (sound_num >= 256 || channel >= 8) { if (sv.protocol == PROTOCOL_NETQUAKE) return; //don't send any info protocol can't support else field_mask |= SND_LARGESOUND; } //johnfitz // directed messages go only to the entity the are targeted on MSG_WriteByte (&sv.datagram, svc_sound); MSG_WriteByte (&sv.datagram, field_mask); if (field_mask & SND_VOLUME) MSG_WriteByte (&sv.datagram, volume); if (field_mask & SND_ATTENUATION) MSG_WriteByte (&sv.datagram, attenuation*64); //johnfitz -- PROTOCOL_FITZQUAKE if (field_mask & SND_LARGEENTITY) { MSG_WriteShort (&sv.datagram, ent); MSG_WriteByte (&sv.datagram, channel); } else MSG_WriteShort (&sv.datagram, (ent<<3) | channel); if (field_mask & SND_LARGESOUND) MSG_WriteShort (&sv.datagram, sound_num); else MSG_WriteByte (&sv.datagram, sound_num); //johnfitz for (i = 0; i < 3; i++) MSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i])); }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() static void SV_SendEffect (sizebuf_t *sb, int idx) { qboolean DoTest; vec3_t TestO1, Diff; float Size, TestDistance; int i, count; if (sb == &sv.reliable_datagram && sv_ce_scale.value > 0) DoTest = true; else DoTest = false; VectorClear(TestO1); TestDistance = 0; switch (sv.Effects[idx].type) { case CE_RAIN: case CE_SNOW: DoTest = false; break; case CE_FOUNTAIN: DoTest = false; break; case CE_QUAKE: VectorCopy(sv.Effects[idx].ef.Quake.origin, TestO1); TestDistance = 700; break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_LG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_FBOOM: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_BOMB: case CE_FLOOR_EXPLOSION3: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_RED_FLASH: VectorCopy(sv.Effects[idx].ef.Smoke.origin, TestO1); TestDistance = 250; break; case CE_RIDER_DEATH: DoTest = false; break; case CE_GRAVITYWELL: DoTest = false; break; case CE_TELEPORTERPUFFS: VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1); TestDistance = 350; break; case CE_TELEPORTERBODY: VectorCopy(sv.Effects[idx].ef.Teleporter.origin, TestO1); TestDistance = 350; break; case CE_BONESHARD: case CE_BONESHRAPNEL: VectorCopy(sv.Effects[idx].ef.Missile.origin, TestO1); TestDistance = 600; break; case CE_CHUNK: VectorCopy(sv.Effects[idx].ef.Chunk.origin, TestO1); TestDistance = 600; break; default: PR_RunError ("%s: bad type", __thisfunc__); break; } if (!DoTest) count = 1; else { count = svs.maxclients; TestDistance = (float)TestDistance * sv_ce_scale.value; TestDistance *= TestDistance; } for (i = 0 ; i < count ; i++) { if (DoTest) { if (svs.clients[i].active) { sb = &svs.clients[i].datagram; VectorSubtract(svs.clients[i].edict->v.origin, TestO1, Diff); Size = (Diff[0]*Diff[0]) + (Diff[1]*Diff[1]) + (Diff[2]*Diff[2]); if (Size > TestDistance) continue; if (sv_ce_max_size.value > 0 && sb->cursize > sv_ce_max_size.value) continue; } else continue; } MSG_WriteByte (sb, svc_start_effect); MSG_WriteByte (sb, idx); MSG_WriteByte (sb, sv.Effects[idx].type); switch (sv.Effects[idx].type) { case CE_RAIN: MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.e_size[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.color); MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.count); MSG_WriteFloat(sb, sv.Effects[idx].ef.Rain.wait); break; case CE_SNOW: MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.min_org[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.max_org[2]); MSG_WriteByte(sb, sv.Effects[idx].ef.Rain.flags); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Rain.dir[2]); MSG_WriteByte(sb, sv.Effects[idx].ef.Rain.count); //MSG_WriteShort(sb, sv.Effects[idx].ef.Rain.veer); break; case CE_FOUNTAIN: MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.pos[2]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[0]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[1]); MSG_WriteAngle(sb, sv.Effects[idx].ef.Fountain.angle[2]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Fountain.movedir[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.Fountain.color); MSG_WriteByte(sb, sv.Effects[idx].ef.Fountain.cnt); break; case CE_QUAKE: MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Quake.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Quake.radius); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.velocity[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.framelength); /* smoke frame is a mission pack thing only. */ if (sv_protocol > PROTOCOL_RAVEN_111) MSG_WriteFloat(sb, sv.Effects[idx].ef.Smoke.frame); break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_LG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_FLOOR_EXPLOSION3: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: case CE_BRN_BOUNCE: case CE_LSHOCK: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_RED_FLASH: MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Smoke.origin[2]); break; case CE_RIDER_DEATH: MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[2]); break; case CE_TELEPORTERPUFFS: MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[2]); break; case CE_TELEPORTERBODY: MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Teleporter.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.velocity[0][2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Teleporter.skinnum); break; case CE_BONESHARD: case CE_BONESHRAPNEL: MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Missile.origin[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.velocity[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.angle[2]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[0]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[1]); MSG_WriteFloat(sb, sv.Effects[idx].ef.Missile.avelocity[2]); break; case CE_GRAVITYWELL: MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.RD.origin[2]); MSG_WriteShort(sb, sv.Effects[idx].ef.RD.color); MSG_WriteFloat(sb, sv.Effects[idx].ef.RD.lifetime); break; case CE_CHUNK: MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.origin[2]); MSG_WriteByte (sb, sv.Effects[idx].ef.Chunk.type); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[0]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[1]); MSG_WriteCoord(sb, sv.Effects[idx].ef.Chunk.srcVel[2]); MSG_WriteByte (sb, sv.Effects[idx].ef.Chunk.numChunks); // Con_Printf ("Adding %d chunks on server...\n", sv.Effects[idx].Chunk.numChunks); break; default: PR_RunError ("%s: bad type", __thisfunc__); break; } } }
// Take over the user controls and track a player. // We find a nice position to watch the player and move there void Cam_Track(usercmd_t *cmd) { player_state_t *player, *self; frame_t *frame; vec3_t vec; int do_tmove; if (!cl.spectator) return; if (!autocam || cls.state != ca_active) return; if (locked && (!cl.players[spec_track].name[0] || cl.players[spec_track].spectator)) { locked = false; Cam_Unlock(); return; } frame = &cl.frames[cl.validsequence & UPDATE_MASK]; if (autocam && cls.mvdplayback) { if (ideal_track != spec_track && cls.realtime - last_lock > 0.1 && frame->playerstate[ideal_track].messagenum == cl.parsecount) Cam_Lock(ideal_track); if (frame->playerstate[spec_track].messagenum != cl.parsecount) { int i; for (i = 0; i < MAX_CLIENTS; i++) { if (frame->playerstate[i].messagenum == cl.parsecount) break; } if (i < MAX_CLIENTS) Cam_Lock(i); } } player = frame->playerstate + spec_track; self = frame->playerstate + cl.playernum; if (!locked || !Cam_IsVisible(player, desired_position)) { if (!locked || cls.realtime - cam_lastviewtime > 0.1) { if (!InitFlyby(self, player, true)) InitFlyby(self, player, false); cam_lastviewtime = cls.realtime; } } else { cam_lastviewtime = cls.realtime; } // couldn't track for some reason if (!locked || !autocam) return; do_tmove = 0; if (cl_chasecam.value) { cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; VectorCopy(player->viewangles, cl.viewangles); VectorCopy(player->origin, desired_position); if (memcmp(&desired_position, &self->origin, sizeof(desired_position)) != 0) { do_tmove = 1; // move there locally immediately VectorCopy(desired_position, self->origin); } } else { // Ok, move to our desired position and set our angles to view // the player VectorSubtract(desired_position, self->origin, vec); cmd->forwardmove = cmd->sidemove = cmd->upmove = 0; if (VectorLength(vec) > 16) { // close enough? do_tmove = 1; } // move there locally immediately VectorCopy(desired_position, self->origin); VectorSubtract(player->origin, desired_position, vec); vectoangles(vec, cl.viewangles); cl.viewangles[0] = -cl.viewangles[0]; if (cl.viewangles[0] < 0) cl.viewangles[0] += 360; } Mouse_SetViewAngles(cl.viewangles); #ifdef NETQW if (do_tmove && cls.netqw) NetQW_SetTeleport(cls.netqw, desired_position); #else MSG_WriteByte (&cls.netchan.message, clc_tmove); MSG_WriteCoord (&cls.netchan.message, desired_position[0]); MSG_WriteCoord (&cls.netchan.message, desired_position[1]); MSG_WriteCoord (&cls.netchan.message, desired_position[2]); #endif }
// All changes need to be in SV_SendEffect(), SV_ParseEffect(), // SV_SaveEffects(), SV_LoadEffects(), CL_ParseEffect() void SV_SendEffect(sizebuf_t *sb, int index) { qboolean DoTest; vec3_t TestO; int TestDistance; int i; if (sv_ce_scale.value > 0) DoTest = true; else DoTest = false; VectorCopy(vec3_origin, TestO); switch(sv.Effects[index].type) { case CE_HWSHEEPINATOR: case CE_HWXBOWSHOOT: VectorCopy(sv.Effects[index].Xbow.origin[5], TestO); TestDistance = 900; break; case CE_SCARABCHAIN: VectorCopy(sv.Effects[index].Chain.origin, TestO); TestDistance = 900; break; case CE_TRIPMINE: VectorCopy(sv.Effects[index].Chain.origin, TestO); // DoTest = false; break; //ACHTUNG!!!!!!! setting DoTest to false here does not insure that effect will be sent to everyone! case CE_TRIPMINESTILL: TestDistance = 10000; DoTest = false; break; case CE_RAIN: TestDistance = 10000; DoTest = false; break; case CE_FOUNTAIN: TestDistance = 10000; DoTest = false; break; case CE_QUAKE: VectorCopy(sv.Effects[index].Quake.origin, TestO); TestDistance = 700; break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_FBOOM: case CE_BRN_BOUNCE: case CE_LSHOCK: case CE_BOMB: case CE_FLOOR_EXPLOSION3: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: VectorCopy(sv.Effects[index].Smoke.origin, TestO); TestDistance = 250; break; case CE_RIDER_DEATH: DoTest = false; break; case CE_TELEPORTERPUFFS: VectorCopy(sv.Effects[index].Teleporter.origin, TestO); TestDistance = 350; break; case CE_TELEPORTERBODY: VectorCopy(sv.Effects[index].Teleporter.origin, TestO); TestDistance = 350; break; case CE_DEATHBUBBLES: if (sv.Effects[index].Bubble.owner < 0 || sv.Effects[index].Bubble.owner >= sv.num_edicts) { return; } VectorCopy(PROG_TO_EDICT(sv.Effects[index].Bubble.owner)->v.origin, TestO); TestDistance = 400; break; case CE_HWDRILLA: case CE_BONESHARD: case CE_BONESHRAPNEL: case CE_HWBONEBALL: case CE_HWRAVENSTAFF: case CE_HWRAVENPOWER: VectorCopy(sv.Effects[index].Missile.origin, TestO); TestDistance = 900; break; case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: VectorCopy(sv.Effects[index].Missile.origin, TestO); TestDistance = 600; break; default: // Sys_Error ("SV_SendEffect: bad type"); PR_RunError ("SV_SendEffect: bad type"); break; } MSG_WriteByte (&sv.multicast, svc_start_effect); MSG_WriteByte (&sv.multicast, index); MSG_WriteByte (&sv.multicast, sv.Effects[index].type); switch(sv.Effects[index].type) { case CE_RAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.min_org[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.max_org[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.e_size[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Rain.dir[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Rain.color); MSG_WriteShort(&sv.multicast, sv.Effects[index].Rain.count); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Rain.wait); break; case CE_FOUNTAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.pos[2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[1]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Fountain.angle[2]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Fountain.movedir[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Fountain.color); MSG_WriteByte(&sv.multicast, sv.Effects[index].Fountain.cnt); break; case CE_QUAKE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Quake.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Quake.radius); break; case CE_WHITE_SMOKE: case CE_GREEN_SMOKE: case CE_GREY_SMOKE: case CE_RED_SMOKE: case CE_SLOW_WHITE_SMOKE: case CE_TELESMK1: case CE_TELESMK2: case CE_GHOST: case CE_REDCLOUD: case CE_FLAMESTREAM: case CE_ACID_MUZZFL: case CE_FLAMEWALL: case CE_FLAMEWALL2: case CE_ONFIRE: case CE_RIPPLE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.velocity[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Smoke.framelength); break; case CE_SM_WHITE_FLASH: case CE_YELLOWRED_FLASH: case CE_BLUESPARK: case CE_YELLOWSPARK: case CE_SM_CIRCLE_EXP: case CE_BG_CIRCLE_EXP: case CE_SM_EXPLOSION: case CE_SM_EXPLOSION2: case CE_BG_EXPLOSION: case CE_FLOOR_EXPLOSION: case CE_BLUE_EXPLOSION: case CE_REDSPARK: case CE_GREENSPARK: case CE_ICEHIT: case CE_MEDUSA_HIT: case CE_MEZZO_REFLECT: case CE_FLOOR_EXPLOSION2: case CE_XBOW_EXPLOSION: case CE_NEW_EXPLOSION: case CE_MAGIC_MISSILE_EXPLOSION: case CE_BONE_EXPLOSION: case CE_BLDRN_EXPL: case CE_ACID_HIT: case CE_ACID_SPLAT: case CE_ACID_EXPL: case CE_LBALL_EXPL: case CE_FIREWALL_SMALL: case CE_FIREWALL_MEDIUM: case CE_FIREWALL_LARGE: case CE_FBOOM: case CE_BOMB: case CE_BRN_BOUNCE: case CE_LSHOCK: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); break; case CE_WHITE_FLASH: case CE_BLUE_FLASH: case CE_SM_BLUE_FLASH: case CE_HWSPLITFLASH: case CE_RED_FLASH: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Smoke.origin[2]); break; case CE_RIDER_DEATH: MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].RD.origin[2]); break; case CE_TELEPORTERPUFFS: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[2]); break; case CE_TELEPORTERBODY: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Teleporter.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.velocity[0][2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Teleporter.skinnum); break; case CE_BONESHRAPNEL: case CE_HWBONEBALL: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.angle[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.avelocity[2]); break; case CE_BONESHARD: case CE_HWRAVENSTAFF: case CE_HWMISSILESTAR: case CE_HWEIDOLONSTAR: case CE_HWRAVENPOWER: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Missile.velocity[2]); break; case CE_HWDRILLA: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Missile.origin[2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Missile.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Missile.angle[1]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Missile.speed); break; case CE_DEATHBUBBLES: MSG_WriteShort(&sv.multicast, sv.Effects[index].Bubble.owner); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[0]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[1]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.offset[2]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Bubble.count); break; case CE_SCARABCHAIN: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[2]); MSG_WriteShort(&sv.multicast, sv.Effects[index].Chain.owner+sv.Effects[index].Chain.material); MSG_WriteByte(&sv.multicast, sv.Effects[index].Chain.tag); break; case CE_TRIPMINESTILL: case CE_TRIPMINE: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Chain.origin[2]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[0]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[1]); MSG_WriteFloat(&sv.multicast, sv.Effects[index].Chain.velocity[2]); break; case CE_HWSHEEPINATOR: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[1]); //now send the guys that have turned MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.turnedbolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.activebolts); for (i=0;i<5;i++) { if ((1<<i)&sv.Effects[index].Xbow.turnedbolts) { MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][1]); } } break; case CE_HWXBOWSHOOT: MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[5][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.angle[1]); // MSG_WriteFloat(&sv.multicast, sv.Effects[index].Xbow.angle[2]); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.bolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.randseed); //now send the guys that have turned MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.turnedbolts); MSG_WriteByte(&sv.multicast, sv.Effects[index].Xbow.activebolts); for (i=0;i<5;i++) { if ((1<<i)&sv.Effects[index].Xbow.turnedbolts) { MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][0]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][1]); MSG_WriteCoord(&sv.multicast, sv.Effects[index].Xbow.origin[i][2]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][0]); MSG_WriteAngle(&sv.multicast, sv.Effects[index].Xbow.vel[i][1]); } } break; default: // Sys_Error ("SV_SendEffect: bad type"); PR_RunError ("SV_SendEffect: bad type"); break; } if (sb) { SZ_Write (sb, sv.multicast.data, sv.multicast.cursize); SZ_Clear (&sv.multicast); } else { if (DoTest) { SV_Multicast (TestO, MULTICAST_PVS_R); } else { SV_Multicast (TestO, MULTICAST_ALL_R); } sv.Effects[index].client_list = clients_multicast; } }
/* ==================== CL_Record Called by CL_Record_f and CL_EasyRecord_f ==================== */ static void CL_Record (void) { sizebuf_t buf; byte buf_data[MAX_MSGLEN]; int n, i, j; char *s; entity_t *ent; entity_state_t *es, blankes; player_info_t *player; int seq = 1; #ifdef MVDPLAY if (cls.mvdplayback) { Com_Printf ("Can't record while playing MVD demo.\n"); return; } #endif cls.demorecording = true; /*-------------------------------------------------*/ // serverdata // send the info about the new client to all connected clients SZ_Init (&buf, buf_data, sizeof(buf_data)); // send the serverdata MSG_WriteByte (&buf, svc_serverdata); MSG_WriteLong (&buf, PROTOCOL_VERSION); MSG_WriteLong (&buf, cl.servercount); MSG_WriteString (&buf, cls.gamedirfile); if (cl.spectator) MSG_WriteByte (&buf, cl.playernum | 128); else MSG_WriteByte (&buf, cl.playernum); // send full levelname MSG_WriteString (&buf, cl.levelname); // send the movevars MSG_WriteFloat(&buf, movevars.gravity); MSG_WriteFloat(&buf, movevars.stopspeed); MSG_WriteFloat(&buf, cl.maxspeed); MSG_WriteFloat(&buf, movevars.spectatormaxspeed); MSG_WriteFloat(&buf, movevars.accelerate); MSG_WriteFloat(&buf, movevars.airaccelerate); MSG_WriteFloat(&buf, movevars.wateraccelerate); MSG_WriteFloat(&buf, movevars.friction); MSG_WriteFloat(&buf, movevars.waterfriction); MSG_WriteFloat(&buf, cl.entgravity); // send music MSG_WriteByte (&buf, svc_cdtrack); MSG_WriteByte (&buf, 0); // none in demos // send server info string MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) ); // flush packet CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); // soundlist MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, 0); n = 0; s = cl.sound_name[n+1]; while (*s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, n + 1); } n++; s = cl.sound_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } #ifdef VWEP_TEST // vwep modellist if ((cl.z_ext & Z_EXT_VWEP) && cl.vw_model_name[0][0]) { // send VWep precaches // pray we don't overflow for (i = 0; i < MAX_VWEP_MODELS; i++) { s = cl.vw_model_name[i]; if (!*s) continue; MSG_WriteByte (&buf, svc_serverinfo); MSG_WriteString (&buf, "#vw"); MSG_WriteString (&buf, va("%i %s", i, TrimModelName(s))); } // send end-of-list messsage MSG_WriteByte (&buf, svc_serverinfo); MSG_WriteString (&buf, "#vw"); MSG_WriteString (&buf, ""); } // don't bother flushing, the vwep list is not that large (I hope) #endif // modellist MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, 0); n = 0; s = cl.model_name[n+1]; while (*s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, n + 1); } n++; s = cl.model_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // spawnstatic for (i = 0; i < cl.num_statics; i++) { ent = cl_static_entities + i; MSG_WriteByte (&buf, svc_spawnstatic); for (j = 1; j < MAX_MODELS; j++) if (ent->model == cl.model_precache[j]) break; if (j == MAX_MODELS) MSG_WriteByte (&buf, 0); else MSG_WriteByte (&buf, j); MSG_WriteByte (&buf, ent->frame); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, ent->skinnum); for (j=0 ; j<3 ; j++) { MSG_WriteCoord (&buf, ent->origin[j]); MSG_WriteAngle (&buf, ent->angles[j]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // spawnstaticsound for (i = 0; i < cl.num_static_sounds; i++) { static_sound_t *ss = &cl.static_sounds[i]; MSG_WriteByte (&buf, svc_spawnstaticsound); for (j = 0; j < 3; j++) MSG_WriteCoord (&buf, ss->org[j]); MSG_WriteByte (&buf, ss->sound_num); MSG_WriteByte (&buf, ss->vol); MSG_WriteByte (&buf, ss->atten); if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // baselines memset(&blankes, 0, sizeof(blankes)); for (i = 0; i < MAX_CL_EDICTS; i++) { es = &cl_entities[i].baseline; if (memcmp(es, &blankes, sizeof(blankes))) { MSG_WriteByte (&buf,svc_spawnbaseline); MSG_WriteShort (&buf, i); MSG_WriteByte (&buf, es->modelindex); MSG_WriteByte (&buf, es->frame); MSG_WriteByte (&buf, es->colormap); MSG_WriteByte (&buf, es->skinnum); for (j=0 ; j<3 ; j++) { MSG_WriteShort (&buf, es->s_origin[j]); MSG_WriteByte (&buf, es->s_angles[j]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } } MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("cmd spawn %i 0\n", cl.servercount) ); if (buf.cursize) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // send current status of all other players for (i = 0; i < MAX_CLIENTS; i++) { player = cl.players + i; MSG_WriteByte (&buf, svc_updatefrags); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->frags); MSG_WriteByte (&buf, svc_updateping); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->ping); MSG_WriteByte (&buf, svc_updatepl); MSG_WriteByte (&buf, i); MSG_WriteByte (&buf, player->pl); MSG_WriteByte (&buf, svc_updateentertime); MSG_WriteByte (&buf, i); MSG_WriteFloat (&buf, cls.realtime - player->entertime); MSG_WriteByte (&buf, svc_updateuserinfo); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, player->userid); MSG_WriteString (&buf, player->userinfo); if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // send all current light styles for (i=0 ; i<MAX_LIGHTSTYLES ; i++) { if (!cl_lightstyle[i].length) continue; // don't send empty lightstyle strings MSG_WriteByte (&buf, svc_lightstyle); MSG_WriteByte (&buf, (char)i); MSG_WriteString (&buf, cl_lightstyle[i].map); } for (i = 0; i < MAX_CL_STATS; i++) { if (!cl.stats[i]) continue; // no need to send zero values if (cl.stats[i] >= 0 && cl.stats[i] <= 255) { MSG_WriteByte (&buf, svc_updatestat); MSG_WriteByte (&buf, i); MSG_WriteByte (&buf, cl.stats[i]); } else { MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, cl.stats[i]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("skins\n") ); CL_WriteRecordDemoMessage (&buf, seq++); CL_WriteSetDemoMessage(); // done }
static qbool SV_MVD_Record (mvddest_t *dest) { sizebuf_t buf; byte buf_data[MAX_MSGLEN]; int n, i; char *s, info[MAX_INFO_STRING]; client_t *player; char *gamedir; if (!dest) return false; DestFlush(true); if (!sv.mvdrecording) { memset(&demo, 0, sizeof(demo)); for (i = 0; i < UPDATE_BACKUP; i++) { demo.recorder.frames[i] = demo_frames[i]; demo.recorder.frames[i].entities.entities = demo_entities[i]; } MVDBuffer_Init(&demo.dbuffer, demo.buffer, sizeof(demo.buffer)); MVDSetMsgBuf(NULL, &demo.frames[0].buf); demo.datagram.maxsize = sizeof(demo.datagram_data); demo.datagram.data = demo.datagram_data; sv.mvdrecording = true; } // else // SV_WriteRecordMVDMessage(&buf); demo.pingtime = demo.time = sv.time; dest->nextdest = demo.dest; demo.dest = dest; singledest = dest; /*-------------------------------------------------*/ // serverdata // send the info about the new client to all connected clients SZ_Init (&buf, buf_data, sizeof(buf_data)); // send the serverdata gamedir = Info_ValueForKey (svs.info, "*gamedir"); if (!gamedir[0]) gamedir = "qw"; MSG_WriteByte (&buf, svc_serverdata); MSG_WriteLong (&buf, PROTOCOL_VERSION); MSG_WriteLong (&buf, svs.spawncount); MSG_WriteString (&buf, gamedir); MSG_WriteFloat (&buf, sv.time); // send full levelname MSG_WriteString (&buf, sv.mapname); // send the movevars MSG_WriteFloat(&buf, sv.movevars.gravity); MSG_WriteFloat(&buf, sv.movevars.stopspeed); MSG_WriteFloat(&buf, sv.movevars.maxspeed); MSG_WriteFloat(&buf, sv.movevars.spectatormaxspeed); MSG_WriteFloat(&buf, sv.movevars.accelerate); MSG_WriteFloat(&buf, sv.movevars.airaccelerate); MSG_WriteFloat(&buf, sv.movevars.wateraccelerate); MSG_WriteFloat(&buf, sv.movevars.friction); MSG_WriteFloat(&buf, sv.movevars.waterfriction); MSG_WriteFloat(&buf, sv.movevars.entgravity); // send music MSG_WriteByte (&buf, svc_cdtrack); MSG_WriteByte (&buf, 0); // none in demos // send server info string MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", svs.info) ); // flush packet SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); // soundlist MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, 0); n = 0; s = sv.sound_name[n+1]; while (s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, n + 1); } n++; s = sv.sound_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } // modellist MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, 0); n = 0; s = sv.model_name[n+1]; while (s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, n + 1); } n++; s = sv.model_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } // baselines { entity_state_t from; edict_t *ent; entity_state_t *state; memset(&from, 0, sizeof(from)); for (n = 0; n < sv.num_edicts; n++) { ent = EDICT_NUM(n); state = &ent->baseline; if (!state->number || !state->modelindex) { //ent doesn't have a baseline continue; } if (!ent) { MSG_WriteByte(&buf, svc_spawnbaseline); MSG_WriteShort (&buf, n); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&buf, 0); MSG_WriteAngle(&buf, 0); } } else { MSG_WriteByte(&buf, svc_spawnbaseline); MSG_WriteShort (&buf, n); MSG_WriteByte (&buf, state->modelindex&255); MSG_WriteByte (&buf, state->frame); MSG_WriteByte (&buf, (int)state->colormap); MSG_WriteByte (&buf, (int)state->skinnum); for (i=0 ; i<3 ; i++) { MSG_WriteCoord(&buf, state->s_origin[i]); MSG_WriteAngle(&buf, state->s_angles[i]); } } if (buf.cursize > MAX_MSGLEN/2) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } } } //prespawn for (n = 0; n < sv.num_signon_buffers; n++) { if (buf.cursize+sv.signon_buffer_size[n] > MAX_MSGLEN/2) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } SZ_Write (&buf, sv.signon_buffers[n], sv.signon_buffer_size[n]); } if (buf.cursize > MAX_MSGLEN/2) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("cmd spawn %i\n",svs.spawncount) ); if (buf.cursize) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } // send current status of all other players for (i = 0; i < MAX_CLIENTS; i++) { player = svs.clients + i; MSG_WriteByte (&buf, svc_updatefrags); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->old_frags); MSG_WriteByte (&buf, svc_updateping); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, SV_CalcPing(player)); MSG_WriteByte (&buf, svc_updatepl); MSG_WriteByte (&buf, i); MSG_WriteByte (&buf, player->lossage); MSG_WriteByte (&buf, svc_updateentertime); MSG_WriteByte (&buf, i); MSG_WriteFloat (&buf, svs.realtime - player->connection_started); Q_strncpyz (info, player->userinfo, MAX_INFO_STRING); Info_RemovePrefixedKeys (info, '_'); // server passwords, etc MSG_WriteByte (&buf, svc_updateuserinfo); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, player->userid); MSG_WriteString (&buf, info); if (buf.cursize > MAX_MSGLEN/2) { SV_WriteRecordMVDMessage (&buf); SZ_Clear (&buf); } } // send all current light styles for (i=0 ; i<MAX_LIGHTSTYLES ; i++) { MSG_WriteByte (&buf, svc_lightstyle); MSG_WriteByte (&buf, (char)i); MSG_WriteString (&buf, sv.lightstyles[i]); } // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, "skins\n"); SV_WriteRecordMVDMessage (&buf); SV_WriteSetMVDMessage(); singledest = NULL; // done return true; }
/* ==================== CL_Record_f record <demoname> <server> ==================== */ void CL_Record_f (void) { int c; char name[MAX_OSPATH]; sizebuf_t buf; char buf_data[MAX_MSGLEN]; int n, i, j; char *s; entity_t *ent; entity_state_t *es, blankes; player_info_t *player; extern char gamedirfile[]; int seq = 1; c = Cmd_Argc(); if (c != 2) { Con_Printf ("record <demoname>\n"); return; } if (cls.state != ca_active) { Con_Printf ("You must be connected to record.\n"); return; } if (cls.demorecording) CL_Stop_f(); sprintf (name, "%s/%s", com_gamedir, Cmd_Argv(1)); // // open the demo file // COM_DefaultExtension (name, ".qwd"); cls.demofile = fopen (name, "wb"); if (!cls.demofile) { Con_Printf ("ERROR: couldn't open.\n"); return; } Con_Printf ("recording to %s.\n", name); cls.demorecording = true; /*-------------------------------------------------*/ // serverdata // send the info about the new client to all connected clients memset(&buf, 0, sizeof(buf)); buf.data = buf_data; buf.maxsize = sizeof(buf_data); // send the serverdata MSG_WriteByte (&buf, svc_serverdata); MSG_WriteLong (&buf, PROTOCOL_VERSION); MSG_WriteLong (&buf, cl.servercount); MSG_WriteString (&buf, gamedirfile); if (cl.spectator) MSG_WriteByte (&buf, cl.playernum | 128); else MSG_WriteByte (&buf, cl.playernum); // send full levelname MSG_WriteString (&buf, cl.levelname); // send the movevars MSG_WriteFloat(&buf, movevars.gravity); MSG_WriteFloat(&buf, movevars.stopspeed); MSG_WriteFloat(&buf, movevars.maxspeed); MSG_WriteFloat(&buf, movevars.spectatormaxspeed); MSG_WriteFloat(&buf, movevars.accelerate); MSG_WriteFloat(&buf, movevars.airaccelerate); MSG_WriteFloat(&buf, movevars.wateraccelerate); MSG_WriteFloat(&buf, movevars.friction); MSG_WriteFloat(&buf, movevars.waterfriction); MSG_WriteFloat(&buf, movevars.entgravity); // send music MSG_WriteByte (&buf, svc_cdtrack); MSG_WriteByte (&buf, 0); // none in demos // send server info string MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("fullserverinfo \"%s\"\n", cl.serverinfo) ); // flush packet CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); // soundlist MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, 0); n = 0; s = cl.sound_name[n+1]; while (*s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_soundlist); MSG_WriteByte (&buf, n + 1); } n++; s = cl.sound_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // modellist MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, 0); n = 0; s = cl.model_name[n+1]; while (*s) { MSG_WriteString (&buf, s); if (buf.cursize > MAX_MSGLEN/2) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, n); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); MSG_WriteByte (&buf, svc_modellist); MSG_WriteByte (&buf, n + 1); } n++; s = cl.model_name[n+1]; } if (buf.cursize) { MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, 0); CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // spawnstatic for (i = 0; i < cl.num_statics; i++) { ent = cl_static_entities + i; MSG_WriteByte (&buf, svc_spawnstatic); for (j = 1; j < MAX_MODELS; j++) if (ent->model == cl.model_precache[j]) break; if (j == MAX_MODELS) MSG_WriteByte (&buf, 0); else MSG_WriteByte (&buf, j); MSG_WriteByte (&buf, ent->frame); MSG_WriteByte (&buf, 0); MSG_WriteByte (&buf, ent->skinnum); for (j=0 ; j<3 ; j++) { MSG_WriteCoord (&buf, ent->origin[j]); MSG_WriteAngle (&buf, ent->angles[j]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // spawnstaticsound // static sounds are skipped in demos, life is hard // baselines memset(&blankes, 0, sizeof(blankes)); for (i = 0; i < MAX_EDICTS; i++) { es = cl_baselines + i; if (memcmp(es, &blankes, sizeof(blankes))) { MSG_WriteByte (&buf,svc_spawnbaseline); MSG_WriteShort (&buf, i); MSG_WriteByte (&buf, es->modelindex); MSG_WriteByte (&buf, es->frame); MSG_WriteByte (&buf, es->colormap); MSG_WriteByte (&buf, es->skinnum); for (j=0 ; j<3 ; j++) { MSG_WriteCoord(&buf, es->origin[j]); MSG_WriteAngle(&buf, es->angles[j]); } if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } } MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("cmd spawn %i 0\n", cl.servercount) ); if (buf.cursize) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } // send current status of all other players for (i = 0; i < MAX_CLIENTS; i++) { player = cl.players + i; MSG_WriteByte (&buf, svc_updatefrags); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->frags); MSG_WriteByte (&buf, svc_updateping); MSG_WriteByte (&buf, i); MSG_WriteShort (&buf, player->ping); MSG_WriteByte (&buf, svc_updatepl); MSG_WriteByte (&buf, i); MSG_WriteByte (&buf, player->pl); MSG_WriteByte (&buf, svc_updateentertime); MSG_WriteByte (&buf, i); MSG_WriteFloat (&buf, player->entertime); MSG_WriteByte (&buf, svc_updateuserinfo); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, player->userid); MSG_WriteString (&buf, player->userinfo); if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } // send all current light styles for (i=0 ; i<MAX_LIGHTSTYLES ; i++) { MSG_WriteByte (&buf, svc_lightstyle); MSG_WriteByte (&buf, (char)i); MSG_WriteString (&buf, cl_lightstyle[i].map); } for (i = 0; i < MAX_CL_STATS; i++) { MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, i); MSG_WriteLong (&buf, cl.stats[i]); if (buf.cursize > MAX_MSGLEN/2) { CL_WriteRecordDemoMessage (&buf, seq++); SZ_Clear (&buf); } } #if 0 MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, STAT_TOTALMONSTERS); MSG_WriteLong (&buf, cl.stats[STAT_TOTALMONSTERS]); MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, STAT_SECRETS); MSG_WriteLong (&buf, cl.stats[STAT_SECRETS]); MSG_WriteByte (&buf, svc_updatestatlong); MSG_WriteByte (&buf, STAT_MONSTERS); MSG_WriteLong (&buf, cl.stats[STAT_MONSTERS]); #endif // get the client to check and download skins // when that is completed, a begin command will be issued MSG_WriteByte (&buf, svc_stufftext); MSG_WriteString (&buf, va("skins\n") ); CL_WriteRecordDemoMessage (&buf, seq++); CL_WriteSetDemoMessage(); // done }
static void PF_clientsound (progs_t *pr) { const char *sample; int channel; edict_t *entity; int volume; float attenuation; int sound_num; int i; pr_int_t ent; vec3_t origin; entity = P_EDICT (pr, 0); channel = P_FLOAT (pr, 1); sample = P_GSTRING (pr, 2); volume = P_FLOAT (pr, 3) * 255; attenuation = P_FLOAT (pr, 4); ent = NUM_FOR_EDICT (pr, entity); // If not a client go away if (ent > MAX_CLIENTS || ent < 1) return; if (volume < 0 || volume > 255) Sys_Error ("SV_StartSound: volume = %i", volume); if (attenuation < 0 || attenuation > 4) Sys_Error ("SV_StartSound: attenuation = %f", attenuation); if (channel < 0 || channel > 15) Sys_Error ("SV_StartSound: channel = %i", channel); // find precache number for sound for (sound_num = 1; sound_num < MAX_SOUNDS && sv.sound_precache[sound_num]; sound_num++) if (!strcmp (sample, sv.sound_precache[sound_num])) break; if (sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num]) { Sys_Printf ("SV_StartSound: %s not precacheed\n", sample); return; } channel &= 7; channel = (ent << 3) | channel; if (volume != DEFAULT_SOUND_PACKET_VOLUME) channel |= SND_VOLUME; if (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION) channel |= SND_ATTENUATION; // use the entity origin VectorCopy (SVvector (entity, origin), origin); MSG_WriteByte (&svs.clients[ent - 1].netchan.message, svc_sound); MSG_WriteShort (&svs.clients[ent - 1].netchan.message, channel); if (channel & SND_VOLUME) MSG_WriteByte (&svs.clients[ent - 1].netchan.message, volume); if (channel & SND_ATTENUATION) MSG_WriteByte (&svs.clients[ent - 1].netchan.message, attenuation * 64); MSG_WriteByte (&svs.clients[ent - 1].netchan.message, sound_num); for (i = 0; i < 3; i++) MSG_WriteCoord (&svs.clients[ent - 1].netchan.message, origin[i]); }