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