]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/w_arc.qc
Begin fixing ammo field usage
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / weapons / w_arc.qc
1 #ifdef REGISTER_WEAPON
2 REGISTER_WEAPON(
3 /* WEP_##id */ ARC,
4 /* function */ w_arc,
5 /* ammotype */ ammo_cells,
6 /* impulse  */ 5,
7 /* flags    */ WEP_FLAG_NORMAL,
8 /* rating   */ BOT_PICKUP_RATING_HIGH,
9 /* model    */ "arc",
10 /* netname  */ "arc",
11 /* fullname */ _("Arc")
12 );
13
14 #define ARC_SETTINGS(w_cvar,w_prop) ARC_SETTINGS_LIST(w_cvar, w_prop, ARC, arc)
15 #define ARC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
16         w_cvar(id, sn, MO_BOTH, ammo) \
17         w_cvar(id, sn, MO_PRI,  animtime) \
18         w_cvar(id, sn, MO_PRI,  damage) \
19         w_cvar(id, sn, MO_PRI,  falloff_halflifedist) \
20         w_cvar(id, sn, MO_PRI,  falloff_maxdist) \
21         w_cvar(id, sn, MO_PRI,  falloff_mindist) \
22         w_cvar(id, sn, MO_PRI,  force) \
23         w_cvar(id, sn, MO_PRI,  range) \
24         w_cvar(id, sn, MO_PRI,  refire) \
25         w_prop(id, sn, float,  reloading_ammo, reload_ammo) \
26         w_prop(id, sn, float,  reloading_time, reload_time) \
27         w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
28         w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
29         w_prop(id, sn, string, weaponreplace, weaponreplace) \
30         w_prop(id, sn, float,  weaponstart, weaponstart) \
31         w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride)
32
33 #ifndef MENUQC
34 vector arc_shotorigin[4];
35 #endif
36 #ifdef SVQC
37 ARC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
38 void ArcInit();
39 .vector hook_start, hook_end; // used for beam
40 .entity arc_beam; // used for beam
41 .float BUTTON_ATCK_prev; // for better animation control
42 .float lg_fire_prev; // for better animation control
43 #endif
44 #else
45 #ifdef SVQC
46 void spawnfunc_weapon_arc() { weapon_defaultspawnfunc(WEP_ARC); }
47
48 float W_Arc_Beam_Send(entity to, float sf)
49 {
50         WriteByte(MSG_ENTITY, ENT_CLIENT_ARC_BEAM);
51         sf = sf & 0x7F;
52         if(sound_allowed(MSG_BROADCAST, self.owner))
53                 sf |= 0x80;
54         WriteByte(MSG_ENTITY, sf);
55         if(sf & 1)
56         {
57                 WriteByte(MSG_ENTITY, num_for_edict(self.owner));
58                 WriteCoord(MSG_ENTITY, WEP_CVAR_PRI(arc, range));
59         }
60         if(sf & 2)
61         {
62                 WriteCoord(MSG_ENTITY, self.hook_start_x);
63                 WriteCoord(MSG_ENTITY, self.hook_start_y);
64                 WriteCoord(MSG_ENTITY, self.hook_start_z);
65         }
66         if(sf & 4)
67         {
68                 WriteCoord(MSG_ENTITY, self.hook_end_x);
69                 WriteCoord(MSG_ENTITY, self.hook_end_y);
70                 WriteCoord(MSG_ENTITY, self.hook_end_z);
71         }
72         return TRUE;
73 }
74
75 void W_Arc_Beam_Think()
76 {
77         self.owner.lg_fire_prev = time;
78         if (self != self.owner.arc_beam)
79         {
80                 remove(self);
81                 return;
82         }
83         if (self.owner.weaponentity.state != WS_INUSE || (self.owner.ammo_cells <= 0 && !(self.owner.items & IT_UNLIMITED_WEAPON_AMMO)) || self.owner.deadflag != DEAD_NO || !self.owner.BUTTON_ATCK || self.owner.freezetag_frozen)
84         {
85                 if(self == self.owner.arc_beam)
86                         self.owner.arc_beam = world;
87                 remove(self);
88                 return;
89         }
90
91         self.nextthink = time;
92
93         makevectors(self.owner.v_angle);
94
95         float dt, f;
96         dt = frametime;
97         if(!(self.owner.items & IT_UNLIMITED_WEAPON_AMMO))
98         {
99                 if(WEP_CVAR_PRI(arc, ammo))
100                 {
101                         dt = min(dt, self.owner.ammo_cells / WEP_CVAR_PRI(arc, ammo));
102                         self.owner.ammo_cells = max(0, self.owner.ammo_cells - WEP_CVAR_PRI(arc, ammo) * frametime);
103                 }
104         }
105
106         W_SetupShot_Range(self.owner, TRUE, 0, "", 0, WEP_CVAR_PRI(arc, damage) * dt, WEP_CVAR_PRI(arc, range));
107         WarpZone_traceline_antilag(self.owner, w_shotorg, w_shotend, MOVE_NORMAL, self.owner, ANTILAG_LATENCY(self.owner));
108
109         // apply the damage
110         if(trace_ent)
111         {
112                 vector force;
113                 force = w_shotdir * WEP_CVAR_PRI(arc, force);
114
115                 f = ExponentialFalloff(WEP_CVAR_PRI(arc, falloff_mindist), WEP_CVAR_PRI(arc, falloff_maxdist), WEP_CVAR_PRI(arc, falloff_halflifedist), vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos) - w_shotorg));
116
117                 if(accuracy_isgooddamage(self.owner, trace_ent))
118                         accuracy_add(self.owner, WEP_ARC, 0, WEP_CVAR_PRI(arc, damage) * dt * f);
119                 Damage (trace_ent, self.owner, self.owner, WEP_CVAR_PRI(arc, damage) * dt * f, WEP_ARC, trace_endpos, force * dt);
120         }
121
122         // draw effect
123         if(w_shotorg != self.hook_start)
124         {
125                 self.SendFlags |= 2;
126                 self.hook_start = w_shotorg;
127         }
128         if(w_shotend != self.hook_end)
129         {
130                 self.SendFlags |= 4;
131                 self.hook_end = w_shotend;
132         }
133 }
134
135 // Attack functions ========================= 
136 void W_Arc_Attack1 (void)
137 {
138         // only play fire sound if 0.5 sec has passed since player let go the fire button
139         if(time - self.lg_fire_prev > 0.5)
140                 sound (self, CH_WEAPON_A, "weapons/lgbeam_fire.wav", VOL_BASE, ATTN_NORM);
141
142         entity beam, oldself;
143
144         self.arc_beam = beam = spawn();
145         beam.classname = "W_Arc_Beam";
146         beam.solid = SOLID_NOT;
147         beam.think = W_Arc_Beam_Think;
148         beam.owner = self;
149         beam.movetype = MOVETYPE_NONE;
150         beam.shot_spread = 1;
151         beam.bot_dodge = TRUE;
152         beam.bot_dodgerating = WEP_CVAR_PRI(arc, damage);
153         Net_LinkEntity(beam, FALSE, 0, W_Arc_Beam_Send);
154
155         oldself = self;
156         self = beam;
157         self.think();
158         self = oldself;
159 }
160
161 float w_arc(float req)
162 {
163         switch(req)
164         {
165                 case WR_AIM:
166                 {
167                         self.BUTTON_ATCK = bot_aim(1000000, 0, 0.001, FALSE);
168                         /*
169                         self.BUTTON_ATCK=FALSE;
170                         self.BUTTON_ATCK2=FALSE;
171                         if(vlen(self.origin-self.enemy.origin) > 1000)
172                                 self.bot_aim_whichfiretype = 0;
173                         if(self.bot_aim_whichfiretype == 0)
174                         {
175                                 float shoot;
176
177                                 if(autocvar_g_balance_arc_primary_speed)
178                                         shoot = bot_aim(autocvar_g_balance_arc_primary_speed, 0, autocvar_g_balance_arc_primary_lifetime, FALSE);
179                                 else
180                                         shoot = bot_aim(1000000, 0, 0.001, FALSE);
181
182                                 if(shoot)
183                                 {
184                                         self.BUTTON_ATCK = TRUE;
185                                         if(random() < 0.01) self.bot_aim_whichfiretype = 1;
186                                 }
187                         }
188                         else // todo
189                         {
190                                 //if(bot_aim(autocvar_g_balance_arc_secondary_speed, autocvar_g_balance_grenadelauncher_secondary_speed_up, autocvar_g_balance_arc_secondary_lifetime, TRUE))
191                                 //{
192                                 //      self.BUTTON_ATCK2 = TRUE;
193                                 //      if(random() < 0.03) self.bot_aim_whichfiretype = 0;
194                                 //}
195                         }
196                         */
197                         
198                         return TRUE;
199                 }
200                 case WR_THINK:
201                 {
202                         if (self.BUTTON_ATCK)
203                         {
204                                 if(self.BUTTON_ATCK_prev) // TODO: Find another way to implement this!
205                                         /*if(self.animstate_startframe == self.anim_shoot_x && self.animstate_numframes == self.anim_shoot_y)
206                                                 weapon_thinkf(WFRAME_DONTCHANGE, autocvar_g_balance_arc_primary_animtime, w_ready);
207                                         else*/
208                                                 weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(arc, animtime), w_ready);
209                                 
210                                 if (weapon_prepareattack(0, 0))
211                                 {
212                                         if ((!self.arc_beam) || wasfreed(self.arc_beam))
213                                                 W_Arc_Attack1();
214                                         
215                                         if(!self.BUTTON_ATCK_prev)
216                                         {
217                                                 weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(arc, animtime), w_ready);
218                                                 self.BUTTON_ATCK_prev = 1;
219                                         }
220                                 }
221                         } 
222                         else // todo
223                         {
224                                 if (self.BUTTON_ATCK_prev != 0)
225                                 {
226                                         weapon_thinkf(WFRAME_FIRE1, WEP_CVAR_PRI(arc, animtime), w_ready);
227                                         ATTACK_FINISHED(self) = time + WEP_CVAR_PRI(arc, refire) * W_WeaponRateFactor();
228                                 }
229                                 self.BUTTON_ATCK_prev = 0;
230                         }
231
232                         //if (self.BUTTON_ATCK2)
233                                 //if (weapon_prepareattack(1, autocvar_g_balance_arc_secondary_refire))
234                                 //{
235                                 //      W_Arc_Attack2();
236                                 //      self.arc_count = autocvar_g_balance_arc_secondary_count;
237                                 //      weapon_thinkf(WFRAME_FIRE2, autocvar_g_balance_arc_secondary_animtime, w_arc_checkattack);
238                                 //      self.arc_secondarytime = time + autocvar_g_balance_arc_secondary_refire2 * W_WeaponRateFactor();
239                                 //}
240                                 
241                         return TRUE;
242                 }
243                 case WR_INIT:
244                 {
245                         precache_model ("models/weapons/g_arc.md3");
246                         precache_model ("models/weapons/v_arc.md3");
247                         precache_model ("models/weapons/h_arc.iqm");
248                         //precache_sound ("weapons/arc_bounce.wav");
249                         precache_sound ("weapons/arc_fire.wav");
250                         precache_sound ("weapons/arc_fire2.wav");
251                         precache_sound ("weapons/arc_impact.wav");
252                         //precache_sound ("weapons/arc_impact_combo.wav");
253                         //precache_sound ("weapons/W_Arc_Beam_fire.wav");
254                         return TRUE;
255                 }
256                 case WR_CHECKAMMO1:
257                 {
258                         return !WEP_CVAR_PRI(arc, ammo) || (self.ammo_cells > 0);
259                 }
260                 case WR_CHECKAMMO2:
261                 {
262                         return self.ammo_cells >= WEP_CVAR_SEC(arc, ammo);
263                 }
264                 case WR_CONFIG:
265                 {
266                         ARC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS)
267                         return TRUE;
268                 }
269                 case WR_KILLMESSAGE:
270                 {
271                         if(w_deathtype & HITTYPE_SECONDARY)
272                         {
273                                 return WEAPON_ELECTRO_MURDER_ORBS;
274                         }
275                         else
276                         {
277                                 if(w_deathtype & HITTYPE_BOUNCE)
278                                         return WEAPON_ELECTRO_MURDER_COMBO;
279                                 else
280                                         return WEAPON_ELECTRO_MURDER_BOLT;
281                         }
282                 }
283                 case WR_RESETPLAYER:
284                 {
285                         //self.arc_secondarytime = time;
286                         return TRUE;
287                 }
288         }
289         return TRUE;
290 }
291
292 void ArcInit()
293 {
294         WEP_ACTION(WEP_ARC, WR_INIT);
295         arc_shotorigin[0] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC), FALSE, FALSE, 1);
296         arc_shotorigin[1] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC), FALSE, FALSE, 2);
297         arc_shotorigin[2] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC), FALSE, FALSE, 3);
298         arc_shotorigin[3] = shotorg_adjust_values(CL_Weapon_GetShotOrg(WEP_ARC), FALSE, FALSE, 4);
299         ARC_SETTINGS(WEP_SKIPCVAR, WEP_SET_PROP)
300 }
301 #endif
302 #ifdef CSQC
303 float w_arc(float req)
304 {
305         switch(req)
306         {
307                 case WR_IMPACTEFFECT:
308                 {
309                         vector org2;
310                         org2 = w_org + w_backoff * 6;
311                         
312                         if(w_deathtype & HITTYPE_SECONDARY)
313                         {
314                                 pointparticles(particleeffectnum("arc_ballexplode"), org2, '0 0 0', 1);
315                                 if(!w_issilent)
316                                         sound(self, CH_SHOTS, "weapons/arc_impact.wav", VOL_BASE, ATTN_NORM);
317                         }
318                         else
319                         {
320                                 pointparticles(particleeffectnum("arc_impact"), org2, '0 0 0', 1);
321                                 if(!w_issilent)
322                                         sound(self, CH_SHOTS, "weapons/arc_impact.wav", VOL_BASE, ATTN_NORM);
323                         }
324                         
325                         return TRUE;
326                 }
327                 case WR_INIT:
328                 {
329                         precache_sound("weapons/arc_impact.wav");
330                         precache_sound("weapons/arc_impact_combo.wav");
331                         return TRUE;
332                 }
333         }
334         return TRUE;
335 }
336 #endif
337 #endif