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