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