Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
selection.qc File Reference
Include dependency graph for selection.qc:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Functions

bool client_hasweapon (entity this, Weapon wpn,.entity weaponentity, float andammo, bool complain)
 REPLICATE_APPLYCHANGE ("cl_weaponpriority", for(int slot=0;slot< MAX_WEAPONSLOTS;++slot) { .entity weaponentity=weaponentities[slot];if(this.(weaponentity) &&(this.(weaponentity).m_weapon !=WEP_Null||slot==0)) this.(weaponentity).m_switchweapon=w_getbestweapon(this, weaponentity);})
void Send_WeaponComplain (entity e, float wpn, float type)
 Switch between weapons.
void W_CycleWeapon (entity this, string weaponorder, float dir,.entity weaponentity)
float W_GetCycleWeapon (entity this, string weaponorder, float dir, float imp, bool complain, bool skipmissing,.entity weaponentity)
void W_LastWeapon (entity this,.entity weaponentity)
 Goto previously used if exists and has ammo, (second) best otherwise.
void W_NextWeapon (entity this, int list,.entity weaponentity)
 Goto next weapon.
void W_NextWeaponOnImpulse (entity this, float imp,.entity weaponentity)
void W_PreviousWeapon (entity this, float list,.entity weaponentity)
 Goto prev weapon.
void W_SwitchToOtherWeapon (entity this,.entity weaponentity)
 Perform weapon to attack (weaponstate and attack_finished check is here)
bool W_SwitchWeapon (entity this, Weapon w,.entity weaponentity)
void W_SwitchWeapon_Force (Player this, Weapon wep,.entity weaponentity)
void W_SwitchWeapon_TryOthers (entity this, Weapon w,.entity weaponentity)
void Weapon_whereis (Weapon this, entity cl)

Function Documentation

◆ client_hasweapon()

bool client_hasweapon ( entity this,
Weapon wpn,
.entity weaponentity,
float andammo,
bool complain )

Definition at line 47 of file selection.qc.

