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