2 #include "../dpdefs/csprogsdefs.qh"
4 #include "../common/util.qh"
5 #include "autocvars.qh"
6 #include "bgmscript.qh"
12 #define CONSTANT_SPEED_DECAY
15 float bgmscriptbufsize;
16 float bgmscriptbufloaded;
19 .float bgmscriptline0;
20 .float bgmscriptvolume;
22 .float bgmscriptstate;
23 .float bgmscriptstatetime;
25 float GetAttackDecaySustainAmplitude(float a, float d, float s, float t)
28 // attack: from 0 to 1, in time a for a full length
29 // decay: from 1 to s, in time d
41 return ((t - a) / d) * (s - 1) + 1;
46 float GetReleaseAmplitude(float d, float s, float r, float t)
48 float decayval, releaseval;
56 releaseval = s * (1 - t / r);
64 // value is s at time 0
66 decayval = ((t + d) / d) * (s - 1) + 1;
67 return max(decayval, releaseval);
73 float GetAttackTime(float a, float amp)
78 float GetReleaseTime(float d, float s, float r, float amp)
80 float decaytime, releasetime;
85 // if amp > s, we may be in the attack or in the prolonged decay curve
86 releasetime = (1 - amp / s) * r;
90 if(s == 1) // gracefully handle division by zero here
94 // value is s at time 0
96 decaytime = (amp - 1) / (s - 1) * d - d;
97 return max(decaytime, releasetime);
103 void BGMScript_Init()
107 bgmscriptbuf = bgmscriptbufsize = 0;
108 bgmscriptbufloaded = 1;
109 s = strcat("maps/", mi_shortname, ".bgs");
110 fh = fopen(s, FILE_READ);
113 bgmscriptbuf = buf_create();
114 while((s = fgets(fh)))
116 bufstr_set(bgmscriptbuf, bgmscriptbufsize, s);
122 void BGMScript_InitEntity(entity e)
126 if(e.bgmscript != "")
128 if(!bgmscriptbufloaded)
133 m = strcat(e.bgmscript, " ");
136 e.bgmscriptline0 = -1;
137 for(i = 0; i < bgmscriptbufsize; ++i)
139 if(substring(bufstr_get(bgmscriptbuf, i), 0, l) == m)
142 e.bgmscriptline = e.bgmscriptline0 = i;
143 if(i >= bgmscriptbufsize)
145 printf("ERROR: bgmscript does not define %s\n", e.bgmscript);
146 strunzone(e.bgmscript);
147 e.bgmscript = string_null;
152 float GetCurrentAmplitude(entity e, float trel)
155 return GetAttackDecaySustainAmplitude(e.bgmscriptattack, e.bgmscriptdecay, e.bgmscriptsustain, trel) * e.bgmscriptvolume;
158 #ifdef CONSTANT_SPEED_DECAY
159 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, trel);
161 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, trel) * e.bgmscriptvolume;
166 float GetTimeForAmplitude(entity e, float amp)
169 return GetAttackTime(e.bgmscriptattack, amp / e.bgmscriptvolume);
172 #ifdef CONSTANT_SPEED_DECAY
173 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, amp);
175 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, amp / e.bgmscriptvolume);
180 float BGMScript(entity e)
184 if(e.bgmscript == "")
187 if(autocvar_bgmvolume <= 0)
190 e.just_toggled = false;
195 if(bgmtime < e.bgmscripttime)
197 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime + drawframetime);
199 e.bgmscriptline = e.bgmscriptline0;
200 e.bgmscripttime = bgmtime;
202 // treat this as a stop event for all notes, to prevent sticking keys
203 e.bgmscriptstate = false;
204 e.bgmscriptvolume = 1;
205 e.bgmscriptstatetime = bgmtime - GetTimeForAmplitude(e, amp);
208 // find the CURRENT line
211 tokenize_console(bufstr_get(bgmscriptbuf, e.bgmscriptline));
212 if(stof(argv(1)) >= bgmtime || argv(0) != e.bgmscript)
214 e.bgmscripttime = bgmtime;
215 return GetCurrentAmplitude(e, bgmtime - e.bgmscriptstatetime);
217 else if(bgmtime >= stof(argv(1)))
219 e.bgmscriptline += 1;
220 e.bgmscripttime = stof(argv(1));
222 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime);
224 // time code reached!
228 e.just_toggled = e.bgmscriptstate = true;
229 e.bgmscriptvolume = vel;
232 e.just_toggled = e.bgmscriptstate = false;
234 e.bgmscriptstatetime = e.bgmscripttime - GetTimeForAmplitude(e, amp);