]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/effects/qc/globalsound.qc
Merge branch 'master' into Mario/entrap_nade
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / effects / qc / globalsound.qc
index 0d21895ec77b8b7682ec91d30d547c95e0ac3113..a2653238e7ebea30ad5a22f26203adf9156c66e1 100644 (file)
 #include "globalsound.qh"
+
+#include <common/ent_cs.qh>
+
 #ifdef IMPLEMENTATION
-    #include "../../animdecide.qh"
+       #include <common/animdecide.qh>
 
-    #ifdef SVQC
-        #include "../../../server/cl_player.qh"
-    #endif
+       #ifdef SVQC
+               #include <server/cl_player.qh>
+       #endif
 
        REGISTER_NET_TEMP(globalsound)
+       REGISTER_NET_TEMP(playersound)
 
-    #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));
+       string GlobalSound_sample(string pair, float r);
+
+       #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)
+               {
+                       //assert(IS_PLAYER(from), eprint(from));
+                       if (channel == MSG_ONE && !IS_REAL_CLIENT(msg_entity)) return;
+                       if (!autocvar_g_debug_globalsounds) {
+                               string sample = GlobalSound_sample(gs.m_globalsoundstr, r);
+                               switch (channel) {
+                                       case MSG_ONE:
+                                               soundto(channel, from, chan, sample, _vol, _atten);
+                                               break;
+                                       case MSG_ALL:
+                                               _sound(from, chan, sample, _vol, _atten);
+                                               break;
+                               }
+                               return;
+                       }
+                       WriteHeader(channel, globalsound);
+                       WriteByte(channel, gs.m_id);
+                       WriteByte(channel, r * 255);
+                       WriteByte(channel, etof(from));
+                       WriteByte(channel, chan);
+                       WriteByte(channel, floor(_vol * 255));
+                       WriteByte(channel, floor(_atten * 64));
+                       entcs_force_origin(from);
                        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);
+               /**
+               * @param from the source entity, its position is sent
+               * @param ps the player sound def
+               * @param r a random number in 0..1
+               */
+               void playersound(int channel, entity from, entity ps, float r, int chan, float _vol, float _atten)
+               {
+                       //assert(IS_PLAYER(from), eprint(from));
+                       if (channel == MSG_ONE && !IS_REAL_CLIENT(msg_entity)) return;
+                       if (!autocvar_g_debug_globalsounds) {
+                               //UpdatePlayerSounds(from);
+                               string s = from.(ps.m_playersoundfld);
+                               string sample = GlobalSound_sample(s, r);
+                               switch (channel) {
+                                       case MSG_ONE:
+                                               soundto(channel, from, chan, sample, _vol, _atten);
+                                               break;
+                                       case MSG_ALL:
+                                               _sound(from, chan, sample, _vol, _atten);
+                                               break;
+                               }
+                               return;
+                       }
+                       WriteHeader(channel, playersound);
+                       WriteByte(channel, ps.m_id);
+                       WriteByte(channel, r * 255);
+                       WriteByte(channel, etof(from));
+                       WriteByte(channel, chan);
+                       WriteByte(channel, floor(_vol * 255));
+                       WriteByte(channel, floor(_atten * 64));
+                       entcs_force_origin(from);
+                       vector o = from.origin + 0.5 * (from.mins + from.maxs);
+                       WriteCoord(channel, o.x);
+                       WriteCoord(channel, o.y);
+                       WriteCoord(channel, o.z);
+               }
+       #endif
 
        #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;
+                       entity gs = GlobalSounds_from(ReadByte());
+                       float r = ReadByte() / 255;
+                       string sample = GlobalSound_sample(gs.m_globalsoundstr, r);
+                       int who = ReadByte();
+                       entity e = entcs_receiver(who - 1);
+                       int chan = ReadSByte();
+                       float vol = ReadByte() / 255;
+                       float atten = ReadByte() / 64;
+                       vector o;
+                       o.x = ReadCoord();
+                       o.y = ReadCoord();
+                       o.z = ReadCoord();
+                       // TODO: is this really what we want to be doing? Footsteps that follow the player at head height?
+                       if (who == player_currententnum) e = findfloat(NULL, entnum, who);  // play at camera position for full volume
+                       else if (e) e.origin = o;
+                       if (e)
+                       {
+                               sound7(e, chan, sample, vol, atten, 0, 0);
+                       }
+                       else
+                       {
+                               // Can this happen?
+                               LOG_WARNINGF("Missing entcs data for player %d\n", who);
+                               sound8(e, o, chan, sample, vol, atten, 0, 0);
+                       }
+                       return true;
+               }
+
+               NET_HANDLE(playersound, bool isnew)
+               {
+                       entity ps = PlayerSounds_from(ReadByte());
+                       float r = ReadByte() / 255;
+                       int who = ReadByte();
+                       entity e = entcs_receiver(who - 1);
+                       UpdatePlayerSounds(e);
+                       string s = e.(ps.m_playersoundfld);
+                       string sample = GlobalSound_sample(s, r);
+                       int chan = ReadSByte();
+                       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);
+                       if (who == player_currententnum) e = findfloat(NULL, entnum, who);  // play at camera position for full volume
+                       else if (e) e.origin = o;
+                       if (e)
+                       {
+                               // TODO: for non-visible players, origin should probably continue to be updated as long as the sound is playing
                                sound7(e, chan, sample, vol, atten, 0, 0);
-                   }
-                   else
-                   {
-                               entity e = new(globalsound);
-                               e.origin = o;
+                       }
+                       else
+                       {
+                               // Can this happen?
+                               LOG_WARNINGF("Missing entcs data for player %d\n", who);
                                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;
-    }
+       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)
        {
                }
        }
 
