]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/w_seeker.qc
support for more weapon sounds
[divverent/nexuiz.git] / data / qcsrc / server / w_seeker.qc
1 //.float speed; = switchweapon\r
2 //.float proxytime; = autoswitch\r
3 //.float tl; = wait\r
4 \r
5 void Seeker_Missile_Explode ()\r
6 {\r
7         vector  org2;\r
8         float b;\r
9         org2 = findbetterlocation (self.origin, 12);\r
10         te_explosion (org2);\r
11 \r
12         b = crandom();\r
13         if (b<-0.7)\r
14                 sound (self, CHAN_PROJECTILE, "weapons/seekerexp1.wav", 1, ATTN_NORM);\r
15         else if (b<0.4)\r
16                 sound (self, CHAN_PROJECTILE, "weapons/seekerexp2.wav", 1, ATTN_NORM);\r
17         else if (b<1)\r
18                 sound (self, CHAN_PROJECTILE, "weapons/seekerexp3.wav", 1, ATTN_NORM);\r
19 \r
20         self.event_damage = SUB_Null;\r
21         RadiusDamage (self, self.owner, cvar("g_balance_seeker_missile_damage"), cvar("g_balance_seeker_missile_edgedamage"), cvar("g_balance_seeker_missile_radius"), world, cvar("g_balance_seeker_missile_force"), self.projectiledeathtype, other);\r
22 \r
23         remove (self);\r
24 }\r
25 \r
26 void Seeker_Missile_Touch()\r
27 {\r
28         PROJECTILE_TOUCH;\r
29 \r
30         Seeker_Missile_Explode();\r
31 }\r
32 \r
33 void Seeker_Missile_Think()\r
34 {\r
35         entity e;\r
36         vector desireddir, olddir, newdir;\r
37         float turnrate;\r
38         float dist;\r
39 \r
40         if (time > self.cnt)\r
41                 Seeker_Missile_Explode();\r
42 \r
43         if (!self.switchweapon)\r
44                 self.switchweapon = cvar("g_balance_seeker_missile_speed");\r
45 \r
46         if ((self.switchweapon < cvar("g_balance_seeker_missile_speed_max")) && cvar("g_balance_seeker_missile_speed_accel"))\r
47                 self.switchweapon = self.switchweapon * cvar("g_balance_seeker_missile_accel");\r
48 \r
49         if (self.switchweapon > cvar("g_balance_seeker_missile_speed_max"))\r
50                 self.switchweapon = self.switchweapon * cvar("g_balance_seeker_missile_decel");\r
51 \r
52         if (self.enemy != world)\r
53                 if (self.enemy.takedamage != DAMAGE_AIM || self.enemy.deadflag != DEAD_NO)\r
54                         self.enemy = world;\r
55 \r
56         if (self.enemy != world)\r
57         {\r
58                 e               = self.enemy;\r
59                 turnrate        = cvar("g_balance_seeker_missile_turnrate");                // how fast to turn\r
60                 desireddir      = normalize(e.origin - self.origin);\r
61                 olddir          = normalize(self.velocity);                                         // get my current direction\r
62                 dist            = vlen(e.origin - self.origin);\r
63 \r
64                 // Do evasive maneuvers for world objects? ( this should be a cpu hog. :P )\r
65                 if (cvar("g_balance_seeker_missile_smart") && (dist > cvar("g_balance_seeker_missile_smart_mindist")))\r
66                 {\r
67                         // Is it a better idea (shorter distance) to trace to the target itself?\r
68                         if ( vlen(self.origin + olddir * self.wait) < dist)\r
69                                 traceline(self.origin, self.origin + olddir * self.wait, FALSE, self);\r
70                         else\r
71                                 traceline(self.origin, self.enemy.origin, FALSE, self);\r
72 \r
73                         // Setup adaptive tracelength\r
74                         self.wait = vlen(self.origin - trace_endpos);\r
75                         if (self.wait < cvar("g_balance_seeker_missile_smart_trace_min")) self.wait = cvar("g_balance_seeker_missile_smart_trace_min");\r
76                         if (self.wait > cvar("g_balance_seeker_missile_smart_trace_max")) self.wait = cvar("g_balance_seeker_missile_smart_trace_max");\r
77 \r
78                         // Calc how important it is that we turn and add this to the desierd (enemy) dir.\r
79                         desireddir  = normalize(((trace_plane_normal * (1 - trace_fraction)) + (desireddir * trace_fraction)) * 0.5);\r
80                 }\r
81 \r
82                 //newdir = normalize((olddir + desireddir * turnrate) * 0.5);// take the average of the 2 directions; not the best method but simple & easy\r
83                 newdir = normalize(olddir + desireddir * turnrate);// take the average of the 2 directions; not the best method but simple & easy\r
84 \r
85                 self.velocity = newdir * self.switchweapon;                                         // make me fly in the new direction at my flight speed\r
86         }\r
87 \r
88         // Proxy\r
89         if (cvar("g_balance_seeker_missile_proxy"))\r
90         {\r
91                 if ( dist <= cvar("g_balance_seeker_missile_proxy_maxrange"))\r
92                 {\r
93                         if (self.autoswitch == 0)\r
94                         {\r
95                                 self.autoswitch = time + cvar("g_balance_seeker_missile_proxy_delay");\r
96                         }\r
97                         else\r
98                         {\r
99                                 if (self.autoswitch <= time)\r
100                                 {\r
101                                         Seeker_Missile_Explode();\r
102                                         self.autoswitch = 0;\r
103                                 }\r
104                         }\r
105                 }\r
106                 else\r
107                 {\r
108                         if (self.autoswitch != 0)\r
109                                 self.autoswitch = 0;\r
110                 }\r
111         }\r
112         ///////////////\r
113 \r
114         if (self.enemy.deadflag != DEAD_NO)\r
115         {\r
116                 self.enemy = world;\r
117                 self.cnt = time + 1 + (random() * 4);\r
118                 self.nextthink = self.cnt;\r
119                 return;\r
120         }\r
121 \r
122         self.angles = vectoangles(self.velocity);                       // turn model in the new flight direction\r
123         self.nextthink = time + 0.05;\r
124 \r
125 }\r
126 \r
127 \r
128 \r
129 void Seeker_Missile_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
130 {\r
131         float d;\r
132         d = damage;\r
133 \r
134         if (self.owner == attacker)\r
135                 d = d * 0.25;\r
136 \r
137         self.health = self.health - d;\r
138 \r
139         if (self.health <= 0)\r
140                 W_PrepareExplosionByDamage(attacker, Seeker_Missile_Explode);\r
141 }\r
142 \r
143 #define EF_ROCKET                               16777216\r
144 void Seeker_Missile_Animate()\r
145 {\r
146         self.frame = self.frame +1;\r
147         self.nextthink = time + 0.05;\r
148 \r
149         if (self.enemy != world)\r
150                 if (self.enemy.takedamage != DAMAGE_AIM || self.enemy.deadflag != DEAD_NO)\r
151                         self.enemy = world;\r
152 \r
153         if(self.frame == 5)\r
154         {\r
155                 self.think           = Seeker_Missile_Think;\r
156                 self.nextthink       = time + cvar("g_balance_seeker_missile_activate_delay");\r
157                 self.effects         = EF_LOWPRECISION | EF_NOSHADOW | EF_ROCKET;\r
158 \r
159                 if (cvar("g_balance_seeker_guided_proxy"))\r
160                         self.movetype    = MOVETYPE_BOUNCEMISSILE;\r
161                 else\r
162                         self.movetype    = MOVETYPE_FLYMISSILE;\r
163         }\r
164 }\r
165 \r
166 void Seeker_Fire_Missile(vector f_org)\r
167 {\r
168         local entity missile;\r
169 \r
170         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)\r
171                 self.ammo_rockets = self.ammo_rockets - cvar("g_balance_seeker_missile_ammo");\r
172 \r
173         makevectors(self.v_angle);\r
174         W_SetupShot (self, f_org, FALSE, 2, "weapons/seeker_fire.wav");\r
175         pointparticles(particleeffectnum("seeker_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);\r
176 \r
177         //self.detornator         = FALSE;\r
178 \r
179         missile                 = spawn();\r
180         missile.owner           = self;\r
181         missile.classname       = "seeker_missile";\r
182         missile.bot_dodge       = TRUE;\r
183         missile.bot_dodgerating = cvar("g_balance_seeker_missile_damage");\r
184 \r
185         missile.think           = Seeker_Missile_Animate;\r
186 \r
187         //if (!cvar("g_balance_seeker_missile_proxy"))\r
188         missile.touch           = Seeker_Missile_Touch;\r
189 \r
190         missile.event_damage    = Seeker_Missile_Damage;\r
191         missile.nextthink       = time + 0.2;// + cvar("g_balance_seeker_missile_activate_delay");\r
192         missile.cnt             = time + cvar("g_balance_seeker_missile_lifetime");\r
193         missile.enemy           = self.enemy;\r
194         missile.switchweapon           = cvar("g_balance_seeker_missile_speed");\r
195         missile.effects         = EF_LOWPRECISION | EF_NOSHADOW;// | EF_ROCKET;\r
196         missile.solid           = SOLID_BBOX;\r
197         missile.scale           = 2;\r
198         missile.takedamage          = DAMAGE_YES;\r
199         missile.damageforcescale    = 4;\r
200         missile.health              = 5;\r
201         missile.projectiledeathtype = WEP_SEEKER;\r
202 \r
203         setorigin (missile, w_shotorg);\r
204         setmodel  (missile, "models/tagrocket.md3");\r
205         setsize (missile, '-2 -2 -2', '2 2 2');\r
206 \r
207 \r
208         missile.movetype    = MOVETYPE_FLYMISSILE;// MOVETYPE_TOSS;\r
209 \r
210         missile.flags       = FL_PROJECTILE;\r
211 \r
212         missile.velocity    = (w_shotdir + '0 0 0.45') * missile.switchweapon;\r
213         W_SetupProjectileVelocity(missile);\r
214 \r
215         missile.switchweapon = vlen(missile.velocity);\r
216         missile.angles = vectoangles (missile.velocity);\r
217 \r
218 }\r
219 \r
220 void Seeker_Vollycontroler_Think()\r
221 {\r
222         float c;\r
223         entity oldself,oldenemy;\r
224         self.cnt = self.cnt - 1;\r
225 \r
226         if ((self.owner.ammo_rockets < cvar("g_balance_seeker_missile_ammo")) || (self.cnt <= -1) || (self.owner.deadflag != DEAD_NO))\r
227         {\r
228                 remove(self);\r
229                 return;\r
230         }\r
231 \r
232         self.nextthink = time + cvar("g_balance_seeker_missile_delay");\r
233 \r
234         oldself = self;\r
235         self = self.owner;\r
236 \r
237         oldenemy = self.enemy;\r
238         self.enemy = oldself.enemy;\r
239 \r
240         c = mod(oldself.cnt, 4);\r
241         switch(c)\r
242         {\r
243                 case 0:\r
244                         Seeker_Fire_Missile('37.5 17 -22');\r
245                         break;\r
246                 case 1:\r
247                         Seeker_Fire_Missile('37.5 9.5 -22');\r
248                         break;\r
249                 case 2:\r
250                         Seeker_Fire_Missile('40 17 -29');\r
251                         break;\r
252                 case 3:\r
253                 default:\r
254                         Seeker_Fire_Missile('40 9.5 -29');\r
255                         break;\r
256         }\r
257 \r
258         self.enemy = oldenemy;\r
259         self = oldself;\r
260 }\r
261 \r
262 void Seeker_Tag_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
263 {\r
264         self.health = self.health - damage;\r
265         if (self.health <= 0)\r
266                 self.think ();\r
267 }\r
268 \r
269 void Seeker_Tag_Explode ()\r
270 {\r
271         vector  org2;\r
272         float b;\r
273 \r
274         //if(other==self.owner)\r
275         //    return;\r
276 \r
277         org2 = findbetterlocation (self.origin, 12);\r
278         te_explosion (org2);\r
279 \r
280         b = crandom();\r
281         if (b<-0.7)\r
282                 sound (self, CHAN_PROJECTILE, "weapons/tagexp1.wav", 1, ATTN_NORM);\r
283         else if (b<0.4)\r
284                 sound (self, CHAN_PROJECTILE, "weapons/tagexp2.wav", 1, ATTN_NORM);\r
285         else if (b<1)\r
286                 sound (self, CHAN_PROJECTILE, "weapons/tagexp3.wav", 1, ATTN_NORM);\r
287 \r
288         remove (self);\r
289 }\r
290 \r
291 void Seeker_Tag_Think()\r
292 {\r
293         remove(self);\r
294         return;\r
295 }\r
296 \r
297 void Seeker_Tag_Touch()\r
298 {\r
299         vector dir;\r
300         vector org2;\r
301 \r
302         PROJECTILE_TOUCH_NOSOUND;\r
303 \r
304         dir     = normalize (self.owner.origin - self.origin);\r
305         org2    = findbetterlocation (self.origin, 8);\r
306 \r
307         te_knightspike(org2);\r
308 \r
309         self.event_damage = SUB_Null;\r
310         sound (self, CHAN_PROJECTILE, "weapons/tagimpact.wav", 1, ATTN_NORM);\r
311 \r
312         if (other.takedamage == DAMAGE_AIM && other.deadflag == DEAD_NO)\r
313         {\r
314                 entity e;\r
315                 e           = spawn();\r
316                 e.cnt       = cvar("g_balance_seeker_missile_count");\r
317                 e.owner     = self.owner;\r
318                 e.enemy     = other;\r
319                 e.think     = Seeker_Vollycontroler_Think;\r
320                 e.nextthink = time;\r
321 \r
322                 //sprint(self.owner, "^1Target lock ^3[^7 ",other.netname, " ^3]^1 acquired - autofire activated.\n");\r
323                 //sprint(other,"^1You are targeted!\n");\r
324 \r
325                 // stuffcmd(other,"play2 weapons/zany-alarm4.ogg\n");\r
326                 // stuffcmd(self.owner, "play2 weapons/zany-lock4.ogg\n");\r
327         }\r
328 \r
329         remove(self);\r
330         return;\r
331 }\r
332 \r
333 \r
334 \r
335 void Seeker_Fire_Tag()\r
336 {\r
337         local entity missile;\r
338         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)\r
339                 self.ammo_rockets = self.ammo_rockets - cvar("g_balance_seeker_tag_ammo");\r
340 \r
341         W_SetupShot (self, '56 13 -15', FALSE, 2, "weapons/tag_fire.wav");\r
342 \r
343         missile                 = spawn();\r
344         missile.owner           = self;\r
345         missile.classname       = "seeker_tag";\r
346         missile.bot_dodge       = TRUE;\r
347         missile.bot_dodgerating = 50;\r
348         missile.touch           = Seeker_Tag_Touch;\r
349         missile.think           = Seeker_Tag_Think;\r
350         missile.nextthink       = time + 15;\r
351         missile.movetype        = MOVETYPE_FLY;\r
352         missile.solid           = SOLID_BBOX;\r
353         missile.owner           = self;\r
354 \r
355         missile.takedamage       = DAMAGE_YES;\r
356         missile.event_damage    = Seeker_Tag_Explode;\r
357         missile.health          = 5;\r
358 \r
359         setmodel (missile, "models/laser.mdl"); // TODO make this seeker specific\r
360         setorigin (missile, w_shotorg);\r
361         setsize (missile, '0 0 0', '0 0 0');\r
362 \r
363         missile.effects     = EF_FULLBRIGHT | EF_NOSHADOW | EF_LOWPRECISION;\r
364         missile.modelflags  = MF_TRACER3;\r
365         sound (missile, CHAN_PROJECTILE, "weapons/tag_rocket_fly.wav", VOL_BASE, ATTN_NORM);\r
366         missile.flags       = FL_PROJECTILE;\r
367 \r
368         missile.velocity    = w_shotdir  * cvar("g_balance_seeker_tag_speed");\r
369         missile.movetype    = MOVETYPE_BOUNCEMISSILE;\r
370         W_SetupProjectileVelocity(missile);\r
371         missile.angles = vectoangles (missile.velocity);\r
372 }\r
373 \r
374 \r
375 void Seeker_Flac_Explode ()\r
376 {\r
377         vector  org2;\r
378         float b;\r
379         org2 = findbetterlocation (self.origin, 12);\r
380         te_explosion (org2);\r
381 \r
382         b = crandom();\r
383         if (b<-0.7)\r
384                 sound (self, CHAN_PROJECTILE, "weapons/flacexp1.wav", 1, ATTN_NORM);\r
385         else if (b<0.4)\r
386                 sound (self, CHAN_PROJECTILE, "weapons/flacexp2.wav", 1, ATTN_NORM);\r
387         else if (b<1)\r
388                 sound (self, CHAN_PROJECTILE, "weapons/flacexp3.wav", 1, ATTN_NORM);\r
389 \r
390         self.event_damage = SUB_Null;\r
391 \r
392         RadiusDamage (self, self.owner, cvar("g_balance_seeker_flac_damage"), cvar("g_balance_seeker_flac_edgedamage"), cvar("g_balance_seeker_flac_radius"), world, cvar("g_balance_seeker_flac_force"), self.projectiledeathtype, other);\r
393 \r
394         remove (self);\r
395 }\r
396 \r
397 void Seeker_Flac_Touch()\r
398 {\r
399         PROJECTILE_TOUCH;\r
400 \r
401         Seeker_Flac_Explode();\r
402 }\r
403 \r
404 void Seeker_Fire_Flac()\r
405 {\r
406         local entity missile;\r
407         vector f_org;\r
408         float c;\r
409 \r
410         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)\r
411                 self.ammo_rockets = self.ammo_rockets - cvar("g_balance_seeker_flac_ammo");\r
412 \r
413         c = mod(self.bulletcounter, 4);\r
414         switch(c)\r
415         {\r
416                 case 1:\r
417                         f_org = '37.5 17 -22';\r
418                         break;\r
419                 case 2:\r
420                         f_org = '37.5 9.5 -22';\r
421                         break;\r
422                 case 3:\r
423                         f_org = '40 17 -29';\r
424                         break;\r
425                 case 0:\r
426                 default:\r
427                         f_org = '40 9.5 -29';\r
428                         break;\r
429         }\r
430         W_SetupShot (self, f_org, FALSE, 2, "weapons/flac_fire.wav");\r
431 \r
432                 pointparticles(particleeffectnum("hagar_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);\r
433 \r
434         missile = spawn ();\r
435         missile.owner = missile.realowner = self;\r
436         missile.classname = "missile";\r
437         missile.bot_dodge = TRUE;\r
438         missile.bot_dodgerating = cvar("g_balance_seeker_flac_damage");\r
439         missile.touch = Seeker_Flac_Explode;\r
440         missile.use = Seeker_Flac_Explode;\r
441         missile.think = Seeker_Flac_Explode;\r
442         missile.nextthink = time + cvar("g_balance_seeker_flac_lifetime") + cvar("g_balance_seeker_flac_lifetime_rand");\r
443         missile.solid = SOLID_BBOX;\r
444         missile.scale = 0.4; // BUG: the model is too big\r
445         missile.projectiledeathtype = WEP_SEEKER;\r
446         setorigin (missile, w_shotorg);\r
447         setmodel (missile, "models/hagarmissile.mdl"); // precision set below\r
448         setsize (missile, '0 0 0', '0 0 0');\r
449         missile.projectiledeathtype = WEP_SEEKER | HITTYPE_SECONDARY;\r
450 \r
451         missile.effects = EF_LOWPRECISION;\r
452         missile.modelflags = MF_TRACER3;\r
453 \r
454         missile.movetype = MOVETYPE_FLY;\r
455         w_shotdir = w_shotdir + '0 0 0.3';\r
456         missile.velocity    = (w_shotdir  + randomvec() * cvar("g_balance_seeker_flac_spread")) * cvar("g_balance_seeker_flac_speed");\r
457 \r
458         W_SetupProjectileVelocity(missile);\r
459 \r
460         missile.angles = vectoangles (missile.velocity);\r
461         missile.flags = FL_PROJECTILE;\r
462 }\r
463 \r
464 void spawnfunc_weapon_seeker (void)\r
465 {\r
466         weapon_defaultspawnfunc(WEP_SEEKER);\r
467 }\r
468 \r
469 float w_seeker(float req)\r
470 {\r
471         if (req == WR_AIM)\r
472                 self.BUTTON_ATCK = bot_aim(cvar("g_balance_seeker_tag_speed"), 0, 20, FALSE);\r
473 \r
474         else if (req == WR_THINK)\r
475         {\r
476                 if (self.BUTTON_ATCK)\r
477                         if (weapon_prepareattack(0, cvar("g_balance_seeker_tag_refire")))\r
478                         {\r
479                                 Seeker_Fire_Tag();\r
480                                 weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_seeker_tag_animtime"), w_ready);\r
481                         }\r
482 \r
483                 if (self.BUTTON_ATCK2)\r
484                         if (weapon_prepareattack(1, cvar("g_balance_seeker_flac_refire")))\r
485                         {\r
486                                 Seeker_Fire_Flac();\r
487                                 weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_seeker_flac_animtime"), w_ready);\r
488                         }\r
489 \r
490         }\r
491         else if (req == WR_PRECACHE)\r
492         {\r
493                 precache_model ("models/hagarmissile.mdl");\r
494                 precache_model ("models/tagrocket.md3");\r
495                 precache_model ("models/weapons/g_seeker.md3");\r
496                 precache_model ("models/weapons/v_seeker.md3");\r
497                 precache_model ("models/weapons/w_seeker.zym");\r
498                 precache_sound ("weapons/tag_fire.wav");\r
499                 precache_sound ("weapons/tag_impact.wav");\r
500                 precache_sound ("weapons/tagexp1.wav");\r
501                 precache_sound ("weapons/tagexp2.wav");\r
502                 precache_sound ("weapons/tagexp3.wav");\r
503                 precache_sound ("weapons/tag_rocket_fly.wav");\r
504                 precache_sound ("weapons/flac_fire.wav");\r
505                 precache_sound ("weapons/flacexp1.wav");\r
506                 precache_sound ("weapons/flacexp2.wav");\r
507                 precache_sound ("weapons/flacexp3.wav");\r
508                 precache_sound ("weapons/seeker_fire.wav");\r
509                 precache_sound ("weapons/seekerexp1.wav");\r
510                 precache_sound ("weapons/seekerexp2.wav");\r
511                 precache_sound ("weapons/seekerexp3.wav");\r
512         }\r
513         else if (req == WR_SETUP)\r
514                 weapon_setup(WEP_SEEKER);\r
515         else if (req == WR_CHECKAMMO1)\r
516                 return self.ammo_rockets >= cvar("g_balance_seeker_tag_ammo") + cvar("g_balance_seeker_missile_ammo");\r
517         else if (req == WR_CHECKAMMO2)\r
518                 return self.ammo_rockets >= cvar("g_balance_seeker_flac_ammo");\r
519         else if (req == WR_SUICIDEMESSAGE)\r
520                 w_deathtypestring = "played with tiny rockets";\r
521         else if (req == WR_KILLMESSAGE)\r
522         {\r
523                 if(w_deathtype & HITTYPE_SECONDARY)\r
524                         w_deathtypestring = "ran into #'s flac";\r
525                 else\r
526                         w_deathtypestring = "was tagged by";\r
527         }\r
528         return TRUE;\r
529 };\r
530 \r