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