48{
50 complain = 0;
51
52 // ignore hook button when using other offhand equipment
53 if (this.offhand != OFFHAND_HOOK
54 && wpn == WEP_HOOK && !((STAT(WEAPONS, this) | weaponsInMap) & WepSet_FromWeapon(wpn)))
55 complain = 0;
56
57 if (complain)
58 CS(this).hasweapon_complain_spam = time + 0.2;
59
60 if (wpn == WEP_Null)
61 {
62 if (complain)
63 sprint(this, "Invalid weapon\n");
64 return false;
65 }
66 if (autocvar_g_weaponswitch_debug == 2 && weaponslot(weaponentity) > 0
67 && !(wpn.spawnflags & WEP_FLAG_DUALWIELD) && !(PS(this).dual_weapons & wpn.m_wepset))
68 return false; // no complaints needed
69
70 float f = 0;
71 if (STAT(WEAPONS, this) & WepSet_FromWeapon(wpn))
72 {
73 if (andammo)
74 {
75 if (this.items & IT_UNLIMITED_AMMO)
76 f = 1;
77 else
78 {
79 f = wpn.wr_checkammo1(wpn, this, weaponentity) + wpn.wr_checkammo2(wpn, this, weaponentity);
80
81 // always allow selecting the Mine Layer if we placed mines, so that we can detonate them
82 if (wpn == WEP_MINE_LAYER)
83 IL_EACH(g_mines, it.owner == this && it.weaponentity_fld == weaponentity,
84 {
85 f = 1;
86 break; // no need to continue
87 });
88 }
89 if (!f)
90 {
91 if (complain && IS_REAL_CLIENT(this))
92 {
93 play2(this, SND(UNAVAILABLE));
94 Send_WeaponComplain (this, wpn.m_id, 0);
95 }
96 return false;
97 }
98 }
99 return true;
100 }
101 if (complain
102 && IS_REAL_CLIENT(this))
103 {
104 // DRESK - 3/16/07
105 // Report Proper Weapon Status / Modified Weapon Ownership Message
107 {
108 Send_WeaponComplain(this, wpn.m_id, 1);
110 Weapon_whereis(wpn, this);
111 else
112 FOREACH(Weapons, it.impulse == wpn.impulse, Weapon_whereis(it, this));
113 }
114 else
115 Send_WeaponComplain(this, wpn.m_id, 2);
116
117 play2(this, SND(UNAVAILABLE));
118 }
119 return false;
120}
int impulse
M: impulse : weapon impulse.
Definition weapon.qh:58
int m_id
Definition weapon.qh:43
virtual void wr_checkammo2()
(SERVER) checks ammo for weapon second
Definition weapon.qh:105
int spawnflags
M: flags : WEPSPAWNFLAG_... combined.
Definition weapon.qh:60
virtual void wr_checkammo1()
(SERVER) checks ammo for weapon primary
Definition weapon.qh:100
const int IT_UNLIMITED_AMMO
Definition item.qh:23
int items
Definition player.qh:226
vector weaponsInMap
all the weapons actually spawned in the map, does not include filtered items
Definition stats.qh:53
OffhandHook OFFHAND_HOOK
Definition hook.qh:83
float time
Weapons
Definition guide.qh:113
#define IL_EACH(this, cond, body)
#define FOREACH(list, cond, body)
Definition iter.qh:19
#define STAT(...)
Definition stats.qh:82
void sprint(float clientnum, string text,...)
IntrusiveList g_mines
Definition minelayer.qh:87
void Send_WeaponComplain(entity e, float wpn, float type)
Switch between weapons.
Definition selection.qc:18
void Weapon_whereis(Weapon this, entity cl)
Definition selection.qc:26
WepSet dual_weapons
Definition selection.qh:12
bool autocvar_g_weaponswitch_debug
Definition selection.qh:7
float hasweapon_complain_spam
Definition selection.qh:17
int autocvar_g_showweaponspawns
Definition selection.qh:6
void play2(entity e, string filename)
Definition all.qc:116
#define SND(id)
Definition all.qh:35
#define PS(this)
Definition state.qh:18
ClientState CS(Client this)
Definition state.qh:47
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
void Weapon_whereis(Weapon this, entity cl)
Definition selection.qc:26
#define WepSet_FromWeapon(it)
Definition all.qh:48
const int WEP_FLAG_DUALWIELD
Definition weapon.qh:264
OffhandWeapon offhand
Definition weapon.qh:241
int weaponslot(.entity weaponentity)
Definition weapon.qh:19

References autocvar_g_showweaponspawns, autocvar_g_weaponswitch_debug, CS(), dual_weapons, entity(), FOREACH, g_mines, hasweapon_complain_spam, IL_EACH, Weapon::impulse, IS_REAL_CLIENT, IT_UNLIMITED_AMMO, items, Weapon::m_id, offhand, OFFHAND_HOOK, play2(), PS, Send_WeaponComplain(), SND, Weapon::spawnflags, sprint(), STAT, time, Weapon_whereis(), Weapons, weaponsInMap, weaponslot(), WEP_FLAG_DUALWIELD, WepSet_FromWeapon, Weapon::wr_checkammo1(), and Weapon::wr_checkammo2().

Referenced by bot_cmd_select_weapon(), GiveItems(), havocbot_chooseweapon(), havocbot_movetogoal(), Item_GiveTo(), NIX_GiveCurrentWeapon(), REGISTER_MUTATOR(), W_LastWeapon(), and W_SwitchWeapon().

◆ REPLICATE_APPLYCHANGE()

REPLICATE_APPLYCHANGE ( "cl_weaponpriority" ,
for(int slot=0;slot< MAX_WEAPONSLOTS;++slot) { .entity weaponentity=weaponentities[slot];if(this.(weaponentity) &&(this.(weaponentity).m_weapon !=WEP_Null||slot==0)) this.(weaponentity).m_switchweapon=w_getbestweapon(this, weaponentity);}  )

◆ Send_WeaponComplain()

void Send_WeaponComplain ( entity e,
float wpn,
float type )

Switch between weapons.

