From: TimePath Date: Sun, 8 Nov 2015 01:24:48 +0000 (+1100) Subject: GlobalSound: send as tempentity X-Git-Tag: xonotic-v0.8.2~1653^2~13 X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=11699a3c83f90d15c9bd86f69497e77fb4880083;p=xonotic%2Fxonotic-data.pk3dir.git GlobalSound: send as tempentity --- diff --git a/qcsrc/common/effects/qc/all.inc b/qcsrc/common/effects/qc/all.inc index cda1a638c..6b5c2fffe 100644 --- a/qcsrc/common/effects/qc/all.inc +++ b/qcsrc/common/effects/qc/all.inc @@ -1,5 +1,6 @@ #include "casings.qc" #include "damageeffects.qc" #include "gibs.qc" +#include "globalsound.qc" #include "lightningarc.qc" #include "modeleffects.qc" diff --git a/qcsrc/common/effects/qc/globalsound.qc b/qcsrc/common/effects/qc/globalsound.qc new file mode 100644 index 000000000..0d21895ec --- /dev/null +++ b/qcsrc/common/effects/qc/globalsound.qc @@ -0,0 +1,376 @@ +#include "globalsound.qh" +#ifdef IMPLEMENTATION + #include "../../animdecide.qh" + + #ifdef SVQC + #include "../../../server/cl_player.qh" + #endif + + REGISTER_NET_TEMP(globalsound) + + #ifdef SVQC + /** + * @param from the source entity, its position is sent + * @param gs the global sound def + * @param r a random number in 0..1 + */ + void globalsound(int channel, entity from, entity gs, float r, int chan, float vol, float atten) + { + if (channel == MSG_ONE && !IS_REAL_CLIENT(msg_entity)) return; + WriteHeader(channel, globalsound); + WriteByte(channel, gs.m_id); + WriteByte(channel, r * 255); + WriteByte(channel, etof(from)); + WriteByte(channel, fabs(chan)); + WriteByte(channel, floor(vol * 255)); + WriteByte(channel, floor(atten * 64)); + vector o = from.origin + 0.5 * (from.mins + from.maxs); + WriteCoord(channel, o.x); + WriteCoord(channel, o.y); + WriteCoord(channel, o.z); + } + #endif + + string GlobalSound_sample(string pair, float r); + + #ifdef CSQC + + NET_HANDLE(globalsound, bool isnew) + { + entity gs = GlobalSounds_from(ReadByte()); + float r = ReadByte() / 255; + string sample = GlobalSound_sample(gs.m_globalsoundstr, r); + int who = ReadByte(); + int chan = ReadByte(); + float vol = ReadByte() / 255; + float atten = ReadByte() / 64; + vector o; + o.x = ReadCoord(); + o.y = ReadCoord(); + o.z = ReadCoord(); + if (who == player_localnum + 1) + { + // client knows better, play at current position to unlag + entity e = findfloat(world, entnum, who); + sound7(e, chan, sample, vol, atten, 0, 0); + } + else + { + entity e = new(globalsound); + e.origin = o; + sound8(e, o, chan, sample, vol, atten, 0, 0); + remove(e); // debug with: e.think = SUB_Remove; e.nextthink = time + 1; + } + return true; + } + + #endif + + string GlobalSound_sample(string pair, float r) + { + int n; + { + string s = cdr(pair); + if (s) n = stof(s); + else n = 0; + } + string sample = car(pair); + if (n > 0) sample = sprintf("%s%d.wav", sample, floor(r * n + 1)); // randomization + else sample = sprintf("%s.wav", sample); + return sample; + } + + void PrecacheGlobalSound(string sample) + { + int n; + { + string s = cdr(sample); + if (s) n = stof(s); + else n = 0; + } + sample = car(sample); + if (n > 0) + { + for (int i = 1; i <= n; ++i) + precache_sound(sprintf("%s%d.wav", sample, i)); + } + else + { + precache_sound(sprintf("%s.wav", sample)); + } + } + + #ifdef SVQC + + int GetVoiceMessageVoiceType(string type) + { + if (type == "taunt") return VOICETYPE_TAUNT; + if (type == "teamshoot") return VOICETYPE_LASTATTACKER; + return VOICETYPE_TEAMRADIO; + } + + .string GetVoiceMessageSampleField(string type) + { + GetPlayerSoundSampleField_notFound = false; + switch (type) + { + #define X(m) case #m: return playersound_##m; + ALLVOICEMSGS(X) + #undef X + } + GetPlayerSoundSampleField_notFound = true; + return playersound_taunt; + } + + .string GetPlayerSoundSampleField(string type) + { + GetPlayerSoundSampleField_notFound = false; + switch (type) + { + #define X(m) case #m: return playersound_##m; + ALLPLAYERSOUNDS(X) + #undef X + } + GetPlayerSoundSampleField_notFound = true; + return playersound_taunt; + } + + string allvoicesamples; + + void PrecachePlayerSounds(string f) + { + int fh = fopen(f, FILE_READ); + if (fh < 0) + { + LOG_WARNINGF("Player sound file not found: %s\n", f); + return; + } + for (string s; (s = fgets(fh)); ) + { + int n = tokenize_console(s); + if (n != 3) + { + if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s); + continue; + } + string file = argv(1); + string variants = argv(2); + PrecacheGlobalSound(strcat(file, " ", variants)); + } + fclose(fh); + + if (!allvoicesamples) + { + #define X(m) allvoicesamples = strcat(allvoicesamples, " ", #m); + ALLVOICEMSGS(X) + #undef X + allvoicesamples = strzone(substring(allvoicesamples, 1, -1)); + } + } + + void ClearPlayerSounds(entity this) + { + #define X(m) \ + if (this.playersound_##m) \ + { \ + strunzone(this.playersound_##m); \ + this.playersound_##m = string_null; \ + } + ALLPLAYERSOUNDS(X) + ALLVOICEMSGS(X) + #undef X + } + + bool LoadPlayerSounds(string f, bool strict) + { + SELFPARAM(); + int fh = fopen(f, FILE_READ); + if (fh < 0) + { + if (strict) LOG_WARNINGF("Player sound file not found: %s\n", f); + return false; + } + for (string s; (s = fgets(fh)); ) + { + int n = tokenize_console(s); + if (n != 3) + { + if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s); + continue; + } + string key = argv(0); + var.string field = GetPlayerSoundSampleField(key); + if (GetPlayerSoundSampleField_notFound) field = GetVoiceMessageSampleField(key); + if (GetPlayerSoundSampleField_notFound) + { + LOG_TRACEF("Invalid sound info field: %s\n", key); + continue; + } + string file = argv(1); + string variants = argv(2); + if (self.(field)) strunzone(self.(field)); + self.(field) = strzone(strcat(file, " ", variants)); + } + fclose(fh); + return true; + } + + .int modelindex_for_playersound; + .int skin_for_playersound; + + void UpdatePlayerSounds(entity this) + { + if (this.modelindex == this.modelindex_for_playersound && this.skin == this.skin_for_playersound) return; + this.modelindex_for_playersound = this.modelindex; + this.skin_for_playersound = this.skin; + ClearPlayerSounds(this); + LoadPlayerSounds("sound/player/default.sounds", true); + if (autocvar_g_debug_defaultsounds) return; + if (!LoadPlayerSounds(get_model_datafilename(this.model, this.skin, "sounds"), false)) + LoadPlayerSounds(get_model_datafilename( + this.model, 0, + "sounds"), + true); + } + + void _GlobalSound(entity gs, string sample, int chan, int voicetype, bool fake) + { + SELFPARAM(); + if (gs == NULL && sample == "") return; + float r = random(); + if (sample != "") sample = GlobalSound_sample(sample, r); + switch (voicetype) + { + case VOICETYPE_LASTATTACKER_ONLY: + case VOICETYPE_LASTATTACKER: + { + if (!fake) + { + if (!this.pusher) break; + msg_entity = this.pusher; + if (IS_REAL_CLIENT(msg_entity)) + { + float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; + if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASEVOICE, atten); + else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); + } + } + if (voicetype == VOICETYPE_LASTATTACKER_ONLY) break; + msg_entity = this; + if (IS_REAL_CLIENT(msg_entity)) + { + if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASE, ATTEN_NONE); + else soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NONE); + } + break; + } + case VOICETYPE_TEAMRADIO: + { + #define X() \ + do \ + { \ + float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; \ + if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASEVOICE, atten); \ + else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \ + } \ + while (0) + + if (fake) { msg_entity = this; X(); } + else + { + FOR_EACH_REALCLIENT(msg_entity) + { + if (!teamplay || msg_entity.team == this.team) X(); + } + } + #undef X + break; + } + case VOICETYPE_AUTOTAUNT: + case VOICETYPE_TAUNT: + { + if (voicetype == VOICETYPE_AUTOTAUNT) if (!sv_autotaunt) { break; }else {} + else if (IS_PLAYER(this) && this.deadflag == DEAD_NO) animdecide_setaction(this, ANIMACTION_TAUNT, + true); + if (!sv_taunt) break; + if (autocvar_sv_gentle) break; + float tauntrand = 0; + if (voicetype == VOICETYPE_AUTOTAUNT) tauntrand = random(); + #define X() \ + do \ + { \ + if (voicetype != VOICETYPE_AUTOTAUNT || tauntrand < msg_entity.cvar_cl_autotaunt) \ + { \ + float atten = (msg_entity.cvar_cl_voice_directional >= 1) \ + ? bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, \ + ATTEN_MAX) \ + : ATTEN_NONE; \ + if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASEVOICE, atten); \ + else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \ + } \ + } \ + while (0) + if (fake) + { + msg_entity = this; + X(); + } + else + { + FOR_EACH_REALCLIENT(msg_entity) + { + X(); + } + } + #undef X + break; + } + case VOICETYPE_PLAYERSOUND: + { + msg_entity = this; + if (fake) + { + if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASE, ATTEN_NORM); + else soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NORM); + } + else + { + if (gs) globalsound(MSG_ALL, this, gs, r, chan, VOL_BASE, ATTEN_NORM); + else _sound(this, chan, sample, VOL_BASE, ATTEN_NORM); + } + break; + } + default: + { + backtrace("Invalid voice type!"); + break; + } + } + } + + void PlayerSound(.string samplefield, int chan, float voicetype) + { + SELFPARAM(); + _GlobalSound(NULL, this.(samplefield), chan, voicetype, false); + } + + void VoiceMessage(string type, string msg) + { + SELFPARAM(); + var.string sample = GetVoiceMessageSampleField(type); + if (GetPlayerSoundSampleField_notFound) + { + sprint(this, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples)); + return; + } + int voicetype = GetVoiceMessageVoiceType(type); + bool ownteam = (voicetype == VOICETYPE_TEAMRADIO); + int flood = Say(this, ownteam, world, msg, true); + bool fake; + if (IS_SPEC(this) || IS_OBSERVER(this) || flood < 0) fake = true; + else if (flood > 0) fake = false; + else return; + _GlobalSound(NULL, this.(sample), CH_VOICE, voicetype, fake); + } + #endif +#endif diff --git a/qcsrc/common/effects/qc/globalsound.qh b/qcsrc/common/effects/qc/globalsound.qh new file mode 100644 index 000000000..926e0ba04 --- /dev/null +++ b/qcsrc/common/effects/qc/globalsound.qh @@ -0,0 +1,91 @@ +#ifndef GLOBALSOUND_H +#define GLOBALSOUND_H + +// player sounds, voice messages +// TODO implemented fall and falling +#define ALLPLAYERSOUNDS(X) \ + X(death) \ + X(drown) \ + X(fall) \ + X(falling) \ + X(gasp) \ + X(jump) \ + X(pain100) \ + X(pain25) \ + X(pain50) \ + X(pain75) + +#define ALLVOICEMSGS(X) \ + X(attack) \ + X(attackinfive) \ + X(coverme) \ + X(defend) \ + X(freelance) \ + X(incoming) \ + X(meet) \ + X(needhelp) \ + X(seenflag) \ + X(taunt) \ + X(teamshoot) + +// reserved sound names for the future (some models lack sounds for them): +// _VOICEMSG(flagcarriertakingdamage) +// _VOICEMSG(getflag) +// reserved sound names for the future (ALL models lack sounds for them): +// _VOICEMSG(affirmative) +// _VOICEMSG(attacking) +// _VOICEMSG(defending) +// _VOICEMSG(roaming) +// _VOICEMSG(onmyway) +// _VOICEMSG(droppedflag) +// _VOICEMSG(negative) +// _VOICEMSG(seenenemy) + +.string m_globalsoundstr; +REGISTRY(GlobalSounds, BITS(8) - 1) +#define GlobalSounds_from(i) _GlobalSounds_from(i, NULL) +#define REGISTER_GLOBALSOUND(id, str) \ + REGISTER(RegisterGlobalSounds, GS, GlobalSounds, id, m_id, new(GlobalSound)) \ + { \ + make_pure(this); \ + this.m_globalsoundstr = str; \ + } +REGISTER_REGISTRY(RegisterGlobalSounds) +REGISTRY_SORT(GlobalSounds, 0) +STATIC_INIT(GlobalSounds_renumber) { FOREACH(GlobalSounds, true, LAMBDA(it.m_id = i)); } +REGISTRY_CHECK(GlobalSounds) +void PrecacheGlobalSound(string samplestring); +PRECACHE(GlobalSounds) +{ + FOREACH(GlobalSounds, true, LAMBDA(PrecacheGlobalSound(it.m_globalsoundstr))); +} + +REGISTER_GLOBALSOUND(STEP, "misc/footstep0 6") +REGISTER_GLOBALSOUND(STEP_METAL, "misc/metalfootstep0 6") +REGISTER_GLOBALSOUND(FALL, "misc/hitground 4") +REGISTER_GLOBALSOUND(FALL_METAL, "misc/metalhitground 4") + +#ifdef SVQC + + #define X(m) .string playersound_##m; + ALLPLAYERSOUNDS(X) + ALLVOICEMSGS(X) + #undef X + + bool GetPlayerSoundSampleField_notFound; + float GetVoiceMessageVoiceType(string type); + .string GetVoiceMessageSampleField(string type); + .string GetPlayerSoundSampleField(string type); + void PrecachePlayerSounds(string f); + void ClearPlayerSounds(entity this); + float LoadPlayerSounds(string f, bool strict); + void UpdatePlayerSounds(entity this); + #define FakeGlobalSound(sample, chan, voicetype) _GlobalSound(NULL, sample, chan, voicetype, true) + void _GlobalSound(entity gs, string sample, float chan, float voicetype, bool fake); + #define GlobalSound(def, chan, voicetype) _GlobalSound(def, string_null, chan, voicetype, false) + void PlayerSound(.string samplefield, float chan, float voicetype); + void VoiceMessage(string type, string msg); + +#endif + +#endif diff --git a/qcsrc/common/monsters/sv_monsters.qc b/qcsrc/common/monsters/sv_monsters.qc index a3610e17f..6c35de85f 100644 --- a/qcsrc/common/monsters/sv_monsters.qc +++ b/qcsrc/common/monsters/sv_monsters.qc @@ -346,7 +346,7 @@ void Monster_Sound(.string samplefield, float sound_delay, float delaytoo, float if(delaytoo) if(time < self.msound_delay) return; // too early - _GlobalSound(self.(samplefield), chan, VOICETYPE_PLAYERSOUND, false); + _GlobalSound(NULL, self.(samplefield), chan, VOICETYPE_PLAYERSOUND, false); self.msound_delay = time + sound_delay; } diff --git a/qcsrc/common/physics.qc b/qcsrc/common/physics.qc index b01efd32b..9f8f2852d 100644 --- a/qcsrc/common/physics.qc +++ b/qcsrc/common/physics.qc @@ -1100,27 +1100,19 @@ void PM_check_frozen() void PM_check_hitground() {SELFPARAM(); #ifdef SVQC - if (IS_ONGROUND(self)) - if (IS_PLAYER(self)) // no fall sounds for observers thank you very much - if (self.wasFlying) - { - self.wasFlying = 0; - if (self.waterlevel < WATERLEVEL_SWIMMING) - if (time >= self.ladder_time) - if (!self.hook) - { - self.nextstep = time + 0.3 + random() * 0.1; - trace_dphitq3surfaceflags = 0; - tracebox(self.origin, self.mins, self.maxs, self.origin - '0 0 1', MOVE_NOMONSTERS, self); - if (!(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS)) - { - if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS) - GlobalSound(GS_FALL_METAL, CH_PLAYER, VOICETYPE_PLAYERSOUND); - else - GlobalSound(GS_FALL, CH_PLAYER, VOICETYPE_PLAYERSOUND); - } - } - } + if (!IS_PLAYER(this)) return; // no fall sounds for observers thank you very much + if (!IS_ONGROUND(this)) return; + if (!this.wasFlying) return; + this.wasFlying = false; + if (this.waterlevel >= WATERLEVEL_SWIMMING) return; + if (time < this.ladder_time) return; + if (this.hook) return; + this.nextstep = time + 0.3 + random() * 0.1; + trace_dphitq3surfaceflags = 0; + tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 1', MOVE_NOMONSTERS, this); + if ((trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOSTEPS)) return; + entity fall = (trace_dphitq3surfaceflags & Q3SURFACEFLAG_METALSTEPS) ? GS_FALL_METAL : GS_FALL; + GlobalSound(fall, CH_PLAYER, VOICETYPE_PLAYERSOUND); #endif } diff --git a/qcsrc/common/sounds/sound.qh b/qcsrc/common/sounds/sound.qh index 36bdaa833..503290b6c 100644 --- a/qcsrc/common/sounds/sound.qh +++ b/qcsrc/common/sounds/sound.qh @@ -1,22 +1,29 @@ #ifndef SOUND_H #define SOUND_H +// negative = SVQC autochannels +// positive = one per entity + const int CH_INFO = 0; -const int CH_TRIGGER = -3; const int CH_WEAPON_A = -1; +const int CH_WEAPON_B = -1; const int CH_WEAPON_SINGLE = 1; const int CH_VOICE = -2; -const int CH_BGM_SINGLE = 8; -const int CH_AMBIENT = -9; +// const int CH_VOICE_SINGLE = 2; +const int CH_TRIGGER = -3; const int CH_TRIGGER_SINGLE = 3; const int CH_SHOTS = -4; const int CH_SHOTS_SINGLE = 4; -const int CH_WEAPON_B = -1; +// const int CH_TUBA = -5; +const int CH_TUBA_SINGLE = 5; const int CH_PAIN = -6; const int CH_PAIN_SINGLE = 6; const int CH_PLAYER = -7; const int CH_PLAYER_SINGLE = 7; -const int CH_TUBA_SINGLE = 5; +// const int CH_BGM_SINGLE = -8; +const int CH_BGM_SINGLE = 8; +const int CH_AMBIENT = -9; +// const int CH_AMBIENT_SINGLE = 9; const float ATTEN_NONE = 0; const float ATTEN_MIN = 0.015625; diff --git a/qcsrc/lib/net.qh b/qcsrc/lib/net.qh index f6013f97a..84a65ea5c 100644 --- a/qcsrc/lib/net.qh +++ b/qcsrc/lib/net.qh @@ -86,11 +86,12 @@ #ifdef CSQC #define REGISTER_NET_LINKED(id) \ - [[accumulate]] NET_HANDLE(id, bool) \ + [[accumulate]] NET_HANDLE(id, bool isnew) \ { \ this = self; \ this.sourceLocFile = __FILE__; \ this.sourceLocLine = __LINE__; \ + if (!this) isnew = true; \ } \ REGISTER(RegisterLinkedEntities, NET, LinkedEntities, id, m_id, new(net_linked_packet)) \ { \ diff --git a/qcsrc/server/cl_player.qc b/qcsrc/server/cl_player.qc index b49488b05..a9a5d03cb 100644 --- a/qcsrc/server/cl_player.qc +++ b/qcsrc/server/cl_player.qc @@ -959,282 +959,3 @@ int Say(entity source, float teamsay, entity privatesay, string msgin, bool floo return ret; } - -int GetVoiceMessageVoiceType(string type) -{ - if (type == "taunt") return VOICETYPE_TAUNT; - if (type == "teamshoot") return VOICETYPE_LASTATTACKER; - return VOICETYPE_TEAMRADIO; -} - -.string GetVoiceMessageSampleField(string type) -{ - GetPlayerSoundSampleField_notFound = false; - switch (type) - { -#define X(m) case #m: return playersound_##m; - ALLVOICEMSGS(X) -#undef X - } - GetPlayerSoundSampleField_notFound = true; - return playersound_taunt; -} - -.string GetPlayerSoundSampleField(string type) -{ - GetPlayerSoundSampleField_notFound = false; - switch (type) - { -#define X(m) case #m: return playersound_##m; - ALLPLAYERSOUNDS(X) -#undef X - } - GetPlayerSoundSampleField_notFound = true; - return playersound_taunt; -} - -void PrecacheGlobalSound(string sample) -{ - int n; - { - string s = cdr(sample); - if (s) n = stof(s); - else n = 0; - } - sample = car(sample); - if (n > 0) - { - for (int i = 1; i <= n; ++i) - precache_sound(sprintf("%s%d.wav", sample, i)); - } - else - { - precache_sound(sprintf("%s.wav", sample)); - } -} - -string allvoicesamples; - -void PrecachePlayerSounds(string f) -{ - int fh = fopen(f, FILE_READ); - if (fh < 0) - { - LOG_WARNINGF("Player sound file not found: %s\n", f); - return; - } - for (string s; (s = fgets(fh)); ) - { - int n = tokenize_console(s); - if (n != 3) - { - if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s); - continue; - } - string file = argv(1); - string variants = argv(2); - PrecacheGlobalSound(strcat(file, " ", variants)); - } - fclose(fh); - - if (!allvoicesamples) - { -#define X(m) allvoicesamples = strcat(allvoicesamples, " ", #m); - ALLVOICEMSGS(X) -#undef X - allvoicesamples = strzone(substring(allvoicesamples, 1, -1)); - } -} - -void ClearPlayerSounds(entity this) -{ -#define X(m) if (this.playersound_##m) { strunzone(this.playersound_##m); this.playersound_##m = string_null; } - ALLPLAYERSOUNDS(X) - ALLVOICEMSGS(X) -#undef X -} - -bool LoadPlayerSounds(string f, bool strict) -{ - SELFPARAM(); - int fh = fopen(f, FILE_READ); - if (fh < 0) - { - if (strict) LOG_WARNINGF("Player sound file not found: %s\n", f); - return false; - } - for (string s; (s = fgets(fh)); ) - { - int n = tokenize_console(s); - if (n != 3) - { - if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s); - continue; - } - string key = argv(0); - var .string field = GetPlayerSoundSampleField(key); - if (GetPlayerSoundSampleField_notFound) field = GetVoiceMessageSampleField(key); - if (GetPlayerSoundSampleField_notFound) - { - LOG_TRACEF("Invalid sound info field: %s\n", key); - continue; - } - string file = argv(1); - string variants = argv(2); - if (self.(field)) strunzone(self.(field)); - self.(field) = strzone(strcat(file, " ", variants)); - } - fclose(fh); - return true; -} - -.int modelindex_for_playersound; -.int skin_for_playersound; - -void UpdatePlayerSounds(entity this) -{ - if (this.modelindex == this.modelindex_for_playersound && this.skin == this.skin_for_playersound) return; - this.modelindex_for_playersound = this.modelindex; - this.skin_for_playersound = this.skin; - ClearPlayerSounds(this); - LoadPlayerSounds("sound/player/default.sounds", true); - if (autocvar_g_debug_defaultsounds) return; - if (!LoadPlayerSounds(get_model_datafilename(this.model, this.skin, "sounds"), false)) - LoadPlayerSounds(get_model_datafilename(this.model, 0, "sounds"), true); -} - -void _GlobalSound(string sample, int chan, int voicetype, bool fake) -{ - SELFPARAM(); - if (sample == "") return; - int n; - { - string s = cdr(sample); - if (s) n = stof(s); - else n = 0; - } - sample = car(sample); - if (n > 0) sample = sprintf("%s%d.wav", sample, floor(random() * n + 1)); // randomization - else sample = sprintf("%s.wav", sample); - switch (voicetype) - { - case VOICETYPE_LASTATTACKER_ONLY: - case VOICETYPE_LASTATTACKER: - { - if (!fake) - { - if (!this.pusher) break; - msg_entity = this.pusher; - if (IS_REAL_CLIENT(msg_entity)) - { - float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; - soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); - } - } - if (voicetype == VOICETYPE_LASTATTACKER_ONLY) break; - msg_entity = this; - if (IS_REAL_CLIENT(msg_entity)) soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NONE); - break; - } - case VOICETYPE_TEAMRADIO: - { - #define X() \ - do \ - { \ - float atten = (msg_entity.cvar_cl_voice_directional == 1) ? ATTEN_MIN : ATTEN_NONE; \ - soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \ - } \ - while (0) - - if (fake) { msg_entity = this; X(); } - else - { - FOR_EACH_REALCLIENT(msg_entity) - { - if (!teamplay || msg_entity.team == this.team) X(); - } - } - #undef X - break; - } - case VOICETYPE_AUTOTAUNT: - case VOICETYPE_TAUNT: - { - if (voicetype == VOICETYPE_AUTOTAUNT) if (!sv_autotaunt) { break; }else {} - else if (IS_PLAYER(this) && this.deadflag == DEAD_NO) animdecide_setaction(this, ANIMACTION_TAUNT, true); - if (!sv_taunt) break; - if (autocvar_sv_gentle) break; - float tauntrand = 0; - if (voicetype == VOICETYPE_AUTOTAUNT) tauntrand = random(); - #define X() \ - do \ - { \ - if (voicetype != VOICETYPE_AUTOTAUNT || tauntrand < msg_entity.cvar_cl_autotaunt) \ - { \ - float atten = (msg_entity.cvar_cl_voice_directional >= 1) \ - ? bound(ATTEN_MIN, msg_entity.cvar_cl_voice_directional_taunt_attenuation, ATTEN_MAX) \ - : ATTEN_NONE; \ - soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \ - } \ - } \ - while (0) - if (fake) - { - msg_entity = this; - X(); - } - else - { - FOR_EACH_REALCLIENT(msg_entity) - { - X(); - } - } - #undef X - break; - } - case VOICETYPE_PLAYERSOUND: - { - if (fake) - { - msg_entity = this; - soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NORM); - } - else - { - _sound(this, chan, sample, VOL_BASE, ATTEN_NORM); - } - break; - } - default: - { - backtrace("Invalid voice type!"); - break; - } - } -} - -void PlayerSound(.string samplefield, int chan, float voicetype) -{ - SELFPARAM(); - _GlobalSound(this.(samplefield), chan, voicetype, false); -} - -void VoiceMessage(string type, string msg) -{ - SELFPARAM(); - var .string sample = GetVoiceMessageSampleField(type); - if (GetPlayerSoundSampleField_notFound) - { - sprint(this, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples)); - return; - } - int voicetype = GetVoiceMessageVoiceType(type); - bool ownteam = (voicetype == VOICETYPE_TEAMRADIO); - int flood = Say(this, ownteam, world, msg, true); - bool fake; - if (IS_SPEC(this) || IS_OBSERVER(this) || flood < 0) fake = true; - else if (flood > 0) fake = false; - else return; - _GlobalSound(this.(sample), CH_VOICE, voicetype, fake); -} diff --git a/qcsrc/server/cl_player.qh b/qcsrc/server/cl_player.qh index b74b6f01c..e55b1c614 100644 --- a/qcsrc/server/cl_player.qh +++ b/qcsrc/server/cl_player.qh @@ -39,86 +39,4 @@ void PlayerDamage(entity inflictor, entity attacker, float damage, int deathtype .float muted; int Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol); -// player sounds, voice messages -// TODO implemented fall and falling -#define ALLPLAYERSOUNDS(X) \ - X(death) \ - X(drown) \ - X(fall) \ - X(falling) \ - X(gasp) \ - X(jump) \ - X(pain100) \ - X(pain25) \ - X(pain50) \ - X(pain75) - -#define ALLVOICEMSGS(X) \ - X(attack) \ - X(attackinfive) \ - X(coverme) \ - X(defend) \ - X(freelance) \ - X(incoming) \ - X(meet) \ - X(needhelp) \ - X(seenflag) \ - X(taunt) \ - X(teamshoot) - -// reserved sound names for the future (some models lack sounds for them): -// _VOICEMSG(flagcarriertakingdamage) -// _VOICEMSG(getflag) -// reserved sound names for the future (ALL models lack sounds for them): -// _VOICEMSG(affirmative) -// _VOICEMSG(attacking) -// _VOICEMSG(defending) -// _VOICEMSG(roaming) -// _VOICEMSG(onmyway) -// _VOICEMSG(droppedflag) -// _VOICEMSG(negative) -// _VOICEMSG(seenenemy) - -#define X(m) .string playersound_##m; -ALLPLAYERSOUNDS(X) -ALLVOICEMSGS(X) -#undef X - -bool GetPlayerSoundSampleField_notFound; -float GetVoiceMessageVoiceType(string type); -.string GetVoiceMessageSampleField(string type); -.string GetPlayerSoundSampleField(string type); -void PrecacheGlobalSound(string samplestring); -void PrecachePlayerSounds(string f); -void ClearPlayerSounds(entity this); -float LoadPlayerSounds(string f, bool strict); -void UpdatePlayerSounds(entity this); -#define FakeGlobalSound(sample, chan, voicetype) _GlobalSound(sample, chan, voicetype, true) -void _GlobalSound(string sample, float chan, float voicetype, bool fake); -#define GlobalSound(def, chan, voicetype) _GlobalSound((def).m_globalsoundstr, chan, voicetype, false) -void PlayerSound(.string samplefield, float chan, float voicetype); -void VoiceMessage(string type, string msg); - -.string m_globalsoundstr; -REGISTRY(GlobalSounds, BITS(8) - 1) -#define GlobalSounds_from(i) _GlobalSounds_from(i, NULL) -#define REGISTER_GLOBALSOUND(id, str) \ - REGISTER(RegisterGlobalSounds, GS, GlobalSounds, id, m_id, new(GlobalSound)) \ - { \ - make_pure(this); \ - this.m_globalsoundstr = str; \ - } -REGISTER_REGISTRY(RegisterGlobalSounds) -REGISTRY_SORT(GlobalSounds, 0) -REGISTRY_CHECK(GlobalSounds) -PRECACHE(GlobalSounds) -{ - FOREACH(GlobalSounds, true, LAMBDA(PrecacheGlobalSound(it.m_globalsoundstr))); -} - -REGISTER_GLOBALSOUND(STEP, "misc/footstep0 6") -REGISTER_GLOBALSOUND(STEP_METAL, "misc/metalfootstep0 6") -REGISTER_GLOBALSOUND(FALL, "misc/hitground 4") -REGISTER_GLOBALSOUND(FALL_METAL, "misc/metalhitground 4") - #endif