]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_grenadelauncher.qc
563496170e431d7e008bac0324e1b2eec7e4bf82
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_grenadelauncher.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(GRENADE_LAUNCHER, w_glauncher, IT_ROCKETS, 4, WEP_FLAG_NORMAL | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH, BOT_PICKUP_RATING_MID, "gl", "grenadelauncher", "Mortar");
3 #else
4 #ifdef SVQC
5 void W_Grenade_Explode (void)
6 {
7         if(other.takedamage == DAMAGE_AIM)
8                 if(other.classname == "player")
9                         if(IsDifferentTeam(self.owner, other))
10                                 if(other.deadflag == DEAD_NO)
11                                         if(IsFlying(other))
12                                                 AnnounceTo(self.owner, "airshot");
13
14         self.event_damage = SUB_Null;
15         self.takedamage = DAMAGE_NO;
16
17         if(self.movetype == MOVETYPE_NONE)
18                 self.velocity = self.oldvelocity;
19
20         RadiusDamage (self, self.owner, cvar("g_balance_grenadelauncher_primary_damage"), cvar("g_balance_grenadelauncher_primary_edgedamage"), cvar("g_balance_grenadelauncher_primary_radius"), world, cvar("g_balance_grenadelauncher_primary_force"), self.projectiledeathtype, other);
21
22         remove (self);
23 }
24
25 void W_Grenade_Explode2 (void)
26 {
27         if(other.takedamage == DAMAGE_AIM)
28                 if(other.classname == "player")
29                         if(IsDifferentTeam(self.owner, other))
30                                 if(IsFlying(other))
31                                         AnnounceTo(self.owner, "airshot");
32
33         self.event_damage = SUB_Null;
34         self.takedamage = DAMAGE_NO;
35
36         if(self.movetype == MOVETYPE_NONE)
37                 self.velocity = self.oldvelocity;
38
39         RadiusDamage (self, self.owner, cvar("g_balance_grenadelauncher_secondary_damage"), cvar("g_balance_grenadelauncher_secondary_edgedamage"), cvar("g_balance_grenadelauncher_secondary_radius"), world, cvar("g_balance_grenadelauncher_secondary_force"), self.projectiledeathtype, other);
40
41         remove (self);
42 }
43
44 void W_Grenade_Damage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
45 {
46         if (self.health <= 0)
47                 return;
48         self.health = self.health - damage;
49         if (self.health <= 0)
50         {
51                 W_PrepareExplosionByDamage(attacker, self.think);
52         }
53 }
54
55 void W_Grenade_Touch1 (void)
56 {
57         PROJECTILE_TOUCH;
58         if(cvar("g_balance_grenadelauncher_primary_sticky") && (!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE)))
59         {
60                 spamsound (self, CHAN_PROJECTILE, "weapons/grenade_stick.wav", VOL_BASE, ATTN_NORM);
61
62                 // let it stick whereever it is
63                 self.oldvelocity = self.velocity;
64                 self.velocity = '0 0 0';
65                 self.movetype = MOVETYPE_NONE; // also disables gravity
66                 self.gravity = 0; // nope, it does NOT! maybe a bug in CSQC code? TODO
67                 UpdateCSQCProjectile(self);
68
69                 // do not respond to any more touches
70                 self.solid = SOLID_NOT;
71
72                 self.nextthink = min(self.nextthink, time + cvar("g_balance_grenadelauncher_primary_lifetime2"));
73         }
74         else
75                 W_Grenade_Explode ();
76 }
77
78 void W_Grenade_Touch2 (void)
79 {
80         PROJECTILE_TOUCH;
81         print(sprintf("%e takedamage=%d movetype=%d\n", other, other.takedamage, other.movetype));
82         if(cvar("g_balance_grenadelauncher_secondary_sticky") && (!other || (other.takedamage != DAMAGE_AIM && other.movetype == MOVETYPE_NONE)))
83         {
84                 spamsound (self, CHAN_PROJECTILE, "weapons/grenade_stick.wav", VOL_BASE, ATTN_NORM);
85
86                 // let it stick whereever it is
87                 self.oldvelocity = self.velocity;
88                 self.velocity = '0 0 0';
89                 self.movetype = MOVETYPE_NONE; // also disables gravity
90                 self.gravity = 0; // nope, it does NOT! maybe a bug in CSQC code? TODO
91                 UpdateCSQCProjectile(self);
92
93                 // do not respond to any more touches
94                 self.solid = SOLID_NOT;
95
96                 self.nextthink = min(self.nextthink, time + cvar("g_balance_grenadelauncher_secondary_lifetime2"));
97         }
98         else
99         {
100                 if (cvar("g_balance_grenadelauncher_secondary_sticky") || other.takedamage == DAMAGE_AIM)
101                 {
102                         self.use ();
103                 }
104                 else
105                 {
106                         float r;
107                         r = random() * 6;
108                         if(r < 1)
109                                 spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce1.wav", VOL_BASE, ATTN_NORM);
110                         else if(r < 2)
111                                 spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce2.wav", VOL_BASE, ATTN_NORM);
112                         else if(r < 3)
113                                 spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce3.wav", VOL_BASE, ATTN_NORM);
114                         else if(r < 4)
115                                 spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce4.wav", VOL_BASE, ATTN_NORM);
116                         else if(r < 5)
117                                 spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce5.wav", VOL_BASE, ATTN_NORM);
118                         else
119                                 spamsound (self, CHAN_PROJECTILE, "weapons/grenade_bounce6.wav", VOL_BASE, ATTN_NORM);
120                         self.projectiledeathtype |= HITTYPE_BOUNCE;
121                 }
122         }
123 }
124
125 void W_Grenade_Attack (void)
126 {
127         local entity gren;
128
129         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
130                 self.ammo_rockets = self.ammo_rockets - cvar("g_balance_grenadelauncher_primary_ammo");
131         W_SetupShot_ProjectileSize (self, '-3 -3 -3', '3 3 3', FALSE, 4, "weapons/grenade_fire.wav", cvar("g_balance_grenadelauncher_primary_damage"));
132         w_shotdir = v_forward; // no TrueAim for grenades please
133
134         pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
135
136         gren = spawn ();
137         gren.owner = self;
138         gren.classname = "grenade";
139         gren.bot_dodge = TRUE;
140         gren.bot_dodgerating = cvar("g_balance_grenadelauncher_primary_damage");
141         gren.movetype = MOVETYPE_BOUNCE;
142         PROJECTILE_MAKETRIGGER(gren);
143         gren.projectiledeathtype = WEP_GRENADE_LAUNCHER;
144         setorigin(gren, w_shotorg);
145         setsize(gren, '-3 -3 -3', '3 3 3');
146
147         gren.nextthink = time + cvar("g_balance_grenadelauncher_primary_lifetime");
148         gren.think = adaptor_think2use_hittype_splash;
149         gren.use = W_Grenade_Explode;
150         gren.touch = W_Grenade_Touch1;
151
152         gren.takedamage = DAMAGE_YES;
153         gren.health = cvar("g_balance_grenadelauncher_primary_health");
154         gren.event_damage = W_Grenade_Damage;
155         W_SETUPPROJECTILEVELOCITY_UP(gren, g_balance_grenadelauncher_primary);
156
157         gren.angles = vectoangles (gren.velocity);
158         gren.flags = FL_PROJECTILE;
159
160         CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE);   
161 }
162
163 void W_Grenade_Attack2 (void)
164 {
165         local entity gren;
166
167         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
168                 self.ammo_rockets = self.ammo_rockets - cvar("g_balance_grenadelauncher_secondary_ammo");
169         W_SetupShot_ProjectileSize (self, '0 0 -3', '0 0 -3', FALSE, 4, "weapons/grenade_fire.wav", cvar("g_balance_grenadelauncher_secondary_damage"));
170         w_shotdir = v_forward; // no TrueAim for grenades please
171
172         pointparticles(particleeffectnum("grenadelauncher_muzzleflash"), w_shotorg, w_shotdir * 1000, 1);
173
174         gren = spawn ();
175         gren.owner = self;
176         gren.classname = "grenade";
177         gren.bot_dodge = TRUE;
178         gren.bot_dodgerating = cvar("g_balance_grenadelauncher_secondary_damage");
179         gren.movetype = MOVETYPE_BOUNCE;
180         gren.bouncefactor = cvar("g_balance_grenadelauncher_secondary_bouncefactor");
181         gren.bouncestop = cvar("g_balance_grenadelauncher_secondary_bouncestop");
182         PROJECTILE_MAKETRIGGER(gren);
183         gren.projectiledeathtype = WEP_GRENADE_LAUNCHER | HITTYPE_SECONDARY;
184         setorigin(gren, w_shotorg);
185         setsize(gren, '-3 -3 -3', '3 3 3');
186
187         gren.nextthink = time + cvar("g_balance_grenadelauncher_secondary_lifetime");
188         gren.think = adaptor_think2use_hittype_splash;
189         gren.use = W_Grenade_Explode2;
190         gren.touch = W_Grenade_Touch2;
191
192         gren.takedamage = DAMAGE_YES;
193         gren.health = cvar("g_balance_grenadelauncher_secondary_health");
194         gren.damageforcescale = cvar("g_balance_grenadelauncher_secondary_damageforcescale");
195         gren.event_damage = W_Grenade_Damage;
196         W_SETUPPROJECTILEVELOCITY_UP(gren, g_balance_grenadelauncher_secondary);
197
198         gren.angles = vectoangles (gren.velocity);
199         gren.flags = FL_PROJECTILE;
200
201         if(cvar("g_balance_grenadelauncher_secondary_sticky"))
202                 CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE, TRUE);
203         else
204                 CSQCProjectile(gren, TRUE, PROJECTILE_GRENADE_BOUNCING, TRUE);
205 }
206
207 void spawnfunc_weapon_grenadelauncher (void)
208 {
209         weapon_defaultspawnfunc(WEP_GRENADE_LAUNCHER);
210 }
211
212 .float bot_secondary_grenademooth;
213 float w_glauncher(float req)
214 {
215         if (req == WR_AIM)
216         {
217                 self.BUTTON_ATCK = FALSE;
218                 self.BUTTON_ATCK2 = FALSE;
219                 if (self.bot_secondary_grenademooth == 0)
220                 {
221                         if(bot_aim(cvar("g_balance_grenadelauncher_primary_speed"), cvar("g_balance_grenadelauncher_primary_speed_up"), cvar("g_balance_grenadelauncher_primary_lifetime"), TRUE))
222                         {
223                                 self.BUTTON_ATCK = TRUE;
224                                 if(random() < 0.01) self.bot_secondary_grenademooth = 1;
225                         }
226                 }
227                 else
228                 {
229                         if(bot_aim(cvar("g_balance_grenadelauncher_secondary_speed"), cvar("g_balance_grenadelauncher_secondary_speed_up"), cvar("g_balance_grenadelauncher_secondary_lifetime"), TRUE))
230                         {
231                                 self.BUTTON_ATCK2 = TRUE;
232                                 if(random() < 0.02) self.bot_secondary_grenademooth = 0;
233                         }
234                 }
235         }
236         else if (req == WR_THINK)
237         {
238                 if (self.BUTTON_ATCK)
239                 if (weapon_prepareattack(0, cvar("g_balance_grenadelauncher_primary_refire")))
240                 {
241                         if(cvar("g_balance_grenadelauncher_primary2secondary"))
242                                 W_Grenade_Attack2();
243                         else
244                                 W_Grenade_Attack();
245                         weapon_thinkf(WFRAME_FIRE1, cvar("g_balance_grenadelauncher_primary_animtime"), w_ready);
246                 }
247                 if (self.BUTTON_ATCK2 && !cvar("g_balance_grenadelauncher_primary2secondary"))
248                 if (weapon_prepareattack(1, cvar("g_balance_grenadelauncher_secondary_refire")))
249                 {
250                         W_Grenade_Attack2();
251                         weapon_thinkf(WFRAME_FIRE2, cvar("g_balance_grenadelauncher_secondary_animtime"), w_ready);
252                 }
253         }
254         else if (req == WR_PRECACHE)
255         {
256                 precache_model ("models/weapons/g_gl.md3");
257                 precache_model ("models/weapons/v_gl.md3");
258                 precache_model ("models/weapons/h_gl.iqm");
259                 precache_sound ("weapons/grenade_bounce1.wav");
260                 precache_sound ("weapons/grenade_bounce2.wav");
261                 precache_sound ("weapons/grenade_bounce3.wav");
262                 precache_sound ("weapons/grenade_bounce4.wav");
263                 precache_sound ("weapons/grenade_bounce5.wav");
264                 precache_sound ("weapons/grenade_bounce6.wav");
265                 precache_sound ("weapons/grenade_stick.wav");
266                 precache_sound ("weapons/grenade_fire.wav");
267         }
268         else if (req == WR_SETUP)
269                 weapon_setup(WEP_GRENADE_LAUNCHER);
270         else if (req == WR_CHECKAMMO1)
271                 return self.ammo_rockets >= cvar("g_balance_grenadelauncher_primary_ammo");
272         else if (req == WR_CHECKAMMO2)
273                 return self.ammo_rockets >= cvar("g_balance_grenadelauncher_secondary_ammo");
274         return TRUE;
275 };
276 #endif
277 #ifdef CSQC
278 float w_glauncher(float req)
279 {
280         if(req == WR_IMPACTEFFECT)
281         {
282                 vector org2;
283                 org2 = w_org + w_backoff * 12;
284                 pointparticles(particleeffectnum("grenade_explode"), org2, '0 0 0', 1);
285                 if(!w_issilent)
286                         sound(self, CHAN_PROJECTILE, "weapons/grenade_impact.wav", VOL_BASE, ATTN_NORM);
287         }
288         else if(req == WR_PRECACHE)
289         {
290                 precache_sound("weapons/grenade_impact.wav");
291         }
292         else if (req == WR_SUICIDEMESSAGE)
293         {
294                 if(w_deathtype & HITTYPE_SECONDARY)
295                         w_deathtypestring = "%s tried out his own grenade";
296                 else
297                         w_deathtypestring = "%s detonated";
298         }
299         else if (req == WR_KILLMESSAGE)
300         {
301                 if(w_deathtype & HITTYPE_SPLASH)
302                         if(w_deathtype & HITTYPE_BOUNCE) // (must be secondary then)
303                                 w_deathtypestring = "%s didn't see %s's grenade";
304                         else // unchecked: SECONDARY
305                                 w_deathtypestring = "%s almost dodged %s's grenade";
306                 else // unchecked: SECONDARY, BOUNCE
307                         w_deathtypestring = "%s ate %s's grenade";
308         }
309         return TRUE;
310 }
311 #endif
312 #endif