diff --git a/src/client/cstrike/progs.src b/src/client/cstrike/progs.src index 88dc70ec..e2e3c3f3 100644 --- a/src/client/cstrike/progs.src +++ b/src/client/cstrike/progs.src @@ -11,6 +11,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../valve/defs.h ../cstrike/defs.h ../valve/particles.h diff --git a/src/client/defs.h b/src/client/defs.h index 39aee21a..9d15aae4 100644 --- a/src/client/defs.h +++ b/src/client/defs.h @@ -84,12 +84,3 @@ void View_SetMuzzleflash(int); void View_UpdateWeapon(entity, entity); void View_PlayAnimation(int); void Game_Input(void); - - - -typedef struct -{ - string m_strSnd; - float m_flPitch; - float len; -} sound_t; diff --git a/src/client/gearbox/progs.src b/src/client/gearbox/progs.src index c3e99a48..fee5c30c 100644 --- a/src/client/gearbox/progs.src +++ b/src/client/gearbox/progs.src @@ -12,6 +12,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../valve/defs.h ../valve/particles.h ../defs.h diff --git a/src/client/hunger/progs.src b/src/client/hunger/progs.src index a21e7051..e7d5912b 100644 --- a/src/client/hunger/progs.src +++ b/src/client/hunger/progs.src @@ -12,6 +12,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../valve/defs.h ../valve/particles.h ../defs.h diff --git a/src/client/poke646/progs.src b/src/client/poke646/progs.src index 3dd298a3..0b86bad0 100644 --- a/src/client/poke646/progs.src +++ b/src/client/poke646/progs.src @@ -12,6 +12,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../valve/defs.h ../valve/particles.h ../defs.h diff --git a/src/client/rewolf/progs.src b/src/client/rewolf/progs.src index 323b1874..e4532fef 100755 --- a/src/client/rewolf/progs.src +++ b/src/client/rewolf/progs.src @@ -12,6 +12,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../valve/defs.h ../valve/particles.h ../defs.h diff --git a/src/client/scihunt/progs.src b/src/client/scihunt/progs.src index d68dae4d..f124c51e 100644 --- a/src/client/scihunt/progs.src +++ b/src/client/scihunt/progs.src @@ -11,6 +11,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../valve/defs.h ../valve/particles.h ../defs.h diff --git a/src/client/sound.c b/src/client/sound.c index ffe15f4e..308acedc 100644 --- a/src/client/sound.c +++ b/src/client/sound.c @@ -65,7 +65,7 @@ void Sound_PlayVOX(string msg) for (int i = 0; i < g_voxcount; i++) { g_voxque[i].m_strSnd = sprintf("vox/%s.wav", argv(i)); - g_voxque[i].len = soundlength(g_voxque[i].m_strSnd); + g_voxque[i].m_flLength = soundlength(g_voxque[i].m_strSnd); } g_voxtime = time; } @@ -85,7 +85,7 @@ void Sound_ProcessWordQue(void) g_voxcount = 0; g_voxpos = 0; } else { - g_voxtime = time + g_voxque[g_voxpos - 1].len; + g_voxtime = time + g_voxque[g_voxpos - 1].m_flLength; } } } diff --git a/src/client/tfc/progs.src b/src/client/tfc/progs.src index 6dd06a07..35206c7b 100755 --- a/src/client/tfc/progs.src +++ b/src/client/tfc/progs.src @@ -11,6 +11,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../valve/defs.h ../valve/particles.h ../defs.h diff --git a/src/client/valve/progs.src b/src/client/valve/progs.src index 133fa6d7..9659b99b 100755 --- a/src/client/valve/progs.src +++ b/src/client/valve/progs.src @@ -11,6 +11,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../valve/defs.h ../valve/particles.h ../defs.h diff --git a/src/gs-entbase/client/baseentity.cpp b/src/gs-entbase/client/baseentity.cpp index f7311050..9ba5938a 100644 --- a/src/gs-entbase/client/baseentity.cpp +++ b/src/gs-entbase/client/baseentity.cpp @@ -149,7 +149,7 @@ CBaseEntity::ProcessWordQue(void) m_iSentencePos = 0; m_pSentenceQue = 0; } else { - m_flSentenceTime = time + m_pSentenceQue[m_iSentenceCount - 1].len; + m_flSentenceTime = time + m_pSentenceQue[m_iSentenceCount - 1].m_flLength; } } @@ -174,7 +174,7 @@ CBaseEntity::Sentence(string msg) for (int i = 0; i < m_iSentenceCount; i++) { m_pSentenceQue[i].m_strSnd = sprintf("%s.wav", argv(i)); - m_pSentenceQue[i].len = soundlength(m_pSentenceQue[i].m_strSnd); + m_pSentenceQue[i].m_flLength = soundlength(m_pSentenceQue[i].m_strSnd); m_pSentenceQue[i].m_flPitch = 100; } m_flSentenceTime = time; diff --git a/src/menu-fn/m_customgame.cpp b/src/menu-fn/m_customgame.cpp index 59eb47e5..c89a3fa5 100644 --- a/src/menu-fn/m_customgame.cpp +++ b/src/menu-fn/m_customgame.cpp @@ -47,6 +47,9 @@ void games_init(void) games = memalloc(sizeof(gameinfo_t) * gameinfo_count); + if (!games) + error(sprintf("Attempting to allocate mod data for %i entries failed\n", gameinfo_count)); + for (id = 0; (gamedirname = getgamedirinfo(id, 0)); id++) { gamedescription = getgamedirinfo(id, 2); diff --git a/src/server/cstrike/progs.src b/src/server/cstrike/progs.src index 6ec2f7f8..be7dc019 100755 --- a/src/server/cstrike/progs.src +++ b/src/server/cstrike/progs.src @@ -12,6 +12,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../../shared/valve/animations.h ../defs.h ../plugins.c diff --git a/src/server/gearbox/gamerules.c b/src/server/gearbox/gamerules.c index 4591a399..5680d849 100644 --- a/src/server/gearbox/gamerules.c +++ b/src/server/gearbox/gamerules.c @@ -51,6 +51,17 @@ Gamerules_DecodeChangeParms(player pl) pl.crossbow_mag = parm28; pl.rpg_mag = parm29; pl.satchel_chg = parm30; + + /* near gearbox additions */ + pl.ammo_556 = parm31; + pl.ammo_762 = parm32; + pl.ammo_spore = parm33; + pl.ammo_shock = parm34; + pl.ammo_penguin = parm35; + pl.eagle_mag = parm36; + pl.sniper_mag = parm37; + pl.m249_mag = parm38; + pl.sporelauncher_mag = parm39; } /* prepare the client-info for level-transition */ @@ -87,6 +98,17 @@ Gamerules_SetChangeParms(player pl) parm28 = pl.crossbow_mag; parm29 = pl.rpg_mag; parm30 = pl.satchel_chg; + + /* near gearbox additions */ + parm31 = pl.ammo_556; + parm32 = pl.ammo_762; + parm33 = pl.ammo_spore; + parm34 = pl.ammo_shock; + parm35 = pl.ammo_penguin; + parm36 = pl.eagle_mag; + parm37 = pl.sniper_mag; + parm38 = pl.m249_mag; + parm39 = pl.sporelauncher_mag; } /* yuck, whenever 'changelevel' does not happen. */ @@ -97,7 +119,8 @@ Gamerules_SetNewParms(void) parm8 = parm9 = parm10 = parm11 = parm12 = parm13 = parm14 = parm15 = parm16 = parm17 = parm18 = parm19 = parm20 = parm21 = parm22 = parm23 = parm24 = parm25 = parm26 = parm27 = parm28 = - parm29 = parm30 = 0; + parm29 = parm30 = parm31 = parm32 = parm33 = parm34 = parm35 = + parm36 = parm37 = parm39 = parm39 = 0; } /* called when the player first spawns/respawns */ diff --git a/src/server/gearbox/progs.src b/src/server/gearbox/progs.src index db67d18f..f53b6b15 100755 --- a/src/server/gearbox/progs.src +++ b/src/server/gearbox/progs.src @@ -13,6 +13,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../../shared/valve/animations.h ../defs.h ../plugins.c diff --git a/src/server/hunger/progs.src b/src/server/hunger/progs.src index b6f64841..64419e29 100755 --- a/src/server/hunger/progs.src +++ b/src/server/hunger/progs.src @@ -13,6 +13,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../../shared/valve/animations.h ../defs.h ../plugins.c diff --git a/src/server/poke646/progs.src b/src/server/poke646/progs.src index 89a977a6..f767e86f 100755 --- a/src/server/poke646/progs.src +++ b/src/server/poke646/progs.src @@ -13,6 +13,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../../shared/valve/animations.h ../defs.h ../plugins.c diff --git a/src/server/rewolf/progs.src b/src/server/rewolf/progs.src index 90ce817e..8d95de88 100755 --- a/src/server/rewolf/progs.src +++ b/src/server/rewolf/progs.src @@ -12,6 +12,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../../shared/valve/animations.h ../defs.h ../plugins.c diff --git a/src/server/scihunt/progs.src b/src/server/scihunt/progs.src index 513ee24b..7100df6b 100755 --- a/src/server/scihunt/progs.src +++ b/src/server/scihunt/progs.src @@ -13,6 +13,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../../shared/valve/animations.h ../defs.h diff --git a/src/server/tfc/progs.src b/src/server/tfc/progs.src index 12afd4df..46323f6c 100755 --- a/src/server/tfc/progs.src +++ b/src/server/tfc/progs.src @@ -12,6 +12,7 @@ ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../../shared/valve/animations.h ../defs.h ../plugins.c diff --git a/src/server/valve/progs.src b/src/server/valve/progs.src index a3dced48..00c80fb0 100755 --- a/src/server/valve/progs.src +++ b/src/server/valve/progs.src @@ -12,6 +12,7 @@ defs.h ../../shared/materials.h ../../shared/events.h ../../shared/entities.h +../../shared/sound.c ../../shared/valve/animations.h ../defs.h ../plugins.c diff --git a/src/shared/defs.h b/src/shared/defs.h index 3d265bc2..c59e3c77 100644 --- a/src/shared/defs.h +++ b/src/shared/defs.h @@ -133,16 +133,6 @@ void Util_Destroy(void) remove(self); } -int Sound_Precache(string s) -{ - return -1; -} - -void Sound_Update(entity a, int b, int c, float d) -{ - -} - __wrap void dprint(string m) { if (cvar("developer") == 1) diff --git a/src/shared/sound.c b/src/shared/sound.c new file mode 100644 index 00000000..1c0db134 --- /dev/null +++ b/src/shared/sound.c @@ -0,0 +1,434 @@ +/* + * Copyright (c) 2016-2020 Marco Hladik + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER + * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING + * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +var hashtable g_hashsounds; + +enumflags +{ + SNDFL_LOOPING, /* forceloop */ + SNDFL_NODUPS, /* don't random the samples */ + SNDFL_GLOBAL, /* no attenuation */ + SNDFL_NOREVERB, /* skip reverb */ + SNDFL_OMNI, /* volume on all channels is equal */ + SNDFL_PRIVATE, /* only play on target */ + SNDFL_FOLLOW +}; + +typedef struct +{ + float dist_min; + float dist_max; + float offset; + float pitch_min; + float pitch_max; + float shake; + float volume; + int flags; + int playc; + int sample_count; + string samples; + string name; +} snd_t; + +typedef struct +{ + string m_strSnd; + float m_flLength; + float m_flPitch; +} sound_t; + +snd_t *g_sounds; +static int g_sounds_count; + +void +Sound_ParseField(int i, int a) +{ + switch (argv(0)) { + case "dist_min": + if (a == 2) { + dprint("\tMin distance set\n"); + g_sounds[i].dist_min = stof(argv(1)); + } + break; + case "dist_max": + if (a == 2) { + dprint("\tMax distance set\n"); + g_sounds[i].dist_max = stof(argv(1)); + } + break; + case "volume": + if (a == 2) { + dprint("\tVolume set\n"); + g_sounds[i].volume = stof(argv(1)); + } + break; + case "shakes": + if (a == 2) { + dprint("\tShake set\n"); + g_sounds[i].shake = stof(argv(1)); + } + break; + case "pitch": + if (a == 2) { + dprint("\tPitch set\n"); + g_sounds[i].pitch_min = fabs(stof(argv(1))) * 100; + g_sounds[i].pitch_max = g_sounds[i].pitch_min; + } + break; + case "pitch_min": + if (a == 2) { + dprint("\tMinimum pitch set\n"); + g_sounds[i].pitch_min = fabs(stof(argv(1))) * 100; + } + break; + case "pitch_max": + if (a == 2) { + dprint("\tMaximum pitch set\n"); + g_sounds[i].pitch_max = fabs(stof(argv(1))) * 100; + } + break; + case "offset": + if (a == 2) { + dprint("\tOffset set\n"); + g_sounds[i].offset = stof(argv(1)); + } + break; + case "looping": + dprint("\tSound set to loop\n"); + g_sounds[i].flags |= SNDFL_LOOPING; + break; + case "nodups": + dprint("\tSound set to not play duplicate samples\n"); + g_sounds[i].flags |= SNDFL_NODUPS; + break; + case "global": + dprint("\tSound set to play everywhere\n"); + g_sounds[i].flags |= SNDFL_GLOBAL; + break; + case "private": + dprint("\tSound set to play privately\n"); + g_sounds[i].flags |= SNDFL_PRIVATE; + break; + case "no_reverb": + dprint("\tSound set to ignore reverb\n"); + g_sounds[i].flags |= SNDFL_NOREVERB; + break; + case "omnidirectional": + dprint("\tSound set to be omnidirectional\n"); + g_sounds[i].flags |= SNDFL_OMNI; + break; + case "follow": + dprint("\tSound set to follow\n"); + g_sounds[i].flags |= SNDFL_FOLLOW; + break; + case "sample": + if (a == 2) { + dprint("\tAdded sample "); + dprint(argv(1)); + dprint("\n"); + precache_sound(argv(1)); + g_sounds[i].samples = sprintf("%s%s\n", g_sounds[i].samples, argv(1)); + g_sounds[i].sample_count++; + } + break; + } +} + +int +Sound_Parse(int i, string line, string shader) +{ + int c; + static string t_name; + static int braced; + + c = tokenize_console(line); + + switch(argv(0)) { + case "{": + /* skip broken syntax */ + if (braced == TRUE || t_name == "") { + break; + } + + dprint("{\n"); + braced = TRUE; + break; + case "}": + /* skip broken syntax */ + if (braced == FALSE) { + break; + } + dprint("}\n"); + braced = FALSE; + t_name = ""; + return TRUE; + break; + default: + if (braced == TRUE) { + Sound_ParseField(i, c); + } else { + /* name/identifer of our message */ + t_name = strtolower(line); + + if (t_name == shader) { + /* I guess it's what we want */ + dprint("Found shader "); + dprint(shader); + dprint(":\n"); + g_sounds[i].name = shader; + } else { + /* not what we're looking for */ + t_name = ""; + } + } + } + return FALSE; +} + +int +Sound_Precache(string shader) +{ + searchhandle sh; + filestream fh; + string line; + int index; + + index = g_sounds_count; + shader = strtolower(shader); + + dprint("[SOUND] Precaching sound shader "); + dprint(shader); + dprint("\n"); + + /* create the hash-table if it doesn't exist */ + if (!g_hashsounds) { + g_hashsounds = hash_createtab(2, HASH_ADD); + } + + /* check if it's already cached */ + for (int i = 0; i < g_sounds_count; i++) { + if (shader == g_sounds[i].name) { + dprint("[SOUND] Shader already precached.\n"); + return i; + } + } + + g_sounds_count++; + g_sounds = memrealloc(g_sounds, sizeof(snd_t), index, g_sounds_count); + + g_sounds[index].volume = 1.0f; + g_sounds[index].dist_max = 1; + g_sounds[index].pitch_min = g_sounds[index].pitch_max = 100; + + sh = search_begin("sound/*.sndshd", TRUE, TRUE); + + for (int i = 0; i < search_getsize(sh); i++) { + fh = fopen(search_getfilename(sh, i), FILE_READ); + if (fh < 0) { + continue; + } + + while ((line = fgets(fh))) { + /* when we found it, quit */ + if (Sound_Parse(index, line, shader) == TRUE) { + search_end(sh); + fclose(fh); + hash_add(g_hashsounds, shader, (int)index); + return index; + } + } + fclose(fh); + } + + dprint("^1[SOUND] No shader found for "); + dprint(shader); + dprint("\n"); + + search_end(sh); + fclose(fh); + return -1; +} + +void +Sound_Play(entity target, int chan, string shader) +{ + int r; + float radius; + float pitch; + int flags; + int sample; + + sample = (int)hash_get(g_hashsounds, shader); + + if (sample < 0) { + return; + } + + /* pick a sample */ + r = floor(random(0, g_sounds[sample].sample_count)); + tokenizebyseparator(g_sounds[sample].samples, "\n"); + + /* set pitch */ + pitch = random(g_sounds[sample].pitch_min, g_sounds[sample].pitch_max); + radius = g_sounds[sample].dist_max; + + /* flags */ + if (g_sounds[sample].flags & SNDFL_NOREVERB) { + flags |= SOUNDFLAG_NOREVERB; + } + if (g_sounds[sample].flags & SNDFL_GLOBAL) { + radius = ATTN_NONE; + } + if (g_sounds[sample].flags & SNDFL_LOOPING) { + flags |= SOUNDFLAG_FORCELOOP; + } + if (g_sounds[sample].flags & SNDFL_NODUPS) { + if (g_sounds[sample].playc >= g_sounds[sample].sample_count) { + g_sounds[sample].playc = 0; + } + r = g_sounds[sample].playc++; + } + if (g_sounds[sample].flags & SOUNDFLAG_FOLLOW) { + flags |= SOUNDFLAG_FOLLOW; + } +#ifdef CSQC + if (g_sounds[sample].flags & SNDFL_OMNI) { + flags |= SOUNDFLAG_NOSPACIALISE; + } +#else + if (g_sounds[sample].flags & SNDFL_PRIVATE) { + flags |= SOUNDFLAG_UNICAST; + msg_entity = target; + } +#endif + +#ifdef DEVELOPER + print(sprintf("Sound_Play: %s\n", argv(r))); +#endif + + sound( + target, + chan, + argv(r), + g_sounds[sample].volume, + radius, + pitch, + flags, + g_sounds[sample].offset + ); +} + +void +Sound_PlayAt(vector pos, string shader) +{ + int r; + float radius; + float pitch; + int flags; + int sample; + + sample = (int)hash_get(g_hashsounds, shader); + + if (sample < 0) { + return; + } + + /* pick a sample */ + r = floor(random(0, g_sounds[sample].sample_count)); + tokenizebyseparator(g_sounds[sample].samples, "\n"); + + /* set pitch */ + pitch = random(g_sounds[sample].pitch_min, g_sounds[sample].pitch_max); + + /* flags */ + if (g_sounds[sample].flags & SNDFL_NOREVERB) { + flags |= SOUNDFLAG_NOREVERB; + } + if (g_sounds[sample].flags & SNDFL_GLOBAL) { + radius = 0; + } + if (g_sounds[sample].flags & SNDFL_LOOPING) { + flags |= SOUNDFLAG_FORCELOOP; + } + if (g_sounds[sample].flags & SNDFL_NODUPS) { + if (g_sounds[sample].playc >= g_sounds[sample].sample_count) { + g_sounds[sample].playc = 0; + } + r = g_sounds[sample].playc++; + } +#ifdef CSQC + if (g_sounds[sample].flags & SNDFL_OMNI) { + flags |= SOUNDFLAG_NOSPACIALISE; + } +#endif + + /* really? this doesn't do any more? */ + pointsound(pos, argv(r), g_sounds[sample].volume, g_sounds[sample].dist_max); +} + +#ifdef CSQC +void +Sound_Update(entity target, int channel, int sample, float volume) +{ + int r; + float radius; + float pitch; + int flags; + + if (sample < 0) { + return; + } + + /* pick a sample */ + r = floor(random(0, g_sounds[sample].sample_count)); + tokenizebyseparator(g_sounds[sample].samples, "\n"); + + /* set pitch */ + pitch = random(g_sounds[sample].pitch_min, g_sounds[sample].pitch_max); + radius = g_sounds[sample].dist_max; + + /* flags */ + if (g_sounds[sample].flags & SNDFL_NOREVERB) { + flags |= SOUNDFLAG_NOREVERB; + } + if (g_sounds[sample].flags & SNDFL_GLOBAL) { + radius = ATTN_NONE; + } + if (g_sounds[sample].flags & SNDFL_LOOPING) { + flags |= SOUNDFLAG_FORCELOOP; + } + if (g_sounds[sample].flags & SNDFL_NODUPS) { + if (g_sounds[sample].playc >= g_sounds[sample].sample_count) { + g_sounds[sample].playc = 0; + } + r = g_sounds[sample].playc++; + } + if (g_sounds[sample].flags & SNDFL_OMNI) { + flags |= SOUNDFLAG_NOSPACIALISE; + } + + soundupdate( + target, + channel, + argv(0), + g_sounds[sample].volume * volume, + radius, + pitch, + flags, + g_sounds[sample].offset + ); +} +#endif