-       #ifdef SVQC
+       entity GetVoiceMessage(string type)
+       {
+               FOREACH(PlayerSounds, it.m_playersoundstr == type && it.instanceOfVoiceMessage == true, return it);
+               return NULL;
+       }
 
-               int GetVoiceMessageVoiceType(string type)
-               {
-                       if (type == "taunt") return VOICETYPE_TAUNT;
-                       if (type == "teamshoot") return VOICETYPE_LASTATTACKER;
-                       return VOICETYPE_TEAMRADIO;
-               }
+       entity GetPlayerSound(string type)
+       {
+               FOREACH(PlayerSounds, it.m_playersoundstr == type && it.instanceOfVoiceMessage == false, return it);
+               return NULL;
+       }
+
+       .string _GetPlayerSoundSampleField(string type, bool voice)
+       {
+               GetPlayerSoundSampleField_notFound = false;
+               entity e = voice ? GetVoiceMessage(type) : GetPlayerSound(type);
+               if (e) return e.m_playersoundfld;
+               GetPlayerSoundSampleField_notFound = true;
+               return playersound_taunt.m_playersoundfld;
+       }
 
-               .string GetVoiceMessageSampleField(string type)
+       .string GetVoiceMessageSampleField(string type)
+       {
+               return _GetPlayerSoundSampleField(type, true);
+       }
+
+       void PrecachePlayerSounds(string f)
+       {
+               int fh = fopen(f, FILE_READ);
+               if (fh < 0)
                {
-                       GetPlayerSoundSampleField_notFound = false;
-                       switch (type)
-                       {
-                               #define X(m) case #m: return playersound_##m;
-                               ALLVOICEMSGS(X)
-               #undef X
-                       }
-                       GetPlayerSoundSampleField_notFound = true;
-                       return playersound_taunt;
+                       LOG_WARNINGF("Player sound file not found: %s\n", f);
+                       return;
                }
-
-               .string GetPlayerSoundSampleField(string type)
+               for (string s; (s = fgets(fh)); )
                {
-                       GetPlayerSoundSampleField_notFound = false;
-                       switch (type)
+                       int n = tokenize_console(s);
+                       if (n != 3)
                        {
-                               #define X(m) case #m: return playersound_##m;
-                               ALLPLAYERSOUNDS(X)
-               #undef X
+                               if (n != 0) LOG_WARNINGF("Invalid sound info line: %s\n", s);
+                               continue;
                        }
-                       GetPlayerSoundSampleField_notFound = true;
-                       return playersound_taunt;
+                       string file = argv(1);
+                       string variants = argv(2);
+                       PrecacheGlobalSound(strcat(file, " ", variants));
                }
+               fclose(fh);
+       }
 
-               string allvoicesamples;
+       //#ifdef CSQC
 
