Merge commit 'origin/master' into divVerent/tag_seeker
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / damage.qc
1 .float silent;
2
3 void Ent_DamageInfo(float isNew)
4 {
5         float hittype, dmg, rad, edge, thisdmg, forcemul;
6         float issilent;
7         vector force, org, thisforce;
8         entity oldself;
9
10         oldself = self;
11
12         hittype = ReadShort();
13
14         issilent = (hittype & 0x8000);
15         hittype = (hittype & 0x7FFF);
16
17         org_x = ReadCoord();
18         org_y = ReadCoord();
19         org_z = ReadCoord();
20
21         dmg = ReadByte();
22         rad = ReadByte();
23         edge = ReadByte();
24         force = decompressShortVector(ReadShort());
25
26         if not(isNew)
27                 return;
28
29         if(rad < 0)
30         {
31                 rad = -rad;
32                 forcemul = -1;
33         }
34         else
35                 forcemul = 1;
36         
37         for(self = findradius(org, rad); self; self = self.chain)
38         {
39                 if(rad)
40                 {
41                         thisdmg = vlen(self.origin - org) / rad;
42                         if(thisdmg >= 1)
43                                 continue;
44                         if(dmg)
45                         {
46                                 thisdmg = dmg + (edge - dmg) * thisdmg;
47                                 thisforce = forcemul * vlen(force) * (thisdmg / dmg) * normalize(self.origin - org);
48                         }
49                         else
50                         {
51                                 thisdmg = 0;
52                                 thisforce = forcemul * vlen(force) * normalize(self.origin - org);
53                         }
54                 }
55                 else
56                 {
57                         thisdmg = dmg;
58                         thisforce = forcemul * force;
59                 }
60
61                 //print("check ", ftos(num_for_edict(self)), " ", self.classname, "\n");
62                 //print(ftos(self.damageforcescale), "\n");
63                 //print(vtos(thisforce), "\n");
64                 if(self.damageforcescale)
65                         if(vlen(thisforce))
66                         {
67                                 self.move_velocity = self.move_velocity + self.damageforcescale * thisforce;
68                                 self.move_flags &~= FL_ONGROUND;
69                                 //print("pushed ", ftos(num_for_edict(self)), " loose\n");
70                         }
71
72                 if(issilent)
73                         self.silent = 1;
74
75                 if(self.event_damage)
76                         self.event_damage(thisdmg, hittype, org, thisforce);
77         }
78
79         self = oldself;
80
81         // TODO spawn particle effects and sounds based on hittype
82         
83         if(!DEATH_ISSPECIAL(hittype))
84         {
85                 float hitwep, secondary, bounce, headshot;
86                 vector org2, backoff;
87                 float r;
88
89                 hitwep = DEATH_WEAPONOFWEAPONDEATH(hittype);
90                 secondary = hittype & HITTYPE_SECONDARY;
91                 bounce = hittype & HITTYPE_BOUNCE;
92                 headshot = hittype & HITTYPE_HEADSHOT;
93                 r = prandom();
94
95                 traceline(org - normalize(force) * 16, org + normalize(force) * 16, MOVE_NOMONSTERS, world);
96                 if(trace_fraction < 1 && hitwep != WEP_NEX && hitwep != WEP_MINSTANEX)
97                         backoff = trace_plane_normal;
98                 else
99                         backoff = -1 * normalize(force);
100
101                 setorigin(self, org + backoff * 2); // for sound() calls
102
103                 switch(hitwep)
104                 {
105                         case WEP_LASER:
106                                 org2 = org + backoff * 6;
107                                 pointparticles(particleeffectnum("laser_impact"), org2, backoff * 1000, 1);
108                                 if(!issilent)
109                                         sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
110                                 break;
111                         case WEP_SHOTGUN:
112                                 org2 = org + backoff * 2;
113                                 pointparticles(particleeffectnum("shotgun_impact"), org2, backoff * 1000, 1);
114                                 if(!issilent)
115                                 {
116                                         if(r < 0.05)
117                                                 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
118                                         else if(r < 0.1)
119                                                 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
120                                         else if(r < 0.2)
121                                                 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
122                                 }
123                                 break;
124                         case WEP_UZI:
125                                 org2 = org + backoff * 2;
126                                 pointparticles(particleeffectnum("machinegun_impact"), org2, backoff * 1000, 1);
127                                 if(!issilent)
128                                         if(r < 0.05)
129                                                 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
130                                         else if(r < 0.1)
131                                                 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
132                                         else if(r < 0.2)
133                                                 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
134                                 break;
135                         case WEP_GRENADE_LAUNCHER:
136                                 org2 = org + backoff * 12;
137                                 pointparticles(particleeffectnum("grenade_explode"), org2, '0 0 0', 1);
138                                 if(!issilent)
139                                         sound(self, CHAN_PROJECTILE, "weapons/grenade_impact.wav", VOL_BASE, ATTN_NORM);
140                                 break;
141                         case WEP_ELECTRO:
142                                 org2 = org + backoff * 6;
143                                 if(secondary)
144                                 {
145                                         pointparticles(particleeffectnum("electro_ballexplode"), org2, '0 0 0', 1);
146                                         if(!issilent)
147                                                 sound(self, CHAN_PROJECTILE, "weapons/electro_impact.wav", VOL_BASE, ATTN_NORM);
148                                 }
149                                 else
150                                 {
151                                         if(bounce)
152                                         {
153                                                 // this is sent as "primary bounce" to distinguish it from secondary bounced balls
154                                                 pointparticles(particleeffectnum("electro_combo"), org2, '0 0 0', 1);
155                                                 if(!issilent)
156                                                         sound(self, CHAN_PROJECTILE, "weapons/electro_impact_combo.wav", VOL_BASE, ATTN_NORM);
157                                         }
158                                         else
159                                         {
160                                                 pointparticles(particleeffectnum("electro_impact"), org2, '0 0 0', 1);
161                                                 if(!issilent)
162                                                         sound(self, CHAN_PROJECTILE, "weapons/electro_impact.wav", VOL_BASE, ATTN_NORM);
163                                         }
164                                 }
165                                 break;
166                         case WEP_CRYLINK:
167                                 org2 = org + backoff * 2;
168                                 if(secondary)
169                                 {
170                                         pointparticles(particleeffectnum("crylink_impact"), org2, '0 0 0', 1);
171                                         if(!issilent)
172                                                 sound(self, CHAN_PROJECTILE, "weapons/crylink_impact2.wav", VOL_BASE, ATTN_NORM);
173                                 }
174                                 else
175                                 {
176                                         pointparticles(particleeffectnum("crylink_impactbig"), org2, '0 0 0', 1);
177                                         if(!issilent)
178                                                 sound(self, CHAN_PROJECTILE, "weapons/crylink_impact.wav", VOL_BASE, ATTN_NORM);
179                                 }
180                                 break;
181                         case WEP_NEX:
182                                 org2 = org + backoff * 6;
183                                 pointparticles(particleeffectnum("nex_impact"), org2, '0 0 0', 1);
184                                 if(!issilent)
185                                         sound(self, CHAN_PROJECTILE, "weapons/neximpact.wav", VOL_BASE, ATTN_NORM);
186                                 break;
187                         case WEP_HAGAR:
188                                 org2 = org + backoff * 6;
189                                 pointparticles(particleeffectnum("hagar_explode"), org2, '0 0 0', 1);
190                                 if(!issilent)
191                                 {
192                                         if (r<0.15)
193                                                 sound(self, CHAN_PROJECTILE, "weapons/hagexp1.wav", VOL_BASE, ATTN_NORM);
194                                         else if (r<0.7)
195                                                 sound(self, CHAN_PROJECTILE, "weapons/hagexp2.wav", VOL_BASE, ATTN_NORM);
196                                         else
197                                                 sound(self, CHAN_PROJECTILE, "weapons/hagexp3.wav", VOL_BASE, ATTN_NORM);
198                                 }
199                                 break;
200                         case WEP_ROCKET_LAUNCHER:
201                                 org2 = org + backoff * 12;
202                                 pointparticles(particleeffectnum("rocket_explode"), org2, '0 0 0', 1);
203                                 if(!issilent)
204                                         sound(self, CHAN_PROJECTILE, "weapons/rocket_impact.wav", VOL_BASE, ATTN_NORM);
205                                 break;
206                         case WEP_PORTO:
207                                 print("Since when does Porto send DamageInfo?\n");
208                                 break;
209                         case WEP_MINSTANEX:
210                                 org2 = org + backoff * 6;
211                                 pointparticles(particleeffectnum("nex_impact"), org2, '0 0 0', 1);
212                                 if(!issilent)
213                                         sound(self, CHAN_PROJECTILE, "weapons/neximpact.wav", VOL_BASE, ATTN_NORM);
214                                 break;
215                         case WEP_HOOK:
216                                 org2 = org + backoff * 2;
217                                 pointparticles(particleeffectnum("hookbomb_explode"), org2, '0 0 0', 1);
218                                 if(!issilent)
219                                         sound(self, CHAN_PROJECTILE, "weapons/hookbomb_impact.wav", VOL_BASE, ATTN_NORM);
220                                 break;
221                         case WEP_SEEKER:
222                                 org2 = org + backoff * 6;
223                                 if(secondary)
224                                 {
225                                         pointparticles(particleeffectnum("flac_explode"), org2, '0 0 0', 1);
226                                         if(!issilent)
227                                         {
228                                                 if (r<0.15)
229                                                         sound(self, CHAN_PROJECTILE, "weapons/flacexp1.wav", 1, ATTN_NORM);
230                                                 else if (r<0.7)
231                                                         sound(self, CHAN_PROJECTILE, "weapons/flacexp2.wav", 1, ATTN_NORM);
232                                                 else
233                                                         sound(self, CHAN_PROJECTILE, "weapons/flacexp3.wav", 1, ATTN_NORM);
234                                         }
235                                 }
236                                 else
237                                 {
238                                         if(bounce)
239                                         {
240                                                 pointparticles(particleeffectnum("hagar_explode"), org2, '0 0 0', 1);
241                                                 if(!issilent)
242                                                 {
243                                                         if (r<0.15)
244                                                                 sound(self, CHAN_PROJECTILE, "weapons/tagexp1.wav", 1, ATTN_NORM);
245                                                         else if (r<0.7)
246                                                                 sound(self, CHAN_PROJECTILE, "weapons/tagexp2.wav", 1, ATTN_NORM);
247                                                         else
248                                                                 sound(self, CHAN_PROJECTILE, "weapons/tagexp3.wav", 1, ATTN_NORM);
249                                                 }
250                                         }
251                                         else if(headshot)
252                                         {
253                                                 if(!issilent)
254                                                         sound(self, CHAN_PROJECTILE, "weapons/tag_impact.wav", 1, ATTN_NORM);
255                                         }
256                                         else
257                                         {
258                                                 pointparticles(particleeffectnum("hagar_explode"), org2, '0 0 0', 1);
259                                                 if(!issilent)
260                                                 {
261                                                         if (r<0.15)
262                                                                 sound(self, CHAN_PROJECTILE, "weapons/seekerexp1.wav", 1, ATTN_NORM);
263                                                         else if (r<0.7)
264                                                                 sound(self, CHAN_PROJECTILE, "weapons/seekerexp2.wav", 1, ATTN_NORM);
265                                                         else
266                                                                 sound(self, CHAN_PROJECTILE, "weapons/seekerexp3.wav", 1, ATTN_NORM);
267                                                 }
268                                         }
269                                 }
270                                 break;
271                         case WEP_HLAC:
272                                 org2 = org + backoff * 6;
273                                 pointparticles(particleeffectnum("laser_impact"), org2, backoff * 1000, 1);
274                                 if(!issilent)
275                                         sound(self, CHAN_PROJECTILE, "weapons/laserimpact.wav", VOL_BASE, ATTN_NORM);
276                                 break;
277                         case WEP_CAMPINGRIFLE:
278                                 org2 = org + backoff * 2;
279                                 pointparticles(particleeffectnum("machinegun_impact"), org2, backoff * 1000, 1);
280                                 if(!issilent)
281                                 {
282                                         if(r < 0.2)
283                                                 sound(self, CHAN_PROJECTILE, "weapons/ric1.wav", VOL_BASE, ATTN_NORM);
284                                         else if(r < 0.4)
285                                                 sound(self, CHAN_PROJECTILE, "weapons/ric2.wav", VOL_BASE, ATTN_NORM);
286                                         else if(r < 0.5)
287                                                 sound(self, CHAN_PROJECTILE, "weapons/ric3.wav", VOL_BASE, ATTN_NORM);
288                                 }
289                                 break;
290                         case WEP_TUBA:
291                                 break;
292                         case WEP_FIREBALL:
293                                 if(secondary)
294                                 {
295                                         // firemine goes out silently
296                                 }
297                                 else
298                                 {
299                                         org2 = org + backoff * 16;
300                                         pointparticles(particleeffectnum("fireball_explode"), org2, '0 0 0', 1);
301                                         if(!issilent)
302                                                 sound(self, CHAN_PROJECTILE, "weapons/fireball_impact2.wav", VOL_BASE, ATTN_NORM * 0.25); // long range boom
303                                 }
304                                 break;
305                         default:
306                                 dprint("Unhandled damage of weapon ", ftos(hitwep), "\n");
307                                 break;
308                 }
309         }
310 }
311
312 void DamageInfo_Precache()
313 {
314         precache_sound("weapons/crylink_impact2.wav");
315         precache_sound("weapons/crylink_impact.wav");
316         precache_sound("weapons/electro_impact.wav");
317         precache_sound("weapons/electro_impact_combo.wav");
318         precache_sound("weapons/flacexp1.wav");
319         precache_sound("weapons/flacexp2.wav");
320         precache_sound("weapons/flacexp3.wav");
321         precache_sound("weapons/grenade_impact.wav");
322         precache_sound("weapons/hagexp1.wav");
323         precache_sound("weapons/hagexp2.wav");
324         precache_sound("weapons/hagexp3.wav");
325         precache_sound("weapons/flacexp1.wav");
326         precache_sound("weapons/flacexp2.wav");
327         precache_sound("weapons/flacexp3.wav");
328         precache_sound("weapons/hookbomb_impact.wav");
329         precache_sound("weapons/laserimpact.wav");
330         precache_sound("weapons/neximpact.wav");
331         precache_sound("weapons/ric1.wav");
332         precache_sound("weapons/ric2.wav");
333         precache_sound("weapons/ric3.wav");
334         precache_sound("weapons/rocket_impact.wav");
335         precache_sound("weapons/fireball_impact.wav");
336         precache_sound("weapons/fireball_impact2.wav");
337         precache_sound("weapons/seekerexp1.wav");
338         precache_sound("weapons/seekerexp2.wav");
339         precache_sound("weapons/seekerexp3.wav");
340         precache_sound("weapons/tagexp1.wav");
341         precache_sound("weapons/tagexp2.wav");
342         precache_sound("weapons/tagexp3.wav");
343         precache_sound("weapons/tag_impact.wav");
344 }