Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
sv_nix.qc
Go to the documentation of this file.
1#include "sv_nix.qh"
2
4#include <server/world.qh>
5
6//string autocvar_g_nix;
22
23// WEAPONTODO
30
31bool NIX_CanChooseWeapon(int wpn);
32
33REGISTER_MUTATOR(nix, expr_evaluate(cvar_string("g_nix")) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok) && !MUTATOR_IS_ENABLED(melee_only) && !MapInfo_LoadedGametype.m_weaponarena)
34{
36 {
39
40 FOREACH(Weapons, it != WEP_Null && NIX_CanChooseWeapon(it.m_id), { it.wr_init(it); });
41 }
42
44 {
45 // nothing to roll back
46 }
47
49 {
50 // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
51 FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
52 SetResource(it, RES_SHELLS, start_ammo_shells);
53 SetResource(it, RES_BULLETS, start_ammo_nails);
54 SetResource(it, RES_ROCKETS, start_ammo_rockets);
55 SetResource(it, RES_CELLS, start_ammo_cells);
56 SetResource(it, RES_FUEL, start_ammo_fuel);
57 STAT(WEAPONS, it) = start_weapons;
58 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
59 {
60 .entity weaponentity = weaponentities[slot];
61 if(it.(weaponentity).m_weapon == WEP_Null && slot != 0)
62 continue;
63 if(!client_hasweapon(it, it.(weaponentity).m_weapon, weaponentity, true, false))
64 it.(weaponentity).m_switchweapon = w_getbestweapon(it, weaponentity);
65 }
66 });
67 }
68
69 return false;
70}
71
73{
74 entity e = REGISTRY_GET(Weapons, wpn);
75 if (e == WEP_Null) return false; // skip dummies
77 {
78 if(!(g_weaponarena_weapons & e.m_wepset))
79 return false;
80 }
81 else
82 {
83 if(wpn == WEP_BLASTER.m_id && autocvar_g_nix_with_blaster)
84 return false;
85 if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
86 return false;
87 if (!(e.spawnflags & WEP_FLAG_NORMAL))
88 return false;
89 }
90 return true;
91}
93{
95 FOREACH(Weapons, it != WEP_Null, {
96 if(NIX_CanChooseWeapon(it.m_id))
97 RandomSelection_AddFloat(it.m_id, 1, (it.m_id != nix_weapon));
98 });
100}
101
103{
104 float dt;
105
106 if(!nix_nextweapon)
108
109 dt = ceil(nix_nextchange - time);
110
111 if(dt <= 0)
112 {
114 nix_nextweapon = 0;
115 if (!nix_nextchange) // no round played yet?
116 nix_nextchange = time; // start the first round now!
117 else
119 // Weapon w = REGISTRY_GET(Weapons, nix_weapon);
120 // w.wr_init(w); // forget it, too slow
121 }
122
123 // get weapon info
125
126 // TODO: registry handles
127 if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
128 {
129 SetResource(this, RES_SHELLS, 0);
130 SetResource(this, RES_BULLETS, 0);
131 SetResource(this, RES_ROCKETS, 0);
132 SetResource(this, RES_CELLS, 0);
133 SetResource(this, RES_FUEL, 0);
134 if(this.items & IT_UNLIMITED_AMMO)
135 {
136 switch (wpn.ammo_type)
137 {
138 case RES_SHELLS: SetResource(this, RES_SHELLS, autocvar_g_pickup_shells_max); break;
139 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_pickup_nails_max); break;
140 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_pickup_rockets_max); break;
141 case RES_CELLS: SetResource(this, RES_CELLS, autocvar_g_pickup_cells_max); break;
142 case RES_FUEL: SetResource(this, RES_FUEL, autocvar_g_pickup_fuel_max); break;
143 }
144 }
145 else
146 {
147 switch (wpn.ammo_type)
148 {
149 case RES_SHELLS: SetResource(this, RES_SHELLS, autocvar_g_balance_nix_ammo_shells); break;
150 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_balance_nix_ammo_nails); break;
151 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammo_rockets); break;
152 case RES_CELLS: SetResource(this, RES_CELLS, autocvar_g_balance_nix_ammo_cells); break;
153 case RES_FUEL: SetResource(this, RES_FUEL, autocvar_g_balance_nix_ammo_fuel); break;
154 }
155 }
156
158 if(dt >= 1 && dt <= 5)
159 this.nix_lastinfotime = -42;
160 else
161 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
162
163 wpn.wr_resetplayer(wpn, this);
164
165 // all weapons must be fully loaded when we spawn
166 if (wpn.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
167 {
168 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
169 {
170 .entity weaponentity = weaponentities[slot];
171 this.(weaponentity).(weapon_load[nix_weapon]) = wpn.reloading_ammo;
172 }
173 }
174
175 // set last change info
177 }
178 if(this.nix_lastinfotime != dt)
179 {
180 this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
181 if(dt >= 1 && dt <= 5)
182 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
183 }
184
185 if(!(this.items & IT_UNLIMITED_AMMO) && time > this.nix_nextincr)
186 {
187 switch (wpn.ammo_type)
188 {
189 case RES_SHELLS: GiveResource(this, RES_SHELLS, autocvar_g_balance_nix_ammoincr_shells); break;
190 case RES_BULLETS: GiveResource(this, RES_BULLETS, autocvar_g_balance_nix_ammoincr_nails); break;
191 case RES_ROCKETS: GiveResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammoincr_rockets); break;
192 case RES_CELLS: GiveResource(this, RES_CELLS, autocvar_g_balance_nix_ammoincr_cells); break;
193 case RES_FUEL: GiveResource(this, RES_FUEL, autocvar_g_balance_nix_ammoincr_fuel); break;
194 }
195
197 }
198
199 STAT(WEAPONS, this) = '0 0 0';
201 STAT(WEAPONS, this) |= WEPSET(BLASTER);
202 STAT(WEAPONS, this) |= wpn.m_wepset;
203
204 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
205 {
206 .entity weaponentity = weaponentities[slot];
207 if (this.(weaponentity).m_weapon == WEP_Null && slot != 0)
208 continue;
209
210 if (this.(weaponentity).m_switchweapon != wpn)
211 if (!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
212 {
213 if (client_hasweapon(this, wpn, weaponentity, true, false))
214 W_SwitchWeapon(this, wpn, weaponentity);
215 }
216 }
217}
218
219MUTATOR_HOOKFUNCTION(nix, SetWeaponStay)
220{
221 // turn weapon stay off
222 M_ARGV(0, int) = 0;
223}
224
225MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
226{
227 return true; // no throwing in NIX
228}
229
230MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
231{
232 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
233}
234
235MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
236{
237 M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
238}
239
240MUTATOR_HOOKFUNCTION(nix, FilterItemDefinition)
241{
242 entity definition = M_ARGV(0, entity);
243
244 if (definition.instanceOfHealth || definition.instanceOfArmor)
245 {
247 }
248 else if (definition.instanceOfPowerup)
249 {
251 }
252
253 return true; // delete all other items
254}
255
256MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
257{
258 entity ent = M_ARGV(0, entity);
259
260 if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
261 return true;
262}
263
265{
266 entity player = M_ARGV(0, entity);
267
268 if(!game_stopped)
269 if(!IS_DEAD(player))
270 if(IS_PLAYER(player))
271 NIX_GiveCurrentWeapon(player);
272}
273
274MUTATOR_HOOKFUNCTION(nix, ForbidRandomStartWeapons)
275{
276 return true;
277}
278
279MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
280{
281 entity player = M_ARGV(0, entity);
282
283 player.nix_lastchange_id = -1;
284 NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
285 player.items |= IT_UNLIMITED_SUPERWEAPONS;
286}
287
289{
290 M_ARGV(0, string) = "NIX";
291}
#define MUTATOR_ONADD
Definition base.qh:365
#define MUTATOR_ONROLLBACK_OR_REMOVE
Definition base.qh:367
#define MUTATOR_IS_ENABLED(this)
Definition base.qh:237
#define REGISTER_MUTATOR(...)
Definition base.qh:349
const int CBC_ORDER_LAST
Definition base.qh:10
#define MUTATOR_HOOKFUNCTION(...)
Definition base.qh:394
#define MUTATOR_ONREMOVE
Definition base.qh:366
#define M_ARGV(idx, type)
Definition base.qh:153
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
void SetResource(entity e, Resource res_type, float amount)
Sets the current amount of resource the given entity will have.
int autocvar_g_pickup_rockets_max
Definition ammo.qh:118
int autocvar_g_pickup_fuel_max
Definition ammo.qh:190
int autocvar_g_pickup_shells_max
Definition ammo.qh:46
int autocvar_g_pickup_cells_max
Definition ammo.qh:154
int autocvar_g_pickup_nails_max
Definition ammo.qh:82
const int IT_UNLIMITED_AMMO
Definition item.qh:23
const int IT_UNLIMITED_SUPERWEAPONS
Definition item.qh:24
int items
Definition player.qh:226
#define IS_DEAD(s)
Definition player.qh:244
#define IS_PLAYER(s)
Definition player.qh:242
float game_stopped
Definition stats.qh:81
float time
ERASEABLE bool expr_evaluate(string s)
Evaluate an expression of the form: [+ | -]?
Definition cvar.qh:48
Weapons
Definition guide.qh:113
#define FOREACH(list, cond, body)
Definition iter.qh:19
#define PlayerPreThink
Definition _all.inc:259
#define STAT(...)
Definition stats.qh:94
Gametype MapInfo_LoadedGametype
Definition mapinfo.qh:220
float ceil(float f)
const string cvar_string(string name)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1500
ERASEABLE void RandomSelection_Init()
Definition random.qc:4
float RandomSelection_chosen_float
Definition random.qh:6
#define RandomSelection_AddFloat(f, weight, priority)
Definition random.qh:15
#define REGISTRY_GET(id, i)
Definition registry.qh:62
bool W_SwitchWeapon(entity this, Weapon w,.entity weaponentity)
Definition selection.qc:265
bool client_hasweapon(entity this, Weapon wpn,.entity weaponentity, float andammo, bool complain)
Definition selection.qc:47
#define w_getbestweapon(ent, wepent)
Definition selection.qh:23
int autocvar_g_balance_nix_ammo_shells
Definition sv_nix.qc:11
int autocvar_g_balance_nix_ammo_fuel
Definition sv_nix.qc:8
float autocvar_g_balance_nix_roundtime
Definition sv_nix.qc:18
int autocvar_g_balance_nix_ammo_rockets
Definition sv_nix.qc:10
int autocvar_g_balance_nix_ammoincr_nails
Definition sv_nix.qc:14
float nix_lastchange_id
Definition sv_nix.qc:27
bool autocvar_g_nix_with_powerups
Definition sv_nix.qc:21
int autocvar_g_balance_nix_ammoincr_shells
Definition sv_nix.qc:16
int autocvar_g_balance_nix_ammo_cells
Definition sv_nix.qc:7
float nix_nextincr
Definition sv_nix.qc:29
void NIX_GiveCurrentWeapon(entity this)
Definition sv_nix.qc:102
int autocvar_g_balance_nix_ammoincr_fuel
Definition sv_nix.qc:13
void NIX_ChooseNextWeapon()
Definition sv_nix.qc:92
bool NIX_CanChooseWeapon(int wpn)
Definition sv_nix.qc:72
float nix_nextweapon
Definition sv_nix.qc:26
bool autocvar_g_nix_with_healtharmor
Definition sv_nix.qc:19
bool autocvar_g_nix_with_blaster
Definition sv_nix.qc:20
int nix_weapon
Definition sv_nix.qc:24
float nix_nextchange
Definition sv_nix.qc:25
int autocvar_g_balance_nix_ammoincr_rockets
Definition sv_nix.qc:15
float nix_lastinfotime
Definition sv_nix.qc:28
int autocvar_g_balance_nix_ammo_nails
Definition sv_nix.qc:9
float autocvar_g_balance_nix_incrtime
Definition sv_nix.qc:17
int autocvar_g_balance_nix_ammoincr_cells
Definition sv_nix.qc:12
void GiveResource(entity receiver, Resource res_type, float amount)
Gives an entity some resource.
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:52
#define WEPSET(id)
Definition all.qh:47
@ WEPARENA_OFF
Definition weapon.qh:273
const int MAX_WEAPONSLOTS
Definition weapon.qh:16
const int WEP_FLAG_RELOADABLE
can has reload
Definition weapon.qh:254
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17
const int WEP_FLAG_MUTATORBLOCKED
hides from impulse 99 etc. (mutators are allowed to clear this flag)
Definition weapon.qh:256
const int WEP_FLAG_NORMAL
in "most weapons" set
Definition weapon.qh:252
float weapon_load[REGISTRY_MAX(Weapons)]
Weapon m_weapon
Definition wepent.qh:26
Weapon m_switchweapon
Definition wepent.qh:25
WepSet start_weapons
Definition world.qh:79
float start_ammo_shells
Definition world.qh:83
float start_ammo_fuel
Definition world.qh:87
WepSet g_weaponarena_weapons
Definition world.qh:75
float start_ammo_cells
Definition world.qh:86
float start_ammo_rockets
Definition world.qh:85
int g_weaponarena_type
Definition world.qh:77
float start_ammo_nails
Definition world.qh:84