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