1 vector PointInBrush_vec;
2 entity PointInBrush_brush;
3 .float dphitcontentsmask;
4 float PointInBrush_Recurse()
10 traceline(PointInBrush_vec, PointInBrush_vec, 0, world);
13 if(trace_ent == PointInBrush_brush)
19 f = PointInBrush_Recurse();
24 float PointInBrush(entity brush, vector point)
28 if not(brush.modelindex)
32 brush.solid = SOLID_BSP;
33 PointInBrush_vec = point;
34 PointInBrush_brush = brush;
35 f = PointInBrush_Recurse();
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
51 .vector movedir; // trace direction
52 .string message; // script stuff
54 float pointparticles_scriptbuf;
55 float pointparticles_scriptbufsize;
56 float pointparticles_scriptbufloaded;
57 void PointparticlesScript_Init()
61 pointparticles_scriptbuf = pointparticles_scriptbufsize = 0;
62 pointparticles_scriptbufloaded = 1;
63 s = strcat("maps/", mi_shortname, ".pp");
64 fh = fopen(s, FILE_READ);
67 pointparticles_scriptbuf = buf_create();
68 while((s = fgets(fh)))
70 bufstr_set(pointparticles_scriptbuf, pointparticles_scriptbufsize, s);
71 ++pointparticles_scriptbufsize;
80 void PointparticlesScript_InitEntity(entity e)
84 if(!pointparticles_scriptbufloaded)
85 PointparticlesScript_Init();
91 mychar = substring(e.message, 0, 1);
92 for(i = 0; i < pointparticles_scriptbufsize; ++i)
94 tokenize_sane(bufstr_get(pointparticles_scriptbuf, i));
98 e.scriptline = e.scriptline0 = i;
99 if(i >= pointparticles_scriptbufsize)
101 print("func_pointparticles: script does not define ", mychar, "\n");
107 float PointparticlesScript(entity e)
117 e.scriptstate = !!e.scriptstate; // turns 0 to 0 and 2 to 1
119 mychar = substring(e.message, 0, 1);
120 mymult = stof(substring(e.message, 1, -1));
121 t = gettime(GETTIME_CDTRACK);
123 tokenize_sane(bufstr_get(pointparticles_scriptbuf, e.scriptline));
126 e.scriptline = e.scriptline0;
128 tokenize_sane(bufstr_get(pointparticles_scriptbuf, e.scriptline));
131 if(argv(0) != mychar)
133 e.scriptstate = 0; // end of script, will revert to beginning later
135 else if(t >= stof(argv(1)))
137 // time code reached!
138 e.scriptstate = stof(argv(2)) * 2; // 0 = off, 2 = on
139 e.scripttime = stof(argv(1));
146 return (e.scriptstate == 2);
148 return pow(0.5, (t - e.scripttime) * (mymult / (1 - mymult)));
154 void Draw_PointParticles()
156 float n, i, fail, force;
161 sz = self.maxs - self.mins;
162 n = self.impulse * drawframetime;
163 n *= PointparticlesScript(self);
167 force = (self.scriptstate == 2);
168 for(i = random(); (force || i <= n) && fail <= 64*n; ++i)
171 p_x += random() * sz_x;
172 p_y += random() * sz_y;
173 p_z += random() * sz_z;
174 if(PointInBrush(self, p))
176 if(self.movedir != '0 0 0')
178 traceline(p, p + normalize(self.movedir) * 4096, 0, world);
180 pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color);
183 pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color);
187 sound(self, CHAN_AUTO, self.noise, VOL_BASE * self.volume, self.atten);
191 else if(self.absolute)
200 void Ent_PointParticles_Remove()
203 strunzone(self.noise);
204 self.noise = string_null;
206 strunzone(self.message);
207 self.message = string_null;
210 void Ent_PointParticles()
217 self.impulse = ReadCoord(); // density (<0: point, >0: volume)
221 self.origin_x = ReadCoord();
222 self.origin_y = ReadCoord();
223 self.origin_z = ReadCoord();
227 self.modelindex = ReadShort();
230 self.mins_x = ReadCoord();
231 self.mins_y = ReadCoord();
232 self.mins_z = ReadCoord();
233 self.maxs_x = ReadCoord();
234 self.maxs_y = ReadCoord();
235 self.maxs_z = ReadCoord();
240 self.maxs_x = ReadCoord();
241 self.maxs_y = ReadCoord();
242 self.maxs_z = ReadCoord();
245 self.cnt = ReadShort(); // effect number
247 self.velocity = decompressShortVector(ReadShort());
248 self.movedir = decompressShortVector(ReadShort());
249 self.waterlevel = ReadCoord();
250 self.count = ReadCoord();
251 self.glow_color = ReadByte();
253 strunzone(self.noise);
254 self.noise = strzone(ReadString());
257 self.atten = ReadByte() / 64.0;
258 self.volume = ReadByte() / 255.0;
261 strunzone(self.message);
262 self.message = strzone(ReadString());
263 PointparticlesScript_InitEntity(self);
268 self.absolute = (self.impulse >= 0);
271 v = self.maxs - self.mins;
272 self.impulse *= -v_x * v_y * v_z / 262144; // relative: particles per 64^3 cube
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;
285 te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, self.count * drawframetime, self.glow_color);
290 te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, self.count * drawframetime, self.glow_color);
293 void Ent_RainOrSnow()
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
306 self.mins = -0.5 * self.maxs;
307 self.maxs = 0.5 * self.maxs;
308 self.origin = self.origin - self.mins;
310 setorigin(self, self.origin);
311 setsize(self, self.mins, self.maxs);
312 self.solid = SOLID_NOT;
314 self.draw = Draw_Rain;
316 self.draw = Draw_Snow;
320 void zcurveparticles(float effectnum, vector start, vector end, float end_dz, float speed, float depth)
323 // IF IT WERE A STRAIGHT LINE, it'd end end_dz above end
326 mid = (start + end) * 0.5;
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
337 zcurve.velocity = speed * normalize(end - start);
338 trailparticles(zcurve, effectnum, start, end);
342 zcurveparticles(effectnum, start, mid, end_dz, speed, depth);
343 zcurveparticles(effectnum, mid, end, end_dz, speed, depth);
347 void Net_ReadZCurveParticles()
351 float effectnum, speed;
356 zcurve.classname = "zcurve";
359 effectnum = ReadShort();
361 start_x = ReadCoord();
362 start_y = ReadCoord();
363 start_z = ReadCoord();
367 end_dz = ReadCoord();
368 speed = ReadShort() * 16;
370 zcurveparticles(effectnum, start, end, end_dz, speed, 5); // at most 32 segments
373 void Net_ReadNexgunBeamParticle()
375 vector shotorg, endpos;
376 shotorg_x = ReadCoord(); shotorg_y = ReadCoord(); shotorg_z = ReadCoord();
377 endpos_x = ReadCoord(); endpos_y = ReadCoord(); endpos_z = ReadCoord();
379 pointparticles(particleeffectnum("nex_muzzleflash"), shotorg, normalize(endpos - shotorg) * 1000, 1);
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);
385 trailparticles(world, particleeffectnum("nex_beam"), shotorg, endpos);