]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/weapons/w_arc.qc
Make it so that weapon zoom reticles are in weapon code, not view code
[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 /* model    */ "arc",
11 /* netname  */ "arc",
12 /* fullname */ _("Arc")
13 );
14
15 #define ARC_SETTINGS(w_cvar,w_prop) ARC_SETTINGS_LIST(w_cvar, w_prop, ARC, arc)
16 #define ARC_SETTINGS_LIST(w_cvar,w_prop,id,sn) \
17         w_cvar(id, sn, BOTH, ammo) \
18         w_cvar(id, sn, PRI,  animtime) \
19         w_cvar(id, sn, PRI,  damage) \
20         w_cvar(id, sn, PRI,  falloff_halflifedist) \
21         w_cvar(id, sn, PRI,  falloff_maxdist) \
22         w_cvar(id, sn, PRI,  falloff_mindist) \
23         w_cvar(id, sn, PRI,  force) \
24         w_cvar(id, sn, PRI,  range) \
25         w_cvar(id, sn, PRI,  refire) \
26         w_prop(id, sn, float,  switchdelay_raise, switchdelay_raise) \
27         w_prop(id, sn, float,  switchdelay_drop, switchdelay_drop) \
28         w_prop(id, sn, string, weaponreplace, weaponreplace) \
29         w_prop(id, sn, float,  weaponstart, weaponstart) \
30         w_prop(id, sn, float,  weaponstartoverride, weaponstartoverride)
31
32 #ifndef MENUQC
33 vector arc_shotorigin[4];
34 #endif
35 #ifdef SVQC
36 ARC_SETTINGS(WEP_ADD_CVAR, WEP_ADD_PROP)
37 void ArcInit();
38 .vector hook_start, hook_end; // used for beam
39 .entity arc_beam; // used for beam
40 .float BUTTON_ATCK_prev; // for better animation control
41 .float lg_fire_prev; // for better animation control
42 #endif
43 #else
44 #ifdef SVQC
45 void spawnfunc_weapon_arc() { weapon_defaultspawnfunc(WEP_ARC); }
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_VAL(WEP_ARC) <= 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(!(self.owner.items & IT_UNLIMITED_WEAPON_AMMO))
97         {
98                 if(WEP_CVAR_PRI(arc, ammo))
99                 {
100                         dt = min(dt, self.owner.AMMO_VAL(WEP_ARC) / WEP_CVAR_PRI(arc, ammo));
101                         self.owner.AMMO_VAL(WEP_ARC) = max(0, self.owner.AMMO_VAL(WEP_ARC) - 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_INIT:
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_CHECKAMMO1:
256                 {
257                         return !WEP_CVAR_PRI(arc, ammo) || (self.AMMO_VAL(WEP_ARC) > 0);
258                 }
259                 case WR_CHECKAMMO2:
260                 {
261                         return self.AMMO_VAL(WEP_ARC) >= WEP_CVAR_SEC(arc, ammo);
262                 }
263                 case WR_CONFIG:
264                 {
265                         ARC_SETTINGS(WEP_CONFIG_WRITE_CVARS, WEP_CONFIG_WRITE_PROPS)
266                         return TRUE;
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         WEP_ACTION(WEP_ARC, WR_INIT);
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         ARC_SETTINGS(WEP_SKIPCVAR, WEP_SET_PROP)
299 }
300 #endif
301 #ifdef CSQC
302 float W_Arc(float req)
303 {
304         switch(req)
305         {
306                 case WR_IMPACTEFFECT:
307                 {
308                         vector org2;
309                         org2 = w_org + w_backoff * 6;
310                         
311                         if(w_deathtype & HITTYPE_SECONDARY)
312                         {
313                                 pointparticles(particleeffectnum("arc_ballexplode"), org2, '0 0 0', 1);
314                                 if(!w_issilent)
315                                         sound(self, CH_SHOTS, "weapons/arc_impact.wav", VOL_BASE, ATTN_NORM);
316                         }
317                         else
318                         {
319                                 pointparticles(particleeffectnum("arc_impact"), org2, '0 0 0', 1);
320                                 if(!w_issilent)
321                                         sound(self, CH_SHOTS, "weapons/arc_impact.wav", VOL_BASE, ATTN_NORM);
322                         }
323                         
324                         return TRUE;
325                 }
326                 case WR_INIT:
327                 {
328                         precache_sound("weapons/arc_impact.wav");
329                         precache_sound("weapons/arc_impact_combo.wav");
330                         return TRUE;
331                 }
332                 case WR_ZOOMRETICLE:
333                 {
334                         // no weapon specific image for this weapon
335                         return FALSE;
336                 }
337         }
338         return TRUE;
339 }
340 #endif
341 #endif