1 #include "bgmscript.qh"
3 #define CONSTANT_SPEED_DECAY
6 float bgmscriptbufsize;
7 float bgmscriptbufloaded;
9 class(BGMScript) .float bgmscriptline;
10 class(BGMScript) .float bgmscriptline0;
11 class(BGMScript) .float bgmscriptvolume;
12 class(BGMScript) .float bgmscripttime;
13 class(BGMScript) .float bgmscriptstate;
14 class(BGMScript) .float bgmscriptstatetime;
16 float GetAttackDecaySustainAmplitude(float a, float d, float s, float t)
19 // attack: from 0 to 1, in time a for a full length
20 // decay: from 1 to s, in time d
32 return ((t - a) / d) * (s - 1) + 1;
37 float GetReleaseAmplitude(float d, float s, float r, float t)
39 float decayval, releaseval;
47 releaseval = s * (1 - t / r);
55 // value is s at time 0
57 decayval = ((t + d) / d) * (s - 1) + 1;
58 return max(decayval, releaseval);
64 float GetAttackTime(float a, float amp)
69 float GetReleaseTime(float d, float s, float r, float amp)
71 float decaytime, releasetime;
76 // if amp > s, we may be in the attack or in the prolonged decay curve
77 releasetime = (1 - amp / s) * r;
81 if(s == 1) // gracefully handle division by zero here
85 // value is s at time 0
87 decaytime = (amp - 1) / (s - 1) * d - d;
88 return max(decaytime, releasetime);
98 bgmscriptbuf = bgmscriptbufsize = 0;
99 bgmscriptbufloaded = 1;
100 s = strcat("maps/", mi_shortname, ".bgs");
101 fh = fopen(s, FILE_READ);
104 bgmscriptbuf = buf_create();
105 while((s = fgets(fh)))
107 bufstr_set(bgmscriptbuf, bgmscriptbufsize, s);
113 void BGMScript_InitEntity(entity e)
117 if(e.bgmscript != "")
119 if(!bgmscriptbufloaded)
124 m = strcat(e.bgmscript, " ");
127 e.bgmscriptline0 = -1;
128 for(i = 0; i < bgmscriptbufsize; ++i)
130 if(substring(bufstr_get(bgmscriptbuf, i), 0, l) == m)
133 e.bgmscriptline = e.bgmscriptline0 = i;
134 if(i >= bgmscriptbufsize)
136 LOG_INFOF("ERROR: bgmscript does not define %s\n", e.bgmscript);
137 strunzone(e.bgmscript);
138 e.bgmscript = string_null;
143 float GetCurrentAmplitude(entity e, float trel)
146 return GetAttackDecaySustainAmplitude(e.bgmscriptattack, e.bgmscriptdecay, e.bgmscriptsustain, trel) * e.bgmscriptvolume;
149 #ifdef CONSTANT_SPEED_DECAY
150 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, trel);
152 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, trel) * e.bgmscriptvolume;
157 float GetTimeForAmplitude(entity e, float amp)
160 return GetAttackTime(e.bgmscriptattack, amp / e.bgmscriptvolume);
163 #ifdef CONSTANT_SPEED_DECAY
164 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, amp);
166 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, amp / e.bgmscriptvolume);
171 float doBGMScript(entity e)
175 if(e.bgmscript == "")
178 if(autocvar_bgmvolume <= 0)
181 e.just_toggled = false;
186 if(bgmtime < e.bgmscripttime)
188 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime + drawframetime);
190 e.bgmscriptline = e.bgmscriptline0;
191 e.bgmscripttime = bgmtime;
193 // treat this as a stop event for all notes, to prevent sticking keys
194 e.bgmscriptstate = false;
195 e.bgmscriptvolume = 1;
196 e.bgmscriptstatetime = bgmtime - GetTimeForAmplitude(e, amp);
199 // find the CURRENT line
202 tokenize_console(bufstr_get(bgmscriptbuf, e.bgmscriptline));
203 if(stof(argv(1)) >= bgmtime || argv(0) != e.bgmscript)
205 e.bgmscripttime = bgmtime;
206 return GetCurrentAmplitude(e, bgmtime - e.bgmscriptstatetime);
208 else if(bgmtime >= stof(argv(1)))
210 e.bgmscriptline += 1;
211 e.bgmscripttime = stof(argv(1));
213 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime);
215 // time code reached!
219 e.just_toggled = e.bgmscriptstate = true;
220 e.bgmscriptvolume = vel;
223 e.just_toggled = e.bgmscriptstate = false;
225 e.bgmscriptstatetime = e.bgmscripttime - GetTimeForAmplitude(e, amp);