]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/client/particles.qc
fix negative pointparticles impulse
[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 absolute;
49 .vector movedir; // trace direction
50
51 void Draw_PointParticles()
52 {
53         float n, i, fail;
54         vector p;
55         vector sz;
56         vector o;
57         o = self.origin;
58         sz = self.maxs - self.mins;
59         n = self.impulse * drawframetime;
60         if(n == 0)
61                 return;
62         fail = 0;
63         for(i = random(); i <= n && fail <= 64*n; ++i)
64         {
65                 p = o + self.mins;
66                 p_x += random() * sz_x;
67                 p_y += random() * sz_y;
68                 p_z += random() * sz_z;
69                 if(PointInBrush(self, p))
70                 {
71                         if(self.movedir != '0 0 0')
72                         {
73                                 traceline(p, p + normalize(self.movedir) * 4096, 0, world);
74                                 p = trace_endpos;
75                                 pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color);
76                         }
77                         else
78                                 pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count, self.glow_color);
79                         if(self.noise != "")
80                         {
81                                 self.origin = p;
82                                 sound(self, CHAN_AUTO, self.noise, 1, ATTN_NORM);
83                         }
84                 }
85                 else if(self.absolute)
86                 {
87                         ++fail;
88                         --i;
89                 }
90         }
91         self.origin = o;
92 }
93
94 void Ent_PointParticles_Remove()
95 {
96         if(self.noise)
97                 strunzone(self.noise);
98         self.noise = string_null;
99 }
100
101 void Ent_PointParticles()
102 {
103         float f;
104         vector v;
105         f = ReadByte();
106         if(f & 2)
107         {
108                 self.impulse = ReadCoord(); // density (<0: point, >0: volume)
109         }
110         if(f & 4)
111         {
112                 self.origin_x = ReadCoord();
113                 self.origin_y = ReadCoord();
114                 self.origin_z = ReadCoord();
115         }
116         if(f & 1)
117         {
118                 self.modelindex = ReadShort();
119                 if(self.modelindex)
120                 {
121                         self.mins_x = ReadCoord();
122                         self.mins_y = ReadCoord();
123                         self.mins_z = ReadCoord();
124                         self.maxs_x = ReadCoord();
125                         self.maxs_y = ReadCoord();
126                         self.maxs_z = ReadCoord();
127                 }
128                 else
129                 {
130                         self.mins    = '0 0 0';
131                         self.maxs_x = ReadCoord();
132                         self.maxs_y = ReadCoord();
133                         self.maxs_z = ReadCoord();
134                 }
135
136                 self.cnt = ReadShort(); // effect number
137
138                 self.velocity = decompressShortVector(ReadShort());
139                 self.movedir = decompressShortVector(ReadShort());
140                 self.waterlevel = ReadCoord();
141                 self.count = ReadCoord();
142                 self.glow_color = ReadByte();
143                 if(self.noise)
144                         strunzone(self.noise);
145                 self.noise = strzone(ReadString());
146         }
147
148         if(f & 2)
149         {
150                 self.absolute = (self.impulse >= 0);
151                 if(!self.absolute)
152                 {
153                         v = self.maxs - self.mins;
154                         self.impulse *= -v_x * v_y * v_z / 262144; // relative: particles per 64^3 cube
155                 }
156         }
157
158         setorigin(self, self.origin);
159         setsize(self, self.mins, self.maxs);
160         self.solid = SOLID_NOT;
161         self.draw = Draw_PointParticles;
162         self.entremove = Ent_PointParticles_Remove;
163 }
164
165 void Draw_Rain()
166 {
167     te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, self.count * drawframetime, self.glow_color);
168 }
169
170 void Draw_Snow()
171 {
172     te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, self.count * drawframetime, self.glow_color);
173 }
174
175 void Ent_RainOrSnow()
176 {
177         self.impulse = ReadByte(); // Rain, Snow, or Whatever
178         self.origin_x = ReadCoord();
179         self.origin_y = ReadCoord();
180         self.origin_z = ReadCoord();
181         self.maxs_x = ReadCoord();
182         self.maxs_y = ReadCoord();
183         self.maxs_z = ReadCoord();
184         self.velocity = decompressShortVector(ReadShort());
185         self.count = ReadShort() * 10;
186         self.glow_color = ReadByte(); // color
187
188         self.mins    = -0.5 * self.maxs;
189         self.maxs    =  0.5 * self.maxs;
190         self.origin  = self.origin - self.mins;
191
192         setorigin(self, self.origin);
193         setsize(self, self.mins, self.maxs);
194         self.solid = SOLID_NOT;
195         if(self.impulse)
196                 self.draw = Draw_Rain;
197         else
198                 self.draw = Draw_Snow;
199 }
200
201 entity zcurve;
202 void zcurveparticles(float effectnum, vector start, vector end, float end_dz, float speed, float depth)
203 {
204         // end_dz:
205         //   IF IT WERE A STRAIGHT LINE, it'd end end_dz above end
206
207         vector mid;
208         mid = (start + end) * 0.5;
209
210         end_dz *= 0.25;
211         mid_z += end_dz;
212
213         --depth;
214         if(depth < 0 || normalize(mid - start) * normalize(end - start) > 0.999999)
215         // TODO make this a variable threshold
216         // currently: 0.081 degrees
217         // 0.99999 would be 0.256 degrees and is visible
218         {
219                 zcurve.velocity = speed * normalize(end - start);
220                 trailparticles(zcurve, effectnum, start, end);
221         }
222         else
223         {
224                 zcurveparticles(effectnum, start, mid, end_dz, speed, depth);
225                 zcurveparticles(effectnum, mid, end, end_dz, speed, depth);
226         }
227 }
228
229 void Net_ReadZCurveParticles()
230 {
231         vector start, end;
232         float end_dz;
233         float effectnum, speed;
234
235         if(!zcurve)
236         {
237                 zcurve = spawn();
238                 zcurve.classname = "zcurve";
239         }
240
241         effectnum = ReadShort();
242
243         start_x = ReadCoord();
244         start_y = ReadCoord();
245         start_z = ReadCoord();
246         end_x = ReadCoord();
247         end_y = ReadCoord();
248         end_z = ReadCoord();
249         end_dz = ReadCoord();
250         speed = ReadShort() * 16;
251
252         zcurveparticles(effectnum, start, end, end_dz, speed, 5); // at most 32 segments
253 }
254
255 void Net_ReadNexgunBeamParticle()
256 {
257         vector shotorg, endpos;
258         shotorg_x = ReadCoord(); shotorg_y = ReadCoord(); shotorg_z = ReadCoord();
259         endpos_x = ReadCoord(); endpos_y = ReadCoord(); endpos_z = ReadCoord();
260         
261         pointparticles(particleeffectnum("nex_muzzleflash"), shotorg, normalize(endpos - shotorg) * 1000, 1);
262         
263         //draw either the old v2.3 beam or the new beam
264         if (cvar("cl_particles_oldnexbeam") && (getstati(STAT_ALLOW_OLDNEXBEAM) || isdemo()))
265                 trailparticles(world, particleeffectnum("TE_TEI_G3"), shotorg, endpos);
266         else
267                 trailparticles(world, particleeffectnum("nex_beam"), shotorg, endpos);
268 }