]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/client/particles.qc
Make client includes order insensitive
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / particles.qc
1 #include "particles.qh"
2
3 #include "../common/util.qh"
4 #include "autocvars.qh"
5 #include "bgmscript.qh"
6 #include "main.qh"
7 #include "../common/stats.qh"
8 #include "../warpzonelib/common.qh"
9
10 void Draw_PointParticles()
11 {
12         float n, i, fail;
13         vector p;
14         vector sz;
15         vector o;
16         o = self.origin;
17         sz = self.maxs - self.mins;
18         n = BGMScript(self);
19         if(self.absolute == 2)
20         {
21                 if(n >= 0)
22                         n = self.just_toggled ? self.impulse : 0;
23                 else
24                         n = self.impulse * drawframetime;
25         }
26         else
27         {
28                 n *= self.impulse * drawframetime;
29                 if(self.just_toggled)
30                         if(n < 1)
31                                 n = 1;
32         }
33         if(n == 0)
34                 return;
35         fail = 0;
36         for(i = random(); i <= n && fail <= 64*n; ++i)
37         {
38                 p = o + self.mins;
39                 p.x += random() * sz.x;
40                 p.y += random() * sz.y;
41                 p.z += random() * sz.z;
42                 if(WarpZoneLib_BoxTouchesBrush(p, p, self, world))
43                 {
44                         if(self.movedir != '0 0 0')
45                         {
46                                 traceline(p, p + normalize(self.movedir) * 4096, 0, world);
47                                 p = trace_endpos;
48                                 pointparticles(self.cnt, p, trace_plane_normal * vlen(self.movedir) + self.velocity + randomvec() * self.waterlevel, self.count);
49                         }
50                         else
51                         {
52                                 pointparticles(self.cnt, p, self.velocity + randomvec() * self.waterlevel, self.count);
53                         }
54                         if(self.noise != "")
55                         {
56                                 setorigin(self, p);
57                                 sound(self, CH_AMBIENT, self.noise, VOL_BASE * self.volume, self.atten);
58                         }
59                         self.just_toggled = 0;
60                 }
61                 else if(self.absolute)
62                 {
63                         ++fail;
64                         --i;
65                 }
66         }
67         setorigin(self, o);
68 }
69
70 void Ent_PointParticles_Remove()
71 {
72         if(self.noise)
73                 strunzone(self.noise);
74         self.noise = string_null;
75         if(self.bgmscript)
76                 strunzone(self.bgmscript);
77         self.bgmscript = string_null;
78 }
79
80 void Ent_PointParticles()
81 {
82         float i;
83         vector v;
84         int f = ReadByte();
85         if(f & 2)
86         {
87                 i = ReadCoord(); // density (<0: point, >0: volume)
88                 if(i && !self.impulse && self.cnt) // self.cnt check is so it only happens if the ent already existed
89                         self.just_toggled = 1;
90                 self.impulse = i;
91         }
92         if(f & 4)
93         {
94                 self.origin_x = ReadCoord();
95                 self.origin_y = ReadCoord();
96                 self.origin_z = ReadCoord();
97         }
98         if(f & 1)
99         {
100                 self.modelindex = ReadShort();
101                 if(f & 0x80)
102                 {
103                         if(self.modelindex)
104                         {
105                                 self.mins_x = ReadCoord();
106                                 self.mins_y = ReadCoord();
107                                 self.mins_z = ReadCoord();
108                                 self.maxs_x = ReadCoord();
109                                 self.maxs_y = ReadCoord();
110                                 self.maxs_z = ReadCoord();
111                         }
112                         else
113                         {
114                                 self.mins    = '0 0 0';
115                                 self.maxs_x = ReadCoord();
116                                 self.maxs_y = ReadCoord();
117                                 self.maxs_z = ReadCoord();
118                         }
119                 }
120                 else
121                 {
122                         self.mins = self.maxs = '0 0 0';
123                 }
124
125                 self.cnt = ReadShort(); // effect number
126
127                 if(f & 0x20)
128                 {
129                         self.velocity = decompressShortVector(ReadShort());
130                         self.movedir = decompressShortVector(ReadShort());
131                 }
132                 else
133                 {
134                         self.velocity = self.movedir = '0 0 0';
135                 }
136                 if(f & 0x40)
137                 {
138                         self.waterlevel = ReadShort() / 16.0;
139                         self.count = ReadByte() / 16.0;
140                 }
141                 else
142                 {
143                         self.waterlevel = 0;
144                         self.count = 1;
145                 }
146                 if(self.noise)
147                         strunzone(self.noise);
148                 if(self.bgmscript)
149                         strunzone(self.bgmscript);
150                 self.noise = strzone(ReadString());
151                 if(self.noise != "")
152                 {
153                         self.atten = ReadByte() / 64.0;
154                         self.volume = ReadByte() / 255.0;
155                 }
156                 self.bgmscript = strzone(ReadString());
157                 if(self.bgmscript != "")
158                 {
159                         self.bgmscriptattack = ReadByte() / 64.0;
160                         self.bgmscriptdecay = ReadByte() / 64.0;
161                         self.bgmscriptsustain = ReadByte() / 255.0;
162                         self.bgmscriptrelease = ReadByte() / 64.0;
163                 }
164                 BGMScript_InitEntity(self);
165         }
166
167         if(f & 2)
168         {
169                 self.absolute = (self.impulse >= 0);
170                 if(!self.absolute)
171                 {
172                         v = self.maxs - self.mins;
173                         self.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
174                 }
175         }
176
177         if(f & 0x10)
178                 self.absolute = 2;
179
180         setorigin(self, self.origin);
181         setsize(self, self.mins, self.maxs);
182         self.solid = SOLID_NOT;
183         self.draw = Draw_PointParticles;
184         self.entremove = Ent_PointParticles_Remove;
185 }
186
187 void Draw_Rain()
188 {
189     te_particlerain(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
190 }
191
192 void Draw_Snow()
193 {
194     te_particlesnow(self.origin + self.mins, self.origin + self.maxs, self.velocity, floor(self.count * drawframetime + random()), self.glow_color);
195 }
196
197 void Ent_RainOrSnow()
198 {
199         self.impulse = ReadByte(); // Rain, Snow, or Whatever
200         self.origin_x = ReadCoord();
201         self.origin_y = ReadCoord();
202         self.origin_z = ReadCoord();
203         self.maxs_x = ReadCoord();
204         self.maxs_y = ReadCoord();
205         self.maxs_z = ReadCoord();
206         self.velocity = decompressShortVector(ReadShort());
207         self.count = ReadShort() * 10;
208         self.glow_color = ReadByte(); // color
209
210         self.mins    = -0.5 * self.maxs;
211         self.maxs    =  0.5 * self.maxs;
212         self.origin  = self.origin - self.mins;
213
214         setorigin(self, self.origin);
215         setsize(self, self.mins, self.maxs);
216         self.solid = SOLID_NOT;
217         if(self.impulse)
218                 self.draw = Draw_Rain;
219         else
220                 self.draw = Draw_Snow;
221 }
222
223 void Net_ReadVortexBeamParticle()
224 {
225         vector shotorg, endpos;
226         float charge;
227         shotorg.x = ReadCoord(); shotorg.y = ReadCoord(); shotorg.z = ReadCoord();
228         endpos.x = ReadCoord(); endpos.y = ReadCoord(); endpos.z = ReadCoord();
229         charge = ReadByte() / 255.0;
230
231         pointparticles(particleeffectnum("nex_muzzleflash"), shotorg, normalize(endpos - shotorg) * 1000, 1);
232
233         //draw either the old v2.3 beam or the new beam
234         charge = sqrt(charge); // divide evenly among trail spacing and alpha
235         particles_alphamin = particles_alphamax = particles_fade = charge;
236
237         if (autocvar_cl_particles_oldvortexbeam && (getstati(STAT_ALLOW_OLDVORTEXBEAM) || isdemo()))
238                 WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum("TE_TEI_G3"), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
239         else
240                 WarpZone_TrailParticles_WithMultiplier(world, particleeffectnum("nex_beam"), shotorg, endpos, 1, PARTICLES_USEALPHA | PARTICLES_USEFADE);
241 }