]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/client/particles.qc
some entity field name improvements for bgmscript
[divverent/nexuiz.git] / data / qcsrc / client / particles.qc
1 vector PointInBrush_vec;
2 entity PointInBrush_brush;
3 .float dphitcontentsmask;
4 float PointInBrush_Recurse()
5 {
6         float s;
7         entity se;
8         float f;
9
10         traceline(PointInBrush_vec, PointInBrush_vec, 0, world);
11         if not(trace_ent)
12                 return 0;
13         if(trace_ent == PointInBrush_brush)
14                 return 1;
15
16         se = trace_ent;
17         s = se.solid;
18         se.solid = SOLID_NOT;
19         f = PointInBrush_Recurse();
20         se.solid = s;
21
22         return f;
23 }
24 float PointInBrush(entity brush, vector point)
25 {
26         float f, s;
27
28         if not(brush.modelindex)
29                 return 1;
30
31         s = brush.solid;
32         brush.solid = SOLID_BSP;
33         PointInBrush_vec = point;
34         PointInBrush_brush = brush;
35         f = PointInBrush_Recurse();
36         brush.solid = s;
37
38         return f;
39 }
40
41 .float cnt; // effect number
42 .vector velocity; // particle velocity
43 .float waterlevel; // direction jitter
44 .float count; // count multiplier
45 .float glow_color; // palette color
46 .float impulse; // density
47 .string noise; // sound
48 .float atten;
49 .float volume;
50 .float absolute;
51 .vector movedir; // trace direction
52 .string bgmscript;
53 .float bgmscriptdecay;
54
55 float pointparticles_scriptbuf;
56 float pointparticles_scriptbufsize;
57 float pointparticles_scriptbufloaded;
58 void PointparticlesScript_Init()
59 {
60         string s;
61         float fh;
62         pointparticles_scriptbuf = pointparticles_scriptbufsize = 0;
63         pointparticles_scriptbufloaded = 1;
64         s = strcat("maps/", mi_shortname, ".pp");
65         fh = fopen(s, FILE_READ);
66         if(fh < 0)
67                 return;
68         pointparticles_scriptbuf = buf_create();
69         while((s = fgets(fh)))
70         {
71                 bufstr_set(pointparticles_scriptbuf, pointparticles_scriptbufsize, s);
72                 ++pointparticles_scriptbufsize;
73         }
74         fclose(fh);
75 }
76
77 .float scriptline;
78 .float scriptline0;
79 .float scriptstate;
80 .float scripttime;
81 void PointparticlesScript_InitEntity(entity e)
82 {
83         if(e.bgmscript != "")
84         {
85                 if(!pointparticles_scriptbufloaded)
86                         PointparticlesScript_Init();
87
88                 string mychar;
89                 float i;
90
91                 e.scriptline0 = -1;
92                 for(i = 0; i < pointparticles_scriptbufsize; ++i)
93                 {
94                         tokenize_sane(bufstr_get(pointparticles_scriptbuf, i));
95                         if(argv(0) == e.bgmscript)
96                                 break;
97                 }
98                 e.scriptline = e.scriptline0 = i;
99                 if(i >= pointparticles_scriptbufsize)
100                 {
101                         print("func_pointparticles: script does not define ", mychar, "\n");
102                         e.bgmscript = "";
103                 }
104         }
105 }
106
107 float PointparticlesScript(entity e)
108 {
109         float t;
110
111         if(e.bgmscript == "")
112                 return 1;
113         
114         if(cvar("bgmvolume") <= 0)
115                 return 0.5;
116
117         e.scriptstate = !!e.scriptstate; // turns 0 to 0 and 2 to 1
118
119         t = gettime(GETTIME_CDTRACK);
120
121         tokenize_sane(bufstr_get(pointparticles_scriptbuf, e.scriptline));
122         if(t < e.scripttime)
123         {
124                 e.scriptline = e.scriptline0;
125                 e.scriptstate = 0;
126                 tokenize_sane(bufstr_get(pointparticles_scriptbuf, e.scriptline));
127         }
128
129         if(argv(0) != e.bgmscript)
130         {
131                 e.scriptstate = 0; // end of script, will revert to beginning later
132         }
133         else if(t >= stof(argv(1)))
134         {
135                 // time code reached!
136                 e.scriptstate = stof(argv(2)) * 2; // 0 = off, 2 = on
137                 e.scripttime = stof(argv(1));
138                 e.scriptline += 1;
139         }
140
141         if(e.scriptstate)
142         {
143                 if(e.bgmscriptdecay >= 1)
144                         return (e.scriptstate == 2);
145                 else
146                         return pow(0.5, (t - e.scripttime) * (e.bgmscriptdecay / (1 - e.bgmscriptdecay)));
147         }
148         else
149                 return 0;
150 }
151
152 void Draw_PointParticles()
153 {
154         float n, i, fail, force;
155         vector p;
156         vector sz;
157         vector o;
158         o = self.origin;
159         sz = self.maxs - self.mins;
160         n = self.impulse * drawframetime;
161         n *= PointparticlesScript(self);
162         if(n == 0)
163                 return;
164         fail = 0;
165         force = (self.scriptstate == 2);
166         for(i = random(); (force || i <= n) && fail <= 64*n; ++i)
167         {
168                 p = o + self.mins;
169                 p_x += random() * sz_x;
170                 p_y += random() * sz_y;
171                 p_z += random() * sz_z;
172                 if(PointInBrush(self, p))
173                 {
174                         if(self.movedir != '0 0 0')
175                         {
176                                 traceline(p, p + normalize(self.movedir) * 4096, 0, world);
177                                 p = trace_endpos;
178                                 pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color);
179                         }
180                         else
181                                 pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color);
182                         if(self.noise != "")
183                         {
184                                 self.origin = p;
185                                 sound(self, CHAN_AUTO, self.noise, VOL_BASE * self.volume, self.atten);
186                         }
187                         force = 0;
188                 }
189                 else if(self.absolute)
190                 {
191                         ++fail;
192                         --i;
193                 }
194         }
195         self.origin = o;
196 }
197
198 void Ent_PointParticles_Remove()
199 {
200         if(self.noise)
201                 strunzone(self.noise);
202         self.noise = string_null;
203         if(self.bgmscript)
204                 strunzone(self.bgmscript);
205         self.bgmscript = string_null;
206 }
207
208 void Ent_PointParticles()
209 {
210         float f;
211         vector v;
212         f = ReadByte();
213         if(f & 2)
214         {
215                 self.impulse = ReadCoord(); // density (<0: point, >0: volume)
216         }
217         if(f & 4)
218         {
219                 self.origin_x = ReadCoord();
220                 self.origin_y = ReadCoord();
221                 self.origin_z = ReadCoord();
222         }
223         if(f & 1)
224         {
225                 self.modelindex = ReadShort();
226                 if(self.modelindex)
227                 {
228                         self.mins_x = ReadCoord();
229                         self.mins_y = ReadCoord();
230                         self.mins_z = ReadCoord();
231                         self.maxs_x = ReadCoord();
232                         self.maxs_y = ReadCoord();
233                         self.maxs_z = ReadCoord();
234                 }
235                 else
236                 {
237                         self.mins    = '0 0 0';
238                         self.maxs_x = ReadCoord();
239                         self.maxs_y = ReadCoord();
240                         self.maxs_z = ReadCoord();
241                 }
242
243                 self.cnt = ReadShort(); // effect number
244
245                 self.velocity = decompressShortVector(ReadShort());
246                 self.movedir = decompressShortVector(ReadShort());
247                 self.waterlevel = ReadCoord();
248                 self.count = ReadCoord();
249                 self.glow_color = ReadByte();
250                 if(self.noise)
251                         strunzone(self.noise);
252                 self.noise = strzone(ReadString());
253                 if(self.noise != "")
254                 {
255                         self.atten = ReadByte() / 64.0;
256                         self.volume = ReadByte() / 255.0;
257                 }
258                 if(self.bgmscript)
259                         strunzone(self.bgmscript);
260                 self.bgmscript = strzone(ReadString());
261                 if(self.bgmscript != "")
262                         self.bgmscriptdecay = ReadByte() / 255.0;
263                 PointparticlesScript_InitEntity(self);
264         }
265
266         if(f & 2)
267         {
268                 self.absolute = (self.impulse >= 0);
269                 if(!self.absolute)
270                 {
271                         v = self.maxs - self.mins;
272                         self.impulse *= -v_x * v_y * v_z / 262144; // relative: particles per 64^3 cube
273                 }
274         }
275
276         setorigin(self, self.origin);
277         setsize(self, self.mins, self.maxs);
278         self.solid = SOLID_NOT;
279         self.draw = Draw_PointParticles;
280         self.entremove = Ent_PointParticles_Remove;
281 }
282
283 void Draw_Rain()
284 {
285     te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, self.count * drawframetime, self.glow_color);
286 }
287
288 void Draw_Snow()
289 {
290     te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, self.count * drawframetime, self.glow_color);
291 }
292
293 void Ent_RainOrSnow()
294 {
295         self.impulse = ReadByte(); // Rain, Snow, or Whatever
296         self.origin_x = ReadCoord();
297         self.origin_y = ReadCoord();
298         self.origin_z = ReadCoord();
299         self.maxs_x = ReadCoord();
300         self.maxs_y = ReadCoord();
301         self.maxs_z = ReadCoord();
302         self.velocity = decompressShortVector(ReadShort());
303         self.count = ReadShort() * 10;
304         self.glow_color = ReadByte(); // color
305
306         self.mins    = -0.5 * self.maxs;
307         self.maxs    =  0.5 * self.maxs;
308         self.origin  = self.origin - self.mins;
309
310         setorigin(self, self.origin);
311         setsize(self, self.mins, self.maxs);
312         self.solid = SOLID_NOT;
313         if(self.impulse)
314                 self.draw = Draw_Rain;
315         else
316                 self.draw = Draw_Snow;
317 }
318
319 entity zcurve;
320 void zcurveparticles(float effectnum, vector start, vector end, float end_dz, float speed, float depth)
321 {
322         // end_dz:
323         //   IF IT WERE A STRAIGHT LINE, it'd end end_dz above end
324
325         vector mid;
326         mid = (start + end) * 0.5;
327
328         end_dz *= 0.25;
329         mid_z += end_dz;
330
331         --depth;
332         if(depth < 0 || normalize(mid - start) * normalize(end - start) > 0.999999)
333         // TODO make this a variable threshold
334         // currently: 0.081 degrees
335         // 0.99999 would be 0.256 degrees and is visible
336         {
337                 zcurve.velocity = speed * normalize(end - start);
338                 trailparticles(zcurve, effectnum, start, end);
339         }
340         else
341         {
342                 zcurveparticles(effectnum, start, mid, end_dz, speed, depth);
343                 zcurveparticles(effectnum, mid, end, end_dz, speed, depth);
344         }
345 }
346
347 void Net_ReadZCurveParticles()
348 {
349         vector start, end;
350         float end_dz;
351         float effectnum, speed;
352
353         if(!zcurve)
354         {
355                 zcurve = spawn();
356                 zcurve.classname = "zcurve";
357         }
358
359         effectnum = ReadShort();
360
361         start_x = ReadCoord();
362         start_y = ReadCoord();
363         start_z = ReadCoord();
364         end_x = ReadCoord();
365         end_y = ReadCoord();
366         end_z = ReadCoord();
367         end_dz = ReadCoord();
368         speed = ReadShort() * 16;
369
370         zcurveparticles(effectnum, start, end, end_dz, speed, 5); // at most 32 segments
371 }
372
373 void Net_ReadNexgunBeamParticle()
374 {
375         vector shotorg, endpos;
376         shotorg_x = ReadCoord(); shotorg_y = ReadCoord(); shotorg_z = ReadCoord();
377         endpos_x = ReadCoord(); endpos_y = ReadCoord(); endpos_z = ReadCoord();
378         
379         pointparticles(particleeffectnum("nex_muzzleflash"), shotorg, normalize(endpos - shotorg) * 1000, 1);
380         
381         //draw either the old v2.3 beam or the new beam
382         if (cvar("cl_particles_oldnexbeam") && (getstati(STAT_ALLOW_OLDNEXBEAM) || isdemo()))
383                 trailparticles(world, particleeffectnum("TE_TEI_G3"), shotorg, endpos);
384         else
385                 trailparticles(world, particleeffectnum("nex_beam"), shotorg, endpos);
386 }