Definition at line 18 of file selection.qc.

19{
20 msg_entity = e;
21 WriteHeader(MSG_ONE, TE_CSQC_WEAPONCOMPLAIN);
22 WriteByte(MSG_ONE, wpn);
23 WriteByte(MSG_ONE, type);
24}
#define WriteHeader(to, id)
Definition net.qh:265
float MSG_ONE
Definition menudefs.qc:56
void WriteByte(float data, float dest, float desto)
entity msg_entity
Definition progsdefs.qc:63

References entity(), msg_entity, MSG_ONE, WriteByte(), and WriteHeader.

Referenced by client_hasweapon().

◆ W_CycleWeapon()

void W_CycleWeapon ( entity this,
string weaponorder,
float dir,
.entity weaponentity )

Definition at line 295 of file selection.qc.

296{
297 float w = W_GetCycleWeapon(this, weaponorder, dir, -1, true, true, weaponentity);
298 if (w > 0)
299 W_SwitchWeapon(this, REGISTRY_GET(Weapons, w), weaponentity);
300}
#define REGISTRY_GET(id, i)
Definition registry.qh:43
bool W_SwitchWeapon(entity this, Weapon w,.entity weaponentity)
Definition selection.qc:265
float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, bool complain, bool skipmissing,.entity weaponentity)
Definition selection.qc:122
int dir
Definition impulse.qc:89
entity weaponorder[REGISTRY_MAX(Weapons)]
Definition weapons.qc:81

References dir, entity(), REGISTRY_GET, W_GetCycleWeapon(), W_SwitchWeapon(), weaponorder, and Weapons.

Referenced by for(), W_NextWeapon(), and W_PreviousWeapon().

◆ W_GetCycleWeapon()

float W_GetCycleWeapon ( entity this,
string weaponorder,
float dir,
float imp,
bool complain,
bool skipmissing,
.entity weaponentity )

Definition at line 122 of file selection.qc.