-               void PrecachePlayerSounds(string f)
+               .string GetPlayerSoundSampleField(string type)
                {
-                       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));
-                       }
+                       return _GetPlayerSoundSampleField(type, false);
                }
 
                void ClearPlayerSounds(entity this)
                {
-                       #define X(m) \
-                               if (this.playersound_##m) \
-                               { \
-                                       strunzone(this.playersound_##m); \
-                                       this.playersound_##m = string_null; \
+                       FOREACH(PlayerSounds, true, {
+                               .string fld = it.m_playersoundfld;
+                               if (this.(fld))
+                               {
+                                       strunzone(this.(fld));
+                                       this.(fld) = string_null;
                                }
-                       ALLPLAYERSOUNDS(X)
-                       ALLVOICEMSGS(X)
-               #undef X
+                       });
                }
 
-               bool LoadPlayerSounds(string f, bool strict)
+               bool LoadPlayerSounds(entity this, string f, bool strict)
                {
-                       SELFPARAM();
                        int fh = fopen(f, FILE_READ);
                        if (fh < 0)
                        {
                                }
                                string file = argv(1);
                                string variants = argv(2);
-                               if (self.(field)) strunzone(self.(field));
-                               self.(field) = strzone(strcat(file, " ", variants));
+                               if (this.(field)) strunzone(this.(field));
+                               this.(field) = strzone(strcat(file, " ", variants));
                        }
                        fclose(fh);
                        return true;
                }
 
-               .int modelindex_for_playersound;
+               .string model_for_playersound;
                .int skin_for_playersound;
 
+               bool autocvar_g_debug_defaultsounds;
+
                void UpdatePlayerSounds(entity this)
                {
-                       if (this.modelindex == this.modelindex_for_playersound && this.skin == this.skin_for_playersound) return;
-                       this.modelindex_for_playersound = this.modelindex;
+                       if (this.model == this.model_for_playersound && this.skin == this.skin_for_playersound) return;
+                       if (this.model_for_playersound) strunzone(this.model_for_playersound);
+                       this.model_for_playersound = strzone(this.model);
                        this.skin_for_playersound = this.skin;
                        ClearPlayerSounds(this);
-                       LoadPlayerSounds("sound/player/default.sounds", true);
+                       LoadPlayerSounds(this, "sound/player/default.sounds", true);
+                       if (this.model == "null"
+                       #ifdef SVQC
+                           && autocvar_g_debug_globalsounds
+                       #endif
+                        ) return;
                        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);
+                       if (LoadPlayerSounds(this, get_model_datafilename(this.model, this.skin, "sounds"), false)) return;
+                       LoadPlayerSounds(this, get_model_datafilename(this.model, 0, "sounds"), true);
                }
 
-               void _GlobalSound(entity gs, string sample, int chan, int voicetype, bool fake)
+       //#endif
+
+       #ifdef SVQC
+
+               void _GlobalSound(entity this, entity gs, entity ps, string sample, int chan, int voicetype, bool fake)
                {
-                       SELFPARAM();
-                       if (gs == NULL && sample == "") return;
+                       if (gs == NULL && ps == NULL && sample == "") return;
+                       if(this.classname == "body") return;
                        float r = random();
                        if (sample != "") sample = GlobalSound_sample(sample, r);
                        switch (voicetype)
                                                {
                                                        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 if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASEVOICE, atten);
                                                        else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten);
                                                }
                                        }
                                        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);
+                                               if (gs) globalsound(MSG_ONE, this, gs, r, chan, VOL_BASE, ATTEN_NONE);
+                                               else if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASE, ATTEN_NONE);
+                                               else soundto(MSG_ONE, this, chan, sample, VOL_BASE, ATTEN_NONE);
                                        }
                                        break;
                                }
                                case VOICETYPE_TEAMRADIO:
                                {
                                        #define X() \
-                                               do \
+                                               MACRO_BEGIN \
                                                { \
                                                        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 if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASEVOICE, atten); \
                                                        else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \
-                                               } \
-                                               while (0)
+                                               } MACRO_END
 
                                        if (fake) { msg_entity = this; X(); }
                                        else
                                        {
-                                               FOR_EACH_REALCLIENT(msg_entity)
-                                               {
-                                                       if (!teamplay || msg_entity.team == this.team) X();
-                                               }
+                                               FOREACH_CLIENT(IS_REAL_CLIENT(it) && (!teamplay || msg_entity.team == this.team), {
+                                                       msg_entity = it;
+                                                       X();
+                                               });
                                        }
                #undef X
                                        break;
                                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,
+                                       else if (IS_PLAYER(this) && !IS_DEAD(this)) 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 \
+                                               MACRO_BEGIN \
                                                { \
                                                        if (voicetype != VOICETYPE_AUTOTAUNT || tauntrand < msg_entity.cvar_cl_autotaunt) \
                                                        { \
                                                                        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); \
+                                                               else if (ps) playersound(MSG_ONE, this, ps, r, chan, VOL_BASEVOICE, atten); \
+                                                               else soundto(MSG_ONE, this, chan, sample, VOL_BASEVOICE, atten); \
                                                        } \
-                                               } \
-                                               while (0)
+                                               } MACRO_END
                                        if (fake)
                                        {
                                                msg_entity = this;
                                        }
                                        else
                                        {
-                                               FOR_EACH_REALCLIENT(msg_entity)
-                                               {
+                                               FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+                                                       msg_entity = it;
                                                        X();
-                                               }
+                                               });
                                        }
                #undef X
                                        break;
                                        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 (ps) playersound(MSG_ONE, this, ps, 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);
+                                               if (gs) globalsound(MSG_ALL, this, gs, r, chan, VOL_BASE, ATTEN_NORM);
+                                               else if (ps) playersound(MSG_ALL, this, ps, r, chan, VOL_BASE, ATTEN_NORM);
+                                               else _sound(this, chan, sample, VOL_BASE, ATTEN_NORM);
                                        }
                                        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