]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/triggers/target/music.qc
0fde9e043904d00f4093fe74bcc45a9ce0a74b52
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / triggers / target / music.qc
1 #include "music.qh"
2 #if defined(CSQC)
3 #elif defined(MENUQC)
4 #elif defined(SVQC)
5     #include <common/constants.qh>
6     #include <server/constants.qh>
7     #include <server/defs.qh>
8 #endif
9
10 REGISTER_NET_TEMP(TE_CSQC_TARGET_MUSIC)
11 REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_MUSIC)
12
13 #ifdef SVQC
14
15 IntrusiveList g_targetmusic_list;
16 STATIC_INIT(g_targetmusic_list) { g_targetmusic_list = IL_NEW(); }
17
18 // values:
19 //   volume
20 //   noise
21 //   targetname
22 //   lifetime
23 //   fade_time
24 //   fade_rate
25 // when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
26 // when targetname is not set, THIS ONE is default
27 void target_music_sendto(entity this, int to, bool is)
28 {
29         WriteHeader(to, TE_CSQC_TARGET_MUSIC);
30         WriteShort(to, etof(this));
31         WriteByte(to, this.volume * 255.0 * is);
32         WriteByte(to, this.fade_time * 16.0);
33         WriteByte(to, this.fade_rate * 16.0);
34         WriteByte(to, this.lifetime);
35         WriteString(to, this.noise);
36 }
37 void target_music_reset(entity this)
38 {
39         if (this.targetname == "") target_music_sendto(this, MSG_ALL, 1);
40 }
41 void target_music_kill()
42 {
43         IL_EACH(g_targetmusic_list, true,
44         {
45                 it.volume = 0;
46         if (it.targetname == "")
47             target_music_sendto(it, MSG_ALL, 1);
48         else
49             target_music_sendto(it, MSG_ALL, 0);
50         });
51 }
52 void target_music_use(entity this, entity actor, entity trigger)
53 {
54         if(!actor)
55                 return;
56         if(IS_REAL_CLIENT(actor))
57         {
58                 msg_entity = actor;
59                 target_music_sendto(this, MSG_ONE, 1);
60         }
61         FOREACH_CLIENT(IS_SPEC(it) && it.enemy == actor, {
62                 msg_entity = it;
63                 target_music_sendto(this, MSG_ONE, 1);
64         });
65 }
66 spawnfunc(target_music)
67 {
68         this.use = target_music_use;
69         this.reset = target_music_reset;
70         if(!this.volume)
71                 this.volume = 1;
72         IL_PUSH(g_targetmusic_list, this);
73         if(this.targetname == "")
74                 target_music_sendto(this, MSG_INIT, 1);
75         else
76                 target_music_sendto(this, MSG_INIT, 0);
77 }
78 void TargetMusic_RestoreGame()
79 {
80         IL_EACH(g_targetmusic_list, true,
81         {
82                 if(it.targetname == "")
83                         target_music_sendto(it, MSG_INIT, 1);
84                 else
85                         target_music_sendto(it, MSG_INIT, 0);
86         });
87 }
88 // values:
89 //   volume
90 //   noise
91 //   targetname
92 //   fade_time
93 // spawnflags:
94 //   1 = START_OFF
95 // when triggered, it is disabled/enabled for everyone
96 bool trigger_music_SendEntity(entity this, entity to, float sf)
97 {
98         WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
99         sf &= ~0x80;
100         if(this.cnt)
101                 sf |= 0x80;
102         WriteByte(MSG_ENTITY, sf);
103         if(sf & 4)
104         {
105                 WriteCoord(MSG_ENTITY, this.origin.x);
106                 WriteCoord(MSG_ENTITY, this.origin.y);
107                 WriteCoord(MSG_ENTITY, this.origin.z);
108         }
109         if(sf & 1)
110         {
111                 if(this.model != "null")
112                 {
113                         WriteShort(MSG_ENTITY, this.modelindex);
114                         WriteCoord(MSG_ENTITY, this.mins.x);
115                         WriteCoord(MSG_ENTITY, this.mins.y);
116                         WriteCoord(MSG_ENTITY, this.mins.z);
117                         WriteCoord(MSG_ENTITY, this.maxs.x);
118                         WriteCoord(MSG_ENTITY, this.maxs.y);
119                         WriteCoord(MSG_ENTITY, this.maxs.z);
120                 }
121                 else
122                 {
123                         WriteShort(MSG_ENTITY, 0);
124                         WriteCoord(MSG_ENTITY, this.maxs.x);
125                         WriteCoord(MSG_ENTITY, this.maxs.y);
126                         WriteCoord(MSG_ENTITY, this.maxs.z);
127                 }
128                 WriteByte(MSG_ENTITY, this.volume * 255.0);
129                 WriteByte(MSG_ENTITY, this.fade_time * 16.0);
130                 WriteByte(MSG_ENTITY, this.fade_rate * 16.0);
131                 WriteString(MSG_ENTITY, this.noise);
132         }
133         return 1;
134 }
135 void trigger_music_reset(entity this)
136 {
137         this.cnt = !(this.spawnflags & 1);
138         this.SendFlags |= 0x80;
139 }
140 void trigger_music_use(entity this, entity actor, entity trigger)
141 {
142         this.cnt = !this.cnt;
143         this.SendFlags |= 0x80;
144 }
145 spawnfunc(trigger_music)
146 {
147         if(this.model != "") _setmodel(this, this.model);
148         if(!this.volume) this.volume = 1;
149         if(!this.modelindex)
150         {
151                 setorigin(this, this.origin + this.mins);
152                 setsize(this, '0 0 0', this.maxs - this.mins);
153         }
154         trigger_music_reset(this);
155
156         this.use = trigger_music_use;
157         this.reset = trigger_music_reset;
158
159         Net_LinkEntity(this, false, 0, trigger_music_SendEntity);
160 }
161 #elif defined(CSQC)
162
163 entity TargetMusic_list;
164 STATIC_INIT(TargetMusic_list)
165 {
166         TargetMusic_list = LL_NEW();
167 }
168
169 void TargetMusic_Advance()
170 {
171         // run AFTER all the thinks!
172         entity best = music_default;
173         if (music_target && time < music_target.lifetime) best = music_target;
174         if (music_trigger) best = music_trigger;
175         LL_EACH(TargetMusic_list, it.noise, {
176                 const float vol0 = (getsoundtime(it, CH_BGM_SINGLE) >= 0) ? it.lastvol : -1;
177                 if (it == best)
178                 {
179                         // increase volume
180                         it.state = (it.fade_time > 0) ? bound(0, it.state + frametime / it.fade_time, 1) : 1;
181                 }
182                 else
183                 {
184                         // decrease volume
185                         it.state = (it.fade_rate > 0) ? bound(0, it.state - frametime / it.fade_rate, 1) : 0;
186                 }
187                 const float vol = it.state * it.volume * autocvar_bgmvolume;
188                 if (vol != vol0)
189                 {
190                         if(vol0 < 0)
191                                 _sound(it, CH_BGM_SINGLE, it.noise, vol, ATTEN_NONE); // restart
192                         else
193                                 _sound(it, CH_BGM_SINGLE, "", vol, ATTEN_NONE);
194                         it.lastvol = vol;
195                 }
196         });
197         music_trigger = NULL;
198         bgmtime = (best) ? getsoundtime(best, CH_BGM_SINGLE) : gettime(GETTIME_CDTRACK);
199 }
200
201 NET_HANDLE(TE_CSQC_TARGET_MUSIC, bool isNew)
202 {
203         Net_TargetMusic();
204         return true;
205 }
206
207 void Net_TargetMusic()
208 {
209         const int id = ReadShort();
210         const float vol = ReadByte() / 255.0;
211         const float fai = ReadByte() / 16.0;
212         const float fao = ReadByte() / 16.0;
213         const float tim = ReadByte();
214         const string noi = ReadString();
215
216         entity e = NULL;
217         LL_EACH(TargetMusic_list, it.count == id, { e = it; break; });
218         if (!e)
219         {
220                 LL_PUSH(TargetMusic_list, e = new_pure(TargetMusic));
221                 e.count = id;
222         }
223         if(e.noise != noi)
224         {
225                 if(e.noise)
226                         strunzone(e.noise);
227                 e.noise = strzone(noi);
228                 precache_sound(e.noise);
229                 _sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
230                 if(getsoundtime(e, CH_BGM_SINGLE) < 0)
231                 {
232                         LOG_TRACEF("Cannot initialize sound %s", e.noise);
233                         strunzone(e.noise);
234                         e.noise = string_null;
235                 }
236         }
237         e.volume = vol;
238         e.fade_time = fai;
239         e.fade_rate = fao;
240         if(vol > 0)
241         {
242                 if(tim == 0)
243                 {
244                         music_default = e;
245                         if(!music_disabled)
246                         {
247                                 e.state = 2;
248                                 cvar_settemp("music_playlist_index", "-1"); // don't use playlists
249                                 localcmd("cd stop\n"); // just in case
250                                 music_disabled = 1;
251                         }
252                 }
253                 else
254                 {
255                         music_target = e;
256                         e.lifetime = time + tim;
257                 }
258         }
259 }
260
261 void Ent_TriggerMusic_Think(entity this)
262 {
263         if(WarpZoneLib_BoxTouchesBrush(view_origin, view_origin, this, NULL))
264         {
265                 music_trigger = this;
266         }
267         this.nextthink = time;
268 }
269
270 void Ent_TriggerMusic_Remove(entity this)
271 {
272         if(this.noise)
273                 strunzone(this.noise);
274         this.noise = string_null;
275 }
276
277 NET_HANDLE(ENT_CLIENT_TRIGGER_MUSIC, bool isnew)
278 {
279         int f = ReadByte();
280         if(f & 4)
281         {
282                 this.origin_x = ReadCoord();
283                 this.origin_y = ReadCoord();
284                 this.origin_z = ReadCoord();
285         }
286         if(f & 1)
287         {
288                 this.modelindex = ReadShort();
289                 if(this.modelindex)
290                 {
291                         this.mins_x = ReadCoord();
292                         this.mins_y = ReadCoord();
293                         this.mins_z = ReadCoord();
294                         this.maxs_x = ReadCoord();
295                         this.maxs_y = ReadCoord();
296                         this.maxs_z = ReadCoord();
297                 }
298                 else
299                 {
300                         this.mins    = '0 0 0';
301                         this.maxs_x = ReadCoord();
302                         this.maxs_y = ReadCoord();
303                         this.maxs_z = ReadCoord();
304                 }
305
306                 this.volume = ReadByte() / 255.0;
307                 this.fade_time = ReadByte() / 16.0;
308                 this.fade_rate = ReadByte() / 16.0;
309                 string s = this.noise;
310                 if(this.noise)
311                         strunzone(this.noise);
312                 this.noise = strzone(ReadString());
313                 if(this.noise != s)
314                 {
315                         precache_sound(this.noise);
316                         _sound(this, CH_BGM_SINGLE, this.noise, 0, ATTEN_NONE);
317                         if(getsoundtime(this, CH_BGM_SINGLE) < 0)
318                         {
319                                 LOG_TRACEF("Cannot initialize sound %s", this.noise);
320                                 strunzone(this.noise);
321                                 this.noise = string_null;
322                         }
323                 }
324         }
325
326         setorigin(this, this.origin);
327         setsize(this, this.mins, this.maxs);
328         this.cnt = 1;
329         setthink(this, Ent_TriggerMusic_Think);
330         this.nextthink = time;
331         return true;
332 }
333
334 #endif