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