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