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