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 classfield(BGMScript) .float bgmscriptline;
15 classfield(BGMScript) .float bgmscriptline0;
16 classfield(BGMScript) .float bgmscriptvolume;
17 classfield(BGMScript) .float bgmscripttime;
18 classfield(BGMScript) .float bgmscriptstate;
19 classfield(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
37 return ((t - a) / d) * (s - 1) + 1;
42 float GetReleaseAmplitude(float d, float s, float r, float t)
44 float decayval, releaseval;
52 releaseval = s * (1 - t / r);
60 // value is s at time 0
62 decayval = ((t + d) / d) * (s - 1) + 1;
63 return max(decayval, releaseval);
69 float GetAttackTime(float a, float amp)
74 float GetReleaseTime(float d, float s, float r, float amp)
76 float decaytime, releasetime;
81 // if amp > s, we may be in the attack or in the prolonged decay curve
82 releasetime = (1 - amp / s) * r;
86 if(s == 1) // gracefully handle division by zero here
90 // value is s at time 0
92 decaytime = (amp - 1) / (s - 1) * d - d;
93 return max(decaytime, releasetime);
103 bgmscriptbuf = bgmscriptbufsize = 0;
104 bgmscriptbufloaded = 1;
105 s = strcat("maps/", mi_shortname, ".bgs");
106 fh = fopen(s, FILE_READ);
109 bgmscriptbuf = buf_create();
110 while((s = fgets(fh)))
112 bufstr_set(bgmscriptbuf, bgmscriptbufsize, s);
118 void BGMScript_InitEntity(entity e)
122 if(e.bgmscript != "")
124 if(!bgmscriptbufloaded)
129 m = strcat(e.bgmscript, " ");
132 e.bgmscriptline0 = -1;
133 for(i = 0; i < bgmscriptbufsize; ++i)
135 if(substring(bufstr_get(bgmscriptbuf, i), 0, l) == m)
138 e.bgmscriptline = e.bgmscriptline0 = i;
139 if(i >= bgmscriptbufsize)
141 LOG_INFOF("ERROR: bgmscript does not define %s", e.bgmscript);
142 strfree(e.bgmscript);
147 float GetCurrentAmplitude(entity e, float trel)
150 return GetAttackDecaySustainAmplitude(e.bgmscriptattack, e.bgmscriptdecay, e.bgmscriptsustain, trel) * e.bgmscriptvolume;
153 #ifdef CONSTANT_SPEED_DECAY
154 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, trel);
156 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, trel) * e.bgmscriptvolume;
161 float GetTimeForAmplitude(entity e, float amp)
164 return GetAttackTime(e.bgmscriptattack, amp / e.bgmscriptvolume);
167 #ifdef CONSTANT_SPEED_DECAY
168 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, amp);
170 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, amp / e.bgmscriptvolume);
175 float doBGMScript(entity e)
179 if(e.bgmscript == "")
182 if(autocvar_bgmvolume <= 0)
185 e.just_toggled = false;
190 if(bgmtime < e.bgmscripttime)
192 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime + drawframetime);
194 e.bgmscriptline = e.bgmscriptline0;
195 e.bgmscripttime = bgmtime;
197 // treat this as a stop event for all notes, to prevent sticking keys
198 e.bgmscriptstate = false;
199 e.bgmscriptvolume = 1;
200 e.bgmscriptstatetime = bgmtime - GetTimeForAmplitude(e, amp);
203 // find the CURRENT line
206 tokenize_console(bufstr_get(bgmscriptbuf, e.bgmscriptline));
207 if(stof(argv(1)) >= bgmtime || argv(0) != e.bgmscript)
209 e.bgmscripttime = bgmtime;
210 return GetCurrentAmplitude(e, bgmtime - e.bgmscriptstatetime);
212 else if(bgmtime >= stof(argv(1)))
214 e.bgmscriptline += 1;
215 e.bgmscripttime = stof(argv(1));
217 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime);
219 // time code reached!
223 e.just_toggled = e.bgmscriptstate = true;
224 e.bgmscriptvolume = vel;
227 e.just_toggled = e.bgmscriptstate = false;
229 e.bgmscriptstatetime = e.bgmscripttime - GetTimeForAmplitude(e, amp);