]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/bgmscript.qc
Sort #includes
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / bgmscript.qc
1 #include "bgmscript.qh"
2
3 #include "autocvars.qh"
4 #include "defs.qh"
5 #include "main.qh"
6 #include "../common/util.qh"
7 #include "../dpdefs/csprogsdefs.qh"
8
9 #define CONSTANT_SPEED_DECAY
10
11 float bgmscriptbuf;
12 float bgmscriptbufsize;
13 float bgmscriptbufloaded;
14
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;
21
22 float GetAttackDecaySustainAmplitude(float a, float d, float s, float t)
23 {
24         // phase:
25         //   attack: from 0 to 1, in time a for a full length
26         //   decay: from 1 to s, in time d
27         //   sustain: s
28
29         if(t < 0)
30                 return 0;
31
32         if(a)
33                 if(t <= a)
34                         return t / a;
35
36         if(d)
37                 if(t <= a + d)
38                         return ((t - a) / d) * (s - 1) + 1;
39
40         return s;
41 }
42
43 float GetReleaseAmplitude(float d, float s, float r, float t)
44 {
45         float decayval, releaseval;
46
47         if(!r)
48                 return 0;
49
50         if(t > r)
51                 return 0;
52
53         releaseval = s * (1 - t / r);
54
55         if(t < -d)
56                 return 1;
57
58         if(t < 0 && t >= -d)
59         {
60                 // pre-time decay
61                 // value is s at time  0
62                 //          1 at time -d
63                 decayval = ((t + d) / d) * (s - 1) + 1;
64                 return max(decayval, releaseval);
65         }
66
67         return releaseval;
68 }
69
70 float GetAttackTime(float a, float amp)
71 {
72         return amp * a;
73 }
74
75 float GetReleaseTime(float d, float s, float r, float amp)
76 {
77         float decaytime, releasetime;
78
79         if(!s)
80                 return 0;
81
82         // if amp > s, we may be in the attack or in the prolonged decay curve
83         releasetime = (1 - amp / s) * r;
84
85         if(amp > s)
86         {
87                 if(s == 1) // gracefully handle division by zero here
88                         return 0;
89
90                 // pre-time decay
91                 // value is s at time  0
92                 //          1 at time -d
93                 decaytime = (amp - 1) / (s - 1) * d - d;
94                 return max(decaytime, releasetime);
95         }
96
97         return releasetime;
98 }
99
100 void BGMScript_Init()
101 {
102         string s;
103         float fh;
104         bgmscriptbuf = bgmscriptbufsize = 0;
105         bgmscriptbufloaded = 1;
106         s = strcat("maps/", mi_shortname, ".bgs");
107         fh = fopen(s, FILE_READ);
108         if(fh < 0)
109                 return;
110         bgmscriptbuf = buf_create();
111         while((s = fgets(fh)))
112         {
113                 bufstr_set(bgmscriptbuf, bgmscriptbufsize, s);
114                 ++bgmscriptbufsize;
115         }
116         fclose(fh);
117 }
118
119 void BGMScript_InitEntity(entity e)
120 {
121         float l;
122         string m;
123         if(e.bgmscript != "")
124         {
125                 if(!bgmscriptbufloaded)
126                         BGMScript_Init();
127
128                 float i;
129
130                 m = strcat(e.bgmscript, " ");
131                 l = strlen(m);
132
133                 e.bgmscriptline0 = -1;
134                 for(i = 0; i < bgmscriptbufsize; ++i)
135                 {
136                         if(substring(bufstr_get(bgmscriptbuf, i), 0, l) == m)
137                                 break;
138                 }
139                 e.bgmscriptline = e.bgmscriptline0 = i;
140                 if(i >= bgmscriptbufsize)
141                 {
142                         printf("ERROR: bgmscript does not define %s\n", e.bgmscript);
143                         strunzone(e.bgmscript);
144                         e.bgmscript = string_null;
145                 }
146         }
147 }
148
149 float GetCurrentAmplitude(entity e, float trel)
150 {
151         if(e.bgmscriptstate)
152                 return GetAttackDecaySustainAmplitude(e.bgmscriptattack, e.bgmscriptdecay, e.bgmscriptsustain, trel) * e.bgmscriptvolume;
153         else
154         {
155 #ifdef CONSTANT_SPEED_DECAY
156                 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, trel);
157 #else
158                 return GetReleaseAmplitude(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, trel) * e.bgmscriptvolume;
159 #endif
160         }
161 }
162
163 float GetTimeForAmplitude(entity e, float amp)
164 {
165         if(e.bgmscriptstate)
166                 return GetAttackTime(e.bgmscriptattack, amp / e.bgmscriptvolume);
167         else
168         {
169 #ifdef CONSTANT_SPEED_DECAY
170                 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain * e.bgmscriptvolume, e.bgmscriptrelease, amp);
171 #else
172                 return GetReleaseTime(e.bgmscriptdecay, e.bgmscriptsustain, e.bgmscriptrelease, amp / e.bgmscriptvolume);
173 #endif
174         }
175 }
176
177 float BGMScript(entity e)
178 {
179         float amp, vel;
180
181         if(e.bgmscript == "")
182                 return 1;
183
184         if(autocvar_bgmvolume <= 0)
185                 return -1;
186
187         e.just_toggled = false;
188
189         if(bgmtime < 0)
190                 return -1;
191
192         if(bgmtime < e.bgmscripttime)
193         {
194                 amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime + drawframetime);
195
196                 e.bgmscriptline = e.bgmscriptline0;
197                 e.bgmscripttime = bgmtime;
198
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);
203         }
204
205         // find the CURRENT line
206         for (;;)
207         {
208                 tokenize_console(bufstr_get(bgmscriptbuf, e.bgmscriptline));
209                 if(stof(argv(1)) >= bgmtime || argv(0) != e.bgmscript)
210                 {
211                         e.bgmscripttime = bgmtime;
212                         return GetCurrentAmplitude(e, bgmtime - e.bgmscriptstatetime);
213                 }
214                 else if(bgmtime >= stof(argv(1)))
215                 {
216                         e.bgmscriptline += 1;
217                         e.bgmscripttime = stof(argv(1));
218
219                         amp = GetCurrentAmplitude(e, e.bgmscripttime - e.bgmscriptstatetime);
220
221                         // time code reached!
222                         vel = stof(argv(2));
223                         if(vel > 0)
224                         {
225                                 e.just_toggled = e.bgmscriptstate = true;
226                                 e.bgmscriptvolume = vel;
227                         }
228                         else
229                                 e.just_toggled = e.bgmscriptstate = false;
230
231                         e.bgmscriptstatetime = e.bgmscripttime - GetTimeForAmplitude(e, amp);
232                 }
233         }
234 }
235