123{
124 // We cannot tokenize in this function, as GiveItems calls this
125 // function. Thus we must use car/cdr.
126 entity wep;
127 string rest;
128 float weaponwant;
129 float first_valid = 0, prev_valid = 0;
130 float weaponcur;
131 bool switchtonext = false, switchtolast = false;
132
133 if (skipmissing || this.(weaponentity).selectweapon == 0)
134 weaponcur = this.(weaponentity).m_switchweapon.m_id;
135 else
136 weaponcur = this.(weaponentity).selectweapon;
137
138 if (dir == 0)
139 switchtonext = true;
140
141 // complain-specific vars
142 int c = 0;
143 entity wepcomplain = NULL;
144 int wepcomplainindex = 0;
145 bool have_other = false;
146
147 // see if we have or can locate (not hidden), some other weapon in the group
148 WepSet customgroup = '0 0 0';
149 if (imp < 0) // custom cl_weaponpriorityN group
150 {
151 // These groups are client-specific, and (imp == -1) here,
152 // so generate a weapon set bitmask to represent the group.
153 rest = weaponorder;
154 while (rest != "")
155 {
156 weaponwant = stof(car(rest));
157 rest = cdr(rest);
158 customgroup |= REGISTRY_GET(Weapons, weaponwant).m_wepset;
159 }
160 }
161 else
162 {} // standard weapon_group, defined by impulse sharing
163 FOREACH(Weapons, (imp >= 0 && it.impulse == imp) || (imp < 0 && (it.m_wepset & customgroup)),
164 {
165 if ((it.m_wepset & STAT(WEAPONS, this))
166 || ((it.m_wepset & weaponsInMap) && !(it.spawnflags & WEP_FLAG_HIDDEN)))
167 {
168 have_other = true;
169 break;
170 }
171 });
172
173 rest = weaponorder;
174 while (rest != "")
175 {
176 weaponwant = stof(car(rest)); rest = cdr(rest);
177 wep = REGISTRY_GET(Weapons, weaponwant);
178 if (imp >= 0 && wep.impulse != imp)
179 continue;
180
181 // skip weapons we don't own that aren't normal and aren't in the map
182 if (!(STAT(WEAPONS, this) & wep.m_wepset))
183 {
184 if (wep.spawnflags & WEP_FLAG_HIDDEN)
185 continue;
186
187 if (!(weaponsInMap & wep.m_wepset)
188 && ((wep.spawnflags & WEP_FLAG_MUTATORBLOCKED) || have_other))
189 continue;
190 }
191
192 if (complain)
193 {
194 if (!wepcomplain || this.weaponcomplainindex == c)
195 {
196 wepcomplain = wep;
197 wepcomplainindex = c;
198 }
199 ++c;
200 }
201
202 if (!skipmissing || client_hasweapon(this, wep, weaponentity, true, false))
203 {
204 if (switchtonext)
205 return weaponwant;
206 if (!first_valid)
207 first_valid = weaponwant;
208 if (weaponwant == weaponcur)
209 {
210 if (dir >= 0)
211 switchtonext = true;
212 else if (prev_valid)
213 return prev_valid;
214 else
215 switchtolast = true;
216 }
217 prev_valid = weaponwant;
218 }
219 }
220 if (first_valid)
221 {
222 if (switchtolast)
223 return prev_valid;
224 else
225 return first_valid;
226 }
227
228 // complain (but only for one weapon on the button that has been pressed)
229 if (wepcomplain)
230 {
231 this.weaponcomplainindex = wepcomplainindex + 1;
232 client_hasweapon(this, wepcomplain, weaponentity, true, true);
233 }
234 return 0;
235}
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
float stof(string val,...)
#define NULL
Definition post.qh:14
bool client_hasweapon(entity this, Weapon wpn,.entity weaponentity, float andammo, bool complain)
Definition selection.qc:47
int weaponcomplainindex
Definition selection.qh:20
int selectweapon
Definition selection.qh:10
int int int imp
Definition impulse.qc:90
ERASEABLE string car(string s)
returns first word
Definition string.qh:259
ERASEABLE string cdr(string s)
returns all but first word
Definition string.qh:268
const int WEP_FLAG_MUTATORBLOCKED
Definition weapon.qh:261
vector WepSet
Definition weapon.qh:14
const int WEP_FLAG_HIDDEN
Definition weapon.qh:258
Weapon m_switchweapon
Definition wepent.qh:25

References car(), cdr(), dir, entity(), FOREACH, imp, m_switchweapon, NULL, REGISTRY_GET, selectweapon, stof(), weaponorder, and Weapons.

Referenced by W_CycleWeapon(), and W_NextWeaponOnImpulse().

◆ W_LastWeapon()

void W_LastWeapon ( entity this,
.entity weaponentity )

Goto previously used if exists and has ammo, (second) best otherwise.

Definition at line 332 of file selection.qc.

333{
334 Weapon wep = REGISTRY_GET(Weapons, this.(weaponentity).cnt);
335 if (client_hasweapon(this, wep, weaponentity, true, false))
336 W_SwitchWeapon(this, wep, weaponentity);
337 else
338 W_SwitchToOtherWeapon(this, weaponentity);
339}
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition weapon.qh:42
float cnt
Definition powerups.qc:24
void W_SwitchToOtherWeapon(entity this,.entity weaponentity)
Perform weapon to attack (weaponstate and attack_finished check is here)
Definition selection.qc:247

References client_hasweapon(), cnt, entity(), REGISTRY_GET, W_SwitchToOtherWeapon(), W_SwitchWeapon(), and Weapons.

Referenced by IMPULSE().

◆ W_NextWeapon()

void W_NextWeapon ( entity this,
int list,
.entity weaponentity )

Goto next weapon.

Definition at line 310 of file selection.qc.

