/* * @brief */ s_sample_t *S_LoadModelSample(entity_state_t *ent, const char *name) { char model[MAX_QPATH]; char path[MAX_QPATH]; char alias[MAX_QPATH]; s_sample_t *sample; if (!s_env.initialized) return NULL; // determine what model the client is using memset(model, 0, sizeof(model)); if (ent->number - 1 >= MAX_CLIENTS) { Com_Warn("Invalid client entity: %d\n", ent->number - 1); return NULL; } uint16_t n = CS_CLIENTS + ent->number - 1; if (cl.config_strings[n][0]) { char *p = strchr(cl.config_strings[n], '\\'); if (p) { p += 1; strcpy(model, p); p = strchr(model, '/'); if (p) *p = 0; } } // if we can't figure it out, use common if (*model == '\0') strcpy(model, "common"); // see if we already know of the model-specific sound g_snprintf(alias, sizeof(path), "#players/%s/%s", model, name + 1); sample = (s_sample_t *) S_FindMedia(alias); if (sample) return sample; // we don't, try it sample = S_LoadSample(alias); if (sample->chunk) return sample; // that didn't work, so load the common one and alias it // the media subsystem will free the previous sample for us g_snprintf(path, sizeof(path), "#players/common/%s", name + 1); sample = S_LoadSample(path); if (sample->chunk) return S_AliasSample(sample, alias); Com_Warn("Failed to load %s\n", alias); return NULL; }
/* * @brief */ void Cl_ParseConfigString(void) { const uint16_t i = (uint16_t) Net_ReadShort(&net_message); if (i >= MAX_CONFIG_STRINGS) { Com_Error(ERR_DROP, "Invalid index %i\n", i); } strcpy(cl.config_strings[i], Net_ReadString(&net_message)); const char *s = cl.config_strings[i]; if (i > CS_MODELS && i < CS_MODELS + MAX_MODELS) { if (cls.state == CL_ACTIVE) { cl.model_precache[i - CS_MODELS] = R_LoadModel(s); if (cl.config_strings[i][0] == '*') { cl.model_clip[i - CS_MODELS] = Cm_Model(s); } else { cl.model_clip[i - CS_MODELS] = NULL; } } } else if (i >= CS_SOUNDS && i < CS_SOUNDS + MAX_SOUNDS) { if (cls.state == CL_ACTIVE) { cl.sound_precache[i - CS_SOUNDS] = S_LoadSample(s); } } else if (i >= CS_IMAGES && i < CS_IMAGES + MAX_IMAGES) { if (cls.state == CL_ACTIVE) { cl.image_precache[i - CS_IMAGES] = R_LoadImage(s, IT_PIC); } } cls.cgame->UpdateConfigString(i); }
/* * S_Frame */ void S_Frame(void) { s_channel_t *ch; int i, j; if (!s_env.initialized) return; S_FrameMusic(); if (cls.state != CL_ACTIVE) { if (Mix_Playing(-1) > 0) S_Stop(); return; } if (s_reverse->modified) { // update reverse stereo Mix_SetReverseStereo(MIX_CHANNEL_POST, s_reverse->integer); s_reverse->modified = false; } // update spatialization for current sounds ch = s_env.channels; for (i = 0; i < MAX_CHANNELS; i++, ch++) { if (!ch->sample) continue; // reset channel's count for loop samples ch->count = 0; S_SpatializeChannel(ch); } // add new dynamic sounds for (i = 0; i < cl.frame.num_entities; i++) { const int e = (cl.frame.entity_state + i) & ENTITY_STATE_MASK; const entity_state_t *ent = &cl.entity_states[e]; if (!ent->sound) continue; for (j = 0; j < MAX_CHANNELS; j++) { if (s_env.channels[j].ent_num == ent->number) break; } if (j == MAX_CHANNELS) S_PlaySample(NULL, ent->number, cl.sound_precache[ent->sound], ATTN_NORM); } if (cl.underwater) // add under water sample if appropriate S_LoopSample(r_view.origin, S_LoadSample("world/under_water")); // reset the update flag s_env.update = false; }
/** * @brief does what the name implies in just one function to avoid exposing s_sample_t * @param s name of the sample * @param origin where to play it * @param attenuation how to reduce volume by distance * @param volume well, the volume */ bool S_LoadAndPlaySample (const char *s, const vec3_t origin, float attenuation, float volume) { s_sample_t *sample = S_LoadSample(s); if (!sample) return false; S_PlaySample(origin, sample, attenuation, volume); return true; }
/** * @note Called at precache phase - only load these soundfiles once at startup or on sound restart * @sa S_Restart_f */ void S_PrecacheSamples (void) { int i, j, k; if (!s_env.initialized) return; /* load weapon sounds */ for (i = 0; i < csi.numODs; i++) { /* i = obj */ const objDef_t *od = INVSH_GetItemByIDX(i); for (j = 0; j < od->numWeapons; j++) { /* j = weapon-entry per obj */ for (k = 0; k < od->numFiredefs[j]; k++) { /* k = firedef per weapon */ const fireDef_t *fd = &od->fd[j][k]; if (fd->fireSound[0] != '\0') S_LoadSample(fd->fireSound); if (fd->impactSound[0] != '\0') S_LoadSample(fd->impactSound); if (fd->hitBodySound[0] != '\0') S_LoadSample(fd->hitBodySound); if (fd->bounceSound[0] != '\0') S_LoadSample(fd->bounceSound); } } } /* precache the sound pool */ stdSoundPool[SOUND_WATER_IN] = S_LoadSample("footsteps/water_in"); stdSoundPool[SOUND_WATER_OUT] = S_LoadSample("footsteps/water_out"); stdSoundPool[SOUND_WATER_MOVE] = S_LoadSample("footsteps/water_under"); }
/** * @brief Plays a sample without spatialization * @param[in] name The sample name * @param[in] relVolume Max mixer volume factor (0.0 - 1.0) * @sa S_PlaySample * @sa S_LoadSample */ void S_StartLocalSample (const char* name, float relVolume) { s_sample_t* sample; if (!s_env.initialized) return; sample = S_LoadSample(name); if (!sample) { Com_Printf("S_StartLocalSample: Failed to load %s\n", name); return; } S_PlaySample(nullptr, sample, SOUND_ATTN_NORM, relVolume); }
/* * S_StartLocalSample */ void S_StartLocalSample(const char *name) { s_sample_t *sample; if (!s_env.initialized) return; sample = S_LoadSample(name); if (!sample) { Com_Warn("S_StartLocalSample: Failed to load %s.\n", name); return; } S_PlaySample(NULL, cl.player_num + 1, sample, ATTN_NONE); }