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