1 .float dphitcontentsmask;
3 .float cnt; // effect number
4 .vector velocity; // particle velocity
5 .float waterlevel; // direction jitter
6 .float count; // count multiplier
7 .float impulse; // density
8 .string noise; // sound
11 .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
12 .vector movedir; // trace direction
14 void Draw_PointParticles()
21 sz = self.maxs - self.mins;
23 if(self.absolute == 2)
26 n = self.just_toggled ? self.impulse : 0;
28 n = self.impulse * drawframetime;
32 n *= self.impulse * drawframetime;
40 for(i = random(); i <= n && fail <= 64*n; ++i)
43 p_x += random() * sz_x;
44 p_y += random() * sz_y;
45 p_z += random() * sz_z;
46 if(WarpZoneLib_BoxTouchesBrush(p, p, self, world))
48 if(self.movedir != '0 0 0')
50 traceline(p, p + normalize(self.movedir) * 4096, 0, world);
52 pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
56 pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
61 sound(self, CH_AMBIENT, self.noise, VOL_BASE * self.volume, self.atten);
63 self.just_toggled = 0;
65 else if(self.absolute)
74 void Ent_PointParticles_Remove()
77 strunzone(self.noise);
78 self.noise = string_null;
80 strunzone(self.bgmscript);
81 self.bgmscript = string_null;
84 void Ent_PointParticles()
91 i = ReadCoord(); // density (<0: point, >0: volume)
92 if(i && !self.impulse && self.cnt) // self.cnt check is so it only happens if the ent already existed
93 self.just_toggled = 1;
98 self.origin_x = ReadCoord();
99 self.origin_y = ReadCoord();
100 self.origin_z = ReadCoord();
104 self.modelindex = ReadShort();
109 self.mins_x = ReadCoord();
110 self.mins_y = ReadCoord();
111 self.mins_z = ReadCoord();
112 self.maxs_x = ReadCoord();
113 self.maxs_y = ReadCoord();
114 self.maxs_z = ReadCoord();
119 self.maxs_x = ReadCoord();
120 self.maxs_y = ReadCoord();
121 self.maxs_z = ReadCoord();
126 self.mins = self.maxs = '0 0 0';
129 self.cnt = ReadShort(); // effect number
133 self.velocity = decompressShortVector(ReadShort());
134 self.movedir = decompressShortVector(ReadShort());
138 self.velocity = self.movedir = '0 0 0';
142 self.waterlevel = ReadShort() / 16.0;
143 self.count = ReadByte() / 16.0;
151 strunzone(self.noise);
153 strunzone(self.bgmscript);
154 self.noise = strzone(ReadString());
157 self.atten = ReadByte() / 64.0;
158 self.volume = ReadByte() / 255.0;
160 self.bgmscript = strzone(ReadString());
161 if(self.bgmscript != "")
163 self.bgmscriptattack = ReadByte() / 64.0;
164 self.bgmscriptdecay = ReadByte() / 64.0;
165 self.bgmscriptsustain = ReadByte() / 255.0;
166 self.bgmscriptrelease = ReadByte() / 64.0;
168 BGMScript_InitEntity(self);
173 self.absolute = (self.impulse >= 0);
176 v = self.maxs - self.mins;
177 self.impulse *= -v_x * v_y * v_z / 262144; // relative: particles per 64^3 cube
184 setorigin(self, self.origin);
185 setsize(self, self.mins, self.maxs);
186 self.solid = SOLID_NOT;
187 self.draw = Draw_PointParticles;
188 self.entremove = Ent_PointParticles_Remove;
191 .float glow_color; // palette index
194 te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
199 te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
202 void Ent_RainOrSnow()
204 self.impulse = ReadByte(); // Rain, Snow, or Whatever
205 self.origin_x = ReadCoord();
206 self.origin_y = ReadCoord();
207 self.origin_z = ReadCoord();
208 self.maxs_x = ReadCoord();
209 self.maxs_y = ReadCoord();
210 self.maxs_z = ReadCoord();
211 self.velocity = decompressShortVector(ReadShort());
212 self.count = ReadShort() * 10;
213 self.glow_color = ReadByte(); // color
215 self.mins = -0.5 * self.maxs;
216 self.maxs = 0.5 * self.maxs;
217 self.origin = self.origin - self.mins;
219 setorigin(self, self.origin);
220 setsize(self, self.mins, self.maxs);
221 self.solid = SOLID_NOT;
223 self.draw = Draw_Rain;
225 self.draw = Draw_Snow;
229 void zcurveparticles(float effectnum, vector start, vector end, float end_dz, float speed, float depth)
232 // IF IT WERE A STRAIGHT LINE, it'd end end_dz above end
235 mid = (start + end) * 0.5;
241 if(depth < 0 || normalize(mid - start) * normalize(end - start) > 0.999999)
242 // TODO make this a variable threshold
243 // currently: 0.081 degrees
244 // 0.99999 would be 0.256 degrees and is visible
246 zcurve.velocity = speed * normalize(end - start);
247 trailparticles(zcurve, effectnum, start, end);
251 zcurveparticles(effectnum, start, mid, end_dz, speed, depth);
252 zcurveparticles(effectnum, mid, end, end_dz, speed, depth);
256 void Net_ReadZCurveParticles()
260 float effectnum, speed;
265 zcurve.classname = "zcurve";
268 effectnum = ReadShort();
270 start_x = ReadCoord();
271 start_y = ReadCoord();
272 start_z = ReadCoord();
279 end_dz = ReadCoord();
281 zcurveparticles(effectnum, start, end, end_dz, 16 * (speed & 0x7FFF), 5); // at most 32 segments
283 while(!(speed & 0x8000));
286 void Net_ReadNexgunBeamParticle()
288 vector shotorg, endpos;
290 shotorg_x = ReadCoord(); shotorg_y = ReadCoord(); shotorg_z = ReadCoord();
291 endpos_x = ReadCoord(); endpos_y = ReadCoord(); endpos_z = ReadCoord();
292 charge = ReadByte() / 255.0;
294 pointparticles(particleeffectnum("nex_muzzleflash"), shotorg, normalize(endpos - shotorg) * 1000, 1);
296 //draw either the old v2.3 beam or the new beam
297 charge = sqrt(charge); // divide evenly among trail spacing and alpha
298 particles_alphamin = particles_alphamax = charge;
299 if (autocvar_cl_particles_oldnexbeam && (getstati(STAT_ALLOW_OLDNEXBEAM) || isdemo()))
300 WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum("TE_TEI_G3"), shotorg, endpos, charge, 1);
302 WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum("nex_beam"), shotorg, endpos, charge, 1);