2 #include "../../../client/particles.qh"
6 // NOTE: also contains func_sparks
8 bool pointparticles_SendEntity(entity this, entity to, float fl)
10 WriteByte(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
12 // optional features to save space
14 if(self.spawnflags & 2)
15 fl |= 0x10; // absolute count on toggle-on
16 if(self.movedir != '0 0 0' || self.velocity != '0 0 0')
17 fl |= 0x20; // 4 bytes - saves CPU
18 if(self.waterlevel || self.count != 1)
19 fl |= 0x40; // 4 bytes - obscure features almost never used
20 if(self.mins != '0 0 0' || self.maxs != '0 0 0')
21 fl |= 0x80; // 14 bytes - saves lots of space
23 WriteByte(MSG_ENTITY, fl);
27 WriteCoord(MSG_ENTITY, self.impulse);
29 WriteCoord(MSG_ENTITY, 0); // off
33 WriteCoord(MSG_ENTITY, self.origin_x);
34 WriteCoord(MSG_ENTITY, self.origin_y);
35 WriteCoord(MSG_ENTITY, self.origin_z);
39 if(self.model != "null")
41 WriteShort(MSG_ENTITY, self.modelindex);
44 WriteCoord(MSG_ENTITY, self.mins_x);
45 WriteCoord(MSG_ENTITY, self.mins_y);
46 WriteCoord(MSG_ENTITY, self.mins_z);
47 WriteCoord(MSG_ENTITY, self.maxs_x);
48 WriteCoord(MSG_ENTITY, self.maxs_y);
49 WriteCoord(MSG_ENTITY, self.maxs_z);
54 WriteShort(MSG_ENTITY, 0);
57 WriteCoord(MSG_ENTITY, self.maxs_x);
58 WriteCoord(MSG_ENTITY, self.maxs_y);
59 WriteCoord(MSG_ENTITY, self.maxs_z);
62 WriteShort(MSG_ENTITY, self.cnt);
65 WriteShort(MSG_ENTITY, compressShortVector(self.velocity));
66 WriteShort(MSG_ENTITY, compressShortVector(self.movedir));
70 WriteShort(MSG_ENTITY, self.waterlevel * 16.0);
71 WriteByte(MSG_ENTITY, self.count * 16.0);
73 WriteString(MSG_ENTITY, self.noise);
76 WriteByte(MSG_ENTITY, floor(self.atten * 64));
77 WriteByte(MSG_ENTITY, floor(self.volume * 255));
79 WriteString(MSG_ENTITY, self.bgmscript);
80 if(self.bgmscript != "")
82 WriteByte(MSG_ENTITY, floor(self.bgmscriptattack * 64));
83 WriteByte(MSG_ENTITY, floor(self.bgmscriptdecay * 64));
84 WriteByte(MSG_ENTITY, floor(self.bgmscriptsustain * 255));
85 WriteByte(MSG_ENTITY, floor(self.bgmscriptrelease * 64));
91 void pointparticles_use()
93 self.state = !self.state;
97 void pointparticles_think()
99 if(self.origin != self.oldorigin)
102 self.oldorigin = self.origin;
104 self.nextthink = time;
107 void pointparticles_reset()
109 if(self.spawnflags & 1)
115 spawnfunc(func_pointparticles)
118 _setmodel(self, self.model);
120 precache_sound (self.noise);
122 if(!self.bgmscriptsustain)
123 self.bgmscriptsustain = 1;
124 else if(self.bgmscriptsustain < 0)
125 self.bgmscriptsustain = 0;
128 self.atten = ATTEN_NORM;
129 else if(self.atten < 0)
140 setorigin(self, self.origin + self.mins);
141 setsize(self, '0 0 0', self.maxs - self.mins);
144 self.cnt = _particleeffectnum(self.mdl);
146 Net_LinkEntity(self, (self.spawnflags & 4), 0, pointparticles_SendEntity);
150 self.use = pointparticles_use;
151 self.reset = pointparticles_reset;
156 self.think = pointparticles_think;
157 self.nextthink = time;
160 spawnfunc(func_sparks)
162 // self.cnt is the amount of sparks that one burst will spawn
164 self.cnt = 25.0; // nice default value
167 // self.wait is the probability that a sparkthink will spawn a spark shower
168 // range: 0 - 1, but 0 makes little sense, so...
169 if(self.wait < 0.05) {
170 self.wait = 0.25; // nice default value
173 self.count = self.cnt;
176 self.velocity = '0 0 -1';
177 self.mdl = "TE_SPARK";
178 self.impulse = 10 * self.wait; // by default 2.5/sec
180 self.cnt = 0; // use mdl
182 spawnfunc_func_pointparticles(this);
186 void Draw_PointParticles(entity this)
193 sz = self.maxs - self.mins;
194 n = doBGMScript(self);
195 if(self.absolute == 2)
198 n = self.just_toggled ? self.impulse : 0;
200 n = self.impulse * drawframetime;
204 n *= self.impulse * drawframetime;
205 if(self.just_toggled)
212 for(i = random(); i <= n && fail <= 64*n; ++i)
215 p.x += random() * sz.x;
216 p.y += random() * sz.y;
217 p.z += random() * sz.z;
218 if(WarpZoneLib_BoxTouchesBrush(p, p, self, world))
220 if(self.movedir != '0 0 0')
222 traceline(p, p + normalize(self.movedir) * 4096, 0, world);
224 pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
228 pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
233 _sound(self, CH_AMBIENT, self.noise, VOL_BASE * self.volume, self.atten);
235 self.just_toggled = 0;
237 else if(self.absolute)
246 void Ent_PointParticles_Remove()
249 strunzone(self.noise);
250 self.noise = string_null;
252 strunzone(self.bgmscript);
253 self.bgmscript = string_null;
256 void Ent_PointParticles()
263 i = ReadCoord(); // density (<0: point, >0: volume)
264 if(i && !self.impulse && self.cnt) // self.cnt check is so it only happens if the ent already existed
265 self.just_toggled = 1;
270 self.origin_x = ReadCoord();
271 self.origin_y = ReadCoord();
272 self.origin_z = ReadCoord();
276 self.modelindex = ReadShort();
281 self.mins_x = ReadCoord();
282 self.mins_y = ReadCoord();
283 self.mins_z = ReadCoord();
284 self.maxs_x = ReadCoord();
285 self.maxs_y = ReadCoord();
286 self.maxs_z = ReadCoord();
291 self.maxs_x = ReadCoord();
292 self.maxs_y = ReadCoord();
293 self.maxs_z = ReadCoord();
298 self.mins = self.maxs = '0 0 0';
301 self.cnt = ReadShort(); // effect number
305 self.velocity = decompressShortVector(ReadShort());
306 self.movedir = decompressShortVector(ReadShort());
310 self.velocity = self.movedir = '0 0 0';
314 self.waterlevel = ReadShort() / 16.0;
315 self.count = ReadByte() / 16.0;
323 strunzone(self.noise);
325 strunzone(self.bgmscript);
326 self.noise = strzone(ReadString());
329 self.atten = ReadByte() / 64.0;
330 self.volume = ReadByte() / 255.0;
332 self.bgmscript = strzone(ReadString());
333 if(self.bgmscript != "")
335 self.bgmscriptattack = ReadByte() / 64.0;
336 self.bgmscriptdecay = ReadByte() / 64.0;
337 self.bgmscriptsustain = ReadByte() / 255.0;
338 self.bgmscriptrelease = ReadByte() / 64.0;
340 BGMScript_InitEntity(self);
345 self.absolute = (self.impulse >= 0);
348 v = self.maxs - self.mins;
349 self.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
356 setorigin(self, self.origin);
357 setsize(self, self.mins, self.maxs);
358 self.solid = SOLID_NOT;
359 self.draw = Draw_PointParticles;
360 self.entremove = Ent_PointParticles_Remove;