]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_crylink.qc
Merge remote branch 'refs/remotes/origin/fruitiex/votesounds'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_crylink.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(CRYLINK, w_crylink, IT_CELLS, 6, WEP_FLAG_NORMAL | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "crylink", "crylink", "Crylink");
3 #else
4 #ifdef SVQC
5 .float gravity;
6
7 .entity realowner;
8
9 .entity queuenext;
10 .entity queueprev;
11
12 // force projectile to explode
13 void W_Crylink_LinkExplode (entity e, entity e2)
14 {
15         float a;
16         a = bound(0, 1 - (time - e.fade_time) * e.fade_rate, 1);
17
18         RadiusDamage (e, e.realowner, cvar("g_balance_crylink_primary_damage") * a, cvar("g_balance_crylink_primary_edgedamage") * a, cvar("g_balance_crylink_primary_radius"), world, cvar("g_balance_crylink_primary_force") * a, e.projectiledeathtype, other);
19
20         if(e.queuenext != e2)
21                 W_Crylink_LinkExplode(e.queuenext, e2);
22         remove (e);
23 }
24
25 // NO bounce protection, as bounces are limited!
26 void W_Crylink_Touch (void)
27 {
28         float finalhit;
29         float f;
30         //PROJECTILE_TOUCH;
31         local entity savenext, saveprev;
32         savenext = self.queuenext;
33         saveprev = self.queueprev;
34         if(WarpZone_Projectile_Touch())
35         {
36                 if(wasfreed(self))
37                 {
38                         savenext.queueprev = saveprev;
39                         saveprev.queuenext = savenext;
40                 }
41                 return;
42         }
43
44         float a;
45         a = bound(0, 1 - (time - self.fade_time) * self.fade_rate, 1);
46
47         finalhit = ((self.cnt <= 0) || (other.takedamage != DAMAGE_NO));
48         if(finalhit)
49                 f = 1;
50         else
51                 f = cvar("g_balance_crylink_primary_bouncedamagefactor");
52         if(a)
53                 f *= a;
54         if (RadiusDamage (self, self.realowner, cvar("g_balance_crylink_primary_damage") * f, cvar("g_balance_crylink_primary_edgedamage") * f, cvar("g_balance_crylink_primary_radius"), world, cvar("g_balance_crylink_primary_force") * f, self.projectiledeathtype, other) || finalhit)
55         {
56                 W_Crylink_LinkExplode(self.queuenext, self);
57                 remove (self);
58                 return;
59         }
60         self.cnt = self.cnt - 1;
61         self.angles = vectoangles(self.velocity);
62         self.owner = world;
63         self.projectiledeathtype |= HITTYPE_BOUNCE;
64         // commented out as it causes a little hitch...
65         //if(proj.cnt == 0)
66         //      CSQCProjectile(proj, TRUE, PROJECTILE_CRYLINK, TRUE);
67 }
68
69 void W_Crylink_Touch2 (void)
70 {
71         float finalhit;
72         float f;
73         //PROJECTILE_TOUCH;
74         local entity savenext, saveprev;
75         savenext = self.queuenext;
76         saveprev = self.queueprev;
77         if(WarpZone_Projectile_Touch())
78         {
79                 if(wasfreed(self))
80                 {
81                         savenext.queueprev = saveprev;
82                         saveprev.queuenext = savenext;
83                 }
84                 return;
85         }
86
87         float a;
88         a = 1 - (time - self.fade_time) * self.fade_rate;
89
90         finalhit = ((self.cnt <= 0) || (other.takedamage != DAMAGE_NO));
91         if(finalhit)
92                 f = 1;
93         else
94                 f = cvar("g_balance_crylink_secondary_bouncedamagefactor");
95         if(a)
96                 f *= a;
97         if (RadiusDamage (self, self.realowner, cvar("g_balance_crylink_secondary_damage") * f, cvar("g_balance_crylink_secondary_edgedamage") * f, cvar("g_balance_crylink_secondary_radius"), world, cvar("g_balance_crylink_secondary_force") * f, self.projectiledeathtype, other) || finalhit)
98         {
99                 W_Crylink_LinkExplode(self.queuenext, self);
100                 remove (self);
101                 return;
102         }
103         self.cnt = self.cnt - 1;
104         self.angles = vectoangles(self.velocity);
105         self.owner = world;
106         self.projectiledeathtype |= HITTYPE_BOUNCE;
107         // commented out as it causes a little hitch...
108         //if(proj.cnt == 0)
109         //      CSQCProjectile(proj, TRUE, PROJECTILE_CRYLINK, TRUE);
110 }
111
112 void W_Crylink_Fadethink (void)
113 {
114         self.queuenext.queueprev = self.queueprev;
115         self.queueprev.queuenext = self.queuenext;
116         remove(self);
117 }
118
119 void W_Crylink_Attack (void)
120 {
121         local float counter, shots;
122         local entity proj, prevproj, firstproj;
123         local vector s;
124         vector forward, right, up;
125
126         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
127                 self.ammo_cells = self.ammo_cells - cvar("g_balance_crylink_primary_ammo");
128
129         W_SetupShot (self, FALSE, 2, "weapons/crylink_fire.wav", (cvar("g_balance_crylink_primary_damage")*cvar("g_balance_crylink_primary_shots")));
130         forward = v_forward;
131         right = v_right;
132         up = v_up;
133
134         shots = cvar("g_balance_crylink_primary_shots");
135         pointparticles(particleeffectnum("crylink_muzzleflash"), w_shotorg, w_shotdir * 1000, shots);
136         while (counter < shots)
137         {
138                 proj = spawn ();
139                 proj.realowner = proj.owner = self;
140                 proj.classname = "spike";
141                 proj.bot_dodge = TRUE;
142                 proj.bot_dodgerating = cvar("g_balance_crylink_primary_damage");
143                 if(counter == 0) { // first projectile, store in firstproj for now
144                         firstproj = proj;
145                 }
146                 else if(counter == shots - 1) { // last projectile, link up with first projectile
147                         prevproj.queuenext = proj;
148                         firstproj.queueprev = proj;
149                         proj.queuenext = firstproj;
150                         proj.queueprev = prevproj;
151                 }
152                 else { // else link up with previous projectile
153                         prevproj.queuenext = proj;
154                         proj.queueprev = prevproj;
155                 }
156
157                 prevproj = proj;
158
159                 proj.movetype = MOVETYPE_BOUNCEMISSILE;
160                 PROJECTILE_MAKETRIGGER(proj);
161                 proj.projectiledeathtype = WEP_CRYLINK;
162                 //proj.gravity = 0.001;
163
164                 setorigin (proj, w_shotorg);
165                 setsize(proj, '0 0 0', '0 0 0');
166
167
168                 s = '0 0 0';
169                 if (counter == 0)
170                         s = '0 0 0';
171                 else
172                 {
173                         makevectors('0 360 0' * (0.75 + (counter - 0.5) / (shots - 1)));
174                         s_y = v_forward_x;
175                         s_z = v_forward_y;
176                 }
177                 s = s * cvar("g_balance_crylink_primary_spread") * g_weaponspreadfactor;
178                 W_SetupProjectileVelocityEx(proj, w_shotdir + right * s_y + up * s_z, v_up, cvar("g_balance_crylink_primary_speed"), 0, 0, 0);
179                 proj.touch = W_Crylink_Touch;
180
181                 proj.think = W_Crylink_Fadethink;
182                 if(counter == 0)
183                 {
184                         proj.fade_time = time + cvar("g_balance_crylink_primary_middle_lifetime");
185                         self.fade_rate = 1 / cvar("g_balance_crylink_primary_middle_fadetime");
186                         proj.nextthink = time + cvar("g_balance_crylink_primary_middle_lifetime") + cvar("g_balance_crylink_primary_middle_fadetime");
187                 }
188                 else if(counter <= 3)
189                 {
190                         proj.fade_time = time + cvar("g_balance_crylink_primary_star_lifetime");
191                         self.fade_rate = 1 / cvar("g_balance_crylink_primary_star_fadetime");
192                         proj.nextthink = time + cvar("g_balance_crylink_primary_star_lifetime") + cvar("g_balance_crylink_primary_star_fadetime");
193                 }
194                 else
195                 {
196                         proj.fade_time = time + cvar("g_balance_crylink_primary_other_lifetime");
197                         self.fade_rate = 1 / cvar("g_balance_crylink_primary_other_fadetime");
198                         proj.nextthink = time + cvar("g_balance_crylink_primary_other_lifetime") + cvar("g_balance_crylink_primary_other_fadetime");
199                 }
200                 proj.cnt = cvar("g_balance_crylink_primary_bounces");
201                 //proj.scale = 1 + 1 * proj.cnt;
202
203                 proj.angles = vectoangles (proj.velocity);
204
205                 //proj.glow_size = 20;
206
207                 proj.flags = FL_PROJECTILE;
208
209                 CSQCProjectile(proj, TRUE, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), TRUE);
210
211                 counter = counter + 1;
212         }
213 }
214
215 void W_Crylink_Attack2 (void)
216 {
217         local float counter, shots;
218         local entity proj, prevproj, firstproj;
219
220         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
221                 self.ammo_cells = self.ammo_cells - cvar("g_balance_crylink_secondary_ammo");
222
223         W_SetupShot (self, FALSE, 2, "weapons/crylink_fire2.wav", (cvar("g_balance_crylink_secondary_damage")*cvar("g_balance_crylink_secondary_shots")));
224
225         shots = cvar("g_balance_crylink_secondary_shots");
226         pointparticles(particleeffectnum("crylink_muzzleflash"), w_shotorg, w_shotdir * 1000, shots);
227         while (counter < shots)
228         {
229                 proj = spawn ();
230                 proj.realowner = proj.owner = self;
231                 proj.classname = "spike";
232                 proj.bot_dodge = TRUE;
233                 proj.bot_dodgerating = cvar("g_balance_crylink_secondary_damage");
234                 if(counter == 0) { // first projectile, store in firstproj for now
235                         firstproj = proj;
236                 }
237                 else if(counter == shots - 1) { // last projectile, link up with first projectile
238                         prevproj.queuenext = proj;
239                         firstproj.queueprev = proj;
240                         proj.queuenext = firstproj;
241                         proj.queueprev = prevproj;
242                 }
243                 else { // else link up with previous projectile
244                         prevproj.queuenext = proj;
245                         proj.queueprev = prevproj;
246                 }
247
248                 prevproj = proj;
249
250                 proj.movetype = MOVETYPE_BOUNCEMISSILE;
251                 PROJECTILE_MAKETRIGGER(proj);
252                 proj.projectiledeathtype = WEP_CRYLINK | HITTYPE_SECONDARY;
253                 //proj.gravity = 0.001;
254
255                 setorigin (proj, w_shotorg);
256                 setsize(proj, '0 0 0', '0 0 0');
257
258                 W_SetupProjectileVelocityEx(proj, (w_shotdir + (((counter + 0.5) / shots) * 2 - 1) * v_right * cvar("g_balance_crylink_secondary_spread") * g_weaponspreadfactor), v_up, cvar("g_balance_crylink_secondary_speed"), 0, 0, 0);
259                 proj.touch = W_Crylink_Touch2;
260                 proj.think = W_Crylink_Fadethink;
261                 if(counter == (shots - 1) / 2)
262                 {
263                         proj.fade_time = time + cvar("g_balance_crylink_secondary_middle_lifetime");
264                         self.fade_rate = 1 / cvar("g_balance_crylink_secondary_middle_fadetime");
265                         proj.nextthink = time + cvar("g_balance_crylink_secondary_middle_lifetime") + cvar("g_balance_crylink_secondary_middle_fadetime");
266                 }
267                 else
268                 {
269                         proj.fade_time = time + cvar("g_balance_crylink_secondary_line_lifetime");
270                         self.fade_rate = 1 / cvar("g_balance_crylink_secondary_line_fadetime");
271                         proj.nextthink = time + cvar("g_balance_crylink_secondary_line_lifetime") + cvar("g_balance_crylink_secondary_line_fadetime");
272                 }
273                 proj.cnt = cvar("g_balance_crylink_secondary_bounces");
274                 //proj.scale = 1 + 1 * proj.cnt;
275
276                 proj.angles = vectoangles (proj.velocity);
277
278                 //proj.glow_size = 20;
279
280                 proj.flags = FL_PROJECTILE;
281
282                 CSQCProjectile(proj, TRUE, (proj.cnt ? PROJECTILE_CRYLINK_BOUNCING : PROJECTILE_CRYLINK), TRUE);
283
284                 counter = counter + 1;
285         }
286 }
287
288 void spawnfunc_weapon_crylink (void)
289 {
290         weapon_defaultspawnfunc(WEP_CRYLINK);
291 }
292
293 float w_crylink(float req)
294 {
295         if (req == WR_AIM)
296         {
297                 if (random() > 0.15)
298                         self.BUTTON_ATCK = bot_aim(cvar("g_balance_crylink_primary_speed"), 0, cvar("g_balance_crylink_primary_middle_lifetime"), FALSE);
299                 else
300                         self.BUTTON_ATCK2 = bot_aim(cvar("g_balance_crylink_secondary_speed"), 0, cvar("g_balance_crylink_secondary_middle_lifetime"), FALSE);
301         }
302         else if (req == WR_THINK)
303         {
304                 if (self.BUTTON_ATCK)
305                 if (weapon_prepareattack(0, cvar("g_balance_crylink_primary_refire")))
306                 {
307                         W_Crylink_Attack();
308                         weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_crylink_primary_animtime"), w_ready);
309                 }
310                 if (self.BUTTON_ATCK2 && cvar("g_balance_crylink_secondary"))
311                 if (weapon_prepareattack(1, cvar("g_balance_crylink_secondary_refire")))
312                 {
313                         W_Crylink_Attack2();
314                         weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_crylink_secondary_animtime"), w_ready);
315                 }
316         }
317         else if (req == WR_PRECACHE)
318         {
319                 precache_model ("models/weapons/g_crylink.md3");
320                 precache_model ("models/weapons/v_crylink.md3");
321                 precache_model ("models/weapons/h_crylink.iqm");
322                 precache_sound ("weapons/crylink_fire.wav");
323                 precache_sound ("weapons/crylink_fire2.wav");
324         }
325         else if (req == WR_SETUP)
326                 weapon_setup(WEP_CRYLINK);
327         else if (req == WR_CHECKAMMO1)
328                 return self.ammo_cells >= cvar("g_balance_crylink_primary_ammo");
329         else if (req == WR_CHECKAMMO2)
330                 return self.ammo_cells >= cvar("g_balance_crylink_secondary_ammo");
331         return TRUE;
332 };
333 #endif
334 #ifdef CSQC
335 float w_crylink(float req)
336 {
337         if(req == WR_IMPACTEFFECT)
338         {
339                 vector org2;
340                 org2 = w_org + w_backoff * 2;
341                 if(w_deathtype & HITTYPE_SECONDARY)
342                 {
343                         pointparticles(particleeffectnum("crylink_impact"), org2, '0 0 0', 1);
344                         if(!w_issilent)
345                                 sound(self, CHAN_PROJECTILE, "weapons/crylink_impact2.wav", VOL_BASE, ATTN_NORM);
346                 }
347                 else
348                 {
349                         pointparticles(particleeffectnum("crylink_impactbig"), org2, '0 0 0', 1);
350                         if(!w_issilent)
351                                 sound(self, CHAN_PROJECTILE, "weapons/crylink_impact.wav", VOL_BASE, ATTN_NORM);
352                 }
353         }
354         else if(req == WR_PRECACHE)
355         {
356                 precache_sound("weapons/crylink_impact2.wav");
357                 precache_sound("weapons/crylink_impact.wav");
358         }
359         else if (req == WR_SUICIDEMESSAGE)
360         {
361                 w_deathtypestring = "%s succeeded at self-destructing themself with the Crylink";
362         }
363         else if (req == WR_KILLMESSAGE)
364         {
365                 if(w_deathtype & HITTYPE_BOUNCE)
366                         w_deathtypestring = "%s could not hide from %s's Crylink"; // unchecked: SPLASH (SECONDARY can't be)
367                 else if(w_deathtype & HITTYPE_SPLASH)
368                         w_deathtypestring = "%s was too close to %s's Crylink"; // unchecked: SECONDARY
369                 else
370                         w_deathtypestring = "%s took a close look at %s's Crylink"; // unchecked: SECONDARY
371         }
372         return TRUE;
373 }
374 #endif
375 #endif