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