]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/w_mortar.qc
Add weapon image specification to REGISTER_WEAPON
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / w_mortar.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(
3 /* WEP_##id  */ MORTAR,
4 /* function  */ W_Mortar,
5 /* ammotype  */ ammo_rockets,
6 /* impulse   */ 4,
7 /* flags     */ WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH,
8 /* rating    */ BOT_PICKUP_RATING_MID,
9 /* color     */ '1 0 0',
10 /* modelname */ "gl",
11 /* simplemdl */ "foobar",
12 /* crosshair */ "gfx/crosshairgrenadelauncher 0.7",
13 /* wepimg    */ "weapongrenadelauncher",
14 /* refname   */ "mortar",
15 /* wepname   */ _("Mortar")
16 );
17
18 #define MORTAR_SETTINGS(w_cvar,w_prop) MORTAR_SETTINGS_LIST(w_cvar, w_prop, MORTAR, mortar)
19 #define MORTAR_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
20         w_cvar(id, sn, BOTH, ammo) \
21         w_cvar(id, sn, BOTH, animtime) \
22         w_cvar(id, sn, NONE, bouncefactor) \
23         w_cvar(id, sn, NONE, bouncestop) \
24         w_cvar(id, sn, BOTH, damage) \
25         w_cvar(id, sn, BOTH, damageforcescale) \
26         w_cvar(id, sn, BOTH, edgedamage) \
27         w_cvar(id, sn, BOTH, force) \
28         w_cvar(id, sn, BOTH, health) \
29         w_cvar(id, sn, BOTH, lifetime) \
30         w_cvar(id, sn, SEC,  lifetime_bounce) \
31         w_cvar(id, sn, BOTH, lifetime_stick) \
32         w_cvar(id, sn, BOTH, radius) \
33         w_cvar(id, sn, BOTH, refire) \
34         w_cvar(id, sn, SEC,  remote_detonateprimary) \
35         w_cvar(id, sn, PRI,  remote_minbouncecnt) \
36         w_cvar(id, sn, BOTH, speed) \
37         w_cvar(id, sn, BOTH, speed_up) \
38         w_cvar(id, sn, BOTH, speed_z) \
39         w_cvar(id, sn, BOTH, spread) \
40         w_cvar(id, sn, BOTH, type) \
41         w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
42         w_prop(id, sn, float,  reloading_time, reload_time) \
43         w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
44         w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
45         w_prop(id, sn, string, weaponreplace, weaponreplace) \
46         w_prop(id, sn, float,  weaponstart, weaponstart) \
47         w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride)
48
49 #ifdef SVQC
50 MORTAR_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
51 .float gl_detonate_later;
52 .float gl_bouncecnt;
53 #endif
54 #else
55 #ifdef SVQC
56
57 void spawnfunc_weapon_mortar() { weapon_defaultspawnfunc(WEP_MORTAR); }
58 void spawnfunc_weapon_grenadelauncher() { spawnfunc_weapon_mortar(); }
59
60 void W_Mortar_Grenade_Explode()
61 {
62         if(other.takedamage == DAMAGE_AIM)
63                 if(IS_PLAYER(other))
64                         if(DIFF_TEAM(self.realowner, other))
65                                 if(other.deadflag == DEAD_NO)
66                                         if(IsFlying(other))
67                                                 Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
68
69         self.event_damage = func_null;
70         self.takedamage = DAMAGE_NO;
71
72         if(self.movetype == MOVETYPE_NONE)
73                 self.velocity = self.oldvelocity;
74
75         RadiusDamage (self, self.realowner, WEP_CVAR_PRI(mortar, damage), WEP_CVAR_PRI(mortar, edgedamage), WEP_CVAR_PRI(mortar, radius), world, world, WEP_CVAR_PRI(mortar, force), self.projectiledeathtype, other);
76
77         remove (self);
78 }
79
80 void W_Mortar_Grenade_Explode2()
81 {
82         if(other.takedamage == DAMAGE_AIM)
83                 if(IS_PLAYER(other))
84                         if(DIFF_TEAM(self.realowner, other))
85                                 if(other.deadflag == DEAD_NO)
86                                         if(IsFlying(other))
87                                                 Send_Notification(NOTIF_ONE, self.realowner, MSG_ANNCE, ANNCE_ACHIEVEMENT_AIRSHOT);
88
89         self.event_damage = func_null;
90         self.takedamage = DAMAGE_NO;
91
92         if(self.movetype == MOVETYPE_NONE)
93                 self.velocity = self.oldvelocity;
94
95         RadiusDamage (self, self.realowner, WEP_CVAR_SEC(mortar, damage), WEP_CVAR_SEC(mortar, edgedamage), WEP_CVAR_SEC(mortar, radius), world, world, WEP_CVAR_SEC(mortar, force), self.projectiledeathtype, other);
96
97         remove (self);
98 }
99
100
101 void W_Mortar_Grenade_Damage(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
102 {
103         if (self.health <= 0)
104                 return;
105                 
106         if (!W_CheckProjectileDamage(inflictor.realowner, self.realowner, deathtype, -1)) // no exceptions
107                 return; // g_projectiles_damage says to halt
108                 
109         self.health = self.health - damage;
110         
111         if (self.health <= 0)
112                 W_PrepareExplosionByDamage(attacker, self.use);
113 }
114
115 void W_Mortar_Grenade_Think1()
116 {
117         self.nextthink = time;
118         if (time > self.cnt)
119         {
120                 other = world;
121                 self.projectiledeathtype |= HITTYPE_BOUNCE;
122                 W_Mortar_Grenade_Explode();
123                 return;
124         }
125         if(self.gl_detonate_later && self.gl_bouncecnt >= WEP_CVAR_PRI(mortar, remote_minbouncecnt))
126                 W_Mortar_Grenade_Explode();
127 }
128
129 void W_Mortar_Grenade_Touch1()
130 {
131         PROJECTILE_TOUCH;
132         if (other.takedamage == DAMAGE_AIM || WEP_CVAR_PRI(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
133         {
134                 self.use ();
135         }
136         else if (WEP_CVAR_PRI(mortar, type) == 1) // bounce
137         {
138                 float r;
139                 r = random() * 6;
140                 if(r < 1)
141                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce1.wav", VOL_BASE, ATTN_NORM);
142                 else if(r < 2)
143                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce2.wav", VOL_BASE, ATTN_NORM);
144                 else if(r < 3)
145                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce3.wav", VOL_BASE, ATTN_NORM);
146                 else if(r < 4)
147                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce4.wav", VOL_BASE, ATTN_NORM);
148                 else if(r < 5)
149                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce5.wav", VOL_BASE, ATTN_NORM);
150                 else
151                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce6.wav", VOL_BASE, ATTN_NORM);
152                 pointparticles(particleeffectnum("hagar_bounce"), self.origin, self.velocity, 1);
153                 self.projectiledeathtype |= HITTYPE_BOUNCE;
154                 self.gl_bouncecnt += 1;
155         }
156         else if(WEP_CVAR_PRI(mortar, type) == 2 && (!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE))) // stick
157         {
158                 spamsound (self, CH_SHOTS, "weapons/grenade_stick.wav", VOL_BASE, ATTN_NORM);
159
160                 // let it stick whereever it is
161                 self.oldvelocity = self.velocity;
162                 self.velocity = '0 0 0';
163                 self.movetype = MOVETYPE_NONE; // also disables gravity
164                 self.gravity = 0; // nope, it does NOT! maybe a bug in CSQC code? TODO
165                 UpdateCSQCProjectile(self);
166
167                 // do not respond to any more touches
168                 self.solid = SOLID_NOT;
169
170                 self.nextthink = min(self.nextthink, time + WEP_CVAR_PRI(mortar, lifetime_stick));
171         }
172 }
173
174 void W_Mortar_Grenade_Touch2()
175 {
176         PROJECTILE_TOUCH;
177         if (other.takedamage == DAMAGE_AIM || WEP_CVAR_SEC(mortar, type) == 0) // always explode when hitting a player, or if normal mortar projectile
178         {
179                 self.use ();
180         }
181         else if (WEP_CVAR_SEC(mortar, type) == 1) // bounce
182         {
183                 float r;
184                 r = random() * 6;
185                 if(r < 1)
186                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce1.wav", VOL_BASE, ATTN_NORM);
187                 else if(r < 2)
188                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce2.wav", VOL_BASE, ATTN_NORM);
189                 else if(r < 3)
190                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce3.wav", VOL_BASE, ATTN_NORM);
191                 else if(r < 4)
192                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce4.wav", VOL_BASE, ATTN_NORM);
193                 else if(r < 5)
194                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce5.wav", VOL_BASE, ATTN_NORM);
195                 else
196                         spamsound (self, CH_SHOTS, "weapons/grenade_bounce6.wav", VOL_BASE, ATTN_NORM);
197                 pointparticles(particleeffectnum("hagar_bounce"), self.origin, self.velocity, 1);
198                 self.projectiledeathtype |= HITTYPE_BOUNCE;
199                 self.gl_bouncecnt += 1;
200                 
201                 if (WEP_CVAR_SEC(mortar, lifetime_bounce) && self.gl_bouncecnt == 1)
202                         self.nextthink = time + WEP_CVAR_SEC(mortar, lifetime_bounce);
203                         
204         }
205         else if(WEP_CVAR_SEC(mortar, type) == 2 && (!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE))) // stick
206         {
207                 spamsound (self, CH_SHOTS, "weapons/grenade_stick.wav", VOL_BASE, ATTN_NORM);
208
209                 // let it stick whereever it is
210                 self.oldvelocity = self.velocity;
211                 self.velocity = '0 0 0';
212                 self.movetype = MOVETYPE_NONE; // also disables gravity
213                 self.gravity = 0; // nope, it does NOT! maybe a bug in CSQC code? TODO
214                 UpdateCSQCProjectile(self);
215
216                 // do not respond to any more touches
217                 self.solid = SOLID_NOT;
218
219                 self.nextthink = min(self.nextthink, time + WEP_CVAR_SEC(mortar, lifetime_stick));
220         }
221 }
222
223 void W_Mortar_Attack()
224 {
225         entity gren;
226
227         W_DecreaseAmmo(WEP_CVAR_PRI(mortar, ammo));
228
229         W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CH_WEAPON_A, WEP_CVAR_PRI(mortar, damage));
230         w_shotdir = v_forward; // no TrueAim for grenades please
231
232         pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
233
234         gren = spawn ();
235         gren.owner = gren.realowner = self;
236         gren.classname = "grenade";
237         gren.bot_dodge = TRUE;
238         gren.bot_dodgerating = WEP_CVAR_PRI(mortar, damage);
239         gren.movetype = MOVETYPE_BOUNCE;
240         gren.bouncefactor = WEP_CVAR(mortar, bouncefactor);
241         gren.bouncestop = WEP_CVAR(mortar, bouncestop);
242         PROJECTILE_MAKETRIGGER(gren);
243         gren.projectiledeathtype = WEP_MORTAR;
244         setorigin(gren, w_shotorg);
245         setsize(gren, '-3 -3 -3', '3 3 3');
246
247         gren.cnt = time + WEP_CVAR_PRI(mortar, lifetime);
248         gren.nextthink = time;
249         gren.think = W_Mortar_Grenade_Think1;
250         gren.use = W_Mortar_Grenade_Explode;
251         gren.touch = W_Mortar_Grenade_Touch1;
252
253         gren.takedamage = DAMAGE_YES;
254         gren.health = WEP_CVAR_PRI(mortar, health);
255         gren.damageforcescale = WEP_CVAR_PRI(mortar, damageforcescale);
256         gren.event_damage = W_Mortar_Grenade_Damage;
257         gren.damagedbycontents = TRUE;
258         gren.missile_flags = MIF_SPLASH | MIF_ARC;
259         W_SetupProjVelocity_UP_PRI(gren, mortar);
260
261         gren.angles = vectoangles (gren.velocity);
262         gren.flags = FL_PROJECTILE;
263
264         if(WEP_CVAR_PRI(mortar, type) == 0 || WEP_CVAR_PRI(mortar, type) == 2)
265                 CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE);
266         else
267                 CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE_BOUNCING, TRUE);
268
269         other = gren; MUTATOR_CALLHOOK(EditProjectile);
270 }
271
272 void W_Mortar_Attack2()
273 {
274         entity gren;
275
276         W_DecreaseAmmo(WEP_CVAR_SEC(mortar, ammo));
277
278         W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", CH_WEAPON_A, WEP_CVAR_SEC(mortar, damage));
279         w_shotdir = v_forward; // no TrueAim for grenades please
280
281         pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
282
283         gren = spawn ();
284         gren.owner = gren.realowner = self;
285         gren.classname = "grenade";
286         gren.bot_dodge = TRUE;
287         gren.bot_dodgerating = WEP_CVAR_SEC(mortar, damage);
288         gren.movetype = MOVETYPE_BOUNCE;
289         gren.bouncefactor = WEP_CVAR(mortar, bouncefactor);
290         gren.bouncestop = WEP_CVAR(mortar, bouncestop);
291         PROJECTILE_MAKETRIGGER(gren);
292         gren.projectiledeathtype = WEP_MORTAR | HITTYPE_SECONDARY;
293         setorigin(gren, w_shotorg);
294         setsize(gren, '-3 -3 -3', '3 3 3');
295
296         gren.nextthink = time + WEP_CVAR_SEC(mortar, lifetime);
297         gren.think = adaptor_think2use_hittype_splash;
298         gren.use = W_Mortar_Grenade_Explode2;
299         gren.touch = W_Mortar_Grenade_Touch2;
300
301         gren.takedamage = DAMAGE_YES;
302         gren.health = WEP_CVAR_SEC(mortar, health);
303         gren.damageforcescale = WEP_CVAR_SEC(mortar, damageforcescale);
304         gren.event_damage = W_Mortar_Grenade_Damage;
305         gren.damagedbycontents = TRUE;
306         gren.missile_flags = MIF_SPLASH | MIF_ARC;
307         W_SetupProjVelocity_UP_SEC(gren, mortar);
308
309         gren.angles = vectoangles (gren.velocity);
310         gren.flags = FL_PROJECTILE;
311
312         if(WEP_CVAR_SEC(mortar, type) == 0 || WEP_CVAR_SEC(mortar, type) == 2)
313                 CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE);
314         else
315                 CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE_BOUNCING, TRUE);
316
317         other = gren; MUTATOR_CALLHOOK(EditProjectile);
318 }
319
320 .float bot_secondary_grenademooth;
321 float W_Mortar(float req)
322 {
323         entity nade;
324         float nadefound;
325         float ammo_amount;
326         switch(req)
327         {
328                 case WR_AIM:
329                 {
330                         self.BUTTON_ATCK = FALSE;
331                         self.BUTTON_ATCK2 = FALSE;
332                         if (self.bot_secondary_grenademooth == 0) // WEAPONTODO: merge this into using WEP_CVAR_BOTH
333                         {
334                                 if(bot_aim(WEP_CVAR_PRI(mortar, speed), WEP_CVAR_PRI(mortar, speed_up), WEP_CVAR_PRI(mortar, lifetime), TRUE))
335                                 {
336                                         self.BUTTON_ATCK = TRUE;
337                                         if(random() < 0.01) self.bot_secondary_grenademooth = 1;
338                                 }
339                         }
340                         else
341                         {
342                                 if(bot_aim(WEP_CVAR_SEC(mortar, speed), WEP_CVAR_SEC(mortar, speed_up), WEP_CVAR_SEC(mortar, lifetime), TRUE))
343                                 {
344                                         self.BUTTON_ATCK2 = TRUE;
345                                         if(random() < 0.02) self.bot_secondary_grenademooth = 0;
346                                 }
347                         }
348                         
349                         return TRUE;
350                 }
351                 /*case WR_CALCINFO:
352                 {
353                         wepinfo_pri_refire = max3(sys_frametime, WEP_CVAR_PRI(mortar, refire), WEP_CVAR_PRI(mortar, animtime));
354                         wepinfo_pri_dps = (WEP_CVAR_PRI(mortar, damage) * (1 / wepinfo_pri_refire));
355                         wepinfo_pri_speed = (1 / max(1, (10000 / max(1, WEP_CVAR_PRI(mortar, speed)))));
356
357                         // for the range calculation, closer to 1 is better
358                         wepinfo_pri_range_max = 2000 * wepinfo_pri_speed;
359                         wepinfo_pri_range = wepinfo_pri_speed * WEP_CVAR_PRI(mortar, 
360                         
361                         wepinfo_sec_refire = max3(sys_frametime, WEP_CVAR_SEC(mortar, refire), WEP_CVAR_SEC(mortar, animtime));
362                         wepinfo_sec_dps = (WEP_CVAR_SEC(mortar, damage) * (1 / wepinfo_sec_refire));
363                         
364                         wepinfo_sec_dps = (WEP_CVAR_SEC(mortar, damage) * (1 / max3(sys_frametime, WEP_CVAR_SEC(mortar, refire), WEP_CVAR_SEC(mortar, animtime))));
365                         wepinfo_ter_dps = 0;
366                         */
367                 case WR_THINK:
368                 {
369                         if(autocvar_g_balance_mortar_reload_ammo && self.clip_load < min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo))) // forced reload
370                                 WEP_ACTION(self.weapon, WR_RELOAD);
371                         else if (self.BUTTON_ATCK)
372                         {
373                                 if (weapon_prepareattack(0, WEP_CVAR_PRI(mortar, refire)))
374                                 {
375                                         W_Mortar_Attack();
376                                         weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(mortar, animtime), w_ready);
377                                 }
378                         }
379                         else if (self.BUTTON_ATCK2)
380                         {
381                                 if(WEP_CVAR_SEC(mortar, remote_detonateprimary))
382                                 {
383                                         nadefound = 0;
384                                         for(nade = world; (nade = find(nade, classname, "grenade")); ) if(nade.realowner == self)
385                                         {
386                                                 if(!nade.gl_detonate_later)
387                                                 {
388                                                         nade.gl_detonate_later = TRUE;
389                                                         nadefound = 1;
390                                                 }
391                                         }
392                                         if(nadefound)
393                                                 sound (self, CH_WEAPON_B, "weapons/rocket_det.wav", VOL_BASE, ATTN_NORM);
394                                 }
395                                 else if (weapon_prepareattack(1, WEP_CVAR_SEC(mortar, refire)))
396                                 {
397                                         W_Mortar_Attack2();
398                                         weapon_thinkf(WFRAME_FIRE2, WEP_CVAR_SEC(mortar, animtime), w_ready);
399                                 }
400                         }
401                         
402                         return TRUE;
403                 }
404                 case WR_INIT:
405                 {
406                         precache_model ("models/weapons/g_gl.md3");
407                         precache_model ("models/weapons/v_gl.md3");
408                         precache_model ("models/weapons/h_gl.iqm");
409                         precache_sound ("weapons/grenade_bounce1.wav");
410                         precache_sound ("weapons/grenade_bounce2.wav");
411                         precache_sound ("weapons/grenade_bounce3.wav");
412                         precache_sound ("weapons/grenade_bounce4.wav");
413                         precache_sound ("weapons/grenade_bounce5.wav");
414                         precache_sound ("weapons/grenade_bounce6.wav");
415                         precache_sound ("weapons/grenade_stick.wav");
416                         precache_sound ("weapons/grenade_fire.wav");
417                         MORTAR_SETTINGS(WEP_SKIP_CVAR, WEP_SET_PROP)
418                         return TRUE;
419                 }
420                 case WR_CHECKAMMO1:
421                 {
422                         ammo_amount = self.WEP_AMMO(MORTAR) >= WEP_CVAR_PRI(mortar, ammo);
423                         ammo_amount += self.(weapon_load[WEP_MORTAR]) >= WEP_CVAR_PRI(mortar, ammo);
424                         return ammo_amount;
425                 }
426                 case WR_CHECKAMMO2:
427                 {
428                         ammo_amount = self.WEP_AMMO(MORTAR) >= WEP_CVAR_SEC(mortar, ammo);
429                         ammo_amount += self.(weapon_load[WEP_MORTAR]) >= WEP_CVAR_SEC(mortar, ammo);
430                         return ammo_amount;
431                 }
432                 case WR_CONFIG:
433                 {
434                         MORTAR_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS)
435                         return TRUE;
436                 }
437                 case WR_RELOAD:
438                 {
439                         W_Reload(min(WEP_CVAR_PRI(mortar, ammo), WEP_CVAR_SEC(mortar, ammo)), "weapons/reload.wav"); // WEAPONTODO
440                         return TRUE;
441                 }
442                 case WR_SUICIDEMESSAGE:
443                 {
444                         if(w_deathtype & HITTYPE_SECONDARY)
445                                 return WEAPON_MORTAR_SUICIDE_BOUNCE;
446                         else
447                                 return WEAPON_MORTAR_SUICIDE_EXPLODE;
448                 }
449                 case WR_KILLMESSAGE:
450                 {
451                         if(w_deathtype & HITTYPE_SECONDARY)
452                                 return WEAPON_MORTAR_MURDER_BOUNCE;
453                         else
454                                 return WEAPON_MORTAR_MURDER_EXPLODE;
455                 }
456         }
457         return TRUE;
458 }
459 #endif
460 #ifdef CSQC
461 float W_Mortar(float req)
462 {
463         switch(req)
464         {
465                 case WR_IMPACTEFFECT:
466                 {
467                         vector org2;
468                         org2 = w_org + w_backoff * 12;
469                         pointparticles(particleeffectnum("grenade_explode"), org2, '0 0 0', 1);
470                         if(!w_issilent)
471                                 sound(self, CH_SHOTS, "weapons/grenade_impact.wav", VOL_BASE, ATTN_NORM);
472                                 
473                         return TRUE;
474                 }
475                 case WR_INIT:
476                 {
477                         precache_sound("weapons/grenade_impact.wav");
478                         return TRUE;
479                 }
480                 case WR_ZOOMRETICLE:
481                 {
482                         // no weapon specific image for this weapon
483                         return FALSE;
484                 }
485         }
486         return TRUE;
487 }
488 #endif
489 #endif