Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
music.qc
Go to the documentation of this file.
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>
8 #include <common/stats.qh>
9#endif
10
11REGISTER_NET_TEMP(TE_CSQC_TARGET_MUSIC)
12REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_MUSIC)
13
14#ifdef SVQC
15
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
31void 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}
42{
43 if (this.targetname == "")
44 {
45 target_music_sendto(this, MSG_ALL, true);
46 }
47}
49{
51 {
52 it.volume = 0;
53 if (it.targetname == "")
55 else
56 target_music_sendto(it, MSG_ALL, false);
57 });
58}
59void 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}
73spawnfunc(target_music)
74{
75 this.use = target_music_use;
76 this.reset = target_music_reset;
77 if(!this.volume)
78 this.volume = 1;
80 if(this.targetname == "")
81 target_music_sendto(this, MSG_INIT, true);
82 else
83 target_music_sendto(this, MSG_INIT, false);
84}
86{
88 {
89 if(it.targetname == "")
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// can be disabled/enabled for everyone with relays
103bool trigger_music_SendEntity(entity this, entity to, int sendflags)
104{
105 WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
106 WriteByte(MSG_ENTITY, sendflags);
107 if(sendflags & SF_MUSIC_ORIGIN)
108 {
109 WriteVector(MSG_ENTITY, this.origin);
110 }
111 if(sendflags & SF_TRIGGER_INIT)
112 {
113 if(this.model != "null")
114 {
116 WriteVector(MSG_ENTITY, this.mins);
117 WriteVector(MSG_ENTITY, this.maxs);
118 }
119 else
120 {
122 WriteVector(MSG_ENTITY, this.maxs);
123 }
124 WriteByte(MSG_ENTITY, this.volume * 255.0);
125 WriteByte(MSG_ENTITY, this.fade_time * 16.0);
126 WriteByte(MSG_ENTITY, this.fade_rate * 16.0);
128 }
129 if(sendflags & SF_TRIGGER_UPDATE)
130 {
132 }
133 return true;
134}
136{
137 if(this.spawnflags & START_DISABLED)
138 {
139 this.setactive(this, ACTIVE_NOT);
140 }
141 else
142 {
143 this.setactive(this, ACTIVE_ACTIVE);
144 }
145}
146
147spawnfunc(trigger_music)
148{
149 if(this.model != "")
150 {
151 _setmodel(this, this.model);
152 }
153 if(!this.volume)
154 {
155 this.volume = 1;
156 }
157 if(!this.modelindex)
158 {
159 setorigin(this, this.origin + this.mins);
160 setsize(this, '0 0 0', this.maxs - this.mins);
161 }
162
163 this.setactive = generic_netlinked_setactive;
164 this.use = generic_netlinked_legacy_use; // backwards compatibility
165 this.reset = trigger_music_reset;
166 this.reset(this);
167
169}
170#elif defined(CSQC)
171
172entity TargetMusic_list;
173STATIC_INIT(TargetMusic_list)
174{
175 TargetMusic_list = LL_NEW();
176}
177
179{
180 // run AFTER all the thinks!
182 if (music_target && time < music_target.lifetime)
183 {
185 }
186 if (music_trigger)
187 {
189 }
190 LL_EACH(TargetMusic_list, it.noise, {
191 const float vol0 = (getsoundtime(it, CH_BGM_SINGLE) >= 0) ? it.lastvol : -1;
192 if (it == best)
193 {
194 // increase volume
195 it.state = (it.fade_time > 0) ? bound(0, it.state + frametime / it.fade_time, 1) : 1;
196 }
197 else
198 {
199 // decrease volume
200 it.state = (it.fade_rate > 0) ? bound(0, it.state - frametime / it.fade_rate, 1) : 0;
201 }
202 const float vol = it.state * it.volume * autocvar_bgmvolume;
203 if (vol != vol0)
204 {
205 if(vol0 < 0)
206 sound7(it, CH_BGM_SINGLE, it.noise, vol, ATTEN_NONE, 0, BIT(4)); // restart
207 else
208 sound7(it, CH_BGM_SINGLE, "", vol, ATTEN_NONE, 0, BIT(4));
209 it.lastvol = vol;
210 }
211 });
213 bgmtime = (best) ? getsoundtime(best, CH_BGM_SINGLE) : gettime(GETTIME_CDTRACK);
214}
215
216NET_HANDLE(TE_CSQC_TARGET_MUSIC, bool isNew)
217{
219 return true;
220}
221
222void Net_TargetMusic()
223{
224 const int id = ReadShort();
225 const float vol = ReadByte() / 255.0;
226 const float fai = ReadByte() / 16.0;
227 const float fao = ReadByte() / 16.0;
228 const float tim = ReadByte();
229 const string noi = ReadString();
230
231 entity e = NULL;
232 LL_EACH(TargetMusic_list, it.count == id, { e = it; break; });
233 if (!e)
234 {
235 LL_PUSH(TargetMusic_list, e = new_pure(TargetMusic));
236 e.count = id;
237 }
238 if(e.noise != noi)
239 {
240 strcpy(e.noise, noi);
241 precache_sound(e.noise);
242 _sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
243 if(getsoundtime(e, CH_BGM_SINGLE) < 0)
244 {
245 LOG_TRACEF("Cannot initialize sound %s", e.noise);
246 strfree(e.noise);
247 }
248 }
249 e.volume = vol;
250 e.fade_time = fai;
251 e.fade_rate = fao;
252 if(vol > 0)
253 {
254 if(tim == 0)
255 {
256 music_default = e;
257 if(!music_disabled)
258 {
259 e.state = 2;
260 cvar_settemp("music_playlist_index", "-1"); // don't use playlists
261 localcmd("cd stop\n"); // just in case
262 music_disabled = 1;
263 }
264 }
265 else
266 {
267 music_target = e;
268 e.lifetime = time + tim;
269 }
270 }
271}
272
274{
275 if(this.active == ACTIVE_NOT || intermission)
276 {
277 return;
278 }
280 if(WarpZoneLib_BoxTouchesBrush(org + STAT(PL_MIN), org + STAT(PL_MAX), this, NULL))
281 {
282 music_trigger = this;
283 }
284}
285
287{
288 strfree(this.noise);
289}
290
291NET_HANDLE(ENT_CLIENT_TRIGGER_MUSIC, bool isnew)
292{
293 int sendflags = ReadByte();
294 if(sendflags & SF_MUSIC_ORIGIN)
295 {
296 this.origin = ReadVector();
297 }
298 if(sendflags & SF_TRIGGER_INIT)
299 {
300 this.modelindex = ReadShort();
301 if(this.modelindex)
302 {
303 this.mins = ReadVector();
304 this.maxs = ReadVector();
305 }
306 else
307 {
308 this.mins = '0 0 0';
309 this.maxs = ReadVector();
310 }
311
312 this.volume = ReadByte() / 255.0;
313 this.fade_time = ReadByte() / 16.0;
314 this.fade_rate = ReadByte() / 16.0;
315 string s = this.noise;
316 strcpy(this.noise, ReadString());
317 if(this.noise != s)
318 {
319 precache_sound(this.noise);
320 sound7(this, CH_BGM_SINGLE, this.noise, 0, ATTEN_NONE, 0, BIT(4));
321 if(getsoundtime(this, CH_BGM_SINGLE) < 0)
322 {
323 LOG_WARNF("Cannot initialize sound %s", this.noise);
324 strfree(this.noise);
325 }
326 }
327 }
328 if(sendflags & SF_TRIGGER_UPDATE)
329 {
330 this.active = ReadByte();
331 }
332
333 setorigin(this, this.origin);
334 setsize(this, this.mins, this.maxs);
335 this.draw = Ent_TriggerMusic_Think;
336 if(isnew)
337 {
338 LL_PUSH(TargetMusic_list, this);
339 IL_PUSH(g_drawables, this);
340 }
341 return true;
342}
343
344#endif
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
#define ReadString
entity csqcplayer
Definition cl_player.qh:26
limitations: NULL cannot be present elements can only be present once a maximum of IL_MAX lists can e...
float bgmtime
Definition bgmscript.qh:9
float autocvar_bgmvolume
Definition bgmscript.qh:5
float lifetime
Definition powerups.qc:23
IntrusiveList g_drawables
Definition main.qh:91
vector view_origin
Definition main.qh:109
int spawnflags
Definition ammo.qh:15
float cvar_settemp(string tmp_cvar, string tmp_value)
Definition util.qc:811
float modelindex
vector mins
float GETTIME_CDTRACK
float time
vector maxs
float intermission
vector origin
#define use
const int ACTIVE_NOT
Definition defs.qh:36
const int START_DISABLED
Definition defs.qh:7
const int SF_TRIGGER_INIT
Definition defs.qh:22
int active
Definition defs.qh:34
const int ACTIVE_ACTIVE
Definition defs.qh:37
const int SF_TRIGGER_UPDATE
Definition defs.qh:23
model
Definition ent_cs.qc:139
best
Definition all.qh:82
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define IL_NEW()
#define IL_EACH(this, cond, body)
#define NET_HANDLE(id, param)
Definition net.qh:15
const int MSG_ENTITY
Definition net.qh:115
#define ReadVector()
Definition net.qh:367
#define WriteHeader(to, id)
Definition net.qh:221
#define REGISTER_NET_LINKED(id)
Definition net.qh:55
void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
Definition net.qh:123
int ReadByte()
#define REGISTER_NET_TEMP(id)
Definition net.qh:28
#define STAT(...)
Definition stats.qh:82
float WarpZoneLib_BoxTouchesBrush(vector mi, vector ma, entity e, entity ig)
Definition common.qc:133
#define LL_NEW()
Definition linkedlist.qh:14
#define LL_EACH(list, cond, body)
Definition linkedlist.qh:73
entity LL_PUSH(LinkedList this, entity e)
Push to tail.
Definition linkedlist.qh:21
#define LOG_WARNF(...)
Definition log.qh:62
#define LOG_TRACEF(...)
Definition log.qh:77
void localcmd(string command,...)
float MSG_ONE
Definition menudefs.qc:56
void WriteString(string data, float dest, float desto)
float gettime(void)
void WriteShort(float data, float dest, float desto)
string precache_sound(string sample)
void WriteByte(float data, float dest, float desto)
float MSG_INIT
Definition menudefs.qc:58
float MSG_ALL
Definition menudefs.qc:57
#define etof(e)
Definition misc.qh:25
void trigger_music_reset(entity this)
Definition music.qc:135
IntrusiveList g_targetmusic_list
Definition music.qc:16
void target_music_kill()
Definition music.qc:48
void target_music_use(entity this, entity actor, entity trigger)
Definition music.qc:59
void TargetMusic_RestoreGame()
Definition music.qc:85
void target_music_sendto(entity this, int to, bool is)
Definition music.qc:31
bool trigger_music_SendEntity(entity this, entity to, int sendflags)
Definition music.qc:103
void target_music_reset(entity this)
Definition music.qc:41
void Ent_TriggerMusic_Remove(entity this)
entity music_trigger
Definition music.qh:11
const int SF_MUSIC_ORIGIN
Definition music.qh:5
float music_disabled
Definition music.qh:8
entity music_target
Definition music.qh:10
void Ent_TriggerMusic_Think(entity this)
void Net_TargetMusic()
void TargetMusic_Advance()
entity music_default
Definition music.qh:9
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:67
#define NULL
Definition post.qh:14
entity msg_entity
Definition progsdefs.qc:63
fade_rate
Definition projectile.qh:14
vector
Definition self.qh:92
vector org
Definition self.qh:92
float fade_time
Definition common.qh:23
const float ATTEN_NONE
Definition sound.qh:27
#define _sound(e, c, s, v, a)
Definition sound.qh:43
const int CH_BGM_SINGLE
Definition sound.qh:23
#define spawnfunc(id)
Definition spawnfunc.qh:96
#define STATIC_INIT(func)
during worldspawn
Definition static.qh:32
#define strfree(this)
Definition string.qh:59
#define strcpy(this, s)
Definition string.qh:52
string noise
Definition subs.qh:83
if(frag_attacker.flagcarried)
Definition sv_ctf.qc:2325
void generic_netlinked_legacy_use(entity this, entity actor, entity trigger)
Definition triggers.qc:98
void generic_netlinked_setactive(entity this, int act)
Definition triggers.qc:65
float volume
Definition triggers.qh:47
string targetname
Definition triggers.qh:56
#define IS_SPEC(v)
Definition utils.qh:10
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:50