Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
rifle.qc
Go to the documentation of this file.
1#include "rifle.qh"
2
3#ifdef SVQC
4
5void W_Rifle_FireBullet(Weapon thiswep, .entity weaponentity, int deathtype, Sound pSound, entity actor, bool isprimary)
6{
7 float pAmmo = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, ammo);
8 float pDamage = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, damage);
9 float pDF_HalfLife = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, damagefalloff_halflife);
10 float pDF_ForceHalfLife = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, damagefalloff_forcehalflife);
11 float pDF_MaxDist = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, damagefalloff_maxdist);
12 float pDF_MinDist = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, damagefalloff_mindist);
13 float pForce = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, force);
14 float pHeadshotDamage = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, headshot_multiplier);
15 float pShots = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, shots);
16 float pSolidPenetration = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, solidpenetration);
17 float pSpread = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, spread);
18 float pTracer = WEP_CVAR_BOTH(WEP_RIFLE, isprimary, tracer);
19
20 W_DecreaseAmmo(thiswep, actor, pAmmo, weaponentity);
21
22 W_SetupShot(actor, weaponentity, true, 2, pSound, CH_WEAPON_A, pDamage * pShots, deathtype);
23
24 W_MuzzleFlash(thiswep, actor, weaponentity, w_shotorg, w_shotdir * 2);
25
26 if(PHYS_INPUT_BUTTON_ZOOM(actor) | PHYS_INPUT_BUTTON_ZOOMSCRIPT(actor)) // if zoomed, shoot from the eye
27 {
29 w_shotorg = actor.origin + actor.view_ofs + ((w_shotorg - actor.origin - actor.view_ofs) * v_forward) * v_forward;
30 }
31
32 for(int i = 0; i < pShots; ++i)
33 fireBullet_falloff(actor, weaponentity, w_shotorg, w_shotdir, pSpread,
34 pSolidPenetration, pDamage, pDF_HalfLife, pDF_MinDist,
35 pDF_MaxDist, pHeadshotDamage, pForce, pDF_ForceHalfLife,
36 deathtype, (pTracer ? EFFECT_RIFLE : EFFECT_RIFLE_WEAK), true);
37
38 if(autocvar_g_casings >= 2)
39 {
40 makevectors(actor.v_angle); // for some reason, this is lost
41 SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), vectoangles(v_forward), 3, actor, weaponentity);
42 }
43}
44
45void W_Rifle_Attack(Weapon thiswep, entity actor, .entity weaponentity)
46{
47 W_Rifle_FireBullet(thiswep, weaponentity, thiswep.m_id, SND_RIFLE_FIRE, actor, true);
48}
49
50void W_Rifle_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
51{
52 W_Rifle_FireBullet(thiswep, weaponentity, thiswep.m_id | HITTYPE_SECONDARY, SND_RIFLE_FIRE2, actor, false);
53}
54
55.void(Weapon thiswep, entity actor, .entity weaponentity) rifle_bullethail_attackfunc;
59void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor, .entity weaponentity, int fire)
60{
61 float r, af;
62
63 Weapon sw = actor.(weaponentity).m_switchweapon; // make it not detect weapon changes as reason to abort firing
64 af = ATTACK_FINISHED(actor, weaponentity);
65 actor.(weaponentity).m_switchweapon = actor.(weaponentity).m_weapon;
66 ATTACK_FINISHED(actor, weaponentity) = time;
67 r = weapon_prepareattack(thiswep, actor, weaponentity, actor.rifle_bullethail_frame == WFRAME_FIRE2, actor.rifle_bullethail_refire);
68 if(actor.(weaponentity).m_switchweapon == actor.(weaponentity).m_weapon)
69 actor.(weaponentity).m_switchweapon = sw;
70 if(r)
71 {
72 actor.rifle_bullethail_attackfunc(thiswep, actor, weaponentity);
73 weapon_thinkf(actor, weaponentity, actor.rifle_bullethail_frame, actor.rifle_bullethail_animtime, W_Rifle_BulletHail_Continue);
74 }
75 else
76 {
77 ATTACK_FINISHED(actor, weaponentity) = af; // reset attack_finished if we didn't fire, so the last shot enforces the refire time
78 }
79}
80
81void W_Rifle_BulletHail(Weapon thiswep, entity actor, .entity weaponentity, float mode, void(Weapon thiswep, entity actor, .entity weaponentity) AttackFunc, WFRAME fr, float animtime, float refire)
82{
83 // if we get here, we have at least one bullet to fire
84 AttackFunc(thiswep, actor, weaponentity);
85 if(mode)
86 {
87 // continue hail
88 actor.rifle_bullethail_attackfunc = AttackFunc;
89 actor.rifle_bullethail_frame = fr;
90 actor.rifle_bullethail_animtime = animtime;
91 actor.rifle_bullethail_refire = refire;
92 weapon_thinkf(actor, weaponentity, fr, animtime, W_Rifle_BulletHail_Continue);
93 }
94 else
95 {
96 // just one shot
97 weapon_thinkf(actor, weaponentity, fr, animtime, w_ready);
98 }
99}
100
102
103METHOD(Rifle, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
104{
105 PHYS_INPUT_BUTTON_ATCK(actor) = false;
106 PHYS_INPUT_BUTTON_ATCK2(actor) = false;
107 if(vdist(actor.origin - actor.enemy.origin, >, 1000))
108 actor.bot_secondary_riflemooth = 0;
109 if(actor.bot_secondary_riflemooth == 0)
110 {
111 if(bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true))
112 {
113 PHYS_INPUT_BUTTON_ATCK(actor) = true;
114 if(random() < 0.01) actor.bot_secondary_riflemooth = 1;
115 }
116 }
117 else
118 {
119 if(bot_aim(actor, weaponentity, 1000000, 0, 0.001, false, true))
120 {
121 PHYS_INPUT_BUTTON_ATCK2(actor) = true;
122 if(random() < 0.03) actor.bot_secondary_riflemooth = 0;
123 }
124 }
125}
126
127METHOD(Rifle, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
128{
129 if(autocvar_g_balance_rifle_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR_PRI(WEP_RIFLE, ammo), WEP_CVAR_SEC(WEP_RIFLE, ammo)))
130 { // forced reload
131 thiswep.wr_reload(thiswep, actor, weaponentity);
132 }
133 else
134 {
135 actor.(weaponentity).rifle_accumulator = bound(time - WEP_CVAR(WEP_RIFLE, bursttime), actor.(weaponentity).rifle_accumulator, time);
136 if(fire & 1)
137 if(weapon_prepareattack_check(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(WEP_RIFLE, refire)))
138 if(time >= actor.(weaponentity).rifle_accumulator + WEP_CVAR_PRI(WEP_RIFLE, burstcost))
139 {
140 weapon_prepareattack_do(actor, weaponentity, false, WEP_CVAR_PRI(WEP_RIFLE, refire));
141 W_Rifle_BulletHail(thiswep, actor, weaponentity, WEP_CVAR_PRI(WEP_RIFLE, bullethail), W_Rifle_Attack, WFRAME_FIRE1, WEP_CVAR_PRI(WEP_RIFLE, animtime), WEP_CVAR_PRI(WEP_RIFLE, refire));
142 actor.(weaponentity).rifle_accumulator += WEP_CVAR_PRI(WEP_RIFLE, burstcost);
143 }
144 if(fire & 2)
145 {
146 if(WEP_CVAR(WEP_RIFLE, secondary))
147 {
148 if(WEP_CVAR_SEC(WEP_RIFLE, reload)) {
149 thiswep.wr_reload(thiswep, actor, weaponentity);
150 }
151 else
152 {
153 if(weapon_prepareattack_check(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(WEP_RIFLE, refire)))
154 if(time >= actor.(weaponentity).rifle_accumulator + WEP_CVAR_SEC(WEP_RIFLE, burstcost))
155 {
156 weapon_prepareattack_do(actor, weaponentity, true, WEP_CVAR_SEC(WEP_RIFLE, refire));
157 W_Rifle_BulletHail(thiswep, actor, weaponentity, WEP_CVAR_SEC(WEP_RIFLE, bullethail), W_Rifle_Attack2, WFRAME_FIRE2, WEP_CVAR_SEC(WEP_RIFLE, animtime), WEP_CVAR_PRI(WEP_RIFLE, refire));
158 actor.(weaponentity).rifle_accumulator += WEP_CVAR_SEC(WEP_RIFLE, burstcost);
159 }
160 }
161 }
162 }
163 }
164}
165
166METHOD(Rifle, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
167{
168 float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(WEP_RIFLE, ammo);
169 ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR_PRI(WEP_RIFLE, ammo);
170 return ammo_amount;
171}
172
173METHOD(Rifle, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
174{
175 float ammo_amount = GetResource(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(WEP_RIFLE, ammo);
176 ammo_amount += actor.(weaponentity).(weapon_load[thiswep.m_id]) >= WEP_CVAR_SEC(WEP_RIFLE, ammo);
177 return ammo_amount;
178}
179
180METHOD(Rifle, wr_resetplayer, void(entity thiswep, entity actor))
181{
182 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
183 {
184 .entity weaponentity = weaponentities[slot];
185 actor.(weaponentity).rifle_accumulator = time - WEP_CVAR(WEP_RIFLE, bursttime);
186 }
187}
188
189METHOD(Rifle, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
190{
191 W_Reload(actor, weaponentity, min(WEP_CVAR_PRI(WEP_RIFLE, ammo), WEP_CVAR_SEC(WEP_RIFLE, ammo)), SND_RELOAD);
192}
193
194METHOD(Rifle, wr_suicidemessage, Notification(entity thiswep))
195{
196 return WEAPON_THINKING_WITH_PORTALS;
197}
198
199METHOD(Rifle, wr_killmessage, Notification(entity thiswep))
200{
202 {
204 return WEAPON_RIFLE_MURDER_HAIL_PIERCING;
205 else
206 return WEAPON_RIFLE_MURDER_HAIL;
207 }
208 else
209 {
211 return WEAPON_RIFLE_MURDER_PIERCING;
212 else
213 return WEAPON_RIFLE_MURDER;
214 }
215}
216
217METHOD(Rifle, wr_zoom, bool(entity thiswep, entity actor))
218{
219 return PHYS_INPUT_BUTTON_ATCK2(actor) && WEP_CVAR(WEP_RIFLE, secondary) == 0;
220}
221
222#endif
223#ifdef CSQC
224
225METHOD(Rifle, wr_impacteffect, void(entity thiswep, entity actor))
226{
227 vector org2 = w_org + w_backoff * 2;
228 pointparticles(EFFECT_RIFLE_IMPACT, org2, w_backoff * 1000, 1);
229 if(!w_issilent)
230 {
232 }
233}
234
235METHOD(Rifle, wr_init, void(entity thiswep))
236{
238 {
239 precache_pic("gfx/reticle_nex");
240 }
241}
242
243METHOD(Rifle, wr_zoom, bool(entity thiswep, entity actor))
244{
246 {
247 return true;
248 }
249 else
250 {
251 // no weapon specific image for this weapon
252 return false;
253 }
254}
255
256METHOD(Rifle, wr_zoomdir, bool(entity thiswep))
257{
258 return button_attack2 && !WEP_CVAR(WEP_RIFLE, secondary);
259}
260
261#endif
262#ifdef MENUQC
264#include "vortex.qh"
265
266METHOD(Rifle, describe, string(Rifle this))
267{
268 TC(Rifle, this);
270 PAR(_("The %s fires bullets that traverse the map instantaneously and deal a significant chunk of damage on impact."), COLORED_NAME(this));
271 PAR(_("The secondary fire shoots a few less powerful bullets at once with a bit of scatter."));
272 PAR(_("It consumes %s ammo for each bullet shot."), COLORED_NAME(ITEM_Bullets)); // shared string
273 PAR(_("Unlike the %s, the secondary fire doesn't zoom, so %s needs to be used manually with the %s. "
274 "Also, it needs to be reloaded after its magazine is emptied."), COLORED_NAME(WEP_VORTEX), strcat("^3", _("zoom"), "^7"), COLORED_NAME(this));
275 PAR(_("Similar to the %s, the %s can be used at any range, but it stands out at long ranges."), COLORED_NAME(WEP_VORTEX), COLORED_NAME(this));
276 PAR(W_Guide_Keybinds(this));
277 PAR(W_Guide_DPS_secondaryMultishot(this.netname, "primary", "secondary", "secondary_shots", "", false));
278 return PAGE_TEXT;
279}
280
281#endif
bool bot_aim(entity this,.entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity, bool shot_accurate)
void SpawnCasing(vector vel, vector ang, int casingtype, entity casingowner,.entity weaponentity)
Definition casings.qc:17
int autocvar_g_casings
Definition casings.qh:17
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition rifle.qh:12
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition weapon.qh:44
int m_id
Definition weapon.qh:45
string netname
Definition powerups.qc:20
bool button_zoom
Definition main.qh:113
bool button_attack2
Definition main.qh:116
#define COLORED_NAME(this)
Definition color.qh:195
#define PHYS_INPUT_BUTTON_ZOOMSCRIPT(s)
Definition player.qh:161
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition player.qh:150
#define PHYS_INPUT_BUTTON_ZOOM(s)
Definition player.qh:153
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition player.qh:152
bool autocvar_cl_reticle_weapon
Definition crosshair.qh:5
bool autocvar_cl_reticle
Definition crosshair.qh:3
vector v_up
float time
vector v_right
vector v_forward
const float ATTN_NORM
vector w_org
int w_deathtype
vector w_backoff
float w_issilent
const int HITTYPE_BOUNCE
Definition all.qh:31
const int HITTYPE_SECONDARY
Definition all.qh:29
#define pointparticles(effect, org, vel, howmany)
Definition effect.qh:7
#define TC(T, sym)
Definition _all.inc:82
float bound(float min, float value, float max)
float random(void)
string precache_pic(string name,...)
vector vectoangles(vector v)
float min(float f,...)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
entity Notification
always last
Definition all.qh:81
#define METHOD(cname, name, prototype)
Definition oo.qh:269
#define makevectors
Definition post.qh:21
WFRAME rifle_bullethail_frame
Definition rifle.qc:56
void W_Rifle_BulletHail_Continue(Weapon thiswep, entity actor,.entity weaponentity, int fire)
Definition rifle.qc:59
void W_Rifle_Attack2(Weapon thiswep, entity actor,.entity weaponentity)
Definition rifle.qc:50
float rifle_bullethail_refire
Definition rifle.qc:58
void W_Rifle_FireBullet(Weapon thiswep,.entity weaponentity, int deathtype, Sound pSound, entity actor, bool isprimary)
Definition rifle.qc:5
float rifle_bullethail_animtime
Definition rifle.qc:57
void W_Rifle_BulletHail(Weapon thiswep, entity actor,.entity weaponentity, float mode, void(Weapon thiswep, entity actor,.entity weaponentity) AttackFunc, WFRAME fr, float animtime, float refire)
Definition rifle.qc:81
float bot_secondary_riflemooth
Definition rifle.qc:101
void W_Rifle_Attack(Weapon thiswep, entity actor,.entity weaponentity)
Definition rifle.qc:45
float rifle_accumulator
Definition rifle.qh:74
vector
Definition self.qh:92
const float VOL_BASE
Definition sound.qh:36
const int CH_SHOTS
Definition sound.qh:14
const int CH_WEAPON_A
Definition sound.qh:7
#define sound(e, c, s, v, a)
Definition sound.qh:52
Sound SND_RIC_RANDOM()
Definition all.inc:33
#define PAGE_TEXT
Definition string.qh:643
#define PAR(...)
Adds an individually translatable paragraph to PAGE_TEXT without having to deal with strcat and sprin...
Definition string.qh:649
#define PAGE_TEXT_INIT()
Definition string.qh:642
float ammo
Definition sv_turrets.qh:43
void fireBullet_falloff(entity this,.entity weaponentity, vector start, vector dir, float spread, float max_solid_penetration, float damage, float falloff_halflife, float falloff_mindist, float falloff_maxdist, float headshot_multiplier, float force, float falloff_forcehalflife, float dtype, entity tracer_effect, bool do_antilag)
Definition tracing.qc:364
vector w_shotdir
Definition tracing.qh:20
vector w_shotorg
Definition tracing.qh:19
#define W_SetupShot(ent, wepent, antilag, recoil, snd, chan, maxdamage, deathtype)
Definition tracing.qh:34
#define vdist(v, cmp, f)
Vector distance comparison, avoids sqrt()
Definition vector.qh:8
float zoomscript_caught
Definition view.qh:121
string W_Guide_Keybinds(Weapon wep)
Definition all.qc:836
string W_Guide_DPS_secondaryMultishot(string name, string pri, string sec, string shots, string refire2, bool sec_variable)
Definition all.qc:967
void W_MuzzleFlash(Weapon thiswep, entity actor,.entity weaponentity, vector shotorg, vector shotdir)
Definition all.qc:728
#define WEP_CVAR_PRI(wep, name)
Definition all.qh:322
#define WEP_CVAR_BOTH(wep, isprimary, name)
Definition all.qh:324
#define WEP_CVAR(wep, name)
Definition all.qh:321
#define WEP_CVAR_SEC(wep, name)
Definition all.qh:323
const int MAX_WEAPONSLOTS
Definition weapon.qh:16
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17
void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use,.entity weaponentity)
void W_Reload(entity actor,.entity weaponentity, float sent_ammo_min, Sound sent_sound)
void weapon_thinkf(entity actor,.entity weaponentity, WFRAME fr, float t, void(Weapon thiswep, entity actor,.entity weaponentity, int fire) func)
bool weapon_prepareattack(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
void w_ready(Weapon thiswep, entity actor,.entity weaponentity, int fire)
void weapon_prepareattack_do(entity actor,.entity weaponentity, bool secondary, float attacktime)
bool weapon_prepareattack_check(Weapon thiswep, entity actor,.entity weaponentity, bool secondary, float attacktime)
#define ATTACK_FINISHED(ent, w)
float weapon_load[REGISTRY_MAX(Weapons)]
Weapon m_switchweapon
Definition wepent.qh:25