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