311{
312 if (list == 0)
313 W_CycleWeapon(this, weaponorder_byid, -1, weaponentity);
314 else if (list == 1)
315 W_CycleWeapon(this, CS_CVAR(this).weaponorder_byimpulse, -1, weaponentity);
316 else if (list == 2)
317 W_CycleWeapon(this, CS_CVAR(this).cvar_cl_weaponpriority, -1, weaponentity);
318}
void W_CycleWeapon(entity this, string weaponorder, float dir,.entity weaponentity)
Definition selection.qc:295
string weaponorder_byimpulse
Definition client.qh:62
#define CS_CVAR(this)
Definition state.qh:51
string weaponorder_byid
Definition weapon.qh:272

References CS_CVAR, entity(), W_CycleWeapon(), weaponorder_byid, and weaponorder_byimpulse.

Referenced by IMPULSE(), IMPULSE(), ObserverOrSpectatorThink(), reset_map(), and X().

◆ W_NextWeaponOnImpulse()

void W_NextWeaponOnImpulse ( entity this,
float imp,
.entity weaponentity )

Definition at line 302 of file selection.qc.

303{
304 float w = W_GetCycleWeapon(this, CS_CVAR(this).cvar_cl_weaponpriority, +1, imp, true, (CS_CVAR(this).cvar_cl_weaponimpulsemode == 0), weaponentity);
305 if (w > 0)
306 W_SwitchWeapon(this, REGISTRY_GET(Weapons, w), weaponentity);
307}

References CS_CVAR, entity(), imp, REGISTRY_GET, W_GetCycleWeapon(), W_SwitchWeapon(), and Weapons.

Referenced by W_SwitchWeapon_TryOthers(), and weapon_group_handle().

◆ W_PreviousWeapon()

void W_PreviousWeapon ( entity this,
float list,
.entity weaponentity )

Goto prev weapon.

Definition at line 321 of file selection.qc.

322{
323 if (list == 0)
324 W_CycleWeapon(this, weaponorder_byid, +1, weaponentity);
325 else if (list == 1)
326 W_CycleWeapon(this, CS_CVAR(this).weaponorder_byimpulse, +1, weaponentity);
327 else if (list == 2)
328 W_CycleWeapon(this, CS_CVAR(this).cvar_cl_weaponpriority, +1, weaponentity);
329}

References CS_CVAR, entity(), W_CycleWeapon(), weaponorder_byid, and weaponorder_byimpulse.

Referenced by IMPULSE(), IMPULSE(), and IMPULSE().

◆ W_SwitchToOtherWeapon()

void W_SwitchToOtherWeapon ( entity this,
.entity weaponentity )

Perform weapon to attack (weaponstate and attack_finished check is here)

Definition at line 247 of file selection.qc.

248{
249 // hack to ensure it switches to an OTHER weapon (in case the other fire mode still has ammo, we want that anyway)
250 Weapon ww;
251 WepSet set = WepSet_FromWeapon(this.(weaponentity).m_weapon);
252 if (STAT(WEAPONS, this) & set)
253 {
254 STAT(WEAPONS, this) &= ~set;
255 ww = w_getbestweapon(this, weaponentity);
256 STAT(WEAPONS, this) |= set;
257 }
258 else
259 ww = w_getbestweapon(this, weaponentity);
260 if (ww == WEP_Null)
261 return;
262 W_SwitchWeapon_Force(this, ww, weaponentity);
263}
void W_SwitchWeapon_Force(Player this, Weapon wep,.entity weaponentity)
Definition selection.qc:237
#define w_getbestweapon(ent, wepent)
Definition selection.qh:23
Weapon m_weapon
Definition wepent.qh:26

References entity(), m_weapon, STAT, w_getbestweapon, W_SwitchWeapon_Force(), and WepSet_FromWeapon.

Referenced by W_Arc_Beam_Think(), W_Hagar_Attack2_Load(), W_LastWeapon(), W_Reload(), and weapon_prepareattack_checkammo().

◆ W_SwitchWeapon()

bool W_SwitchWeapon ( entity this,
Weapon w,
.entity weaponentity )

Definition at line 265 of file selection.qc.

