1 #include "bgmscript.qh"
3 #include <common/util.qh>
4 #include <client/autocvars.qh>
5 #include <client/defs.qh>
6 #include <client/main.qh>
8 #define CONSTANT_SPEED_DECAY
11 float bgmscriptbufsize;
12 float bgmscriptbufloaded;
14 class(BGMScript).float bgmscriptline;
15 class(BGMScript).float bgmscriptline0;
16 class(BGMScript).float bgmscriptvolume;
17 class(BGMScript).float bgmscripttime;
18 class(BGMScript).float bgmscriptstate;
19 class(BGMScript).float bgmscriptstatetime;
21 float GetAttackDecaySustainAmplitude(float a, float d, float s, float t)
24 // attack: from 0 to 1, in time a for a full length
25 // decay: from 1 to s, in time d
40 return ((t - a) / d) * (s - 1) + 1;
47 float GetReleaseAmplitude(float d, float s, float r, float t)
49 float decayval, releaseval;
59 releaseval = s * (1 - t / r);
65 if (t < 0 && t >= -d) {
67 // value is s at time 0
69 decayval = ((t + d) / d) * (s - 1) + 1;
70 return max(decayval, releaseval);
76 float GetAttackTime(float a, float amp)
81 float GetReleaseTime(float d, float s, float r, float amp)
83 float decaytime, releasetime;
89 // if amp > s, we may be in the attack or in the prolonged decay curve
90 releasetime = (1 - amp / s) * r;
93 if (s == 1) { // gracefully handle division by zero here
98 // value is s at time 0
100 decaytime = (amp - 1) / (s - 1) * d - d;
101 return max(decaytime, releasetime);
107 void BGMScript_Init()
111 bgmscriptbuf = bgmscriptbufsize = 0;
112 bgmscriptbufloaded = 1;
113 s = strcat("maps/", mi_shortname, ".bgs");
114 fh = fopen(s, FILE_READ);
118 bgmscriptbuf = buf_create();
119 while ((s = fgets(fh))) {
120 bufstr_set(bgmscriptbuf, bgmscriptbufsize, s);
126 void BGMScript_InitEntity(entity e)
130 if (e.bgmscript != "") {
131 if (!bgmscriptbufloaded) {
137 m = strcat(e.bgmscript, " ");
140 e.bgmscriptline0 = -1;
141 for (i = 0; i < bgmscriptbufsize; ++i) {
142 if (substring(bufstr_get(bgmscriptbuf, i), 0, l) == m) {
146 e.bgmscriptline = e.bgmscriptline0 = i;
147 if (i >= bgmscriptbufsize) {
148 LOG_INFOF("ERROR: bgmscript does not define %s", e.bgmscript);
149 strunzone(e.bgmscript);
150 e.bgmscript = string_null;
155 float GetCurrentAmplitude(entity e, float trel)
157 if (e.bgmscriptstate) {
158 return GetAttackDecaySustainAmplitude(e.bgmscriptattack, e.bgmscriptdecay, e.bgmscriptsustain, trel) * e.bgmscriptvolume;
160 #ifdef CONSTANT_SPEED_DECAY
161 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, trel);
163 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, trel) * e.bgmscriptvolume;
168 float GetTimeForAmplitude(entity e, float amp)
170 if (e.bgmscriptstate) {
171 return GetAttackTime(e.bgmscriptattack, amp / e.bgmscriptvolume);
173 #ifdef CONSTANT_SPEED_DECAY
174 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, amp);
176 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, amp / e.bgmscriptvolume);
181 float doBGMScript(entity e)
185 if (e.bgmscript == "") {
189 if (autocvar_bgmvolume <= 0) {
193 e.just_toggled = false;
199 if (bgmtime < e.bgmscripttime) {
200 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime + drawframetime);
202 e.bgmscriptline = e.bgmscriptline0;
203 e.bgmscripttime = bgmtime;
205 // treat this as a stop event for all notes, to prevent sticking keys
206 e.bgmscriptstate = false;
207 e.bgmscriptvolume = 1;
208 e.bgmscriptstatetime = bgmtime - GetTimeForAmplitude(e, amp);
211 // find the CURRENT line
213 tokenize_console(bufstr_get(bgmscriptbuf, e.bgmscriptline));
214 if (stof(argv(1)) >= bgmtime || argv(0) != e.bgmscript) {
215 e.bgmscripttime = bgmtime;
216 return GetCurrentAmplitude(e, bgmtime - e.bgmscriptstatetime);
217 } else if (bgmtime >= stof(argv(1))) {
218 e.bgmscriptline += 1;
219 e.bgmscripttime = stof(argv(1));
221 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime);
223 // time code reached!
226 e.just_toggled = e.bgmscriptstate = true;
227 e.bgmscriptvolume = vel;
229 e.just_toggled = e.bgmscriptstate = false;
232 e.bgmscriptstatetime = e.bgmscripttime - GetTimeForAmplitude(e, amp);