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