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