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