1 #include "bgmscript.qh"
3 #include "autocvars.qh"
6 #include "../common/util.qh"
7 #include "../dpdefs/csprogsdefs.qh"
9 #define CONSTANT_SPEED_DECAY
12 float bgmscriptbufsize;
13 float bgmscriptbufloaded;
15 class(BGMScript) .float bgmscriptline;
16 class(BGMScript) .float bgmscriptline0;
17 class(BGMScript) .float bgmscriptvolume;
18 class(BGMScript) .float bgmscripttime;
19 class(BGMScript) .float bgmscriptstate;
20 class(BGMScript) .float bgmscriptstatetime;
22 float GetAttackDecaySustainAmplitude(float a, float d, float s, float t)
25 // attack: from 0 to 1, in time a for a full length
26 // decay: from 1 to s, in time d
38 return ((t - a) / d) * (s - 1) + 1;
43 float GetReleaseAmplitude(float d, float s, float r, float t)
45 float decayval, releaseval;
53 releaseval = s * (1 - t / r);
61 // value is s at time 0
63 decayval = ((t + d) / d) * (s - 1) + 1;
64 return max(decayval, releaseval);
70 float GetAttackTime(float a, float amp)
75 float GetReleaseTime(float d, float s, float r, float amp)
77 float decaytime, releasetime;
82 // if amp > s, we may be in the attack or in the prolonged decay curve
83 releasetime = (1 - amp / s) * r;
87 if(s == 1) // gracefully handle division by zero here
91 // value is s at time 0
93 decaytime = (amp - 1) / (s - 1) * d - d;
94 return max(decaytime, releasetime);
100 void BGMScript_Init()
104 bgmscriptbuf = bgmscriptbufsize = 0;
105 bgmscriptbufloaded = 1;
106 s = strcat("maps/", mi_shortname, ".bgs");
107 fh = fopen(s, FILE_READ);
110 bgmscriptbuf = buf_create();
111 while((s = fgets(fh)))
113 bufstr_set(bgmscriptbuf, bgmscriptbufsize, s);
119 void BGMScript_InitEntity(entity e)
123 if(e.bgmscript != "")
125 if(!bgmscriptbufloaded)
130 m = strcat(e.bgmscript, " ");
133 e.bgmscriptline0 = -1;
134 for(i = 0; i < bgmscriptbufsize; ++i)
136 if(substring(bufstr_get(bgmscriptbuf, i), 0, l) == m)
139 e.bgmscriptline = e.bgmscriptline0 = i;
140 if(i >= bgmscriptbufsize)
142 printf("ERROR: bgmscript does not define %s\n", e.bgmscript);
143 strunzone(e.bgmscript);
144 e.bgmscript = string_null;
149 float GetCurrentAmplitude(entity e, float trel)
152 return GetAttackDecaySustainAmplitude(e.bgmscriptattack, e.bgmscriptdecay, e.bgmscriptsustain, trel) * e.bgmscriptvolume;
155 #ifdef CONSTANT_SPEED_DECAY
156 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, trel);
158 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, trel) * e.bgmscriptvolume;
163 float GetTimeForAmplitude(entity e, float amp)
166 return GetAttackTime(e.bgmscriptattack, amp / e.bgmscriptvolume);
169 #ifdef CONSTANT_SPEED_DECAY
170 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, amp);
172 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, amp / e.bgmscriptvolume);
177 float BGMScript(entity e)
181 if(e.bgmscript == "")
184 if(autocvar_bgmvolume <= 0)
187 e.just_toggled = false;
192 if(bgmtime < e.bgmscripttime)
194 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime + drawframetime);
196 e.bgmscriptline = e.bgmscriptline0;
197 e.bgmscripttime = bgmtime;
199 // treat this as a stop event for all notes, to prevent sticking keys
200 e.bgmscriptstate = false;
201 e.bgmscriptvolume = 1;
202 e.bgmscriptstatetime = bgmtime - GetTimeForAmplitude(e, amp);
205 // find the CURRENT line
208 tokenize_console(bufstr_get(bgmscriptbuf, e.bgmscriptline));
209 if(stof(argv(1)) >= bgmtime || argv(0) != e.bgmscript)
211 e.bgmscripttime = bgmtime;
212 return GetCurrentAmplitude(e, bgmtime - e.bgmscriptstatetime);
214 else if(bgmtime >= stof(argv(1)))
216 e.bgmscriptline += 1;
217 e.bgmscripttime = stof(argv(1));
219 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime);
221 // time code reached!
225 e.just_toggled = e.bgmscriptstate = true;
226 e.bgmscriptvolume = vel;
229 e.just_toggled = e.bgmscriptstate = false;
231 e.bgmscriptstatetime = e.bgmscripttime - GetTimeForAmplitude(e, amp);