]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/w_nex.qc
Attempt to further simplify the reload code, as requested. First part of the first...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / w_nex.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(NEX, w_nex, IT_CELLS, 7, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN, BOT_PICKUP_RATING_HIGH, "nex", "nex", _("Nex"))
3 #else
4 #ifdef SVQC
5
6 void W_Nex_Reload()
7 {
8         W_Reload(ammo_cells, min(autocvar_g_balance_nex_primary_ammo, autocvar_g_balance_nex_secondary_ammo), autocvar_g_balance_nex_reload_ammo, autocvar_g_balance_nex_reload_time, "weapons/reload.wav");
9 }
10
11 void SendCSQCNexBeamParticle(float charge) {
12         vector v;
13         v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
14         WriteByte(MSG_BROADCAST, SVC_TEMPENTITY);
15         WriteByte(MSG_BROADCAST, TE_CSQC_NEXGUNBEAMPARTICLE);
16         WriteCoord(MSG_BROADCAST, w_shotorg_x);
17         WriteCoord(MSG_BROADCAST, w_shotorg_y);
18         WriteCoord(MSG_BROADCAST, w_shotorg_z);
19         WriteCoord(MSG_BROADCAST, v_x);
20         WriteCoord(MSG_BROADCAST, v_y);
21         WriteCoord(MSG_BROADCAST, v_z);
22         WriteByte(MSG_BROADCAST, bound(0, 255 * charge, 255));
23 }
24
25 void W_Nex_Attack (float issecondary)
26 {
27         float mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, myammo, charge;
28         if(issecondary)
29         {
30                 mydmg = autocvar_g_balance_nex_secondary_damage;
31                 myforce = autocvar_g_balance_nex_secondary_force;
32                 mymindist = autocvar_g_balance_nex_secondary_damagefalloff_mindist;
33                 mymaxdist = autocvar_g_balance_nex_secondary_damagefalloff_maxdist;
34                 myhalflife = autocvar_g_balance_nex_secondary_damagefalloff_halflife;
35                 myforcehalflife = autocvar_g_balance_nex_secondary_damagefalloff_forcehalflife;
36                 myammo = autocvar_g_balance_nex_secondary_ammo;
37         }
38         else
39         {
40                 mydmg = autocvar_g_balance_nex_primary_damage;
41                 myforce = autocvar_g_balance_nex_primary_force;
42                 mymindist = autocvar_g_balance_nex_primary_damagefalloff_mindist;
43                 mymaxdist = autocvar_g_balance_nex_primary_damagefalloff_maxdist;
44                 myhalflife = autocvar_g_balance_nex_primary_damagefalloff_halflife;
45                 myforcehalflife = autocvar_g_balance_nex_primary_damagefalloff_forcehalflife;
46                 myammo = autocvar_g_balance_nex_primary_ammo;
47         }
48
49         float flying;
50         flying = IsFlying(self); // do this BEFORE to make the trace values from FireRailgunBullet last
51
52         if(autocvar_g_balance_nex_charge)
53         {
54                 charge = autocvar_g_balance_nex_charge_mindmg / mydmg + (1 - autocvar_g_balance_nex_charge_mindmg / mydmg) * self.nex_charge;
55                 self.nex_charge *= autocvar_g_balance_nex_charge_shot_multiplier; // do this AFTER setting mydmg/myforce
56                 // O RLY? -- divVerent
57                 // YA RLY -- FruitieX
58         }
59         else
60                 charge = 1;
61         mydmg *= charge;
62         myforce *= charge;
63
64         W_SetupShot (self, TRUE, 5, "weapons/nexfire.wav", CHAN_WEAPON, mydmg);
65         if(charge > autocvar_g_balance_nex_charge_animlimit && autocvar_g_balance_nex_charge_animlimit) // if the Nex is overcharged, we play an extra sound
66         {
67                 sound (self, CHAN_WEAPON2, "weapons/nexcharge.wav", VOL_BASE * (charge - 0.5 * autocvar_g_balance_nex_charge_animlimit) / (1 - 0.5 * autocvar_g_balance_nex_charge_animlimit), ATTN_NORM);
68         }
69
70         yoda = 0;
71         FireRailgunBullet (w_shotorg, w_shotorg + w_shotdir * MAX_SHOT_DISTANCE, mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, WEP_NEX);
72
73         if(yoda && flying)
74                 AnnounceTo(self, "yoda");
75
76         //beam and muzzle flash done on client
77         SendCSQCNexBeamParticle(charge);
78
79         // flash and burn the wall
80         if (trace_ent.solid == SOLID_BSP && !(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT))
81                 Damage_DamageInfo(trace_endpos, mydmg, 0, 0, myforce * w_shotdir, WEP_NEX, self);
82
83         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
84         if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
85         {
86                 if(autocvar_g_balance_nex_reload_ammo)
87                 {
88                         self.clip_load -= myammo;
89                         self.weapon_load[WEP_NEX] = self.clip_load;
90                 }
91                 else
92                         self.ammo_cells -= myammo;
93         }
94 }
95
96 void spawnfunc_weapon_nex (void); // defined in t_items.qc
97
98 .float nex_chargepool_pauseregen_finished;
99 float w_nex(float req)
100 {
101         float dt;
102         float ammo_amount;
103         if (req == WR_AIM)
104         {
105                 self.BUTTON_ATCK = bot_aim(1000000, 0, 1, FALSE);
106                 self.BUTTON_ATCK2 = bot_aim(1000000, 0, 1, FALSE);
107         }
108         else if (req == WR_THINK)
109         {
110                 if(autocvar_g_balance_nex_charge && self.nex_charge < autocvar_g_balance_nex_charge_limit)
111                         self.nex_charge = min(1, self.nex_charge + autocvar_g_balance_nex_charge_rate * frametime / W_TICSPERFRAME);
112
113                 if(autocvar_g_balance_nex_secondary_chargepool)
114                         if(self.nex_chargepool_ammo < 1)
115                         {
116                                 if(self.nex_chargepool_pauseregen_finished < time)
117                                         self.nex_chargepool_ammo = min(1, self.nex_chargepool_ammo + autocvar_g_balance_nex_secondary_chargepool_regen * frametime / W_TICSPERFRAME);
118                                 self.pauseregen_finished = max(self.pauseregen_finished, time + autocvar_g_balance_nex_secondary_chargepool_pause_health_regen);
119                         }
120
121                 if(autocvar_g_balance_nex_reload_ammo && self.clip_load < min(autocvar_g_balance_nex_primary_ammo, autocvar_g_balance_nex_secondary_ammo)) // forced reload
122                         W_Nex_Reload();
123                 else
124                 {
125                         if (self.BUTTON_ATCK)
126                         {
127                                 if (weapon_prepareattack(0, autocvar_g_balance_nex_primary_refire))
128                                 {
129                                         W_Nex_Attack(0);
130                                         weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_primary_animtime, w_ready);
131                                 }
132                         }
133                         if ((autocvar_g_balance_nex_secondary_charge && !autocvar_g_balance_nex_secondary) ? self.BUTTON_ZOOM : self.BUTTON_ATCK2)
134                         {
135                                 if(autocvar_g_balance_nex_secondary_charge)
136                                 {
137                                         self.nex_charge_rottime = time + autocvar_g_balance_nex_charge_rot_pause;
138                                         dt = frametime / W_TICSPERFRAME;
139
140                                         if(self.nex_charge < 1)
141                                         {
142                                                 if(autocvar_g_balance_nex_secondary_chargepool)
143                                                 {
144                                                         if(autocvar_g_balance_nex_secondary_ammo)
145                                                         {
146                                                                 // always deplete if secondary is held
147                                                                 self.nex_chargepool_ammo = max(0, self.nex_chargepool_ammo - autocvar_g_balance_nex_secondary_ammo * dt);
148
149                                                                 dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
150                                                                 self.nex_chargepool_pauseregen_finished = time + autocvar_g_balance_nex_secondary_chargepool_pause_regen;
151                                                                 dt = min(dt, self.nex_chargepool_ammo);
152                                                                 dt = max(0, dt);
153
154                                                                 self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
155                                                         }
156                                                 }
157
158                                                 else if(autocvar_g_balance_nex_secondary_ammo)
159                                                 {
160                                                         if(self.BUTTON_ATCK2) // only eat ammo when the button is pressed
161                                                         {
162                                                                 dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
163                                                                 if not(self.items & IT_UNLIMITED_WEAPON_AMMO)
164                                                                 {
165                                                                         // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
166                                                                         if(autocvar_g_balance_nex_reload_ammo)
167                                                                         {
168                                                                                 dt = min(dt, (self.clip_load - autocvar_g_balance_nex_primary_ammo) / autocvar_g_balance_nex_secondary_ammo);
169                                                                                 dt = max(0, dt);
170                                                                                 if(dt > 0)
171                                                                                 {
172                                                                                         self.clip_load = max(autocvar_g_balance_nex_secondary_ammo, self.clip_load - autocvar_g_balance_nex_secondary_ammo * dt);
173                                                                                 }
174                                                                                 self.weapon_load[WEP_NEX] = self.clip_load;
175                                                                         }
176                                                                         else
177                                                                         {
178                                                                                 dt = min(dt, (self.ammo_cells - autocvar_g_balance_nex_primary_ammo) / autocvar_g_balance_nex_secondary_ammo);
179                                                                                 dt = max(0, dt);
180                                                                                 if(dt > 0)
181                                                                                 {
182                                                                                         self.ammo_cells = max(autocvar_g_balance_nex_secondary_ammo, self.ammo_cells - autocvar_g_balance_nex_secondary_ammo * dt);
183                                                                                 }
184                                                                         }
185                                                                 }
186                                                                 self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
187                                                         }
188                                                 }
189
190                                                 else
191                                                 {
192                                                         dt = min(dt, (1 - self.nex_charge) / autocvar_g_balance_nex_secondary_charge_rate);
193                                                         self.nex_charge += dt * autocvar_g_balance_nex_secondary_charge_rate;
194                                                 }
195                                         }
196                                 }
197                                 else if(autocvar_g_balance_nex_secondary)
198                                 {
199                                         if (weapon_prepareattack(0, autocvar_g_balance_nex_secondary_refire))
200                                         {
201                                                 W_Nex_Attack(1);
202                                                 weapon_thinkf(WFRAME_FIRE1, autocvar_g_balance_nex_secondary_animtime, w_ready);
203                                         }
204                                 }
205                         }
206                 }
207
208                 if(autocvar_g_balance_nex_charge)
209                 {
210                         self.weaponentity_glowmod_x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
211                         self.weaponentity_glowmod_y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
212                         self.weaponentity_glowmod_z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, self.nex_charge / autocvar_g_balance_nex_charge_animlimit);
213
214                         if(self.nex_charge > autocvar_g_balance_nex_charge_animlimit)
215                         {
216                                 self.weaponentity_glowmod_x = self.weaponentity_glowmod_x + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
217                                 self.weaponentity_glowmod_y = self.weaponentity_glowmod_y + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
218                                 self.weaponentity_glowmod_z = self.weaponentity_glowmod_z + autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (self.nex_charge - autocvar_g_balance_nex_charge_animlimit) / (1 - autocvar_g_balance_nex_charge_animlimit);
219                         }
220                 }
221         }
222         else if (req == WR_PRECACHE)
223         {
224                 precache_model ("models/nexflash.md3");
225                 precache_model ("models/weapons/g_nex.md3");
226                 precache_model ("models/weapons/v_nex.md3");
227                 precache_model ("models/weapons/h_nex.iqm");
228                 precache_sound ("weapons/nexfire.wav");
229                 precache_sound ("weapons/nexcharge.wav");
230                 precache_sound ("weapons/nexwhoosh1.wav");
231                 precache_sound ("weapons/nexwhoosh2.wav");
232                 precache_sound ("weapons/nexwhoosh3.wav");
233                 precache_sound ("weapons/reload.wav");
234         }
235         else if (req == WR_SETUP)
236         {
237                 weapon_setup(WEP_NEX);
238         }
239         else if (req == WR_CHECKAMMO1)
240         {
241                 ammo_amount = self.ammo_cells >= autocvar_g_balance_nex_primary_ammo;
242                 ammo_amount += (autocvar_g_balance_nex_reload_ammo && self.weapon_load[WEP_NEX] >= autocvar_g_balance_nex_primary_ammo);
243                 return ammo_amount;
244         }
245         else if (req == WR_CHECKAMMO2)
246         {
247                 // don't allow charging if we don't have enough ammo
248                 ammo_amount = self.ammo_cells >= autocvar_g_balance_nex_secondary_ammo;
249                 ammo_amount += self.weapon_load[WEP_NEX] >= autocvar_g_balance_nex_secondary_ammo;
250                 return ammo_amount;
251         }
252         else if (req == WR_RELOAD)
253         {
254                 W_Nex_Reload();
255         }
256
257         return TRUE;
258 };
259 #endif
260 #ifdef CSQC
261 float w_nex(float req)
262 {
263         if(req == WR_IMPACTEFFECT)
264         {
265                 vector org2;
266                 org2 = w_org + w_backoff * 6;
267                 pointparticles(particleeffectnum("nex_impact"), org2, '0 0 0', 1);
268                 if(!w_issilent)
269                         sound(self, CHAN_PROJECTILE, "weapons/neximpact.wav", VOL_BASE, ATTN_NORM);
270         }
271         else if(req == WR_PRECACHE)
272         {
273                 precache_sound("weapons/neximpact.wav");
274         }
275         else if (req == WR_SUICIDEMESSAGE)
276                 w_deathtypestring = _("%s did the impossible");
277         else if (req == WR_KILLMESSAGE)
278                 w_deathtypestring = _("%s has been vaporized by %s");
279         return TRUE;
280 }
281 #endif
282 #endif