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