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