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
24// WEAPONTODO
31
32bool NIX_CanChooseWeapon(int wpn);
33
34REGISTER_MUTATOR(nix, expr_evaluate(cvar_string("g_nix")) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok) && !MapInfo_LoadedGametype.m_weaponarena)
35{
37 {
39
42
43 FOREACH(Weapons, it != WEP_Null && NIX_CanChooseWeapon(it.m_id), { it.wr_init(it); });
44 }
45
47 {
48 // nothing to roll back
49 }
50
52 {
53 // as the PlayerSpawn hook will no longer run, NIX is turned off by this!
54 FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
55 SetResource(it, RES_SHELLS, start_ammo_shells);
56 SetResource(it, RES_BULLETS, start_ammo_nails);
57 SetResource(it, RES_ROCKETS, start_ammo_rockets);
58 SetResource(it, RES_CELLS, start_ammo_cells);
59 SetResource(it, RES_FUEL, start_ammo_fuel);
60 STAT(WEAPONS, it) = start_weapons;
61 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
62 {
63 .entity weaponentity = weaponentities[slot];
64 if(it.(weaponentity).m_weapon == WEP_Null && slot != 0)
65 continue;
66 if(!client_hasweapon(it, it.(weaponentity).m_weapon, weaponentity, true, false))
67 it.(weaponentity).m_switchweapon = w_getbestweapon(it, weaponentity);
68 }
69 });
70 }
71
72 return false;
73}
74
76{
77 entity e = REGISTRY_GET(Weapons, wpn);
78 if (e == WEP_Null) return false; // skip dummies
80 {
81 if(!(g_weaponarena_weapons & e.m_wepset))
82 return false;
83 }
84 else
85 {
86 if(wpn == WEP_BLASTER.m_id && g_nix_with_blaster)
87 return false;
88 if(e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
89 return false;
90 if (!(e.spawnflags & WEP_FLAG_NORMAL))
91 return false;
92 }
93 return true;
94}
96{
98 FOREACH(Weapons, it != WEP_Null, {
99 if(NIX_CanChooseWeapon(it.m_id))
100 RandomSelection_AddFloat(it.m_id, 1, (it.m_id != nix_weapon));
101 });
103}
104
106{
107 float dt;
108
109 if(!nix_nextweapon)
111
112 dt = ceil(nix_nextchange - time);
113
114 if(dt <= 0)
115 {
117 nix_nextweapon = 0;
118 if (!nix_nextchange) // no round played yet?
119 nix_nextchange = time; // start the first round now!
120 else
122 // Weapon w = REGISTRY_GET(Weapons, nix_weapon);
123 // w.wr_init(w); // forget it, too slow
124 }
125
126 // get weapon info
128
129 // TODO: registry handles
130 if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
131 {
132 SetResource(this, RES_SHELLS, 0);
133 SetResource(this, RES_BULLETS, 0);
134 SetResource(this, RES_ROCKETS, 0);
135 SetResource(this, RES_CELLS, 0);
136 SetResource(this, RES_FUEL, 0);
137 if(this.items & IT_UNLIMITED_AMMO)
138 {
139 switch (wpn.ammo_type)
140 {
141 case RES_SHELLS: SetResource(this, RES_SHELLS, autocvar_g_pickup_shells_max); break;
142 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_pickup_nails_max); break;
143 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_pickup_rockets_max); break;
144 case RES_CELLS: SetResource(this, RES_CELLS, autocvar_g_pickup_cells_max); break;
145 case RES_FUEL: SetResource(this, RES_FUEL, autocvar_g_pickup_fuel_max); break;
146 }
147 }
148 else
149 {
150 switch (wpn.ammo_type)
151 {
152 case RES_SHELLS: SetResource(this, RES_SHELLS, autocvar_g_balance_nix_ammo_shells); break;
153 case RES_BULLETS: SetResource(this, RES_BULLETS, autocvar_g_balance_nix_ammo_nails); break;
154 case RES_ROCKETS: SetResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammo_rockets); break;
155 case RES_CELLS: SetResource(this, RES_CELLS, autocvar_g_balance_nix_ammo_cells); break;
156 case RES_FUEL: SetResource(this, RES_FUEL, autocvar_g_balance_nix_ammo_fuel); break;
157 }
158 }
159
161 if(dt >= 1 && dt <= 5)
162 this.nix_lastinfotime = -42;
163 else
164 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
165
166 wpn.wr_resetplayer(wpn, this);
167
168 // all weapons must be fully loaded when we spawn
169 if (wpn.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
170 {
171 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
172 {
173 .entity weaponentity = weaponentities[slot];
174 this.(weaponentity).(weapon_load[nix_weapon]) = wpn.reloading_ammo;
175 }
176 }
177
178 // set last change info
180 }
181 if(this.nix_lastinfotime != dt)
182 {
183 this.nix_lastinfotime = dt; // initial value 0 should count as "not seen"
184 if(dt >= 1 && dt <= 5)
185 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_COUNTDOWN, nix_nextweapon, dt);
186 }
187
188 if(!(this.items & IT_UNLIMITED_AMMO) && time > this.nix_nextincr)
189 {
190 switch (wpn.ammo_type)
191 {
192 case RES_SHELLS: GiveResource(this, RES_SHELLS, autocvar_g_balance_nix_ammoincr_shells); break;
193 case RES_BULLETS: GiveResource(this, RES_BULLETS, autocvar_g_balance_nix_ammoincr_nails); break;
194 case RES_ROCKETS: GiveResource(this, RES_ROCKETS, autocvar_g_balance_nix_ammoincr_rockets); break;
195 case RES_CELLS: GiveResource(this, RES_CELLS, autocvar_g_balance_nix_ammoincr_cells); break;
196 case RES_FUEL: GiveResource(this, RES_FUEL, autocvar_g_balance_nix_ammoincr_fuel); break;
197 }
198
200 }
201
202 STAT(WEAPONS, this) = '0 0 0';
204 STAT(WEAPONS, this) |= WEPSET(BLASTER);
205 STAT(WEAPONS, this) |= wpn.m_wepset;
206
207 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
208 {
209 .entity weaponentity = weaponentities[slot];
210 if (this.(weaponentity).m_weapon == WEP_Null && slot != 0)
211 continue;
212
213 if (this.(weaponentity).m_switchweapon != wpn)
214 if (!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
215 {
216 if (client_hasweapon(this, wpn, weaponentity, true, false))
217 W_SwitchWeapon(this, wpn, weaponentity);
218 }
219 }
220}
221
222MUTATOR_HOOKFUNCTION(nix, ForbidThrowCurrentWeapon)
223{
224 return true; // no throwing in NIX
225}
226
227MUTATOR_HOOKFUNCTION(nix, BuildMutatorsString)
228{
229 M_ARGV(0, string) = strcat(M_ARGV(0, string), ":NIX");
230}
231
232MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
233{
234 M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
235}
236
237MUTATOR_HOOKFUNCTION(nix, FilterItemDefinition)
238{
239 entity definition = M_ARGV(0, entity);
240
241 if (definition.instanceOfHealth || definition.instanceOfArmor)
242 {
244 }
245 else if (definition.instanceOfPowerup)
246 {
248 }
249
250 return true; // delete all other items
251}
252
253MUTATOR_HOOKFUNCTION(nix, OnEntityPreSpawn)
254{
255 entity ent = M_ARGV(0, entity);
256
257 if(ent.classname == "target_items") // items triggers cannot work in nix (as they change weapons/ammo)
258 return true;
259}
260
262{
263 entity player = M_ARGV(0, entity);
264
265 if(!game_stopped)
266 if(!IS_DEAD(player))
267 if(IS_PLAYER(player))
268 NIX_GiveCurrentWeapon(player);
269}
270
271MUTATOR_HOOKFUNCTION(nix, ForbidRandomStartWeapons)
272{
273 return true;
274}
275
276MUTATOR_HOOKFUNCTION(nix, PlayerSpawn)
277{
278 entity player = M_ARGV(0, entity);
279
280 player.nix_lastchange_id = -1;
281 NIX_GiveCurrentWeapon(player); // overrides the weapons you got when spawning
282 player.items |= IT_UNLIMITED_SUPERWEAPONS;
283}
284
286{
287 M_ARGV(0, string) = "NIX";
288}
#define MUTATOR_ONADD
Definition base.qh:309
#define MUTATOR_ONROLLBACK_OR_REMOVE
Definition base.qh:311
#define MUTATOR_IS_ENABLED(this)
Definition base.qh:193
#define REGISTER_MUTATOR(...)
Definition base.qh:295
const int CBC_ORDER_LAST
Definition base.qh:11
#define MUTATOR_HOOKFUNCTION(...)
Definition base.qh:335
#define MUTATOR_ONREMOVE
Definition base.qh:310
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:116
int autocvar_g_pickup_fuel_max
Definition ammo.qh:188
int autocvar_g_pickup_shells_max
Definition ammo.qh:44
int autocvar_g_pickup_cells_max
Definition ammo.qh:152
int autocvar_g_pickup_nails_max
Definition ammo.qh:80
const int IT_UNLIMITED_AMMO
Definition item.qh:23
const int IT_UNLIMITED_SUPERWEAPONS
Definition item.qh:24
#define M_ARGV(x, type)
Definition events.qh:17
int items
Definition player.qh:227
#define IS_DEAD(s)
Definition player.qh:245
#define IS_PLAYER(s)
Definition player.qh:243
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:254
#define STAT(...)
Definition stats.qh:82
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:1573
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:43
bool W_SwitchWeapon(entity this, Weapon w,.entity weaponentity)
Definition selection.qc:275
bool client_hasweapon(entity this, Weapon wpn,.entity weaponentity, float andammo, bool complain)
Definition selection.qc:48
#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:28
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:30
float g_nix_with_blaster
Definition sv_nix.qc:23
void NIX_GiveCurrentWeapon(entity this)
Definition sv_nix.qc:105
int autocvar_g_balance_nix_ammoincr_fuel
Definition sv_nix.qc:13
void NIX_ChooseNextWeapon()
Definition sv_nix.qc:95
bool NIX_CanChooseWeapon(int wpn)
Definition sv_nix.qc:75
float nix_nextweapon
Definition sv_nix.qc:27
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:25
float nix_nextchange
Definition sv_nix.qc:26
int autocvar_g_balance_nix_ammoincr_rockets
Definition sv_nix.qc:15
float nix_lastinfotime
Definition sv_nix.qc:29
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:50
#define WEPSET(id)
Definition all.qh:45
const int MAX_WEAPONSLOTS
Definition weapon.qh:16
const int WEP_FLAG_RELOADABLE
Definition weapon.qh:217
entity weaponentities[MAX_WEAPONSLOTS]
Definition weapon.qh:17
const int WEP_FLAG_MUTATORBLOCKED
Definition weapon.qh:219
const int WEP_FLAG_NORMAL
Definition weapon.qh:215
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:80
float start_ammo_shells
Definition world.qh:84
float start_ammo_fuel
Definition world.qh:88
WepSet g_weaponarena_weapons
Definition world.qh:76
float start_ammo_cells
Definition world.qh:87
float g_weaponarena
Definition world.qh:75
float start_ammo_rockets
Definition world.qh:86
float start_ammo_nails
Definition world.qh:85