]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/server/w_seeker.qc
added missing precache for hagarmissile (funny typo btw)
[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/hagexp1.wav", 1, ATTN_NORM);\r
15     else if (b<0.4)\r
16         sound (self, CHAN_PROJECTILE, "weapons/hagexp2.wav", 1, ATTN_NORM);\r
17     else if (b<1)\r
18         sound (self, CHAN_PROJECTILE, "weapons/hagexp3.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     if (other == self.owner)\r
29         return;\r
30 \r
31     Seeker_Missile_Explode();\r
32 }\r
33 \r
34 void Seeker_Missile_Think()\r
35 {\r
36     entity e;\r
37     vector desireddir, olddir, newdir;\r
38     float turnrate;\r
39     float dist;\r
40 \r
41     if (time > self.cnt)\r
42         Seeker_Missile_Explode();\r
43 \r
44     if (!self.switchweapon)\r
45         self.switchweapon = cvar("g_balance_seeker_missile_speed");\r
46 \r
47     if ((self.switchweapon < cvar("g_balance_seeker_missile_speed_max")) && cvar("g_balance_seeker_missile_speed_accel"))\r
48         self.switchweapon = self.switchweapon * cvar("g_balance_seeker_missile_accel");\r
49 \r
50     if (self.switchweapon > cvar("g_balance_seeker_missile_speed_max"))\r
51         self.switchweapon = self.switchweapon * cvar("g_balance_seeker_missile_decel");\r
52 \r
53     if (self.enemy != world)\r
54                 if (self.enemy.takedamage != DAMAGE_AIM || self.enemy.deadflag != DEAD_NO)\r
55                         self.enemy = world;\r
56 \r
57     if (self.enemy != world)\r
58     {\r
59         e               = self.enemy;\r
60         turnrate        = cvar("g_balance_seeker_missile_turnrate");                // how fast to turn\r
61         desireddir      = normalize(e.origin - self.origin);\r
62         olddir          = normalize(self.velocity);                                         // get my current direction\r
63         dist            = vlen(e.origin - 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, self.enemy.origin, 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 }\r
127 \r
128 \r
129 \r
130 void Seeker_Missile_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
131 {\r
132     float d;\r
133     d = damage;\r
134 \r
135     if (self.owner == attacker)\r
136         d = d * 0.25;\r
137 \r
138     self.health = self.health - d;\r
139 \r
140     if (self.health <= 0)\r
141                 W_PrepareExplosionByDamage(attacker, Seeker_Missile_Explode);\r
142 }\r
143 \r
144 #define EF_ROCKET                               16777216\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 | EF_ROCKET;\r
159 \r
160         if (cvar("g_balance_seeker_guided_proxy"))\r
161             self.movetype    = MOVETYPE_BOUNCEMISSILE;\r
162         else\r
163             self.movetype    = MOVETYPE_FLYMISSILE;\r
164     }\r
165 }\r
166 \r
167 void Seeker_Fire_Missile(vector f_org)\r
168 {\r
169     local entity missile;\r
170 \r
171     if not(self.items & IT_UNLIMITED_WEAPON_AMMO)\r
172         self.ammo_rockets = self.ammo_rockets - cvar("g_balance_seeker_missile_ammo");\r
173 \r
174     makevectors(self.v_angle);\r
175     W_SetupShot (self, f_org, FALSE, 2, "weapons/hagar_fire.wav");\r
176     pointparticles(particleeffectnum("seeker_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);\r
177 \r
178     //self.detornator         = FALSE;\r
179 \r
180     missile                 = spawn();\r
181     missile.owner           = self;\r
182     missile.classname       = "seeker_missile";\r
183     missile.bot_dodge       = TRUE;\r
184     missile.bot_dodgerating = cvar("g_balance_seeker_missile_damage");\r
185 \r
186     missile.think           = Seeker_Missile_Animate;\r
187 \r
188     //if (!cvar("g_balance_seeker_missile_proxy"))\r
189     missile.touch           = Seeker_Missile_Touch;\r
190 \r
191     missile.event_damage    = Seeker_Missile_Damage;\r
192     missile.nextthink       = time + 0.2;// + cvar("g_balance_seeker_missile_activate_delay");\r
193     missile.cnt             = time + cvar("g_balance_seeker_missile_lifetime");\r
194     missile.enemy           = self.enemy;\r
195     missile.switchweapon           = cvar("g_balance_seeker_missile_speed");\r
196     missile.effects         = EF_LOWPRECISION | EF_NOSHADOW;// | EF_ROCKET;\r
197     missile.solid           = SOLID_BBOX;\r
198     missile.scale           = 2;\r
199     missile.takedamage          = DAMAGE_YES;\r
200     missile.damageforcescale    = 4;\r
201     missile.health              = 5;\r
202         missile.projectiledeathtype = WEP_SEEKER;\r
203 \r
204     setorigin (missile, w_shotorg);\r
205     setmodel  (missile, "models/tagrocket.md3");\r
206     setsize (missile, '-2 -2 -2', '2 2 2');\r
207 \r
208 \r
209     missile.movetype    = MOVETYPE_FLYMISSILE;// MOVETYPE_TOSS;\r
210 \r
211     missile.flags       = FL_PROJECTILE;\r
212 \r
213     missile.velocity    = (w_shotdir + '0 0 0.45') * missile.switchweapon;\r
214     W_SetupProjectileVelocity(missile);\r
215 \r
216     missile.switchweapon = vlen(missile.velocity);\r
217     missile.angles = vectoangles (missile.velocity);\r
218 \r
219 }\r
220 \r
221 void Seeker_Vollycontroler_Think()\r
222 {\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         Seeker_Fire_Missile('56 13 -15' + 7 * randomvec());\r
241 \r
242 \r
243 \r
244     self.enemy = oldenemy;\r
245     self = oldself;\r
246 }\r
247 \r
248 void Seeker_Tag_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)\r
249 {\r
250     self.health = self.health - damage;\r
251     if (self.health <= 0)\r
252         self.think ();\r
253 }\r
254 \r
255 void Seeker_Tag_Explode ()\r
256 {\r
257     vector      org2;\r
258     float b;\r
259 \r
260     //if(other==self.owner)\r
261     //    return;\r
262 \r
263     org2 = findbetterlocation (self.origin, 12);\r
264     te_explosion (org2);\r
265 \r
266     b = crandom();\r
267     if (b<-0.7)\r
268         sound (self, CHAN_PROJECTILE, "weapons/hagexp1.wav", 1, ATTN_NORM);\r
269     else if (b<0.4)\r
270         sound (self, CHAN_PROJECTILE, "weapons/hagexp2.wav", 1, ATTN_NORM);\r
271     else if (b<1)\r
272         sound (self, CHAN_PROJECTILE, "weapons/hagexp3.wav", 1, ATTN_NORM);\r
273 \r
274     remove (self);\r
275 }\r
276 \r
277 void Seeker_Tag_Think()\r
278 {\r
279     remove(self);\r
280     return;\r
281 }\r
282 \r
283 void Seeker_Tag_Touch()\r
284 {\r
285     vector dir;\r
286     vector org2;\r
287 \r
288         if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)\r
289         {\r
290                 remove(self);\r
291                 return;\r
292         }\r
293 \r
294     if (other == self.owner)\r
295         return;\r
296 \r
297     dir     = normalize (self.owner.origin - self.origin);\r
298     org2    = findbetterlocation (self.origin, 8);\r
299 \r
300     te_knightspike(org2);\r
301 \r
302     self.event_damage = SUB_Null;\r
303     sound (self, CHAN_PROJECTILE, "weapons/laserimpact.wav", 1, ATTN_NORM);\r
304 \r
305     if (other.takedamage == DAMAGE_AIM && other.deadflag == DEAD_NO)\r
306     {\r
307         entity e;\r
308         e           = spawn();\r
309         e.cnt       = cvar("g_balance_seeker_missile_count");\r
310         e.owner     = self.owner;\r
311         e.enemy     = other;\r
312         e.think     = Seeker_Vollycontroler_Think;\r
313         e.nextthink = time;\r
314 \r
315         //sprint(self.owner, "^1Target lock ^3[^7 ",other.netname, " ^3]^1 acquired - autofire activated.\n");\r
316         //sprint(other,"^1You are targeted!\n");\r
317 \r
318         // stuffcmd(other,"play2 weapons/zany-alarm4.ogg\n");\r
319         // stuffcmd(self.owner, "play2 weapons/zany-lock4.ogg\n");\r
320     }\r
321 \r
322     remove(self);\r
323     return;\r
324 }\r
325 \r
326 \r
327 \r
328 void Seeker_Fire_Tag()\r
329 {\r
330     local entity missile;\r
331     if not(self.items & IT_UNLIMITED_WEAPON_AMMO)\r
332         self.ammo_rockets = self.ammo_rockets - cvar("g_balance_seeker_tag_ammo");\r
333 \r
334     W_SetupShot (self, '56 13 -15', FALSE, 2, "weapons/hagar_fire.wav");\r
335 \r
336     missile                 = spawn();\r
337     missile.owner           = self;\r
338     missile.classname       = "seeker_tag";\r
339     missile.bot_dodge       = TRUE;\r
340     missile.bot_dodgerating = 50;\r
341     missile.touch           = Seeker_Tag_Touch;\r
342     missile.think           = Seeker_Tag_Think;\r
343     missile.nextthink       = time + 15;\r
344     missile.movetype        = MOVETYPE_FLY;\r
345     missile.solid           = SOLID_BBOX;\r
346     missile.owner           = self;\r
347 \r
348     missile.takedamage       = DAMAGE_YES;\r
349     missile.event_damage    = Seeker_Tag_Explode;\r
350     missile.health          = 5;\r
351 \r
352     setmodel (missile, "models/laser.mdl"); // TODO make this seeker specific\r
353     setorigin (missile, w_shotorg);\r
354 \r
355     missile.effects     = EF_FULLBRIGHT | EF_NOSHADOW | EF_LOWPRECISION;\r
356     missile.modelflags  = MF_TRACER3;\r
357     missile.flags       = FL_PROJECTILE;\r
358 \r
359     missile.velocity    = w_shotdir  * cvar("g_balance_seeker_tag_speed");\r
360     missile.movetype    = MOVETYPE_BOUNCEMISSILE;\r
361     W_SetupProjectileVelocity(missile);\r
362     missile.angles = vectoangles (missile.velocity);\r
363 }\r
364 \r
365 \r
366 void Seeker_Flac_Explode ()\r
367 {\r
368     vector      org2;\r
369     float b;\r
370     org2 = findbetterlocation (self.origin, 12);\r
371     te_explosion (org2);\r
372 \r
373     b = crandom();\r
374     if (b<-0.7)\r
375         sound (self, CHAN_PROJECTILE, "weapons/hagexp1.wav", 1, ATTN_NORM);\r
376     else if (b<0.4)\r
377         sound (self, CHAN_PROJECTILE, "weapons/hagexp2.wav", 1, ATTN_NORM);\r
378     else if (b<1)\r
379         sound (self, CHAN_PROJECTILE, "weapons/hagexp3.wav", 1, ATTN_NORM);\r
380 \r
381     self.event_damage = SUB_Null;\r
382 \r
383     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
384 \r
385     remove (self);\r
386 }\r
387 \r
388 void Seeker_Flac_Touch()\r
389 {\r
390     if (other == self.owner)\r
391         return;\r
392 \r
393     Seeker_Flac_Explode();\r
394 }\r
395 \r
396 void Seeker_Fire_Flac()\r
397 {\r
398         local entity missile;\r
399 \r
400         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)\r
401                 self.ammo_rockets = self.ammo_rockets - cvar("g_balance_seeker_flac_ammo");\r
402 \r
403     W_SetupShot (self, '56 13 -15', FALSE, 2, "weapons/hagar_fire.wav");\r
404 \r
405         pointparticles(particleeffectnum("hagar_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);\r
406 \r
407         missile = spawn ();\r
408         missile.owner = missile.realowner = self;\r
409         missile.classname = "missile";\r
410         missile.bot_dodge = TRUE;\r
411         missile.bot_dodgerating = cvar("g_balance_seeker_flac_damage");\r
412         missile.touch = Seeker_Flac_Explode;\r
413         missile.use = Seeker_Flac_Explode;\r
414         missile.think = Seeker_Flac_Explode;\r
415         missile.nextthink = time + cvar("g_balance_seeker_flac_lifetime") + cvar("g_balance_seeker_flac_lifetime_rand");\r
416         missile.solid = SOLID_BBOX;\r
417         missile.scale = 0.4; // BUG: the model is too big\r
418         missile.projectiledeathtype = WEP_SEEKER;\r
419         setorigin (missile, w_shotorg);\r
420         setmodel (missile, "models/hagarmissile.mdl"); // precision set below\r
421         setsize (missile, '0 0 0', '0 0 0');\r
422         missile.projectiledeathtype = WEP_SEEKER | HITTYPE_SECONDARY;\r
423 \r
424         missile.effects = EF_LOWPRECISION;\r
425         missile.modelflags = MF_TRACER3;\r
426 \r
427         missile.movetype = MOVETYPE_FLY;\r
428         w_shotdir = w_shotdir + '0 0 0.3';\r
429         missile.velocity    = (w_shotdir  + randomvec() * cvar("g_balance_seeker_flac_spread")) * cvar("g_balance_seeker_flac_speed");\r
430 \r
431         W_SetupProjectileVelocity(missile);\r
432 \r
433         missile.angles = vectoangles (missile.velocity);\r
434         missile.flags = FL_PROJECTILE;\r
435 }\r
436 \r
437 void spawnfunc_weapon_seeker (void)\r
438 {\r
439         weapon_defaultspawnfunc(WEP_SEEKER);\r
440 }\r
441 \r
442 float w_seeker(float req)\r
443 {\r
444     if (req == WR_AIM)\r
445         self.BUTTON_ATCK = bot_aim(cvar("g_balance_seeker_tag_speed"), 0, 20, FALSE);\r
446 \r
447     else if (req == WR_THINK)\r
448     {\r
449         if (self.BUTTON_ATCK)\r
450             if (weapon_prepareattack(0, cvar("g_balance_seeker_tag_refire")))\r
451             {\r
452                 Seeker_Fire_Tag();\r
453                 weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_seeker_tag_animtime"), w_ready);\r
454             }\r
455 \r
456         if (self.BUTTON_ATCK2)\r
457             if (weapon_prepareattack(1, cvar("g_balance_seeker_flac_refire")))\r
458             {\r
459                 Seeker_Fire_Flac();\r
460                 weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_seeker_flac_animtime"), w_ready);\r
461             }\r
462 \r
463     }\r
464     else if (req == WR_PRECACHE)\r
465     {\r
466         precache_model ("models/hagarmissile.mdl");\r
467         precache_model ("models/tagrocket.md3");\r
468         precache_model ("models/weapons/g_seeker.md3");\r
469         precache_model ("models/weapons/v_seeker.md3");\r
470         precache_model ("models/weapons/w_seeker.zym");\r
471         precache_sound ("weapons/hagar_fire.wav");\r
472         precache_sound ("weapons/hagexp1.wav");\r
473         precache_sound ("weapons/hagexp2.wav");\r
474         precache_sound ("weapons/hagexp3.wav");\r
475         precache_sound ("weapons/laserimpact.wav");\r
476     }\r
477     else if (req == WR_SETUP)\r
478         weapon_setup(WEP_SEEKER);\r
479     else if (req == WR_CHECKAMMO1)\r
480         return self.ammo_rockets >= cvar("g_balance_seeker_tag_ammo") + cvar("g_balance_seeker_missile_ammo");\r
481     else if (req == WR_CHECKAMMO2)\r
482         return self.ammo_rockets >= cvar("g_balance_seeker_flac_ammo");\r
483     else if (req == WR_SUICIDEMESSAGE)\r
484         w_deathtypestring = "played with tiny rockets";\r
485     else if (req == WR_KILLMESSAGE)\r
486         {\r
487                 if(w_deathtype & HITTYPE_SECONDARY)\r
488                         w_deathtypestring = "ran into #'s flac";\r
489                 else\r
490                         w_deathtypestring = "was tagged by";\r
491         }\r
492     return TRUE;\r
493 };\r
494 \r