266{
267 if (this.(weaponentity).m_switchweapon != w)
268 {
269 if (client_hasweapon(this, w, weaponentity, true, true))
270 {
271 W_SwitchWeapon_Force(this, w, weaponentity);
272 return true;
273 }
274 else
275 {
276 this.(weaponentity).selectweapon = w.m_id; // update selectweapon anyway
277 return false;
278 }
279 }
280 else if (!weaponLocked(this) && CS_CVAR(this).cvar_cl_weapon_switch_reload)
281 {
282 entity actor = this;
283 w.wr_reload(w, actor, weaponentity);
284 }
285
286 return true; // player already has the weapon out or needs to reload
287}
virtual void wr_reload()
(SERVER) handles reloading for weapon
Definition weapon.qh:128
bool weaponLocked(entity player)

References client_hasweapon(), CS_CVAR, entity(), Weapon::m_id, m_switchweapon, selectweapon, W_SwitchWeapon_Force(), weaponLocked(), and Weapon::wr_reload().

Referenced by GiveBall(), IMPULSE(), MUTATOR_HOOKFUNCTION(), NIX_GiveCurrentWeapon(), W_CycleWeapon(), W_LastWeapon(), W_NextWeaponOnImpulse(), W_SwitchWeapon_TryOthers(), and W_WeaponFrame().

◆ W_SwitchWeapon_Force()

void W_SwitchWeapon_Force ( Player this,
Weapon wep,
.entity weaponentity )

Definition at line 237 of file selection.qc.

238{
239 TC(Weapon, wep);
240 entity w_ent = this.(weaponentity);
241 w_ent.cnt = w_ent.m_switchweapon.m_id;
242 w_ent.m_switchweapon = wep;
243 w_ent.selectweapon = wep.m_id;
244}
#define TC(T, sym)
Definition _all.inc:82

References entity(), Weapon::m_id, and TC.

Referenced by GiveItems(), Item_GiveTo(), MUTATOR_HOOKFUNCTION(), TEST(), W_Hagar_Attack_Auto(), W_HLAC_Attack_Frame(), W_MachineGun_Attack_Auto(), W_MachineGun_Attack_Frame(), W_OverkillHeavyMachineGun_Attack_Auto(), W_OverkillMachineGun_Attack_Auto(), W_Shotgun_Attack3_Frame1(), W_Shotgun_Attack3_Frame2(), W_SwitchToOtherWeapon(), W_SwitchWeapon(), W_ThrowWeapon(), and W_WeaponFrame().

◆ W_SwitchWeapon_TryOthers()

void W_SwitchWeapon_TryOthers ( entity this,
Weapon w,
.entity weaponentity )

Definition at line 289 of file selection.qc.

290{
291 if (!W_SwitchWeapon(this, w, weaponentity) && CS_CVAR(this).cvar_cl_weapon_switch_fallback_to_impulse)
292 W_NextWeaponOnImpulse(this, w.impulse, weaponentity);
293}
void W_NextWeaponOnImpulse(entity this, float imp,.entity weaponentity)
Definition selection.qc:302

References CS_CVAR, entity(), Weapon::impulse, W_NextWeaponOnImpulse(), and W_SwitchWeapon().

Referenced by weapon_byid_handle().

◆ Weapon_whereis()

void Weapon_whereis ( Weapon this,
entity cl )

Definition at line 26 of file selection.qc.

27{
29 return;
30 IL_EACH(g_items, it.weapon == this.m_id && it.model,
31 {
32 if (ITEM_IS_LOOT(it) && autocvar_g_showweaponspawns < 2)
33 continue;
34 entity wp = WaypointSprite_Spawn(
35 WP_Weapon,
36 -2, 0,
37 NULL, it.origin + ('0 0 1' * it.maxs.z) * 1.2,
38 cl, 0,
39 NULL, enemy,
40 0,
41 RADARICON_NONE
42 );
43 wp.wp_extra = this.m_id;
44 });
45}
int spawnflags
Definition ammo.qh:15
IntrusiveList g_items
Definition items.qh:119

References autocvar_g_showweaponspawns, entity(), g_items, IL_EACH, spawnflags, and WEP_FLAG_HIDDEN.

Referenced by client_hasweapon(), and NET_HANDLE().