1 #include "bgmscript.qh"
3 #include "autocvars.qh"
7 #include "../common/util.qh"
9 #include "../dpdefs/csprogsdefs.qh"
11 #define CONSTANT_SPEED_DECAY
14 float bgmscriptbufsize;
15 float bgmscriptbufloaded;
17 class(BGMScript) .float bgmscriptline;
18 class(BGMScript) .float bgmscriptline0;
19 class(BGMScript) .float bgmscriptvolume;
20 class(BGMScript) .float bgmscripttime;
21 class(BGMScript) .float bgmscriptstate;
22 class(BGMScript) .float bgmscriptstatetime;
24 float GetAttackDecaySustainAmplitude(float a, float d, float s, float t)
27 // attack: from 0 to 1, in time a for a full length
28 // decay: from 1 to s, in time d
40 return ((t - a) / d) * (s - 1) + 1;
45 float GetReleaseAmplitude(float d, float s, float r, float t)
47 float decayval, releaseval;
55 releaseval = s * (1 - t / r);
63 // value is s at time 0
65 decayval = ((t + d) / d) * (s - 1) + 1;
66 return max(decayval, releaseval);
72 float GetAttackTime(float a, float amp)
77 float GetReleaseTime(float d, float s, float r, float amp)
79 float decaytime, releasetime;
84 // if amp > s, we may be in the attack or in the prolonged decay curve
85 releasetime = (1 - amp / s) * r;
89 if(s == 1) // gracefully handle division by zero here
93 // value is s at time 0
95 decaytime = (amp - 1) / (s - 1) * d - d;
96 return max(decaytime, releasetime);
102 void BGMScript_Init()
106 bgmscriptbuf = bgmscriptbufsize = 0;
107 bgmscriptbufloaded = 1;
108 s = strcat("maps/", mi_shortname, ".bgs");
109 fh = fopen(s, FILE_READ);
112 bgmscriptbuf = buf_create();
113 while((s = fgets(fh)))
115 bufstr_set(bgmscriptbuf, bgmscriptbufsize, s);
121 void BGMScript_InitEntity(entity e)
125 if(e.bgmscript != "")
127 if(!bgmscriptbufloaded)
132 m = strcat(e.bgmscript, " ");
135 e.bgmscriptline0 = -1;
136 for(i = 0; i < bgmscriptbufsize; ++i)
138 if(substring(bufstr_get(bgmscriptbuf, i), 0, l) == m)
141 e.bgmscriptline = e.bgmscriptline0 = i;
142 if(i >= bgmscriptbufsize)
144 printf("ERROR: bgmscript does not define %s\n", e.bgmscript);
145 strunzone(e.bgmscript);
146 e.bgmscript = string_null;
151 float GetCurrentAmplitude(entity e, float trel)
154 return GetAttackDecaySustainAmplitude(e.bgmscriptattack, e.bgmscriptdecay, e.bgmscriptsustain, trel) * e.bgmscriptvolume;
157 #ifdef CONSTANT_SPEED_DECAY
158 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, trel);
160 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, trel) * e.bgmscriptvolume;
165 float GetTimeForAmplitude(entity e, float amp)
168 return GetAttackTime(e.bgmscriptattack, amp / e.bgmscriptvolume);
171 #ifdef CONSTANT_SPEED_DECAY
172 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, amp);
174 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, amp / e.bgmscriptvolume);
179 float BGMScript(entity e)
183 if(e.bgmscript == "")
186 if(autocvar_bgmvolume <= 0)
189 e.just_toggled = false;
194 if(bgmtime < e.bgmscripttime)
196 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime + drawframetime);
198 e.bgmscriptline = e.bgmscriptline0;
199 e.bgmscripttime = bgmtime;
201 // treat this as a stop event for all notes, to prevent sticking keys
202 e.bgmscriptstate = false;
203 e.bgmscriptvolume = 1;
204 e.bgmscriptstatetime = bgmtime - GetTimeForAmplitude(e, amp);
207 // find the CURRENT line
210 tokenize_console(bufstr_get(bgmscriptbuf, e.bgmscriptline));
211 if(stof(argv(1)) >= bgmtime || argv(0) != e.bgmscript)
213 e.bgmscripttime = bgmtime;
214 return GetCurrentAmplitude(e, bgmtime - e.bgmscriptstatetime);
216 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!
227 e.just_toggled = e.bgmscriptstate = true;
228 e.bgmscriptvolume = vel;
231 e.just_toggled = e.bgmscriptstate = false;
233 e.bgmscriptstatetime = e.bgmscripttime - GetTimeForAmplitude(e, amp);