3 bool autocvar_bot_sound_monopoly;
6 bool sound_allowed(int to, entity e)
10 if (e.classname == "body") e = e.enemy;
11 else if (e.realowner && e.realowner != e) e = e.realowner;
12 else if (e.owner && e.owner != e) e = e.owner;
15 // sounds to self may always pass
16 if (to == MSG_ONE && e == msg_entity) return true;
17 // sounds by players can be removed
18 if (autocvar_bot_sound_monopoly && IS_REAL_CLIENT(e)) return false;
19 // anything else may pass
23 /** hack: string precache_sound(string s) = #19; */
24 int precache_sound_index(string s) = #19;
26 const int SVC_SOUND = 6;
27 const int SVC_STOPSOUND = 16;
29 const int SND_VOLUME = BIT(0);
30 const int SND_ATTENUATION = BIT(1);
31 const int SND_LARGEENTITY = BIT(3);
32 const int SND_LARGESOUND = BIT(4);
34 void soundtoat(int to, entity e, vector o, int chan, string samp, float vol, float attenu)
36 if (!sound_allowed(to, e)) return;
38 int idx = precache_sound_index(samp);
39 attenu = floor(attenu * 64);
40 vol = floor(vol * 255);
42 if (vol != 255) sflags |= SND_VOLUME;
43 if (attenu != 64) sflags |= SND_ATTENUATION;
44 if (entno >= 8192 || chan < 0 || chan > 7) sflags |= SND_LARGEENTITY;
45 if (idx >= 256) sflags |= SND_LARGESOUND;
46 WriteByte(to, SVC_SOUND);
47 WriteByte(to, sflags);
48 if (sflags & SND_VOLUME) WriteByte(to, vol);
49 if (sflags & SND_ATTENUATION) WriteByte(to, attenu);
50 if (sflags & SND_LARGEENTITY)
52 WriteShort(to, entno);
57 WriteShort(to, (entno << 3) | chan);
59 if (sflags & SND_LARGESOUND) WriteShort(to, idx);
60 else WriteByte(to, idx);
66 void soundto(int _dest, entity e, int chan, string samp, float vol, float _atten)
68 if (!sound_allowed(_dest, e)) return;
69 vector o = e.origin + 0.5 * (e.mins + e.maxs);
70 soundtoat(_dest, e, o, chan, samp, vol, _atten);
72 void soundat(entity e, vector o, int chan, string samp, float vol, float _atten)
74 soundtoat(((chan & 8) ? MSG_ALL : MSG_BROADCAST), e, o, chan, samp, vol, _atten);
76 void stopsoundto(int _dest, entity e, int chan)
78 if (!sound_allowed(_dest, e)) return;
80 if (entno >= 8192 || chan < 0 || chan > 7)
82 int idx = precache_sound_index(SND(Null));
83 int sflags = SND_LARGEENTITY;
84 if (idx >= 256) sflags |= SND_LARGESOUND;
85 WriteByte(_dest, SVC_SOUND);
86 WriteByte(_dest, sflags);
87 WriteShort(_dest, entno);
88 WriteByte(_dest, chan);
89 if (sflags & SND_LARGESOUND) WriteShort(_dest, idx);
90 else WriteByte(_dest, idx);
91 WriteCoord(_dest, e.origin.x);
92 WriteCoord(_dest, e.origin.y);
93 WriteCoord(_dest, e.origin.z);
97 WriteByte(_dest, SVC_STOPSOUND);
98 WriteShort(_dest, entno * 8 + chan);
101 void stopsound(entity e, int chan)
103 if (!sound_allowed(MSG_BROADCAST, e)) return;
104 stopsoundto(MSG_BROADCAST, e, chan); // unreliable, gets there fast
105 stopsoundto(MSG_ALL, e, chan); // in case of packet loss
108 void play2(entity e, string filename)
111 soundtoat(MSG_ONE, NULL, '0 0 0', CH_INFO, filename, VOL_BASE, ATTEN_NONE);
115 /** use this one if you might be causing spam (e.g. from touch functions that might get called more than once per frame) */
116 float spamsound(entity e, int chan, string samp, float vol, float _atten)
118 if (!sound_allowed(MSG_BROADCAST, e)) return false;
119 if (time > e.spamtime)
122 _sound(e, chan, samp, vol, _atten);
128 void play2team(float t, string filename)
130 if (autocvar_bot_sound_monopoly) return;
131 FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it.team == t, play2(it, filename));
134 void play2all(string samp)
136 if (autocvar_bot_sound_monopoly) return;
137 _sound(NULL, CH_INFO, samp, VOL_BASE, ATTEN_NONE);