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