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