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