Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
client.qc
Go to the documentation of this file.
1#include "client.qh"
2
5#include <common/debug.qh>
8#include <common/ent_cs.qh>
11#include <common/items/_mod.qh>
29#include <common/net_linked.qh>
30#include <common/net_notice.qh>
33#include <common/playerstats.qh>
35#include <common/state.qh>
36#include <common/stats.qh>
39#include <common/viewloc.qh>
42#include <common/wepent.qh>
46#include <server/anticheat.qh>
47#include <server/antilag.qh>
48#include <server/bot/api.qh>
51#include <server/campaign.qh>
52#include <server/chat.qh>
53#include <server/cheats.qh>
54#include <server/clientkill.qh>
56#include <server/command/cmd.qh>
60#include <server/damage.qh>
61#include <server/gamelog.qh>
62#include <server/handicap.qh>
63#include <server/hook.qh>
64#include <server/impulse.qh>
66#include <server/ipban.qh>
67#include <server/main.qh>
69#include <server/player.qh>
70#include <server/portals.qh>
71#include <server/race.qh>
72#include <server/scores.qh>
74#include <server/spawnpoints.qh>
75#include <server/teamplay.qh>
82#include <server/world.qh>
83
84STATIC_METHOD(Client, Add, void(Client this, int _team))
85{
86 ClientConnect(this);
88 this.frame = 12; // 7
89 this.team = _team;
91}
92
93STATIC_METHOD(Client, Remove, void(Client this))
94{
95 TRANSMUTE(Observer, this);
98}
99
101{
102 if(!player) return 0; // not sure how, but best to be safe
103
104 int spec_count = 0;
105
106 FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
107 {
108 spec_count++;
109 });
110
111 return spec_count;
112}
113
115{
116 if(!player) return; // not sure how, but best to be safe
117
118 int spec_count = 0;
119 FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
120 {
121 if(spec_count >= MAX_SPECTATORS)
122 break;
123 WriteByte(MSG_ENTITY, num_for_edict(it));
124 ++spec_count;
125 });
126}
127
128bool ClientData_Send(entity this, entity to, int sf)
129{
130 assert(to == this.owner, return false);
131
132 entity e = to;
133 if (IS_SPEC(e)) e = e.enemy;
134
135 sf = 0;
136 if (CS(e).race_completed) sf |= BIT(0); // forced scoreboard
137 if (CS(to).spectatee_status) sf |= BIT(1); // spectator ent number follows
138 if (CS(e).zoomstate) sf |= BIT(2); // zoomed
140 sf |= BIT(3); // observing blocked
142 sf |= BIT(4); // show spectators
144 sf |= (autocvar_sv_teamnagger & 0x03) << 5; // BIT(5) | BIT(6)
145 if (to.ignore_list && to.ignore_list_send_time == IGNORE_LIST_SEND_NOW && !IS_SPEC(to))
146 sf |= BIT(7); // ignore list (private, won't be sent to spectators)
147
148 WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA);
150
151 if (sf & BIT(1))
153
154 // spectator list is cleared on the client if this flag is not set
155 if(sf & BIT(4))
156 {
157 float specs = CountSpectators(e, to);
158 WriteByte(MSG_ENTITY, specs);
159 WriteSpectators(e, to);
160 }
161
162 // ignore list is NOT cleared on the client if this flag is not set
163 if (sf & BIT(7))
164 {
165 to.ignore_list_send_time = 0;
166 WriteString(MSG_ENTITY, strcat(to.ignore_list));
167 }
168
169 return true;
170}
171
173{
175 CS(this).clientdata.drawonlytoclient = this;
176 CS(this).clientdata.owner = this;
177}
178
180{
181 delete(CS(this).clientdata);
182 CS(this).clientdata = NULL;
183}
184
185void ClientData_Touch(entity e, bool to_spectators_too)
186{
187 entity cd = CS(e).clientdata;
188 if (cd) cd.SendFlags = 1;
189
190 if (to_spectators_too)
191 FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e,
192 {
193 entity cd_spec = CS(it).clientdata;
194 if (cd_spec) cd_spec.SendFlags = cd.SendFlags;
195 });
196}
197
198
199/*
200=============
201CheckPlayerModel
202
203Checks if the argument string can be a valid playermodel.
204Returns a valid one in doubt.
205=============
206*/
208string CheckPlayerModel(string plyermodel)
209{
210 if(FallbackPlayerModel != cvar_defstring("_cl_playermodel"))
211 {
212 // note: we cannot summon Don Strunzone here, some player may
213 // still have the model string set. In case anyone manages how
214 // to change a cvar default, we'll have a small leak here.
215 FallbackPlayerModel = strzone(cvar_defstring("_cl_playermodel"));
216 }
217 // only in right path
218 if(substring(plyermodel, 0, 14) != "models/player/")
219 return FallbackPlayerModel;
220 // only good file extensions
221 if(substring(plyermodel, -4, 4) != ".iqm"
222 && substring(plyermodel, -4, 4) != ".zym"
223 && substring(plyermodel, -4, 4) != ".dpm"
224 && substring(plyermodel, -4, 4) != ".md3"
225 && substring(plyermodel, -4, 4) != ".psk")
226 return FallbackPlayerModel;
227
228 // forbid the LOD models
229 if(substring(plyermodel, -9, 5) == "_lod1" || substring(plyermodel, -9, 5) == "_lod2")
230 return FallbackPlayerModel;
231 if(plyermodel != strtolower(plyermodel))
232 return FallbackPlayerModel;
233 // also, restrict to server models
235 if(!fexists(plyermodel))
236 return FallbackPlayerModel;
237
238 return plyermodel;
239}
240
241void setplayermodel(entity e, string modelname)
242{
243 precache_model(modelname);
244 _setmodel(e, modelname);
248}
249
251{
254 {
255 RandomSelection_AddEnt(it, 1, 1);
256 });
258}
259
261void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint)
262{
263 bool mutator_returnvalue = MUTATOR_CALLHOOK(MakePlayerObserver, this, is_forced);
264 bool recount_ready = false;
265 PlayerState_detach(this);
266
267 bool was_player = false;
268 if (IS_PLAYER(this))
269 {
270 if(GetResource(this, RES_HEALTH) >= 1)
271 {
272 // despawn effect
273 Send_Effect(EFFECT_SPAWN, this.origin, '0 0 0', 1);
274 }
275
276 // was a player, recount votes and ready status
277 if(IS_REAL_CLIENT(this))
278 {
279 if (vote_called) { VoteCount(false); }
280 this.ready = false;
281 if (warmup_stage || game_starttime > time) /* warmup OR countdown */ recount_ready = true;
282 }
284 was_player = true;
285 }
286
287 if (use_spawnpoint)
288 {
289 // first try to find a random "nice" location to view from
290 entity spot = SelectObservePoint(this);
291 bool is_observepoint = (spot != NULL);
292 if(!spot) // otherwise just use the player spawn points
293 spot = SelectSpawnPoint(this, true);
294 if (!spot) LOG_FATAL("No spawnpoints for observers?!?");
295
296 this.angles = vec2(spot.angles);
297 // offset it so that the spectator spawns higher off the ground, looks better this way
298 setorigin(this, spot.origin + (is_observepoint ? '0 0 0' : autocvar_sv_player_viewoffset));
299 }
300 else // change origin to restore previous view origin
301 setorigin(this, this.origin + STAT(PL_VIEW_OFS, this) - STAT(PL_CROUCH_VIEW_OFS, this));
302 this.fixangle = true;
303
304 if (IS_REAL_CLIENT(this))
305 {
306 msg_entity = this;
308 WriteEntity(MSG_ONE, this);
309 }
310 // give the spectator some space between walls for MOVETYPE_FLY_WORLDONLY
311 // so that your view doesn't go into the ceiling with MOVETYPE_FLY_WORLDONLY, previously "PL_VIEW_OFS"
313 {
314 // needed for player sounds
315 this.model = "";
316 FixPlayermodel(this);
317 }
318 setmodel(this, MDL_Null);
319 setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this));
320 this.view_ofs = '0 0 0';
321
323 Portal_ClearAll(this);
324 SetSpectatee(this, NULL);
325
326 if (this.alivetime_start)
327 {
328 if (!warmup_stage)
330 this.alivetime_start = 0;
331 }
332
333 if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
334
335 TRANSMUTE(Observer, this);
336
338 accuracy_resend(this);
339
341 Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
342
343 CS(this).spectatortime = time;
344 if (!autocvar_sv_spectate && CS(this).autojoin_checked) // unnecessary if autojoin succeeds, on failure it notifies
345 Send_Notification(NOTIF_ONE_ONLY, this, MSG_MULTI, SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
346
347 if(this.bot_attack)
349 this.bot_attack = false;
350 if(this.monster_attack)
352 this.monster_attack = false;
353 STAT(HUD, this) = HUD_NORMAL;
354 this.iscreature = false;
356 if(this.damagedbycontents)
358 this.damagedbycontents = false;
359 SetResourceExplicit(this, RES_HEALTH, FRAGS_SPECTATOR);
360 SetSpectatee_status(this, etof(this));
361 this.takedamage = DAMAGE_NO;
362 this.solid = SOLID_NOT;
363 set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink
364 this.flags = FL_CLIENT | FL_NOTARGET;
365 this.effects = 0;
367 this.pauserotarmor_finished = 0;
369 this.pauseregen_finished = 0;
370 this.damageforcescale = 0;
371 this.death_time = 0;
372 this.respawn_flags = 0;
373 this.respawn_time = 0;
374 STAT(RESPAWN_TIME, this) = 0;
375 this.alpha = 0;
376 this.scale = 0;
377 this.fade_time = 0;
378 this.pain_finished = 0;
379 STAT(AIR_FINISHED, this) = 0;
380 //this.dphitcontentsmask = 0;
384 this.pushltime = 0;
385 this.istypefrag = 0;
386 setthink(this, func_null);
387 this.nextthink = 0;
388 this.deadflag = DEAD_NO;
389 UNSET_DUCKED(this);
390 this.draggable = drag_undraggable;
391
392 player_powerups_remove_all(this, was_player);
393 this.items = 0;
394 STAT(WEAPONS, this) = '0 0 0';
395 this.drawonlytoclient = this;
396
397 this.viewloc = NULL;
398
399 //this.spawnpoint_targ = NULL; // keep it so they can return to where they were?
400
401 this.weaponmodel = "";
402 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
403 {
404 this.weaponentities[slot] = NULL;
405 }
407 CS(this).killcount = FRAGS_SPECTATOR;
408 this.velocity = '0 0 0';
409 this.avelocity = '0 0 0';
410 this.punchangle = '0 0 0';
411 this.punchvector = '0 0 0';
412 this.oldvelocity = this.velocity;
413 this.event_damage = func_null;
414 this.event_heal = func_null;
415
416 for(int slot = 0; slot < MAX_AXH; ++slot)
417 {
418 entity axh = this.(AuxiliaryXhair[slot]);
419 this.(AuxiliaryXhair[slot]) = NULL;
420
421 if(axh.owner == this && axh != NULL && !wasfreed(axh))
422 delete(axh);
423 }
424
425 if (mutator_returnvalue)
426 {
427 // mutator prevents resetting teams+score
428 }
429 else
430 {
431 SetPlayerTeam(this, -1, TEAM_CHANGE_SPECTATOR); // clears scores too in gametypes without teams
432 this.frags = FRAGS_SPECTATOR;
433 }
434
436
437 if (CS(this).just_joined)
438 CS(this).just_joined = false;
439
440 if (recount_ready)
441 ReadyCount(); // must be called after SetPlayerTeam() and TRANSMUTE(Observer
442}
443
445{
446 get_model_parameters(this.model, this.skin);
449 if (s < 0) return SPECIES_HUMAN;
450 return s;
451}
452
455{
456 string defaultmodel = "";
457 int defaultskin = 0;
459 {
460 if(teamplay)
461 {
462 switch(player.team)
463 {
468 }
469 }
470
471 if(defaultmodel == "")
472 {
473 defaultmodel = autocvar_sv_defaultplayermodel;
474 defaultskin = autocvar_sv_defaultplayerskin;
475 }
476
477 int n = tokenize_console(defaultmodel);
478 if(n > 0)
479 {
480 defaultmodel = argv(floor(n * CS(player).model_randomizer));
481 // However, do NOT randomize if the player-selected model is in the list.
482 for (int i = 0; i < n; ++i)
483 if ((argv(i) == player.playermodel && defaultskin == stof(player.playerskin)) || argv(i) == strcat(player.playermodel, ":", player.playerskin))
484 defaultmodel = argv(i);
485 }
486
487 int i = strstrofs(defaultmodel, ":", 0);
488 if(i >= 0)
489 {
490 defaultskin = stof(substring(defaultmodel, i+1, -1));
491 defaultmodel = substring(defaultmodel, 0, i);
492 }
493 }
494 if(autocvar_sv_defaultcharacterskin && !defaultskin)
495 {
496 if(teamplay)
497 {
498 switch(player.team)
499 {
500 case NUM_TEAM_1: defaultskin = autocvar_sv_defaultplayerskin_red; break;
501 case NUM_TEAM_2: defaultskin = autocvar_sv_defaultplayerskin_blue; break;
502 case NUM_TEAM_3: defaultskin = autocvar_sv_defaultplayerskin_yellow; break;
503 case NUM_TEAM_4: defaultskin = autocvar_sv_defaultplayerskin_pink; break;
504 }
505 }
506
507 if(!defaultskin)
508 defaultskin = autocvar_sv_defaultplayerskin;
509 }
510
511 MUTATOR_CALLHOOK(FixPlayermodel, defaultmodel, defaultskin, player);
512 defaultmodel = M_ARGV(0, string);
513 defaultskin = M_ARGV(1, int);
514
515 bool chmdl = false;
516 int oldskin;
517 if(defaultmodel != "")
518 {
519 if (defaultmodel != player.model)
520 {
521 vector m1 = player.mins;
522 vector m2 = player.maxs;
523 setplayermodel (player, defaultmodel);
524 setsize (player, m1, m2);
525 chmdl = true;
526 }
527
528 oldskin = player.skin;
529 player.skin = defaultskin;
530 }
531 else
532 {
533 if (player.playermodel != player.model || player.playermodel == "")
534 {
535 player.playermodel = CheckPlayerModel(player.playermodel); // this is never "", so no endless loop
536 vector m1 = player.mins;
537 vector m2 = player.maxs;
538 setplayermodel (player, player.playermodel);
539 setsize (player, m1, m2);
540 chmdl = true;
541 }
542
544 {
545 oldskin = player.skin;
546 player.skin = stof(player.playerskin);
547 }
548 else
549 {
550 oldskin = player.skin;
551 player.skin = defaultskin;
552 }
553 }
554
555 if(chmdl || oldskin != player.skin) // model or skin has changed
556 {
557 player.species = player_getspecies(player); // update species
559 UpdatePlayerSounds(player); // update skin sounds
560 }
561
562 if(!teamplay)
564 if(player.clientcolors != stof(autocvar_sv_defaultplayercolors))
566}
567
569{
570 SetResource(this, RES_SHELLS, warmup_start_ammo_shells);
571 SetResource(this, RES_BULLETS, warmup_start_ammo_nails);
572 SetResource(this, RES_ROCKETS, warmup_start_ammo_rockets);
573 SetResource(this, RES_CELLS, warmup_start_ammo_cells);
574 SetResource(this, RES_FUEL, warmup_start_ammo_fuel);
575 SetResource(this, RES_HEALTH, warmup_start_health);
577 STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
578}
579
581{
582 if (MUTATOR_CALLHOOK(ForbidSpawn, this))
583 return;
584
585 if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
586
587 PlayerState_attach(this);
588 accuracy_resend(this);
589
590 if (teamplay)
591 {
592 if (this.bot_forced_team)
594 else if (this.team <= 0)
595 {
596 if (this.wants_join > 0)
598 else
600 }
601 }
602
603 entity spot = SelectSpawnPoint(this, false);
604 if (!spot)
605 {
606 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_NOSPAWNS);
607 return; // spawn failed
608 }
609
610 TRANSMUTE(Player, this);
611
612 this.iscreature = true;
614 if(!this.damagedbycontents)
616 this.damagedbycontents = true;
618 this.solid = SOLID_SLIDEBOX;
624 this.frags = FRAGS_PLAYER;
628 this.flags |= FL_NOTARGET;
629 this.takedamage = DAMAGE_AIM;
631
632 if (warmup_stage)
634 else
635 {
636 SetResource(this, RES_SHELLS, start_ammo_shells);
637 SetResource(this, RES_BULLETS, start_ammo_nails);
638 SetResource(this, RES_ROCKETS, start_ammo_rockets);
639 SetResource(this, RES_CELLS, start_ammo_cells);
640 SetResource(this, RES_FUEL, start_ammo_fuel);
641 SetResource(this, RES_HEALTH, start_health);
643 STAT(WEAPONS, this) = start_weapons;
644 if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
645 {
648 }
649 }
650 SetSpectatee_status(this, 0);
651
652 PS(this).dual_weapons = '0 0 0';
653
654 if(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)
655 StatusEffects_apply(STATUSEFFECT_Superweapon, this, time + autocvar_g_balance_superweapons_time, 0);
656
657 this.items = start_items;
658
659 float shieldtime = time + autocvar_g_spawnshieldtime;
660
666 {
667 float f = game_starttime - time;
668 shieldtime += f;
669 this.pauserotarmor_finished += f;
670 this.pauserothealth_finished += f;
671 this.pauseregen_finished += f;
672 }
673
674 StatusEffects_apply(STATUSEFFECT_SpawnShield, this, shieldtime, 0);
675
677 this.death_time = 0;
678 this.respawn_flags = 0;
679 this.respawn_time = 0;
680 STAT(RESPAWN_TIME, this) = 0;
682 ? 0.8125 // DP model scaling uses 1/16 accuracy and 13/16 is closest to 56/69
684 this.fade_time = 0;
685 this.pain_finished = 0;
686 this.pushltime = 0;
687 setthink(this, func_null); // players have no think function
688 this.nextthink = 0;
689 this.dmg_team = 0;
690 PS(this).ballistics_density = autocvar_g_ballistics_density_player;
691
692 this.deadflag = DEAD_NO;
693
694 this.angles = spot.angles;
695 this.angles_z = 0; // never spawn tilted even if the spot says to
696 if (IS_BOT_CLIENT(this))
697 {
698 this.v_angle = this.angles;
699 bot_aim_reset(this);
700 }
701 this.fixangle = true; // turn this way immediately
702 this.oldvelocity = this.velocity = '0 0 0';
703 this.avelocity = '0 0 0';
704 this.punchangle = '0 0 0';
705 this.punchvector = '0 0 0';
706
707 STAT(AIR_FINISHED, this) = 0;
710
711 entity spawnevent = new_pure(spawnevent);
712 spawnevent.owner = this;
713 Net_LinkEntity(spawnevent, false, 0.5, SpawnEvent_Send);
714
715 // Cut off any still running player sounds.
717
718 this.model = "";
719 FixPlayermodel(this);
720 this.drawonlytoclient = NULL;
721
722 this.viewloc = NULL;
723
724 for(int slot = 0; slot < MAX_AXH; ++slot)
725 {
726 entity axh = this.(AuxiliaryXhair[slot]);
727 this.(AuxiliaryXhair[slot]) = NULL;
728
729 if(axh.owner == this && axh != NULL && !wasfreed(axh))
730 delete(axh);
731 }
732
733 this.spawnpoint_targ = NULL;
734
735 UNSET_DUCKED(this);
736 this.view_ofs = STAT(PL_VIEW_OFS, this);
737 setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
738 this.spawnorigin = spot.origin;
739 setorigin(this, spot.origin + '0 0 1' * (1 - this.mins.z - 24));
740 // don't reset back to last position, even if new position is stuck in solid
741 this.oldorigin = this.origin;
742 if(this.conveyor)
743 IL_REMOVE(g_conveyed, this);
744 this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player
745 if(this.swampslug)
746 IL_REMOVE(g_swamped, this);
747 this.swampslug = NULL;
748 this.swamp_interval = 0;
749 if(this.ladder_entity)
750 IL_REMOVE(g_ladderents, this);
751 this.ladder_entity = NULL;
752 IL_EACH(g_counters, it.realowner == this,
753 {
754 delete(it);
755 });
756 STAT(HUD, this) = HUD_NORMAL;
757
758 this.event_damage = PlayerDamage;
759 this.event_heal = PlayerHeal;
760
761 this.draggable = func_null;
762
763 if(!this.bot_attack)
764 IL_PUSH(g_bot_targets, this);
765 this.bot_attack = true;
766 if(!this.monster_attack)
768 this.monster_attack = true;
769 navigation_dynamicgoal_init(this, false);
770
772
773 // player was spectator
774 if (CS(this).killcount == FRAGS_SPECTATOR)
775 {
776 PlayerScore_Clear(this);
777 CS(this).killcount = 0;
778 CS(this).startplaytime = time;
779 }
780
781 for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
782 {
783 .entity weaponentity = weaponentities[slot];
784 CL_SpawnWeaponentity(this, weaponentity);
785 }
787 this.colormod = '1 1 1' * autocvar_g_player_brightness;
789
790 this.speedrunning = false;
791
792 this.counter_cnt = 0;
793 this.fragsfilter_cnt = 0;
794
796
797 // reset fields the weapons may use
798 FOREACH(Weapons, true,
799 {
800 it.wr_resetplayer(it, this);
801 // reload all reloadable weapons
802 if (it.spawnflags & WEP_FLAG_RELOADABLE)
803 {
804 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
805 {
806 .entity weaponentity = weaponentities[slot];
807 this.(weaponentity).weapon_load[it.m_id] = it.reloading_ammo;
808 }
809 }
810 });
811
812 MUTATOR_CALLHOOK(PlayerSpawn, this, spot);
813 {
814 string s = spot.target;
815 if(g_assault || g_race) // TODO: make targeting work in assault & race without this hack
816 spot.target = string_null;
817 SUB_UseTargets(spot, this, NULL);
818 if(g_assault || g_race)
819 spot.target = s;
820 }
821
823 {
824 sprint(this, strcat("spawnpoint origin: ", vtos(spot.origin), "\n"));
825 delete(spot); // usefull for checking if there are spawnpoints, that let drop through the floor
826 }
827
828 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
829 {
830 .entity weaponentity = weaponentities[slot];
831 entity w_ent = this.(weaponentity);
832 if(slot == 0 || autocvar_g_weaponswitch_debug == 1)
833 w_ent.m_switchweapon = w_getbestweapon(this, weaponentity);
834 else
835 w_ent.m_switchweapon = WEP_Null;
836 w_ent.m_weapon = WEP_Null;
837 w_ent.weaponname = "";
838 w_ent.m_switchingweapon = WEP_Null;
839 w_ent.cnt = -1;
840 }
841
842 MUTATOR_CALLHOOK(PlayerWeaponSelect, this);
843
844 if (CS(this).impulse) ImpulseCommands(this);
845
846 W_ResetGunAlign(this, CS_CVAR(this).cvar_cl_gunalign);
847 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
848 {
849 .entity weaponentity = weaponentities[slot];
850 W_WeaponFrame(this, weaponentity);
851 }
852
853 if (!warmup_stage && !this.alivetime_start)
855
856 antilag_clear(this, CS(this));
857
858 if (warmup_stage)
859 ReadyCount();
860}
861
864{
865 if (IS_REAL_CLIENT(this))
866 {
867 msg_entity = this;
869 WriteEntity(MSG_ONE, this);
870 }
871 if (game_stopped)
872 TRANSMUTE(Observer, this);
873
874 bool use_spawnpoint = (!this.enemy); // check this.enemy here since SetSpectatee will clear it
875 SetSpectatee(this, NULL);
876
877 // reset player keys
878 if(PS(this))
879 PS(this).itemkeys = 0;
880
882
883 if (IS_OBSERVER(this))
884 PutObserverInServer(this, false, use_spawnpoint);
885 else if (IS_PLAYER(this))
886 PutPlayerInServer(this);
887
889}
890
891// TODO do we need all these fields, or should we stop autodetecting runtime
892// changes and just have a console command to update this?
893bool ClientInit_SendEntity(entity this, entity to, int sf)
894{
895 WriteHeader(MSG_ENTITY, _ENT_CLIENT_INIT);
896 return = true;
897 msg_entity = to;
898 // MSG_INIT replacement
899 // TODO: make easier to use
902 ClientInit_misc(this);
903 MUTATOR_CALLHOOK(Ent_Init);
904}
906{
907 int channel = MSG_ONE;
908 WriteHeader(channel, ENT_CLIENT_INIT);
909 WriteByte(channel, g_nexball_meter_period * 32);
910 WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[0]));
911 WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[1]));
912 WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[2]));
913 WriteInt24_t(channel, compressShotOrigin(hook_shotorigin[3]));
914 WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[0]));
915 WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[1]));
916 WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[2]));
917 WriteInt24_t(channel, compressShotOrigin(arc_shotorigin[3]));
918
919 if(autocvar_sv_foginterval && world.fog != "")
920 WriteString(channel, world.fog);
921 else
922 WriteString(channel, "");
923 WriteByte(channel, this.count * 255.0); // g_balance_armor_blockpercent
924 WriteByte(channel, this.cnt * 255.0); // g_balance_damagepush_speedfactor
925 WriteByte(channel, serverflags);
927}
928
930{
931 this.nextthink = time;
933 {
935 this.SendFlags |= 1;
936 }
938 {
940 this.SendFlags |= 1;
941 }
942}
943
945{
946 entity e = new_pure(clientinit);
949
951}
952
953/*
954=============
955SetNewParms
956=============
957*/
959{
960 // initialize parms for a new player
961 parm1 = -(86400 * 366);
962
964}
965
966/*
967=============
968SetChangeParms
969=============
970*/
972{
973 // save parms for level change
974 parm1 = CS(this).parm_idlesince - time;
975
977}
978
979/*
980=============
981DecodeLevelParms
982=============
983*/
985{
986 // load parms
987 CS(this).parm_idlesince = parm1;
988 if (CS(this).parm_idlesince == -(86400 * 366))
989 CS(this).parm_idlesince = time;
990
991 // whatever happens, allow 60 seconds of idling directly after connect for map loading
992 CS(this).parm_idlesince = max(CS(this).parm_idlesince, time - autocvar_sv_maxidle + 60);
993
995}
996
998{
999 // send prediction settings to the client
1000 if(autocvar_g_antilag == 3) // client side hitscan
1001 stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
1002 if(autocvar_sv_gentle)
1003 stuffcmd(e, "cl_cmd settemp cl_gentle 1\n");
1004
1005 stuffcmd(e, sprintf("\ncl_jumpspeedcap_min \"%s\"\n", autocvar_sv_jumpspeedcap_min));
1006 stuffcmd(e, sprintf("\ncl_jumpspeedcap_max \"%s\"\n", autocvar_sv_jumpspeedcap_max));
1007
1008 stuffcmd(e, sprintf("\ncl_shootfromfixedorigin \"%s\"\n", autocvar_g_shootfromfixedorigin));
1009
1011}
1012
1013bool findinlist_abbrev(string tofind, string list)
1014{
1015 if(list == "" || tofind == "")
1016 return false; // empty list or search, just return
1017
1018 // this function allows abbreviated strings!
1019 FOREACH_WORD(list, it != "" && it == substring(tofind, 0, strlen(it)),
1020 {
1021 return true;
1022 });
1023
1024 return false;
1025}
1026
1027bool PlayerInIPList(entity p, string iplist)
1028{
1029 // some safety checks (never allow local?)
1030 if(p.netaddress == "local" || p.netaddress == "" || !IS_REAL_CLIENT(p))
1031 return false;
1032
1033 return findinlist_abbrev(p.netaddress, iplist);
1034}
1035
1036bool PlayerInIDList(entity p, string idlist)
1037{
1038 // NOTE: we do NOT check crypto_idfp_signed here, an unsigned ID is fine too for this
1039 if(!p.crypto_idfp)
1040 return false;
1041
1042 return findinlist_abbrev(p.crypto_idfp, idlist);
1043}
1044
1045bool PlayerInList(entity player, string list)
1046{
1047 if (list == "")
1048 return false;
1049 return boolean(PlayerInIDList(player, list) || PlayerInIPList(player, list));
1050}
1051
1052#ifdef DP_EXT_PRECONNECT
1053/*
1054=============
1055ClientPreConnect
1056
1057Called once (not at each match start) when a client begins a connection to the server
1058=============
1059*/
1060void ClientPreConnect(entity this)
1061{
1063 {
1064 GameLogEcho(sprintf(":connect:%d:%d:%s",
1065 this.playerid,
1066 etof(this),
1067 IS_REAL_CLIENT(this) ? this.netaddress : "bot"));
1068 }
1069}
1070#endif
1071
1072// NOTE csqc uses the active mutators list sent by this function
1073// to understand which mutators are enabled
1074// also note that they aren't all registered mutators, e.g. jetpack, low gravity
1075void SendWelcomeMessage(entity this, int msg_type)
1076{
1077 if (boolean(autocvar_g_campaign))
1078 {
1079 WriteByte(msg_type, 1);
1080 WriteByte(msg_type, Campaign_GetLevelNum());
1081 return;
1082 }
1083
1084 int flags = 0;
1085 if (CS(this).version_mismatch)
1086 flags |= 2;
1087 if (CS(this).version < autocvar_gameversion)
1088 flags |= 4;
1090 if (MapInfo_Map_author != "")
1091 flags |= 8;
1092 WriteByte(msg_type, flags);
1093
1094 WriteString(msg_type, autocvar_hostname);
1096
1098 if (flags & 8)
1101
1103 WriteByte(msg_type, GetPlayerLimit());
1104
1105 MUTATOR_CALLHOOK(BuildMutatorsPrettyString, "");
1106 string modifications = M_ARGV(0, string);
1107
1108 if (!g_weaponarena && cvar("g_balance_blaster_weaponstartoverride") == 0)
1109 modifications = strcat(modifications, ", No start weapons");
1110 if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
1111 modifications = strcat(modifications, ", Low gravity");
1112 if(g_weapon_stay && !g_cts)
1113 modifications = strcat(modifications, ", Weapons stay");
1115 modifications = strcat(modifications, ", Jetpack");
1116 modifications = substring(modifications, 2, strlen(modifications) - 2);
1117
1118 WriteString(msg_type, modifications);
1119
1121
1123 {
1126 }
1127
1128 WriteString(msg_type, cache_mutatormsg);
1129
1130 WriteString(msg_type, strreplace("\\n", "\n", autocvar_sv_motd));
1131}
1132
1142{
1143 if (Ban_MaybeEnforceBanOnce(this)) return;
1144 assert(!IS_CLIENT(this), return);
1145 this.flags |= FL_CLIENT;
1146 assert(player_count >= 0, player_count = 0);
1147
1148 TRANSMUTE(Client, this);
1149 CS(this).version_nagtime = time + 10 + random() * 10;
1150
1151 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_CONNECT, this.netname);
1152
1153 bot_clientconnect(this);
1154
1155 this.team = -1;
1157
1158 TRANSMUTE(Observer, this);
1159
1160 PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
1161
1162 // always track bots, don't ask for cl_allow_uidtracking
1163 if (IS_BOT_CLIENT(this))
1165 else
1166 CS(this).allowed_timeouts = autocvar_sv_timeout_number;
1167
1169 GameLogEcho(strcat(":join:", ftos(this.playerid), ":", ftos(etof(this)), ":", ((IS_REAL_CLIENT(this)) ? GameLog_ProcessIP(this.netaddress) : "bot"), ":", playername(this.netname, this.team, false)));
1170
1171 CS(this).just_joined = true; // stop spamming the eventlog with additional lines when the client connects
1172 this.wants_join = 0;
1173
1174 stuffcmd(this, clientstuff, "\n");
1175 stuffcmd(this, "cl_particles_reloadeffects\n"); // TODO do we still need this?
1176
1177 FixClientCvars(this);
1178
1179 // get version info from player
1180 stuffcmd(this, "cmd clientversion $gameversion\n");
1181
1182 // notify about available teams
1183 if (teamplay)
1184 {
1185 entity balance = TeamBalance_CheckAllowedTeams(this);
1186 int t = TeamBalance_GetAllowedTeams(balance);
1187 TeamBalance_Destroy(balance);
1188 stuffcmd(this, sprintf("set _teams_available %d\n", t));
1189 }
1190 else
1191 {
1192 stuffcmd(this, "set _teams_available 0\n");
1193 }
1194
1196
1197 CS(this).spectatortime = time;
1198 CS(this).jointime = time;
1199
1200 if (IS_REAL_CLIENT(this))
1201 {
1203
1204 if (g_weaponarena_weapons == WEPSET(TUBA))
1205 stuffcmd(this, "cl_cmd settemp chase_active 1\n");
1206 // quickmenu file must be put in a subfolder with an unique name
1207 // to reduce chances of overriding custom client quickmenus
1209 stuffcmd(this, sprintf("cl_cmd settemp _hud_panel_quickmenu_file_from_server %s\n", "wpeditor.txt"));
1211 stuffcmd(this, sprintf("cl_cmd settemp _hud_panel_quickmenu_file_from_server %s\n", autocvar_sv_quickmenu_file));
1212 }
1213
1214 if (!autocvar_sv_foginterval && world.fog != "")
1215 stuffcmd(this, strcat("\nfog ", world.fog, "\nr_fog_exp2 0\nr_drawfog 1\n"));
1216
1217 CSQCMODEL_AUTOINIT(this);
1218
1219 CS(this).model_randomizer = random();
1220
1221 if (IS_REAL_CLIENT(this))
1222 sv_notice_join(this);
1223
1224 this.move_qcphysics = true;
1225
1226 // update physics stats (players can spawn before physics runs)
1227 Physics_UpdateStats(this);
1228
1229 IL_EACH(g_initforplayer, it.init_for_player,
1230 {
1231 it.init_for_player(it, this);
1232 });
1233
1234 Handicap_Initialize(this);
1235
1236 // playban
1238 TRANSMUTE(Observer, this);
1239
1240 if (PlayerInList(this, autocvar_g_chatban_list)) // chatban
1241 CS(this).muted = true;
1242
1244
1245 if (player_count == 1)
1246 {
1248 setpause(0);
1249 localcmd("\nsv_hook_firstjoin\n");
1250 }
1251
1252 if (get_nextmap() != "")
1254
1255 // cvar hook/callback TODO: recheck this when the cvar is changed
1258 this.vote_master = true;
1259}
1260
1263void player_powerups_remove_all(entity this, bool allow_poweroff_sound);
1264
1265/*
1266=============
1267ClientDisconnect
1268
1269Called when a client disconnects from the server
1270=============
1271*/
1273{
1274 assert(IS_CLIENT(this), return);
1275
1276 strfree(this.ignore_list);
1278 {
1279 // don't remove permanent ignores from db, only from list
1280 ignore_remove_player(it, this, false);
1281 });
1282
1284 if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
1285 if (CS(this).active_minigame) part_minigame(this);
1286 if (IS_PLAYER(this)) Send_Effect(EFFECT_SPAWN, this.origin, '0 0 0', 1);
1287
1289 GameLogEcho(strcat(":part:", ftos(this.playerid)));
1290
1291 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_DISCONNECT, this.netname);
1292
1293 if(IS_SPEC(this))
1294 SetSpectatee(this, NULL);
1295
1297
1298 strfree(CS(this).netname_previous); // needs to be before the CS entity is removed!
1300 ClientState_detach(this);
1301
1302 Portal_ClearAll(this);
1303
1305
1307
1308 // Here, everything has been done that requires this player to be a client.
1309
1310 this.flags &= ~FL_CLIENT;
1311
1312 if (this.chatbubbleentity) delete(this.chatbubbleentity);
1313 if (this.killindicator) delete(this.killindicator);
1314
1315 IL_EACH(g_counters, it.realowner == this,
1316 {
1317 delete(it);
1318 });
1319
1321
1323
1324 strfree(this.clientstatus);
1325 if (this.personal) delete(this.personal);
1326
1327 this.playerid = 0;
1328 if (warmup_stage || game_starttime > time) /* warmup OR countdown */ ReadyCount();
1329 if (vote_called && IS_REAL_CLIENT(this)) VoteCount(false);
1330
1331 player_powerups_remove_all(this, IS_PLAYER(this)); // stop powerup sound
1332
1333 ONREMOVE(this);
1334
1335 if (player_count == 0)
1336 localcmd("\nsv_hook_lastleave\n");
1337
1342}
1343
1345{
1346 this.nextthink = time;
1347 if ((this.owner.alpha < 0) || this.owner.chatbubbleentity != this)
1348 {
1349 if(this.owner) // but why can that ever be NULL?
1350 this.owner.chatbubbleentity = NULL;
1351 delete(this);
1352 return;
1353 }
1354
1355 this.mdl = "";
1356
1357 if ( !IS_DEAD(this.owner) && IS_PLAYER(this.owner) && !MUTATOR_CALLHOOK(ShowChatBubble, this.owner, this) )
1358 {
1360 this.mdl = "models/sprites/minigame_busy.iqm";
1361 else if (PHYS_INPUT_BUTTON_CHAT(this.owner))
1362 this.mdl = "models/misc/chatbubble.spr";
1363 }
1364
1365 if ( this.model != this.mdl )
1366 _setmodel(this, this.mdl);
1367
1368}
1369
1371{
1372 if (this.alpha < 0)
1373 return;
1374 // spawn a chatbubble entity if needed
1375 if (!this.chatbubbleentity)
1376 {
1378 this.chatbubbleentity.owner = this;
1379 this.chatbubbleentity.exteriormodeltoclient = this;
1381 this.chatbubbleentity.nextthink = time;
1382 setmodel(this.chatbubbleentity, MDL_CHAT); // precision set below
1383 //setorigin(this.chatbubbleentity, this.origin + '0 0 15' + this.maxs_z * '0 0 1');
1384 setorigin(this.chatbubbleentity, '0 0 15' + this.maxs_z * '0 0 1');
1385 setattachment(this.chatbubbleentity, this, ""); // sticks to moving player better, also conserves bandwidth
1386 this.chatbubbleentity.mdl = this.chatbubbleentity.model;
1387 //this.chatbubbleentity.model = "";
1388 this.chatbubbleentity.effects = EF_LOWPRECISION;
1389 }
1390}
1391
1393{
1394 if(MUTATOR_CALLHOOK(CalculateRespawnTime, this))
1395 return;
1396
1397 float gametype_setting_tmp;
1398 float sdelay_max = GAMETYPE_DEFAULTED_SETTING(respawn_delay_max);
1399 float sdelay_small = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small);
1400 float sdelay_large = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large);
1401 float sdelay_small_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small_count);
1402 float sdelay_large_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large_count);
1403 float waves = GAMETYPE_DEFAULTED_SETTING(respawn_waves);
1404
1405 float pcount = 1; // Include myself whether or not team is already set right and I'm a "player".
1406 if (teamplay)
1407 {
1408 FOREACH_CLIENT(IS_PLAYER(it) && it != this,
1409 {
1410 if(it.team == this.team)
1411 ++pcount;
1412 });
1413 if (sdelay_small_count == 0)
1414 sdelay_small_count = 1;
1415 if (sdelay_large_count == 0)
1416 sdelay_large_count = 1;
1417 }
1418 else
1419 {
1420 FOREACH_CLIENT(IS_PLAYER(it) && it != this,
1421 {
1422 ++pcount;
1423 });
1424 if (sdelay_small_count == 0)
1425 {
1426 if (IS_INDEPENDENT_PLAYER(this))
1427 {
1428 // Players play independently. No point in requiring enemies.
1429 sdelay_small_count = 1;
1430 }
1431 else
1432 {
1433 // Players play AGAINST each other. Enemies required.
1434 sdelay_small_count = 2;
1435 }
1436 }
1437 if (sdelay_large_count == 0)
1438 {
1439 if (IS_INDEPENDENT_PLAYER(this))
1440 {
1441 // Players play independently. No point in requiring enemies.
1442 sdelay_large_count = 1;
1443 }
1444 else
1445 {
1446 // Players play AGAINST each other. Enemies required.
1447 sdelay_large_count = 2;
1448 }
1449 }
1450 }
1451
1452 float sdelay;
1453
1454 if (pcount <= sdelay_small_count)
1455 sdelay = sdelay_small;
1456 else if (pcount >= sdelay_large_count)
1457 sdelay = sdelay_large;
1458 else // NOTE: this case implies sdelay_large_count > sdelay_small_count.
1459 sdelay = sdelay_small + (sdelay_large - sdelay_small) * (pcount - sdelay_small_count) / (sdelay_large_count - sdelay_small_count);
1460
1461 if(waves)
1462 this.respawn_time = ceil((time + sdelay) / waves) * waves;
1463 else
1464 this.respawn_time = time + sdelay;
1465
1466 if(sdelay < sdelay_max)
1467 this.respawn_time_max = time + sdelay_max;
1468 else
1469 this.respawn_time_max = this.respawn_time;
1470
1471 if((sdelay + waves >= 5.0) && (this.respawn_time - time > 1.75))
1472 this.respawn_countdown = 10; // first number to count down from is 10
1473 else
1474 this.respawn_countdown = -1; // do not count down
1475
1478}
1479
1480// LordHavoc: this hack will be removed when proper _pants/_shirt layers are
1481// added to the model skins
1482/*void UpdateColorModHack()
1483{
1484 float c;
1485 c = this.clientcolors & 15;
1486 // LordHavoc: only bothering to support white, green, red, yellow, blue
1487 if (!teamplay) this.colormod = '0 0 0';
1488 else if (c == 0) this.colormod = '1.00 1.00 1.00';
1489 else if (c == 3) this.colormod = '0.10 1.73 0.10';
1490 else if (c == 4) this.colormod = '1.73 0.10 0.10';
1491 else if (c == 12) this.colormod = '1.22 1.22 0.10';
1492 else if (c == 13) this.colormod = '0.10 0.10 1.73';
1493 else this.colormod = '1 1 1';
1494}*/
1495
1496void respawn(entity this)
1497{
1498 bool damagedbycontents_prev = this.damagedbycontents;
1499 if(this.alpha >= 0)
1500 {
1502 {
1503 this.solid = SOLID_NOT;
1504 this.takedamage = DAMAGE_NO;
1505 this.damagedbycontents = false;
1511 Send_Effect(EFFECT_RESPAWN_GHOST, this.origin, '0 0 0', 1);
1514 }
1515 else
1516 SUB_SetFade (this, time, 1); // fade out the corpse immediately
1517 }
1518
1519 CopyBody(this, 1);
1520 this.damagedbycontents = damagedbycontents_prev;
1521
1522 this.effects |= EF_NODRAW; // prevent another CopyBody
1523 PutClientInServer(this);
1524}
1525
1526void play_countdown(entity this, float finished, Sound samp)
1527{
1528 TC(Sound, samp);
1529 float time_left = finished - time;
1530 if(IS_REAL_CLIENT(this) && time_left < 6 && floor(time_left - frametime) != floor(time_left))
1531 sound(this, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
1532}
1533
1534// it removes special powerups not handled by StatusEffects
1535void player_powerups_remove_all(entity this, bool allow_poweroff_sound)
1536{
1538 {
1539 // don't play the poweroff sound when the game restarts or the player disconnects
1540 if (allow_poweroff_sound && time > game_starttime + 1 && IS_CLIENT(this)
1542 sound(this, CH_INFO, SND_POWEROFF, VOL_BASE, ATTEN_NORM);
1543
1545 stopsound(this, CH_TRIGGER_SINGLE); // get rid of the pickup sound
1546
1548 }
1549}
1550
1552{
1553 if((this.items & IT_USING_JETPACK) && !IS_DEAD(this) && !game_stopped)
1554 this.modelflags |= MF_ROCKET;
1555 else
1556 this.modelflags &= ~MF_ROCKET;
1557
1558 this.effects &= ~EF_NODEPTHTEST;
1559
1560 if (IS_DEAD(this))
1561 player_powerups_remove_all(this, true);
1562
1563 if((this.alpha < 0 || IS_DEAD(this)) && !this.vehicle) // don't apply the flags if the player is gibbed
1564 return;
1565
1566 // add a way to see what the items were BEFORE all of these checks for the mutator hook
1567 int items_prev = this.items;
1568
1569 if (!MUTATOR_IS_ENABLED(mutator_instagib))
1570 {
1571 // NOTE: superweapons are a special case and as such are handled here instead of the status effects system
1572 if (this.items & IT_SUPERWEAPON)
1573 {
1574 if (!(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
1575 {
1576 StatusEffects_remove(STATUSEFFECT_Superweapon, this, STATUSEFFECT_REMOVE_NORMAL);
1577 this.items &= ~IT_SUPERWEAPON;
1578 //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_LOST, this.netname);
1579 Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_LOST);
1580 }
1581 else if (this.items & IT_UNLIMITED_SUPERWEAPONS)
1582 {
1583 // don't let them run out
1584 }
1585 else
1586 {
1587 play_countdown(this, StatusEffects_gettime(STATUSEFFECT_Superweapon, this), SND_POWEROFF);
1588 if (time >= StatusEffects_gettime(STATUSEFFECT_Superweapon, this))
1589 {
1590 this.items &= ~IT_SUPERWEAPON;
1591 STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
1592 //Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_BROKEN, this.netname);
1593 Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_BROKEN);
1594 }
1595 }
1596 }
1597 else if(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)
1598 {
1599 if (time < StatusEffects_gettime(STATUSEFFECT_Superweapon, this) || (this.items & IT_UNLIMITED_SUPERWEAPONS))
1600 {
1601 this.items |= IT_SUPERWEAPON;
1602 if(!(this.items & IT_UNLIMITED_SUPERWEAPONS))
1603 {
1604 if(!g_cts)
1605 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_SUPERWEAPON_PICKUP, this.netname);
1606 Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_SUPERWEAPON_PICKUP);
1607 }
1608 }
1609 else
1610 {
1611 if(StatusEffects_active(STATUSEFFECT_Superweapon, this))
1612 StatusEffects_remove(STATUSEFFECT_Superweapon, this, STATUSEFFECT_REMOVE_TIMEOUT);
1613 STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
1614 }
1615 }
1616 else if(StatusEffects_active(STATUSEFFECT_Superweapon, this)) // cheaper to check than to update each frame!
1617 {
1618 StatusEffects_remove(STATUSEFFECT_Superweapon, this, STATUSEFFECT_REMOVE_CLEAR);
1619 }
1620 }
1621
1623 this.effects |= EF_NODEPTHTEST;
1624
1626 this.effects |= EF_FULLBRIGHT;
1627
1628 MUTATOR_CALLHOOK(PlayerPowerups, this, items_prev);
1629}
1630
1631float CalcRegen(float current, float stable, float regenfactor, float regenframetime)
1632{
1633 if(current > stable)
1634 return current;
1635 else if(current > stable - 0.25) // when close enough, "snap"
1636 return stable;
1637 else
1638 return min(stable, current + (stable - current) * regenfactor * regenframetime);
1639}
1640
1641float CalcRot(float current, float stable, float rotfactor, float rotframetime)
1642{
1643 if(current < stable)
1644 return current;
1645 else if(current < stable + 0.25) // when close enough, "snap"
1646 return stable;
1647 else
1648 return max(stable, current + (stable - current) * rotfactor * rotframetime);
1649}
1650
1651void RotRegen(entity this, Resource res, float limit_mod,
1652 float regenstable, float regenfactor, float regenlinear, float regenframetime,
1653 float rotstable, float rotfactor, float rotlinear, float rotframetime)
1654{
1655 float old = GetResource(this, res);
1656 float current = old;
1657 if(current > rotstable)
1658 {
1659 if(rotframetime > 0)
1660 {
1661 current = CalcRot(current, rotstable, rotfactor, rotframetime);
1662 current = max(rotstable, current - rotlinear * rotframetime);
1663 }
1664 }
1665 else if(current < regenstable)
1666 {
1667 if(regenframetime > 0)
1668 {
1669 current = CalcRegen(current, regenstable, regenfactor, regenframetime);
1670 current = min(regenstable, current + regenlinear * regenframetime);
1671 }
1672 }
1673
1674 float limit = GetResourceLimit(this, res) * limit_mod;
1675 if(current > limit)
1676 current = limit;
1677
1678 if (current != old)
1679 SetResource(this, res, current);
1680}
1681
1683{
1684 float max_mod, regen_mod, rot_mod, limit_mod;
1685 max_mod = regen_mod = rot_mod = limit_mod = 1;
1686
1687 float regen_health = autocvar_g_balance_health_regen;
1688 float regen_health_linear = autocvar_g_balance_health_regenlinear;
1689 float regen_health_rot = autocvar_g_balance_health_rot;
1690 float regen_health_rotlinear = autocvar_g_balance_health_rotlinear;
1691 float regen_health_stable = autocvar_g_balance_health_regenstable;
1692 float regen_health_rotstable = autocvar_g_balance_health_rotstable;
1693 bool mutator_returnvalue = MUTATOR_CALLHOOK(PlayerRegen, this, max_mod, regen_mod, rot_mod, limit_mod, regen_health, regen_health_linear, regen_health_rot,
1694 regen_health_rotlinear, regen_health_stable, regen_health_rotstable);
1695 max_mod = M_ARGV(1, float);
1696 regen_mod = M_ARGV(2, float);
1697 rot_mod = M_ARGV(3, float);
1698 limit_mod = M_ARGV(4, float);
1699 regen_health = M_ARGV(5, float);
1700 regen_health_linear = M_ARGV(6, float);
1701 regen_health_rot = M_ARGV(7, float);
1702 regen_health_rotlinear = M_ARGV(8, float);
1703 regen_health_stable = M_ARGV(9, float);
1704 regen_health_rotstable = M_ARGV(10, float);
1705
1706 float rotstable, regenstable, rotframetime, regenframetime;
1707
1708 if(!mutator_returnvalue)
1709 {
1712 regenframetime = (time > this.pauseregen_finished) ? (regen_mod * frametime) : 0;
1713 rotframetime = (time > this.pauserotarmor_finished) ? (rot_mod * frametime) : 0;
1714 RotRegen(this, RES_ARMOR, limit_mod,
1717
1718 // NOTE: max_mod is only applied to health
1719 regenstable = regen_health_stable * max_mod;
1720 rotstable = regen_health_rotstable * max_mod;
1721 regenframetime = (time > this.pauseregen_finished) ? (regen_mod * frametime) : 0;
1722 rotframetime = (time > this.pauserothealth_finished) ? (rot_mod * frametime) : 0;
1723 RotRegen(this, RES_HEALTH, limit_mod,
1724 regenstable, regen_health, regen_health_linear, regenframetime,
1725 rotstable, regen_health_rot, regen_health_rotlinear, rotframetime);
1726 }
1727
1728 // if player rotted to death... die!
1729 // check this outside above checks, as player may still be able to rot to death
1730 if(GetResource(this, RES_HEALTH) < 1)
1731 {
1732 if(this.vehicle)
1734 if(this.event_damage)
1735 this.event_damage(this, this, this, 1, DEATH_ROT.m_id, DMG_NOWEP, this.origin, '0 0 0');
1736 }
1737
1738 if (!(this.items & IT_UNLIMITED_AMMO))
1739 {
1742 regenframetime = ((time > this.pauseregen_finished) && (this.items & ITEM_FuelRegen.m_itemid)) ? frametime : 0;
1743 rotframetime = (time > this.pauserotfuel_finished) ? frametime : 0;
1744 RotRegen(this, RES_FUEL, 1,
1747 }
1748}
1749
1751void SetZoomState(entity this, float newzoom)
1752{
1753 if(newzoom != CS(this).zoomstate)
1754 {
1755 CS(this).zoomstate = newzoom;
1756 ClientData_Touch(this, true);
1757 }
1758 zoomstate_set = true;
1759}
1760
1762{
1764 if (game_stopped)
1765 {
1766 CS(this).pressedkeys = 0;
1767 STAT(PRESSED_KEYS, this) = 0;
1768 return;
1769 }
1770
1771 // NOTE: GetPressedKeys and PM_dodging_GetPressedKeys use similar code
1772 int keys = STAT(PRESSED_KEYS, this);
1773 keys = BITSET(keys, KEY_FORWARD, CS(this).movement.x > 0);
1774 keys = BITSET(keys, KEY_BACKWARD, CS(this).movement.x < 0);
1775 keys = BITSET(keys, KEY_RIGHT, CS(this).movement.y > 0);
1776 keys = BITSET(keys, KEY_LEFT, CS(this).movement.y < 0);
1777
1778 keys = BITSET(keys, KEY_JUMP, PHYS_INPUT_BUTTON_JUMP(this));
1779 keys = BITSET(keys, KEY_CROUCH, IS_DUCKED(this)); // workaround: player can't un-crouch until their path is clear, so we keep the button held here
1780 keys = BITSET(keys, KEY_ATCK, PHYS_INPUT_BUTTON_ATCK(this));
1781 keys = BITSET(keys, KEY_ATCK2, PHYS_INPUT_BUTTON_ATCK2(this));
1782 CS(this).pressedkeys = keys; // store for other users
1783
1784 STAT(PRESSED_KEYS, this) = keys;
1785}
1786
1787/*
1788======================
1789spectate mode routines
1790======================
1791*/
1792
1793void SpectateCopy(entity this, entity spectatee)
1794{
1795 TC(Client, this); TC(Client, spectatee);
1796
1797 MUTATOR_CALLHOOK(SpectateCopy, spectatee, this);
1798 PS(this) = PS(spectatee);
1799 this.armortype = spectatee.armortype;
1801 SetResourceExplicit(this, RES_CELLS, GetResource(spectatee, RES_CELLS));
1802 SetResourceExplicit(this, RES_SHELLS, GetResource(spectatee, RES_SHELLS));
1803 SetResourceExplicit(this, RES_BULLETS, GetResource(spectatee, RES_BULLETS));
1804 SetResourceExplicit(this, RES_ROCKETS, GetResource(spectatee, RES_ROCKETS));
1805 SetResourceExplicit(this, RES_FUEL, GetResource(spectatee, RES_FUEL));
1806 this.effects = spectatee.effects & EFMASK_CHEAP; // eat performance
1807 SetResourceExplicit(this, RES_HEALTH, GetResource(spectatee, RES_HEALTH));
1808 CS(this).impulse = 0;
1809 this.disableclientprediction = 1; // no need to run prediction on a spectator
1810 this.items = spectatee.items;
1811 STAT(LAST_PICKUP, this) = STAT(LAST_PICKUP, spectatee);
1812 STAT(HIT_TIME, this) = STAT(HIT_TIME, spectatee);
1813 STAT(AIR_FINISHED, this) = STAT(AIR_FINISHED, spectatee);
1814 STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
1815 STAT(WEAPONS, this) = STAT(WEAPONS, spectatee);
1816 this.punchangle = spectatee.punchangle;
1817 this.view_ofs = spectatee.view_ofs;
1818 this.velocity = spectatee.velocity;
1819 this.dmg_take = spectatee.dmg_take;
1820 this.dmg_save = spectatee.dmg_save;
1821 this.dmg_inflictor = spectatee.dmg_inflictor;
1822 this.v_angle = spectatee.v_angle;
1823 this.angles = spectatee.v_angle;
1824 this.viewloc = spectatee.viewloc;
1825 if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
1826 this.fixangle = true;
1827 setorigin(this, spectatee.origin);
1828 setsize(this, spectatee.mins, spectatee.maxs);
1829 SetZoomState(this, CS(spectatee).zoomstate);
1830
1831 anticheat_spectatecopy(this, spectatee);
1832 STAT(HUD, this) = STAT(HUD, spectatee);
1833 if(spectatee.vehicle)
1834 {
1835 this.angles = spectatee.v_angle;
1836
1837 //this.fixangle = false;
1838 //this.velocity = spectatee.vehicle.velocity;
1839 this.vehicle_health = spectatee.vehicle_health;
1840 this.vehicle_shield = spectatee.vehicle_shield;
1841 this.vehicle_energy = spectatee.vehicle_energy;
1842 this.vehicle_ammo1 = spectatee.vehicle_ammo1;
1843 this.vehicle_ammo2 = spectatee.vehicle_ammo2;
1844 this.vehicle_reload1 = spectatee.vehicle_reload1;
1845 this.vehicle_reload2 = spectatee.vehicle_reload2;
1846
1847 //msg_entity = this;
1848
1849 // WriteByte (MSG_ONE, SVC_SETVIEWANGLES);
1850 //WriteAngle(MSG_ONE, spectatee.v_angle.x);
1851 // WriteAngle(MSG_ONE, spectatee.v_angle.y);
1852 // WriteAngle(MSG_ONE, spectatee.v_angle.z);
1853
1854 //WriteByte (MSG_ONE, SVC_SETVIEW);
1855 // WriteEntity(MSG_ONE, this);
1856 //makevectors(spectatee.v_angle);
1857 //setorigin(this, spectatee.origin - v_forward * 400 + v_up * 300);*/
1858 }
1859}
1860
1862{
1863 if(!this.enemy)
1864 return false;
1865
1866 if(!IS_PLAYER(this.enemy) || this == this.enemy)
1867 {
1868 SetSpectatee(this, NULL);
1869 return false;
1870 }
1871
1872 SpectateCopy(this, this.enemy);
1873 if (IS_OBSERVER(this))
1874 TRANSMUTE(Spectator, this);
1875
1876 return true;
1877}
1878
1880{
1881 if(!IS_PLAYER(this.enemy))
1882 return false;
1883
1884 ClientData_Touch(this.enemy, true);
1885
1886 msg_entity = this;
1888 WriteEntity(MSG_ONE, this.enemy);
1890 accuracy_resend(this);
1891
1892 if(!SpectateUpdate(this))
1893 PutObserverInServer(this, false, true);
1894
1895 return true;
1896}
1897
1898void SetSpectatee_status(entity this, int spectatee_num)
1899{
1900 int oldspectatee_status = CS(this).spectatee_status;
1901 CS(this).spectatee_status = spectatee_num;
1902
1903 if (CS(this).spectatee_status != oldspectatee_status)
1904 {
1905 if (STAT(PRESSED_KEYS, this))
1906 {
1907 CS(this).pressedkeys = 0;
1908 STAT(PRESSED_KEYS, this) = 0;
1909 }
1910
1911 ClientData_Touch(this, true);
1912
1913 // init or clear race data
1914 if ((g_race || g_cts) && g_race_qualifying && IS_REAL_CLIENT(this))
1915 {
1916 msg_entity = this;
1917
1918 if (this.enemy && this.enemy.race_laptime)
1919 {
1920 // init
1922 }
1923 else
1924 {
1925 // send reset to this spectator
1926 WriteHeader(MSG_ONE, TE_CSQC_RACE);
1928 }
1929 }
1930 }
1931}
1932
1933void SetSpectatee(entity this, entity spectatee)
1934{
1935 if(IS_BOT_CLIENT(this))
1936 return; // bots abuse .enemy, this code is useless to them
1937
1938 entity old_spectatee = this.enemy;
1939
1940 this.enemy = spectatee;
1941
1942 // WEAPONTODO
1943 // these are required to fix the spectator bug with arc
1944 if(old_spectatee)
1945 {
1946 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
1947 {
1948 .entity weaponentity = weaponentities[slot];
1949 if(old_spectatee.(weaponentity).arc_beam)
1950 old_spectatee.(weaponentity).arc_beam.SendFlags |= ARC_SF_UPDATE;
1951 }
1952 }
1953 if(spectatee)
1954 {
1955 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
1956 {
1957 .entity weaponentity = weaponentities[slot];
1958 if(spectatee.(weaponentity).arc_beam)
1959 spectatee.(weaponentity).arc_beam.SendFlags |= ARC_SF_UPDATE;
1960 }
1961 }
1962
1963 if (spectatee)
1964 SetSpectatee_status(this, etof(spectatee));
1965
1966 // needed to update spectator list
1967 if(old_spectatee)
1968 ClientData_Touch(old_spectatee, true);
1969}
1970
1971bool Spectate(entity this, entity pl)
1972{
1973 if(MUTATOR_CALLHOOK(SpectateSet, this, pl))
1974 return false;
1975 pl = M_ARGV(1, entity);
1976
1977 SetSpectatee(this, pl);
1978 return SpectateSet(this);
1979}
1980
1982{
1983 entity ent = find(this.enemy, classname, STR_PLAYER);
1984
1985 if (MUTATOR_CALLHOOK(SpectateNext, this, ent))
1986 ent = M_ARGV(1, entity);
1987 else if (!ent)
1988 ent = find(ent, classname, STR_PLAYER);
1989
1990 if(ent) SetSpectatee(this, ent);
1991
1992 return SpectateSet(this);
1993}
1994
1996{
1997 // NOTE: chain order is from the highest to the lower entnum (unlike find)
1998 entity ent = findchain(classname, STR_PLAYER);
1999 if (!ent) // no player
2000 return false;
2001
2002 entity first = ent;
2003 // skip players until current spectated player
2004 if(this.enemy)
2005 while(ent && ent != this.enemy)
2006 ent = ent.chain;
2007
2008 switch (MUTATOR_CALLHOOK(SpectatePrev, this, ent, first))
2009 {
2010 case MUT_SPECPREV_FOUND:
2011 ent = M_ARGV(1, entity);
2012 break;
2014 return true;
2016 default:
2017 {
2018 if(ent.chain)
2019 ent = ent.chain;
2020 else
2021 ent = first;
2022 break;
2023 }
2024 }
2025
2026 SetSpectatee(this, ent);
2027 return SpectateSet(this);
2028}
2029
2030/*
2031=============
2032ShowRespawnCountdown()
2033
2034Update a respawn countdown display.
2035=============
2036*/
2038{
2039 float number;
2040 if(!IS_DEAD(this)) // just respawned?
2041 return;
2042 else
2043 {
2044 number = ceil(this.respawn_time - time);
2045 if(number <= 0)
2046 return;
2047 if(number <= this.respawn_countdown)
2048 {
2049 this.respawn_countdown = number - 1;
2050 if(ceil(this.respawn_time - (time + 0.5)) == number) // only say it if it is the same number even in 0.5s; to prevent overlapping sounds
2051 Send_Notification(NOTIF_ONE, this, MSG_ANNCE, Announcer_PickNumber(CNT_RESPAWN, number));
2052 }
2053 }
2054}
2055
2057{
2059 return false;
2060 if (QueuedPlayersReady(this, true))
2061 return false;
2062 if (frametime) // once per frame is more than enough
2063 stuffcmd(this, "_scoreboard_team_selection 1\n");
2064 return true;
2065}
2066
2068void Join(entity this, bool queued_join)
2069{
2070 entity player_with_dibs = NULL;
2071
2073 {
2075 ReadyRestart(true);
2077 }
2078
2079 if(queued_join
2080 && TeamBalance_AreEqual(this, true)) // if a player couldn't tag in for balance, don't join them here as it would cause a stack
2081 {
2082 // First we must join player(s) queued for specific team(s) (they chose first)
2083 // so TeamBalance_JoinBestTeam() (if necessary) won't select the same team(s).
2084 // Relies on `this` skipping the queue (this.team already set, this.wants_join not set) or using autoselect.
2085 FOREACH_CLIENT(it != this && it.wants_join > 0,
2086 {
2087 // detect any conflict between `this` and a queued player (queuePlayer() handles other conflicts)
2088 if (this.team < 0 && this.team_selected > 0 // `this` can't have their preference
2089 && it.wants_join == this.team_selected) // `it` is the player who already chose the team `this` wanted
2090 player_with_dibs = it;
2091
2092 Join(it, false);
2093 });
2094
2095 // Second pass: queued players whose team will be autoselected
2096 FOREACH_CLIENT(it != this && it.wants_join < 0,
2097 {
2098 Join(it, false);
2099 });
2100 }
2101
2102 Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_PREVENT_JOIN);
2103
2104 TRANSMUTE(Player, this);
2105 PutClientInServer(this);
2106
2107 if(IS_PLAYER(this)) // could be false due to PutClientInServer() mutator hook
2108 {
2109 if (!teamplay)
2110 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_PLAY, this.netname);
2111 else if (player_with_dibs)
2112 // limitation: notifications support only 1 translated team name
2113 // so the team `this` preferred can't be mentioned, only the team they got assigned to.
2114 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_JOIN_PLAY_TEAM_QUEUECONFLICT), player_with_dibs.netname);
2115 else
2116 {
2117 if (this.wants_join && game_starttime < time && !warmup_stage) // No countdown running && not returning to warmup via ReadyRestart_force
2118 Send_Notification(NOTIF_ONE_ONLY, this, MSG_ANNCE, ANNCE_BEGIN); // Get queued player's attention
2119 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_JOIN_PLAY_TEAM));
2120 }
2121 }
2122
2123 this.team_selected = 0;
2124 this.wants_join = 0;
2125}
2126
2128{
2129 if(g_duel)
2130 return 2; // TODO: this workaround is needed since the mutator hook from duel can't be activated before the gametype is loaded (e.g. switching modes via gametype vote screen)
2131 // don't return map_maxplayers during intermission as it would interfere with MapHasRightSize()
2133 MUTATOR_CALLHOOK(GetPlayerLimit, player_limit);
2134 player_limit = M_ARGV(0, int);
2135 return player_limit < maxclients && player_limit > 0 ? player_limit : 0;
2136}
2137
2144{
2145 if(!this)
2146 // this is called that way when checking if anyone may be able to join (to build qcstatus)
2147 // so report 0 free slots if restricted
2148 {
2149 if(autocvar_g_forced_team_otherwise == "spectate"
2150 || autocvar_g_forced_team_otherwise == "spectator"
2151 || (teamplay && lockteams))
2152 return 0;
2153 }
2154
2155 int totalClients = 0;
2156 int currentlyPlaying = 0;
2157 FOREACH_CLIENT(it != this,
2158 {
2159 ++totalClients;
2160 if(IS_PLAYER(it) || INGAME(it))
2161 ++currentlyPlaying;
2162 });
2163
2164 int player_limit = GetPlayerLimit();
2165
2166 int free_slots = max(0, (player_limit ? player_limit : maxclients) - currentlyPlaying);
2167 if (this || maxclients - totalClients) // don't add bot slots in the getstatus case if nobody can connect
2168 free_slots += bots_would_leave;
2169 if (!this) // getstatus case
2170 free_slots = min(free_slots, maxclients - totalClients);
2171
2172 if(this && !free_slots)
2173 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT, player_limit);
2174
2175 return free_slots;
2176}
2177
2178// Callsites other than ClientCommand_selectteam() should pass this.wants_join as team_index
2179// so the player won't accidentally reset a specific preference by pressing +jump
2180// and will see the centreprint with their current preference each time they press +jump.
2181bool queuePlayer(entity this, int team_index)
2182{
2183 // check if a queued player already chose the selected team
2184 if (team_index > 0)
2185 {
2186 FOREACH_CLIENT(it != this && it.wants_join == team_index,
2187 {
2188 if (QueuedPlayersReady(this, false))
2189 {
2190 // Join() will handle the notification so it can mention the team `player` will actually get
2191 this.team = -1; // force autoselect in Join() (last player skips queue)
2192 this.team_selected = team_index; // tell it which team to check for to find the conflict
2193 }
2194 else // > 2 teams
2195 {
2196 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, APP_TEAM_NUM(Team_IndexToTeam(team_index), CENTER_JOIN_PREVENT_QUEUE_TEAM_CONFLICT), it.netname);
2197 this.wants_join = -1; // force autoselect in Join()
2198 this.team_selected = -1; // prevents clobbering by CENTER_JOIN_PREVENT_QUEUE
2199 }
2200 return true;
2201 });
2202 }
2203
2204 if (QueuedPlayersReady(this, false))
2205 return false;
2206
2207 if (team_index <= 0) // team auto select deferred until Join()
2208 {
2209 if (team_index != this.wants_join || !this.wants_join) // prevents chatcon spam
2210 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_JOIN_WANTS, this.netname);
2211 if (this.team_selected >= 0) // prevents CENTER_JOIN_PREVENT_QUEUE_TEAM_CONFLICT getting clobbered
2212 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT_QUEUE);
2213 this.wants_join = -1;
2214 this.team_selected = 0;
2215 }
2216 else
2217 {
2218 int team_num = Team_IndexToTeam(team_index);
2219 if (team_index != this.wants_join) // prevents chatcon spam
2220 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(team_num, INFO_JOIN_WANTS_TEAM), this.netname);
2221 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, APP_TEAM_NUM(team_num, CENTER_JOIN_PREVENT_QUEUE_TEAM));
2222 this.wants_join = team_index; // Player queued to join
2223 this.team_selected = team_index;
2224 }
2225
2226 return true;
2227}
2228
2230bool joinAllowed(entity this, int team_index)
2231{
2232 if (CS(this).version_mismatch)
2233 {
2234 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT_VERSIONMISMATCH);
2235 return false;
2236 }
2237 if (time < CS(this).jointime + MIN_SPEC_TIME) return false;
2238 if (teamplay && lockteams)
2239 {
2240 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_TEAMCHANGE_LOCKED);
2241 return false;
2242 }
2243
2244 if (Player_GetForcedTeamIndex(this) == TEAM_FORCE_SPECTATOR) return false;
2245
2246 if (!INGAME(this) && PlayerInList(this, autocvar_g_playban_list))
2247 {
2248 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PLAYBAN);
2249 return false;
2250 }
2251
2252 // IS_PLAYER for most gametypes, INGAME for ca, lms, surv
2253 if (autocvar_g_maxping && !(IS_PLAYER(this) || INGAME(this)) && !this.wants_join)
2254 {
2255 if (this.ping <= 0) return false; // too soon
2256 if (this.ping > autocvar_g_maxping)
2257 {
2258 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_JOIN_PREVENT_PING);
2259 return false;
2260 }
2261 }
2262
2263 if (QueueNeeded(this))
2264 {
2265 if (team_index == 0) // so ClientCommand_selectteam() can check joinAllowed() before calling SetPlayerTeam() without chicken/egg problem
2266 if (ShowTeamSelection(this)) return false; // only needed by callsites other than selectteam
2267 // queuePlayer called here so that only conditions above block queuing (g_maxplayers shouldn't)
2268 if (queuePlayer(this, team_index)) return false;
2269 if (!nJoinAllowed(this)) return false;
2270 }
2271 else
2272 {
2273 if (!nJoinAllowed(this)) return false;
2274 if (team_index == 0) // so ClientCommand_selectteam() can check joinAllowed() before calling SetPlayerTeam() without chicken/egg problem
2275 if (ShowTeamSelection(this)) return false; // only needed by callsites other than selectteam
2276 }
2277
2278 return true;
2279}
2280
2282{
2283 // waypoint editor implements a similar feature for waypoints
2285 return;
2286
2287 if (wasfreed(this.wp_aimed))
2288 this.wp_aimed = NULL;
2289
2291 entity ent = NULL;
2292 if (trace_ent)
2293 {
2294 ent = trace_ent;
2295 if (ent != this.wp_aimed)
2296 {
2297 string str = sprintf(
2298 "^7ent #%d\n^8 netname: ^3%s\n^8 classname: ^5%s\n^8 origin: ^2'%s'",
2299 etof(ent), ent.netname, ent.classname, vtos(ent.origin));
2300 debug_text_3d((ent.absmin + ent.absmax) * 0.5, str, 0, 7, '0 0 0');
2301 }
2302 }
2303 if (this.wp_aimed != ent)
2304 this.wp_aimed = ent;
2305}
2306
2309{
2311 {
2312 this.modelflags &= ~MF_ROCKET;
2314 IntermissionThink(this);
2315 return false;
2316 }
2317
2319 {
2320 // don't allow the player to turn around while game is paused
2321 // FIXME turn this into CSQC stuff
2322 this.v_angle = this.lastV_angle;
2323 this.angles = this.lastV_angle;
2324 this.fixangle = true;
2325 }
2326
2327 if (frametime) player_powerups(this);
2328
2330
2331 if (IS_DEAD(this))
2332 {
2333 if (this.personal && g_race_qualifying
2334 && (autocvar_g_allow_checkpoints || CheatsAllowed(this, CHIMPULSE_SPEEDRUN.impulse, 0, 0, false, true)))
2335 {
2336 if (time > this.respawn_time)
2337 {
2338 STAT(RESPAWN_TIME, this) = this.respawn_time = time + 1; // only retry once a second
2339 respawn(this);
2340 CS(this).impulse = CHIMPULSE_SPEEDRUN.impulse;
2341 }
2342 }
2343 else
2344 {
2345 if (frametime) player_anim(this);
2346
2347 if (this.respawn_flags & RESPAWN_DENY)
2348 {
2349 STAT(RESPAWN_TIME, this) = 0;
2350 return false;
2351 }
2352
2353 bool button_pressed = (PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this) || PHYS_INPUT_BUTTON_ATCK2(this) || PHYS_INPUT_BUTTON_HOOK(this) || PHYS_INPUT_BUTTON_USE(this));
2354
2355 switch(this.deadflag)
2356 {
2357 case DEAD_DYING:
2358 {
2359 if ((this.respawn_flags & RESPAWN_FORCE) && !(this.respawn_time < this.respawn_time_max))
2361 else if (!button_pressed || (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE)))
2362 this.deadflag = DEAD_DEAD;
2363 break;
2364 }
2365 case DEAD_DEAD:
2366 {
2367 if (button_pressed)
2369 else if (time >= this.respawn_time_max && (this.respawn_flags & RESPAWN_FORCE))
2371 break;
2372 }
2373 case DEAD_RESPAWNABLE:
2374 {
2375 if (!button_pressed || (this.respawn_flags & RESPAWN_FORCE))
2377 break;
2378 }
2379 case DEAD_RESPAWNING:
2380 {
2381 if (time > this.respawn_time)
2382 {
2383 this.respawn_time = time + 1; // only retry once a second
2384 this.respawn_time_max = this.respawn_time;
2385 respawn(this);
2386 }
2387 break;
2388 }
2389 }
2390
2392
2393 if (this.respawn_flags & RESPAWN_SILENT)
2394 STAT(RESPAWN_TIME, this) = 0;
2395 else if ((this.respawn_flags & RESPAWN_FORCE) && this.respawn_time < this.respawn_time_max)
2396 {
2397 if (time < this.respawn_time)
2398 STAT(RESPAWN_TIME, this) = this.respawn_time;
2399 else if (this.deadflag != DEAD_RESPAWNING)
2400 STAT(RESPAWN_TIME, this) = -this.respawn_time_max;
2401 }
2402 else
2403 STAT(RESPAWN_TIME, this) = this.respawn_time;
2404 }
2405
2406 // if respawning, invert stat_respawn_time to indicate this, the client translates it
2407 if (this.deadflag == DEAD_RESPAWNING && STAT(RESPAWN_TIME, this) > 0)
2408 STAT(RESPAWN_TIME, this) *= -1;
2409
2410 return false;
2411 }
2412
2413 FixPlayermodel(this);
2414
2416 {
2418 stuffcmd(this, sprintf("\ncl_shootfromfixedorigin \"%s\"\n", autocvar_g_shootfromfixedorigin));
2419 }
2420
2421 // reset gun alignment when dual wielding status changes
2422 // to ensure guns are always aligned right and left
2423 bool dualwielding = W_DualWielding(this);
2424 if(this.dualwielding_prev != dualwielding)
2425 {
2426 W_ResetGunAlign(this, CS_CVAR(this).cvar_cl_gunalign);
2427 this.dualwielding_prev = dualwielding;
2428 }
2429
2430 // LordHavoc: allow firing on move frames (sub-ticrate), this gives better timing on slow servers
2431 //if(frametime)
2432 {
2433 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
2434 {
2435 .entity weaponentity = weaponentities[slot];
2436 if(WEP_CVAR(WEP_VORTEX, charge_always))
2437 W_Vortex_Charge(this, weaponentity, frametime);
2438 W_WeaponFrame(this, weaponentity);
2439 }
2440 }
2441
2442 if (frametime)
2443 {
2444 // WEAPONTODO: Add a weapon request for this
2445 // rot vortex charge to the charge limit
2446 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
2447 {
2448 .entity weaponentity = weaponentities[slot];
2449 if (WEP_CVAR(WEP_VORTEX, charge_rot_rate) && this.(weaponentity).vortex_charge > WEP_CVAR(WEP_VORTEX, charge_limit) && this.(weaponentity).vortex_charge_rottime < time)
2450 this.(weaponentity).vortex_charge = bound(WEP_CVAR(WEP_VORTEX, charge_limit), this.(weaponentity).vortex_charge - WEP_CVAR(WEP_VORTEX, charge_rot_rate) * frametime / W_TICSPERFRAME, 1);
2451 }
2452
2453 player_regen(this);
2454 player_anim(this);
2456 }
2457
2458 monsters_setstatus(this);
2459
2460 return true;
2461}
2462
2464// merged SpectatorThink and ObserverThink (old names are here so you can grep for them)
2466{
2467 bool is_spec = IS_SPEC(this);
2468 if ( CS(this).impulse )
2469 {
2470 int r = MinigameImpulse(this, CS(this).impulse);
2471 if (!is_spec || r)
2472 CS(this).impulse = 0;
2473
2474 if (is_spec && CS(this).impulse == IMP_weapon_drop.impulse)
2475 {
2476 STAT(CAMERA_SPECTATOR, this) = (STAT(CAMERA_SPECTATOR, this) + 1) % 3;
2477 CS(this).impulse = 0;
2478 return;
2479 }
2480 }
2481
2483
2484 if (IS_BOT_CLIENT(this) && !CS(this).autojoin_checked)
2485 {
2486 CS(this).autojoin_checked = 1;
2487 TRANSMUTE(Player, this);
2488 PutClientInServer(this);
2489
2490 .entity weaponentity = weaponentities[0];
2491 if(this.(weaponentity).m_weapon == WEP_Null)
2492 W_NextWeapon(this, 0, weaponentity);
2493
2494 return;
2495 }
2496
2497 if (this.flags & FL_JUMPRELEASED)
2498 {
2499 if (PHYS_INPUT_BUTTON_JUMP(this) && (joinAllowed(this, this.wants_join) || time < CS(this).jointime + MIN_SPEC_TIME))
2500 {
2501 this.flags &= ~FL_JUMPRELEASED;
2502 this.flags |= FL_SPAWNING;
2503 }
2504 else if((is_spec && (PHYS_INPUT_BUTTON_ATCK(this) || CS(this).impulse == 10 || CS(this).impulse == 15 || CS(this).impulse == 18 || (CS(this).impulse >= 200 && CS(this).impulse <= 209)))
2505 || (!is_spec && ((PHYS_INPUT_BUTTON_ATCK(this) && !CS(this).version_mismatch) || this.would_spectate)))
2506 {
2507 this.flags &= ~FL_JUMPRELEASED;
2508 if (autocvar_sv_spectate == 2 && !warmup_stage && !this.vote_master)
2509 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_SPECTATE_SPEC_NOTALLOWED);
2510 else if(SpectateNext(this))
2511 { }
2512 else if (is_spec)
2513 {
2514 TRANSMUTE(Observer, this);
2515 PutClientInServer(this);
2516 }
2517 else
2518 this.would_spectate = false; // unable to spectate anyone
2519
2520 if (is_spec)
2521 CS(this).impulse = 0;
2522 }
2523 else if (is_spec)
2524 {
2525 if(CS(this).impulse == 12 || CS(this).impulse == 16 || CS(this).impulse == 19 || (CS(this).impulse >= 220 && CS(this).impulse <= 229))
2526 {
2527 this.flags &= ~FL_JUMPRELEASED;
2528 if (!SpectatePrev(this))
2529 {
2530 TRANSMUTE(Observer, this);
2531 PutClientInServer(this);
2532 }
2533 CS(this).impulse = 0;
2534 }
2535 else if(PHYS_INPUT_BUTTON_ATCK2(this))
2536 {
2538 {
2539 this.would_spectate = false;
2540 this.flags &= ~FL_JUMPRELEASED;
2541 TRANSMUTE(Observer, this);
2542 PutClientInServer(this);
2543 }
2544 }
2545 else if(!SpectateUpdate(this) && !SpectateNext(this))
2546 {
2547 PutObserverInServer(this, false, true);
2548 this.would_spectate = true;
2549 }
2550 }
2551 else
2552 {
2553 bool wouldclip = CS_CVAR(this).cvar_cl_clippedspectating;
2554 if (PHYS_INPUT_BUTTON_USE(this))
2555 wouldclip = !wouldclip;
2556 int preferred_movetype = (wouldclip ? MOVETYPE_FLY_WORLDONLY : MOVETYPE_NOCLIP);
2557 set_movetype(this, preferred_movetype);
2558 }
2559 }
2560 else
2561 { // jump pressed
2562 if ((is_spec && !(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this)))
2563 || (!is_spec && !(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_JUMP(this))))
2564 {
2565 this.flags |= FL_JUMPRELEASED;
2566 // primary attack pressed
2567 if(this.flags & FL_SPAWNING)
2568 {
2569 this.flags &= ~FL_SPAWNING;
2570 if(joinAllowed(this, this.wants_join))
2571 Join(this, teamplay);
2572 else if(time < CS(this).jointime + MIN_SPEC_TIME)
2573 CS(this).autojoin_checked = -1;
2574 return;
2575 }
2576 }
2577 if(is_spec && !SpectateUpdate(this))
2578 PutObserverInServer(this, false, true);
2579 }
2580 if (is_spec)
2581 this.flags |= FL_CLIENT | FL_NOTARGET;
2582}
2583
2585{
2586 if (!IS_PLAYER(this))
2587 return;
2588
2589 if(this.vehicle)
2590 {
2591 if(!game_stopped)
2592 {
2594 return;
2595 }
2596 }
2597 else if(autocvar_g_vehicles_enter)
2598 {
2599 if(!game_stopped && !STAT(FROZEN, this) && !StatusEffects_active(STATUSEFFECT_Frozen, this) && !IS_DEAD(this) && !IS_INDEPENDENT_PLAYER(this))
2600 {
2601 entity head, closest_target = NULL;
2603
2604 while(head) // find the closest acceptable target to enter
2605 {
2606 if(IS_VEHICLE(head) && !IS_DEAD(head) && head.takedamage != DAMAGE_NO)
2607 if(!head.owner || ((head.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(head.owner, this)))
2608 {
2609 if(closest_target)
2610 {
2611 if(vlen2(this.origin - head.origin) < vlen2(this.origin - closest_target.origin))
2612 closest_target = head;
2613 }
2614 else
2615 closest_target = head;
2616 }
2617
2618 head = head.chain;
2619 }
2620
2621 if(closest_target)
2622 {
2623 vehicles_enter(this, closest_target);
2624 return;
2625 }
2626 }
2627 }
2628
2629 // a use key was pressed; call handlers
2631}
2632
2633
2634/*
2635=============
2636PlayerPreThink
2637
2638Called every frame for each real client by DP (and for each bot by StartFrame()),
2639and when executing every asynchronous move, so only include things that MUST be done then.
2640Use PlayerFrame() instead for code that only needs to run once per server frame.
2641frametime == 0 in the asynchronous code path.
2642
2643TODO: move more stuff from here and PlayerThink() and ObserverOrSpectatorThink() to PlayerFrame() (frametime is always set there)
2644=============
2645*/
2648{
2650
2651 zoomstate_set = false;
2652
2654
2655 if(PHYS_INPUT_BUTTON_USE(this) && !CS(this).usekeypressed)
2656 PlayerUseKey(this);
2657 CS(this).usekeypressed = PHYS_INPUT_BUTTON_USE(this);
2658
2659 if (IS_PLAYER(this))
2660 {
2661 if (IS_REAL_CLIENT(this) && time < CS(this).jointime + MIN_SPEC_TIME)
2662 error("Client can't be spawned as player on connection!");
2663 if(!PlayerThink(this))
2664 return;
2665 }
2667 {
2669 IntermissionThink(this);
2670 return;
2671 }
2672 else if (IS_REAL_CLIENT(this) && CS(this).autojoin_checked <= 0 && time >= CS(this).jointime + MIN_SPEC_TIME
2673 && this.ping > 0) // delay until centreprints could work (still on loading screen but timers start when it disappears)
2674 {
2675 bool early_join_requested = (CS(this).autojoin_checked < 0);
2676 CS(this).autojoin_checked = 1;
2677 // don't do this in ClientConnect
2678 // many things can go wrong if a client is spawned as player on connection
2679 if (early_join_requested || MUTATOR_CALLHOOK(AutoJoinOnConnection, this)
2682 {
2683 if(joinAllowed(this, this.wants_join))
2684 Join(this, teamplay);
2685 else if (!autocvar_sv_spectate) // we really want to join and some blockers may be brief (g_maxping)
2686 if (time < CS(this).spectatortime + MIN_SPEC_TIME) // centreprints don't appear while spamming
2687 CS(this).autojoin_checked = -1; // keep trying for MIN_SPEC_TIME
2688 return;
2689 }
2690 }
2691 else if (IS_OBSERVER(this) || IS_SPEC(this))
2693
2694 // WEAPONTODO: Add weapon request for this
2695 if (!zoomstate_set)
2696 {
2697 bool wep_zoomed = false;
2698 for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
2699 {
2700 .entity weaponentity = weaponentities[slot];
2701 Weapon thiswep = this.(weaponentity).m_weapon;
2702 if(thiswep != WEP_Null && thiswep.wr_zoom)
2703 wep_zoomed += thiswep.wr_zoom(thiswep, this);
2704 }
2705 SetZoomState(this, PHYS_INPUT_BUTTON_ZOOM(this) || PHYS_INPUT_BUTTON_ZOOMSCRIPT(this) || wep_zoomed);
2706 }
2707
2708 // Voice sound effects
2709 if (CS(this).teamkill_soundtime && time > CS(this).teamkill_soundtime)
2710 {
2711 CS(this).teamkill_soundtime = 0;
2712
2713 entity e = CS(this).teamkill_soundsource;
2714 entity oldpusher = e.pusher;
2715 e.pusher = this;
2717 e.pusher = oldpusher;
2718 }
2719
2720 if (CS(this).taunt_soundtime && time > CS(this).taunt_soundtime)
2721 {
2722 CS(this).taunt_soundtime = 0;
2723 PlayerSound(this, playersound_taunt, CH_VOICE, VOL_BASEVOICE, VOICETYPE_AUTOTAUNT);
2724 }
2725
2727}
2728
2730{
2731 // TODO: mutator hook to prevent drowning?
2732 if(IS_DEAD(this) || game_stopped || time < game_starttime || this.vehicle
2733 || STAT(FROZEN, this) || this.watertype != CONTENT_WATER)
2734 {
2735 STAT(AIR_FINISHED, this) = 0;
2736 return;
2737 }
2738
2739 if (this.waterlevel != WATERLEVEL_SUBMERGED)
2740 {
2741 if(STAT(AIR_FINISHED, this) && STAT(AIR_FINISHED, this) < time)
2742 PlayerSound(this, playersound_gasp, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
2743 STAT(AIR_FINISHED, this) = 0;
2744 }
2745 else
2746 {
2747 if (!STAT(AIR_FINISHED, this))
2748 STAT(AIR_FINISHED, this) = time + autocvar_g_balance_contents_drowndelay;
2749 if (STAT(AIR_FINISHED, this) < time)
2750 { // drown!
2751 if (this.pain_finished < time)
2752 {
2754 this.pain_finished = time + 0.5;
2755 }
2756 }
2757 }
2758}
2759
2761
2763{
2765
2766 if(!this.move_qcphysics)
2767 return;
2768
2769 if(!frametime && !CS(this).pm_frametime)
2770 return;
2771
2772 Movetype_Physics_NoMatchTicrate(this, CS(this).pm_frametime, true);
2773
2774 CS(this).pm_frametime = 0;
2775}
2776
2777/*
2778=============
2779PlayerPostThink
2780
2781Called every frame for each real client by DP (and for each bot by StartFrame()),
2782and when executing every asynchronous move, so only include things that MUST be done then.
2783Use PlayerFrame() instead for code that only needs to run once per server frame.
2784frametime == 0 in the asynchronous code path.
2785=============
2786*/
2788{
2789 Player_Physics(this);
2790
2791 if (IS_PLAYER(this))
2792 {
2793 DrownPlayer(this);
2794 UpdateChatBubble(this);
2795 if (CS(this).impulse)
2796 ImpulseCommands(this);
2797 GetPressedKeys(this);
2798 if (game_stopped)
2799 {
2801 return;
2802 }
2803 }
2804 else if (IS_OBSERVER(this) && STAT(PRESSED_KEYS, this))
2805 {
2806 CS(this).pressedkeys = 0;
2807 STAT(PRESSED_KEYS, this) = 0;
2808 }
2809
2811}
2812
2813/*
2814=============
2815PlayerFrame
2816
2817Called every frame for each client by StartFrame().
2818Use this for code that only needs to run once per server frame.
2819frametime is always set here.
2820=============
2821*/
2823{
2824// formerly PreThink code
2825
2826 if (this.score_frame_dmg)
2827 {
2829 GameRules_scoring_add(this, DMG, this.score_frame_dmg);
2830 this.score_frame_dmg = 0;
2831 }
2832 if (this.score_frame_dmgtaken)
2833 {
2835 GameRules_scoring_add(this, DMGTAKEN, this.score_frame_dmgtaken);
2836 this.score_frame_dmgtaken = 0;
2837 }
2838
2839 STAT(GUNALIGN, this) = CS_CVAR(this).cvar_cl_gunalign; // TODO
2840 STAT(MOVEVARS_CL_TRACK_CANJUMP, this) = CS_CVAR(this).cvar_cl_movement_track_canjump;
2841
2842 // physics frames: update anticheat stuff
2843 anticheat_prethink(this);
2844
2845 // Check if spectating is allowed
2846 // cvar hook/callback TODO: make this event-driven
2848 && (IS_SPEC(this) || IS_OBSERVER(this)) && !INGAME(this))
2849 {
2850 float cutoff = CS(this).spectatortime + autocvar_g_maxplayers_spectator_blocktime;
2851 if (time > cutoff + MIN_SPEC_TIME * 0.5 // sv_spectate was disabled recently (or the server was stalled far too long)
2852 || CS(this).autojoin_checked == 0) // or too soon to have tried to autojoin
2853 {
2854 CS(this).spectatortime = time; // reset the grace period
2855 if (CS(this).autojoin_checked) // only notify when sv_spectate was disabled recently, to prevent spam
2856 Send_Notification(NOTIF_ONE_ONLY, this, MSG_MULTI, SPECTATE_WARNING, autocvar_g_maxplayers_spectator_blocktime);
2857 }
2858 else if (time > cutoff)
2859 if (dropclient_schedule(this))
2860 Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_QUIT_KICK_SPECTATING);
2861 }
2862
2863 // Check for nameless players
2864 if (this.netname == "" || this.netname != CS(this).netname_previous)
2865 {
2866 bool assume_unchanged = (CS(this).netname_previous == "");
2867 if (autocvar_sv_name_maxlength > 0 && strlennocol(this.netname) > autocvar_sv_name_maxlength)
2868 {
2869 int new_length = textLengthUpToLength(this.netname, autocvar_sv_name_maxlength, strlennocol);
2870 this.netname = strzone(strcat(substring(this.netname, 0, new_length), "^7"));
2871 sprint(this, sprintf("Warning: your name is longer than %d characters, it has been truncated.\n", autocvar_sv_name_maxlength));
2872 assume_unchanged = false;
2873 // stuffcmd(this, strcat("name ", this.netname, "\n")); // maybe?
2874 }
2875 if (isInvisibleString(this.netname))
2876 {
2877 this.netname = strzone(sprintf("Player#%d", this.playerid));
2878 sprint(this, "Warning: invisible names are not allowed.\n");
2879 assume_unchanged = false;
2880 // stuffcmd(this, strcat("name ", this.netname, "\n")); // maybe?
2881 }
2882 if (!assume_unchanged && autocvar_sv_eventlog)
2883 GameLogEcho(strcat(":name:", ftos(this.playerid), ":", playername(this.netname, this.team, false)));
2884 strcpy(CS(this).netname_previous, this.netname);
2885 }
2886
2887 // version nagging
2888 if (CS(this).version_nagtime && CS_CVAR(this).cvar_g_xonoticversion && time > CS(this).version_nagtime)
2889 {
2890 CS(this).version_nagtime = 0;
2891 if (strstrofs(CS_CVAR(this).cvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(CS_CVAR(this).cvar_g_xonoticversion, "autobuild", 0) >= 0)
2892 {
2893 // git client
2894 }
2895 else if (strstrofs(autocvar_g_xonoticversion, "git", 0) >= 0 || strstrofs(autocvar_g_xonoticversion, "autobuild", 0) >= 0)
2896 {
2897 // git server
2898 Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_BETA, autocvar_g_xonoticversion, CS_CVAR(this).cvar_g_xonoticversion);
2899 }
2900 else
2901 {
2902 int r = vercmp(CS_CVAR(this).cvar_g_xonoticversion, autocvar_g_xonoticversion);
2903 if (r < 0) // old client
2904 Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OUTDATED, autocvar_g_xonoticversion, CS_CVAR(this).cvar_g_xonoticversion);
2905 else if (r > 0) // old server
2906 Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_VERSION_OLD, autocvar_g_xonoticversion, CS_CVAR(this).cvar_g_xonoticversion);
2907 }
2908 }
2909
2910 if (this.ignore_list_send_time > 0 && time > this.ignore_list_send_time)
2911 ignore_list_send(this);
2912
2913 // GOD MODE info
2914 if (!(this.flags & FL_GODMODE) && this.max_armorvalue)
2915 {
2916 Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_GODMODE_OFF, this.max_armorvalue);
2917 this.max_armorvalue = 0;
2918 }
2919
2920 // Vehicles
2921 if(autocvar_g_vehicles_enter && (time > this.last_vehiclecheck) && !game_stopped && !this.vehicle)
2922 if(IS_PLAYER(this) && !STAT(FROZEN, this) && !StatusEffects_active(STATUSEFFECT_Frozen, this) && !IS_DEAD(this) && !IS_INDEPENDENT_PLAYER(this))
2923 {
2925 {
2926 if(!it.owner)
2927 {
2928 if(!it.team || SAME_TEAM(this, it))
2929 Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER);
2930 else if(autocvar_g_vehicles_steal)
2931 Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_STEAL);
2932 }
2933 else if((it.vehicle_flags & VHF_MULTISLOT) && SAME_TEAM(it.owner, this))
2934 {
2935 Send_Notification(NOTIF_ONE, this, MSG_CENTER, CENTER_VEHICLE_ENTER_GUNNER);
2936 }
2937 });
2938
2939 this.last_vehiclecheck = time + 1;
2940 }
2941
2942
2943
2944// formerly PostThink code
2946 if (IS_REAL_CLIENT(this))
2948 if (!intermission_running) // NextLevel() kills all centerprints after setting this true
2949 {
2950 int totalClients = 0;
2952 {
2953 // maxidle disabled in local matches by not counting clients (totalClients 0)
2955 {
2957 {
2958 ++totalClients;
2959 });
2960 if (maxclients - totalClients > autocvar_sv_maxidle_slots)
2961 totalClients = 0;
2962 }
2963 }
2964 else if ((IS_PLAYER(this) || this.wants_join) && autocvar_sv_maxidle_playertospectator > 0)
2965 {
2967 {
2968 ++totalClients;
2969 });
2970 }
2971
2972 if (totalClients < autocvar_sv_maxidle_minplayers)
2973 {
2974 // idle kick disabled
2975 CS(this).parm_idlesince = time;
2976 }
2977 else if (time - CS(this).parm_idlesince < 1) // instead of (time == this.parm_idlesince) to support sv_maxidle <= 10
2978 {
2979 if (CS(this).idlekick_lasttimeleft)
2980 {
2981 CS(this).idlekick_lasttimeleft = 0;
2982 Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_IDLING);
2983 }
2984 }
2985 else
2986 {
2987 float maxidle_time = autocvar_sv_maxidle;
2988 if ((IS_PLAYER(this) || this.wants_join)
2991 float timeleft = ceil(maxidle_time - (time - CS(this).parm_idlesince));
2992 float countdown_time = max(min(10, maxidle_time - 1), ceil(maxidle_time * 0.33)); // - 1 to support maxidle_time <= 10
2993 if (timeleft == countdown_time && !CS(this).idlekick_lasttimeleft)
2994 {
2996 {
2997 if (!this.wants_join) // no countdown centreprint when getting kicked off the join queue
2998 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOVETOSPEC_IDLING, timeleft);
2999 }
3000 else
3001 Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_DISCONNECT_IDLING, timeleft);
3002 }
3003 if (timeleft <= 0)
3004 {
3005 if ((IS_PLAYER(this) || this.wants_join)
3007 {
3008 if (this.wants_join)
3009 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_IDLING_QUEUE, this.netname, maxidle_time);
3010 else
3011 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_IDLING, this.netname, maxidle_time);
3012 PutObserverInServer(this, true, true);
3013 // Can't do this in PutObserverInServer() or SetPlayerTeam() cos it causes
3014 // mouse2 (change spectate mode) to kick the player off the join queue.
3015 this.wants_join = 0;
3016 this.team_selected = 0;
3017 // when the player is kicked off the server, these are called in ClientDisconnect()
3021 }
3022 else
3023 {
3024 if (dropclient_schedule(this))
3025 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK_IDLING, this.netname, maxidle_time);
3026 }
3027 return;
3028 }
3029 else if (timeleft <= countdown_time
3030 && !this.wants_join) // no countdown bangs when getting kicked off the join queue
3031 {
3032 if (timeleft != CS(this).idlekick_lasttimeleft)
3033 play2(this, SND(TALK2));
3034 CS(this).idlekick_lasttimeleft = timeleft;
3035 }
3036 }
3037 }
3038
3039 CheatFrame(this);
3040
3041 if (game_stopped)
3042 {
3043 this.solid = SOLID_NOT;
3044 this.takedamage = DAMAGE_NO;
3046 CS(this).teamkill_complain = 0;
3047 CS(this).teamkill_soundtime = 0;
3048 CS(this).teamkill_soundsource = NULL;
3049 }
3050
3052 float hp = healtharmor_maxdamage(GetResource(this, RES_HEALTH), GetResource(this, RES_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id).x;
3054 }
3055}
3056
3057// hack to copy the button fields from the client entity to the Client State
3059{
3060 if(this.impulse)
3061 store.impulse = this.impulse;
3062 this.impulse = 0;
3063
3064 bool typing = this.buttonchat || this.button12;
3065
3066 store.button0 = (typing) ? 0 : this.button0;
3067 //button1?!
3068 store.button2 = (typing) ? 0 : this.button2;
3069 store.button3 = (typing) ? 0 : this.button3;
3070 store.button4 = this.button4;
3071 store.button5 = (typing) ? 0 : this.button5;
3072 store.button6 = this.button6;
3073 store.button7 = this.button7;
3074 store.button8 = this.button8;
3075 store.button9 = this.button9;
3076 store.button10 = this.button10;
3077 store.button11 = this.button11;
3078 store.button12 = this.button12;
3079 store.button13 = this.button13;
3080 store.button14 = this.button14;
3081 store.button15 = this.button15;
3082 store.button16 = this.button16;
3083 store.buttonuse = this.buttonuse;
3084 store.buttonchat = this.buttonchat;
3085
3086 store.cursor_active = this.cursor_active;
3087 store.cursor_screen = this.cursor_screen;
3088 store.cursor_trace_start = this.cursor_trace_start;
3089 store.cursor_trace_endpos = this.cursor_trace_endpos;
3090 store.cursor_trace_ent = this.cursor_trace_ent;
3091
3092 store.ping = this.ping;
3093 store.ping_packetloss = this.ping_packetloss;
3094 store.ping_movementloss = this.ping_movementloss;
3095
3096 store.v_angle = this.v_angle;
3097 store.movement = this.movement;
3098}
3099
3100NET_HANDLE(fpsreport, bool)
3101{
3102 int fps = ReadShort();
3103 PlayerScore_Set(sender, SP_FPS, fps);
3104 return true;
3105}
void accuracy_resend(entity e)
force a resend of a player's accuracy stats
Definition accuracy.qc:80
float frame
primary framegroup animation (strength = 1 - lerpfrac - lerpfrac3 - lerpfrac4)
Definition anim.qh:6
void anticheat_spectatecopy(entity this, entity spectatee)
Definition anticheat.qc:166
void anticheat_prethink(entity this)
Definition anticheat.qc:172
void antilag_clear(entity e, entity store)
Definition antilag.qc:114
int autocvar_g_antilag
Definition antilag.qh:3
float bot_forced_team
Definition api.qh:41
void navigation_dynamicgoal_init(entity this, bool initially_static)
Definition navigation.qc:77
float bot_attack
Definition api.qh:38
IntrusiveList g_bot_targets
Definition api.qh:149
void bot_aim_reset(entity this)
Definition aim.qc:134
int bots_would_leave
how many bots would leave so humans can replace them
Definition api.qh:101
int player_count
Definition api.qh:103
void bot_relinkplayerlist()
Definition bot.qc:424
const int ARC_SF_UPDATE
Definition arc.qh:120
vector arc_shotorigin[4]
Definition arc.qh:104
entity arc_beam
Definition arc.qh:128
#define g_assault
Definition assault.qh:27
string autocvar_g_playban_list
Definition banning.qh:14
string autocvar_g_chatban_list
Definition banning.qh:13
#define MUTATOR_CALLHOOK(id,...)
Definition base.qh:143
#define MUTATOR_IS_ENABLED(this)
Definition base.qh:193
#define BIT(n)
Only ever assign into the first 24 bits in QC (so max is BIT(23)).
Definition bits.qh:8
#define BITSET(var, mask, flag)
Definition bits.qh:11
#define boolean(value)
Definition bool.qh:9
float CheatFrame(entity this)
Definition cheats.qc:709
bool drag_undraggable(entity draggee, entity dragger)
Definition cheats.qc:903
float CheatsAllowed(entity this, float imp, int argc, float cheatframe, bool logattempt, bool ignoredead)
Definition cheats.qc:59
bool speedrunning
Definition cheats.qh:22
entity personal
Definition cheats.qh:24
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
vector punchangle
float pain_finished
entity active_minigame
void SetResource(entity e, Resource res_type, float amount)
Sets the current amount of resource the given entity will have.
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
bool SetResourceExplicit(entity e, Resource res_type, float amount)
Sets the resource amount of an entity without calling any hooks.
const int MAX_AXH
entity AuxiliaryXhair[MAX_AXH]
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition weapon.qh:44
virtual void wr_zoom()
(BOTH) weapon specific zoom reticle
Definition weapon.qh:116
string netname
Definition powerups.qc:20
float cnt
Definition powerups.qc:24
vector colormod
Definition powerups.qc:21
float count
Definition powerups.qc:22
float alpha
Definition items.qc:13
float ping
Definition main.qh:169
float ping_movementloss
Definition main.qh:169
float ping_packetloss
Definition main.qh:169
entity owner
Definition main.qh:87
bool ready
Definition main.qh:88
int spectatee_status
the -1 disables HUD panels before CSQC receives necessary data
Definition main.qh:197
string ignore_list
Definition main.qh:130
bool warmup_stage
Definition main.qh:120
int serverflags
Definition main.qh:211
vector hook_shotorigin[4]
Definition main.qh:205
int team
Definition main.qh:188
entity killindicator
Definition clientkill.qh:7
void ignore_list_update_on_connection(entity this)
Updates ignore list of all the players.
Definition cmd.qc:153
void ignore_list_send(entity this)
Definition cmd.qc:168
void ignore_remove_player(entity this, entity ignore, bool from_db_too)
Removes a player from the ignore list of another player.
Definition cmd.qc:47
float ignore_list_send_time
Definition cmd.qh:9
const int IGNORE_LIST_SEND_NOW
Definition cmd.qh:8
#define debug_text_3d(...)
Definition debug.qh:486
#define g_race
Definition race.qh:48
const int IT_USING_JETPACK
Definition item.qh:27
const int IT_SUPERWEAPON
Definition item.qh:41
string mdl
Definition item.qh:89
const int IT_UNLIMITED_AMMO
Definition item.qh:23
const int IT_UNLIMITED_SUPERWEAPONS
Definition item.qh:24
#define setmodel(this, m)
Definition model.qh:26
#define M_ARGV(x, type)
Definition events.qh:17
void Physics_UpdateStats(entity this)
Definition player.qc:44
string autocvar_sv_jumpspeedcap_max
Definition player.qh:47
int items
Definition player.qh:227
vector autocvar_sv_player_viewoffset
Definition player.qh:348
vector movement
Definition player.qh:229
#define IS_CLIENT(s)
Definition player.qh:242
#define IS_DEAD(s)
Definition player.qh:245
#define UNSET_DUCKED(s)
Definition player.qh:212
#define PHYS_INPUT_BUTTON_JUMP(s)
Definition player.qh:151
#define PHYS_INPUT_BUTTON_HOOK(s)
Definition player.qh:155
#define PHYS_INPUT_BUTTON_CHAT(s)
Definition player.qh:159
vector v_angle
Definition player.qh:237
float watertype
Definition player.qh:225
float waterlevel
Definition player.qh:226
#define PHYS_INPUT_BUTTON_ZOOMSCRIPT(s)
Definition player.qh:161
#define IS_DUCKED(s)
Definition player.qh:210
#define PHYS_INPUT_BUTTON_MINIGAME(s)
Definition player.qh:164
#define IS_PLAYER(s)
Definition player.qh:243
string autocvar_sv_jumpspeedcap_min
Definition player.qh:49
#define PHYS_INPUT_BUTTON_USE(s)
Definition player.qh:158
#define PHYS_INPUT_BUTTON_ATCK(s)
Definition player.qh:150
#define PHYS_INPUT_BUTTON_ZOOM(s)
Definition player.qh:153
entity conveyor
Definition player.qh:57
#define PHYS_INPUT_BUTTON_ATCK2(s)
Definition player.qh:152
int timeout_status
Definition stats.qh:87
float game_starttime
Definition stats.qh:82
float game_stopped
Definition stats.qh:81
string playername(string thename, int teamid, bool team_colorize)
Definition util.qc:2082
vector healtharmor_maxdamage(float h, float a, float armorblock, int deathtype)
Definition util.qc:1289
Notification Announcer_PickNumber(int type, int num)
Definition util.qc:1827
float compressShotOrigin(vector v)
Definition util.qc:1248
float textLengthUpToLength(string theText, int maxLength, textLengthUpToLength_lenFunction_t w)
Definition util.qc:924
float get_model_parameters(string m, float sk)
Definition util.qc:1394
string mi_shortname
Definition util.qh:126
float get_model_parameters_species
Definition util.qh:180
string strtolower(string s)
const int CNT_RESPAWN
Definition util.qh:255
const int FL_CLIENT
Definition constants.qh:72
const int KEY_JUMP
Definition constants.qh:39
const int KEY_ATCK2
Definition constants.qh:42
const int KEY_RIGHT
Definition constants.qh:38
const int FL_PICKUPITEMS
Definition constants.qh:88
const int FL_NOTARGET
Definition constants.qh:76
const int FL_JUMPRELEASED
Definition constants.qh:81
const int KEY_BACKWARD
Definition constants.qh:36
const int FL_SPAWNING
Definition constants.qh:87
const int HUD_NORMAL
Definition constants.qh:47
const int KEY_FORWARD
Definition constants.qh:35
const int FL_GODMODE
Definition constants.qh:75
const int KEY_LEFT
Definition constants.qh:37
const int KEY_CROUCH
Definition constants.qh:40
const int FRAGS_PLAYER
Definition constants.qh:3
const int KEY_ATCK
Definition constants.qh:41
const int SPECIES_HUMAN
Definition constants.qh:22
const int FRAGS_SPECTATOR
Definition constants.qh:4
#define EFMASK_CHEAP
Definition constants.qh:107
IntrusiveList g_conveyed
Definition conveyor.qh:4
float counter_cnt
Definition counter.qh:6
IntrusiveList g_counters
Definition counter.qh:8
string classname
float movetype
float flags
const float SOLID_SLIDEBOX
float maxclients
entity trace_ent
float DPCONTENTS_BOTCLIP
float DPCONTENTS_SOLID
vector avelocity
float frametime
vector velocity
float DPCONTENTS_BODY
const float CONTENT_WATER
const float EF_FULLBRIGHT
const float SOLID_NOT
float effects
float DPCONTENTS_PLAYERCLIP
float skin
float time
float nextthink
const float EF_NODEPTHTEST
vector origin
vector oldorigin
const float CONTENT_EMPTY
const float EF_NODRAW
float dphitcontentsmask
int modelflags
float death_time
const int EF_TELEPORT_BIT
const int MF_ROCKET
const int EF_RESTARTANIM_BIT
#define CSQCMODEL_AUTOUPDATE(e)
#define CSQCMODEL_EF_RESPAWNGHOST
#define CSQCMODEL_AUTOINIT(e)
#define g_cts
Definition cts.qh:36
int autocvar_bot_vs_human
Definition cvars.qh:67
void Damage(entity targ, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition damage.qc:503
float taunt_soundtime
Definition damage.qh:59
float dmg_team
Definition damage.qh:53
float damagedbycontents
Definition damage.qh:45
float autocvar_g_balance_armor_blockpercent
Definition damage.qh:21
IntrusiveList g_damagedbycontents
Definition damage.qh:135
float autocvar_g_teamdamage_resetspeed
Definition damage.qh:22
float teamkill_soundtime
Definition damage.qh:55
#define DMG_NOWEP
Definition damage.qh:104
float autocvar_g_balance_damagepush_speedfactor
Definition damage.qh:18
float damageforcescale
string clientstatus
float disableclientprediction
float button10
float button12
float button3
float button7
float button11
float button16
entity drawonlytoclient
float button4
vector cursor_screen
float button6
string netaddress
string crypto_idfp
entity cursor_trace_ent
float EF_LOWPRECISION
float button8
float buttonchat
float buttonuse
float crypto_idfp_signed
float button9
float button15
float button13
vector punchvector
float button14
vector cursor_trace_start
float button5
vector cursor_trace_endpos
#define strstrofs
#define strlen
#define tokenize_console
#define g_duel
Definition duel.qh:32
bool move_qcphysics
Definition physics.qh:25
void Send_Effect(entity eff, vector eff_loc, vector eff_vel, int eff_cnt)
Definition all.qc:124
RES_ARMOR
Definition ent_cs.qc:130
ent angles
Definition ent_cs.qc:121
model
Definition ent_cs.qc:139
solid
Definition ent_cs.qc:165
void entcs_update_players(entity player)
Definition ent_cs.qc:183
int frags
Definition ent_cs.qh:71
int wants_join
Definition ent_cs.qh:73
ERASEABLE bool fexists(string f)
Definition file.qh:4
string GameLog_ProcessIP(string s)
Definition gamelog.qc:8
void GameLogEcho(string s)
Definition gamelog.qc:15
bool autocvar_sv_eventlog
Definition gamelog.qh:3
void UpdatePlayerSounds(entity this)
const int VOICETYPE_LASTATTACKER_ONLY
#define PlayerSound(this, def, chan, vol, voicetype)
bool autocvar_g_debug_globalsounds
Use new sound handling.
Definition globalsound.qh:9
const int VOICETYPE_PLAYERSOUND
const int VOICETYPE_AUTOTAUNT
Weapons
Definition guide.qh:113
void Handicap_Initialize(entity player)
Initializes handicap to its default value.
Definition handicap.qc:16
float Handicap_GetTotalHandicap(entity player, bool receiving)
Returns the total handicap of the player.
Definition handicap.qc:96
Header file that describes the handicap system.
float handicap_avg_taken_sum
Definition handicap.qh:72
float handicap_avg_given_sum
Definition handicap.qh:71
void IntermissionThink(entity this)
void Send_NextMap_To_Player(entity pl)
bool intermission_running
#define get_nextmap()
ERASEABLE void IL_REMOVE(IntrusiveList this, entity it)
Remove any element, anywhere in the list.
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
#define IL_EACH(this, cond, body)
bool Ban_MaybeEnforceBanOnce(entity client)
Definition ipban.qc:471
#define FOREACH_WORD(words, cond, body)
Definition iter.qh:33
#define FOREACH_ENTITY_RADIUS(org, dist, cond, body)
Definition iter.qh:160
#define FOREACH(list, cond, body)
Definition iter.qh:19
void SUB_UseTargets(entity this, entity actor, entity trigger)
Definition triggers.qc:344
float pushltime
Definition jumppads.qh:21
bool istypefrag
Definition jumppads.qh:22
entity ladder_entity
Definition ladder.qh:11
IntrusiveList g_ladderents
Definition ladder.qh:3
#define PlayerPostThink
Definition _all.inc:258
#define ClientConnect
Definition _all.inc:238
#define PlayerPreThink
Definition _all.inc:254
#define SetChangeParms
Definition _all.inc:228
#define PutClientInServer
Definition _all.inc:246
#define ClientDisconnect
Definition _all.inc:242
#define TC(T, sym)
Definition _all.inc:82
#define SetNewParms
Definition _all.inc:224
int SendFlags
Definition net.qh:118
#define NET_HANDLE(id, param)
Definition net.qh:15
const int MSG_ENTITY
Definition net.qh:115
#define WriteHeader(to, id)
Definition net.qh:221
void Net_LinkEntity(entity e, bool docull, float dt, bool(entity this, entity to, int sendflags) sendfunc)
Definition net.qh:123
#define STAT(...)
Definition stats.qh:82
entity WarpZone_FindRadius(vector org, float rad, bool needlineofsight)
Definition common.qc:686
#define LOG_FATAL(...)
Definition log.qh:53
#define assert(expr,...)
Definition log.qh:8
int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
Definition mapinfo.qc:1390
void MapInfo_ClearTemps()
Definition mapinfo.qc:1639
int map_minplayers
Definition mapinfo.qh:190
int map_maxplayers
Definition mapinfo.qh:191
string MapInfo_Map_author
Definition mapinfo.qh:10
string MapInfo_Map_titlestring
Definition mapinfo.qh:8
entity viewloc
Definition viewloc.qh:13
bool autocvar_g_campaign
Definition menu.qc:747
void localcmd(string command,...)
float ceil(float f)
float MSG_ONE
Definition menudefs.qc:56
float stof(string val,...)
float bound(float min, float value, float max)
string substring(string s, float start, float length)
void WriteString(string data, float dest, float desto)
float cvar(string name)
void sprint(float clientnum, string text,...)
entity find(entity start,.string field, string match)
float random(void)
void WriteEntity(entity data, float dest, float desto)
vector randomvec(void)
void WriteCoord(float data, float dest, float desto)
string vtos(vector v)
float min(float f,...)
string ftos(float f)
void WriteByte(float data, float dest, float desto)
float floor(float f)
const string cvar_defstring(string name)
string strzone(string s)
string argv(float n)
float max(float f,...)
#define etof(e)
Definition misc.qh:25
void set_movetype(entity this, int mt)
Definition movetypes.qc:4
void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient)
Definition movetypes.qc:779
const int MOVETYPE_WALK
Definition movetypes.qh:132
const int MOVETYPE_NONE
Definition movetypes.qh:129
const int MOVETYPE_QCPLAYER
Definition movetypes.qh:150
const int WATERLEVEL_SUBMERGED
Definition movetypes.qh:14
const int WATERLEVEL_NONE
Definition movetypes.qh:11
const int MOVETYPE_FLY_WORLDONLY
Definition movetypes.qh:143
float move_movetype
Definition movetypes.qh:76
const int MOVETYPE_NOCLIP
Definition movetypes.qh:137
const int MOVETYPE_FLY
Definition movetypes.qh:134
@ STATUSEFFECT_REMOVE_CLEAR
Effect is being forcibly removed without calling any additional mechanics.
Definition all.qh:30
@ STATUSEFFECT_REMOVE_NORMAL
Effect is being removed by a function, calls regular removal mechanics.
Definition all.qh:28
@ STATUSEFFECT_REMOVE_TIMEOUT
Definition all.qh:29
const int RACE_NET_CHECKPOINT_CLEAR
Definition net_linked.qh:12
void sv_notice_join(entity _to)
Definition net_notice.qc:14
var void func_null()
string string_null
Definition nil.qh:9
s1 s2 s1 s2 FLAG s1 s2 FLAG spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 CPID_PREVENT_JOIN
Definition all.inc:730
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
s1 s2 s1 s2 FLAG s1 s2 FLAG spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 CPID_IDLING
Definition all.inc:688
void Send_Notification(NOTIF broadcast, entity client, MSG net_type, Notification net_name,...count)
Definition all.qc:1573
void Kill_Notification(NOTIF broadcast, entity client, MSG net_type, CPID net_cpid)
Definition all.qc:1537
#define APP_TEAM_NUM(num, prefix)
Definition all.qh:84
#define TRANSMUTE(cname, this,...)
Definition oo.qh:136
#define new_pure(class)
purely logical entities (not linked to the area grid)
Definition oo.qh:67
#define STATIC_METHOD(cname, name, prototype)
Definition oo.qh:278
void PlayerStats_GameReport_FinalizePlayer(entity p)
void PlayerStats_GameReport_AddPlayer(entity e)
void PlayerStats_GameReport_AddEvent(string event_id)
const string PLAYERSTATS_ALIVETIME
#define PlayerStats_GameReport_Event_Player(ent, eventid, val)
void Portal_ClearAll(entity own)
Definition portals.qc:588
#define NULL
Definition post.qh:14
#define world
Definition post.qh:15
#define error
Definition pre.qh:6
#define setcolor
Definition pre.qh:11
float DEAD_DYING
Definition progsdefs.qc:275
float parm1
Definition progsdefs.qc:45
float button2
Definition progsdefs.qc:156
float button0
Definition progsdefs.qc:154
entity msg_entity
Definition progsdefs.qc:63
vector view_ofs
Definition progsdefs.qc:151
float DEAD_NO
Definition progsdefs.qc:274
float fixangle
Definition progsdefs.qc:160
float deadflag
Definition progsdefs.qc:149
float DEAD_RESPAWNABLE
Definition progsdefs.qc:277
float impulse
Definition progsdefs.qc:158
float DEAD_RESPAWNING
Definition progsdefs.qc:278
string weaponmodel
Definition progsdefs.qc:140
float dmg_save
Definition progsdefs.qc:199
float DEAD_DEAD
Definition progsdefs.qc:276
float armortype
Definition progsdefs.qc:178
entity dmg_inflictor
Definition progsdefs.qc:200
#define stuffcmd(cl,...)
Definition progsdefs.qh:23
float scale
Definition projectile.qc:14
q3compat
Definition quake3.qc:59
bool autocvar_sv_q3compat_changehitbox
Definition quake3.qh:7
int fragsfilter_cnt
Definition quake3.qh:11
ERASEABLE void RandomSelection_Init()
Definition random.qc:4
#define RandomSelection_AddEnt(e, weight, priority)
Definition random.qh:14
entity RandomSelection_chosen_ent
Definition random.qh:5
ERASEABLE ACCUMULATE void Registry_send_all()
Definition registry.qh:167
float PlayerScore_Set(entity player, PlayerScoreField scorefield, float score)
Sets the player's score to the score parameter.
Definition scores.qc:384
bool PlayerScore_Clear(entity player)
Initialize the score of this player if needed.
Definition scores.qc:285
#define AVAILABLE_TEAMS
void W_NextWeapon(entity this, int list,.entity weaponentity)
Definition selection.qc:322
#define w_getbestweapon(ent, wepent)
Definition selection.qh:23
bool autocvar_g_weaponswitch_debug
Definition selection.qh:7
#define setthink(e, f)
vector
Definition self.qh:92
int Campaign_GetLevelNum()
Definition campaign.qc:44
bool campaign_bots_may_start
campaign mode: bots shall spawn but wait for the player to spawn before they do anything in other gam...
Definition campaign.qh:26
#define CHAT_NOSPECTATORS()
Definition chat.qh:30
void player_powerups_remove_all(entity this, bool allow_poweroff_sound)
Definition client.qc:1535
int player_getspecies(entity this)
Definition client.qc:444
bool SpectateSet(entity this)
Definition client.qc:1879
void play_countdown(entity this, float finished, Sound samp)
Definition client.qc:1526
entity chatbubbleentity
Definition client.qc:1262
void SpectateCopy(entity this, entity spectatee)
Definition client.qc:1793
void WriteSpectators(entity player, entity to)
Definition client.qc:114
int CountSpectators(entity player, entity to)
Definition client.qc:100
float CalcRegen(float current, float stable, float regenfactor, float regenframetime)
Definition client.qc:1631
void GiveWarmupResources(entity this)
Definition client.qc:568
entity SelectObservePoint(entity this)
Definition client.qc:250
bool ShowTeamSelection(entity this)
Definition client.qc:2056
int GetPlayerLimit()
Definition client.qc:2127
bool SpectateUpdate(entity this)
Definition client.qc:1861
void DrownPlayer(entity this)
Definition client.qc:2729
void GetPressedKeys(entity this)
Definition client.qc:1761
void PlayerUseKey(entity this)
Definition client.qc:2584
float autocvar_g_maxping
Definition client.qc:2229
void ClientData_Detach(entity this)
Definition client.qc:179
void player_powerups(entity this)
Definition client.qc:1551
void SetNewParms()
Definition client.qc:958
void SendWelcomeMessage(entity this, int msg_type)
Definition client.qc:1075
bool zoomstate_set
Definition client.qc:1750
void UpdateChatBubble(entity this)
Definition client.qc:1370
void FixClientCvars(entity e)
Definition client.qc:997
bool PlayerInIDList(entity p, string idlist)
Definition client.qc:1036
bool would_spectate
Definition client.qc:2463
void SetZoomState(entity this, float newzoom)
Definition client.qc:1751
float model_randomizer
Definition client.qc:453
string CheckPlayerModel(string plyermodel)
Definition client.qc:208
void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint)
putting a client as observer in the server
Definition client.qc:261
void player_regen(entity this)
Definition client.qc:1682
float last_vehiclecheck
Definition client.qc:2646
void Player_Physics(entity this)
Definition client.qc:2762
bool SpectateNext(entity this)
Definition client.qc:1981
void ChatBubbleThink(entity this)
Definition client.qc:1344
void respawn(entity this)
Definition client.qc:1496
void PutPlayerInServer(entity this)
Definition client.qc:580
void calculate_player_respawn_time(entity this)
Definition client.qc:1392
float CalcRot(float current, float stable, float rotfactor, float rotframetime)
Definition client.qc:1641
void ClientInit_CheckUpdate(entity this)
Definition client.qc:929
bool PlayerThink(entity this)
Definition client.qc:2308
bool ClientInit_SendEntity(entity this, entity to, int sf)
Definition client.qc:893
void ObserverOrSpectatorThink(entity this)
Definition client.qc:2465
bool PlayerInIPList(entity p, string iplist)
Definition client.qc:1027
bool queuePlayer(entity this, int team_index)
Definition client.qc:2181
void ShowRespawnCountdown(entity this)
Definition client.qc:2037
int nJoinAllowed(entity this)
Determines how many player slots are free.
Definition client.qc:2143
void PM_UpdateButtons(entity this, entity store)
Definition client.qc:3058
void SetSpectatee_status(entity this, int spectatee_num)
Definition client.qc:1898
bool Spectate(entity this, entity pl)
Definition client.qc:1971
bool joinAllowed(entity this, int team_index)
Definition client.qc:2230
bool dualwielding_prev
Definition client.qc:2307
bool findinlist_abbrev(string tofind, string list)
Definition client.qc:1013
void FixPlayermodel(entity player)
Definition client.qc:454
bool SpectatePrev(entity this)
Definition client.qc:1995
void PlayerFrame(entity this)
Definition client.qc:2822
bool PlayerInList(entity player, string list)
Definition client.qc:1045
void ClientInit_Spawn()
Definition client.qc:944
void ClientData_Attach(entity this)
Definition client.qc:172
void RotRegen(entity this, Resource res, float limit_mod, float regenstable, float regenfactor, float regenlinear, float regenframetime, float rotstable, float rotfactor, float rotlinear, float rotframetime)
Definition client.qc:1651
void DecodeLevelParms(entity this)
Definition client.qc:984
void show_entnum(entity this)
Definition client.qc:2281
string shootfromfixedorigin
Definition client.qc:1261
void Join(entity this, bool queued_join)
it's assumed this isn't called for bots (campaign_bots_may_start, centreprints)
Definition client.qc:2068
void ClientInit_misc(entity this)
Definition client.qc:905
void SetSpectatee(entity this, entity spectatee)
Definition client.qc:1933
void setplayermodel(entity e, string modelname)
Definition client.qc:241
string FallbackPlayerModel
Definition client.qc:207
void ClientData_Touch(entity e, bool to_spectators_too)
Definition client.qc:185
bool ClientData_Send(entity this, entity to, int sf)
Definition client.qc:128
int killcount
Definition client.qh:315
string autocvar_sv_quickmenu_file
Definition client.qh:54
float autocvar_sv_foginterval
Definition client.qh:36
float autocvar_sv_maxidle
Definition client.qh:37
float respawn_time_max
Definition client.qh:322
string autocvar_g_xonoticversion
Definition client.qh:46
int respawn_flags
Definition client.qh:320
const int RESPAWN_SILENT
Definition client.qh:327
bool autocvar_g_respawn_ghosts
Definition client.qh:28
bool autocvar_g_forced_respawn
Definition client.qh:43
string weaponorder_byimpulse
Definition client.qh:62
float autocvar_g_balance_pause_health_rot_spawn
Definition client.qh:15
string autocvar_sv_motd
Definition client.qh:52
bool autocvar_sv_servermodelsonly
Definition client.qh:55
int playerid
Definition client.qh:82
bool autocvar_sv_teamnagger
Definition client.qh:58
string autocvar_g_mutatormsg
Definition client.qh:35
bool autocvar_sv_spectate
Definition client.qh:57
#define INDEPENDENT_PLAYERS
Definition client.qh:311
bool autocvar_g_fullbrightplayers
Definition client.qh:17
const int MIN_SPEC_TIME
Definition client.qh:403
IntrusiveList g_observepoints
Definition client.qh:371
int team_selected
Definition client.qh:75
bool autocvar_g_botclip_collisions
Definition client.qh:16
float autocvar_sv_player_scale
Definition client.qh:59
bool just_joined
Definition client.qh:76
float autocvar_g_balance_pause_armor_rot_spawn
Definition client.qh:12
int autocvar_sv_maxidle_minplayers
Definition client.qh:38
IntrusiveList g_initforplayer
Definition client.qh:370
int autocvar_g_balance_armor_start
Definition client.qh:11
float autocvar_sv_maxidle_playertospectator
Definition client.qh:39
float autocvar_g_balance_pause_fuel_rot_spawn
Definition client.qh:13
bool autocvar__notarget
Definition client.qh:9
float autocvar_g_maxplayers_spectator_blocktime
Definition client.qh:45
#define IS_INDEPENDENT_PLAYER(e)
Definition client.qh:312
string autocvar_hostname
Definition client.qh:50
const int RESPAWN_DENY
Definition client.qh:328
float jointime
Definition client.qh:66
float pauserotfuel_finished
Definition client.qh:340
float autocvar_g_respawn_ghosts_time
Definition client.qh:31
bool zoomstate
Definition client.qh:72
float respawn_time
Definition client.qh:321
float autocvar_g_respawn_ghosts_alpha
Definition client.qh:29
bool autocvar_sv_maxidle_slots_countbots
Definition client.qh:42
int autocvar_spawn_debug
Definition client.qh:51
bool autocvar_g_playerclip_collisions
Definition client.qh:18
bool autocvar_g_nodepthtestplayers
Definition client.qh:34
float pauseregen_finished
Definition client.qh:337
#define GAMETYPE_DEFAULTED_SETTING(str)
Definition client.qh:347
#define MAKE_INDEPENDENT_PLAYER(e)
Definition client.qh:313
int autocvar_g_maxplayers
Definition client.qh:44
float pauserothealth_finished
Definition client.qh:338
float autocvar_g_respawn_ghosts_speed
Definition client.qh:32
const int SVC_SETVIEW
Definition client.qh:334
float respawn_countdown
Definition client.qh:324
float autocvar_g_player_brightness
Definition client.qh:20
float autocvar_g_player_damageforcescale
Definition client.qh:21
float pauserotarmor_finished
Definition client.qh:339
float spectatortime
Definition client.qh:330
const int RESPAWN_FORCE
Definition client.qh:326
int autocvar_sv_name_maxlength
Definition client.qh:53
float autocvar_gameversion
Definition client.qh:47
int autocvar_sv_maxidle_slots
Definition client.qh:41
float autocvar_g_respawn_ghosts_fadetime
Definition client.qh:30
bool autocvar_sv_show_entnum
Definition client.qh:10
float autocvar_g_balance_pause_health_regen_spawn
Definition client.qh:14
entity clientdata
Definition client.qh:64
bool autocvar_sv_maxidle_alsokickspectators
Definition client.qh:40
float alivetime_start
Definition client.qh:68
bool autocvar_sv_showspectators
Definition client.qh:56
int autocvar_sv_timeout_number
Definition common.qh:8
vector lastV_angle
Definition common.qh:62
const float TIMEOUT_ACTIVE
Definition common.qh:49
void ReadyCount()
Definition vote.qc:553
void VoteCount(float first_count)
Definition vote.qc:220
void ReadyRestart(bool forceWarmupEnd)
Definition vote.qc:526
string autocvar_sv_vote_master_ids
Definition vote.qh:14
bool vote_master
Definition vote.qh:51
int vote_called
Definition vote.qh:45
void RemoveGrapplingHooks(entity pl)
Definition hook.qc:30
void ImpulseCommands(entity this)
Definition impulse.qc:371
int int number
Definition impulse.qc:89
void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names, entity ammo_entity)
Give several random weapons and ammo to the entity.
Definition items.qc:446
float autocvar_g_balance_superweapons_time
Definition items.qh:6
float max_armorvalue
Definition items.qh:25
bool dropclient_schedule(entity this)
Schedules dropclient for a player and returns true; if dropclient is already scheduled (for that play...
Definition main.qc:44
bool autocvar_sv_autopause
Definition main.qh:19
int autocvar_g_balance_contents_playerdamage_drowning
Definition main.qh:5
vector oldvelocity
Definition main.qh:42
float autocvar_g_balance_contents_drowndelay
Definition main.qh:4
float autocvar_g_balance_contents_damagerate
Definition main.qh:3
bool iscreature
Definition main.qh:46
@ MUT_SPECPREV_RETURN
Definition events.qh:985
@ MUT_SPECPREV_CONTINUE
Definition events.qh:984
@ MUT_SPECPREV_FOUND
Definition events.qh:986
void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype,.entity weaponentity, vector hitloc, vector force)
Definition player.qc:234
void player_anim(entity this)
Definition player.qc:153
bool PlayerHeal(entity targ, entity inflictor, float amount, float limit)
Definition player.qc:615
void player_setupanimsformodel(entity this)
Definition player.qc:146
void CopyBody(entity this, float keepvelocity)
Definition player.qc:64
string autocvar_sv_defaultplayermodel_blue
Definition player.qh:14
int autocvar_sv_defaultplayerskin_pink
Definition player.qh:9
float score_frame_dmgtaken
Definition player.qh:26
float score_frame_dmg
Definition player.qh:25
int autocvar_sv_defaultplayerskin_yellow
Definition player.qh:11
string autocvar_sv_defaultplayermodel_yellow
Definition player.qh:17
string autocvar_sv_defaultplayermodel_red
Definition player.qh:16
string autocvar_sv_defaultplayercolors
Definition player.qh:12
bool autocvar_sv_defaultcharacter
Definition player.qh:6
int autocvar_sv_defaultplayerskin_blue
Definition player.qh:8
float autocvar_g_spawnshieldtime
Definition player.qh:3
int autocvar_sv_defaultplayerskin_red
Definition player.qh:10
int autocvar_sv_defaultplayerskin
Definition player.qh:18
string autocvar_sv_defaultplayermodel
Definition player.qh:13
string autocvar_sv_defaultplayermodel_pink
Definition player.qh:15
bool autocvar_sv_defaultcharacterskin
Definition player.qh:7
void race_SendNextCheckpoint(entity e, float spec)
Definition race.qc:209
bool autocvar_g_allow_checkpoints
Definition race.qh:3
float race_completed
Definition race.qh:26
int g_race_qualifying
Definition race.qh:13
bool SpawnEvent_Send(entity this, entity to, int sf)
entity SelectSpawnPoint(entity this, bool anypoint)
bool W_DualWielding(entity player)
Definition common.qc:20
float fade_time
Definition common.qh:23
void WarpZone_PlayerPhysics_FixVAngle(entity this)
Definition server.qc:865
const float VOL_BASEVOICE
Definition sound.qh:37
const int CH_TRIGGER_SINGLE
Definition sound.qh:13
const int CH_PLAYER_SINGLE
Definition sound.qh:21
const float VOL_BASE
Definition sound.qh:36
const int CH_INFO
Definition sound.qh:6
const int CH_VOICE
Definition sound.qh:10
const float ATTEN_NORM
Definition sound.qh:30
#define sound(e, c, s, v, a)
Definition sound.qh:52
const int CH_PLAYER
Definition sound.qh:20
void play2(entity e, string filename)
Definition all.qc:116
void stopsound(entity e, int chan)
Definition all.qc:109
#define SND(id)
Definition all.qh:35
entity spawnpoint_targ
Definition spawnpoint.qh:4
void PlayerState_attach(entity this)
Definition state.qc:12
void bot_clientconnect(entity this)
Definition bot.qc:469
void ClientState_detach(entity this)
Definition state.qc:73
void PlayerState_detach(entity this)
Definition state.qc:22
void DecodeLevelParms(entity this)
Definition client.qc:984
#define CS_CVAR(this)
Definition state.qh:51
#define PS(this)
Definition state.qh:18
ClientState CS(Client this)
Definition state.qh:47
void StatusEffects_remove(StatusEffect this, entity actor, int removal_type)
float StatusEffects_gettime(StatusEffect this, entity actor)
bool StatusEffects_active(StatusEffect this, entity actor)
void StatusEffects_apply(StatusEffect this, entity actor, float eff_time, int eff_flags)
void ONREMOVE(entity this)
#define strfree(this)
Definition string.qh:59
ERASEABLE int vercmp(string v1, string v2)
Definition string.qh:557
#define strcpy(this, s)
Definition string.qh:52
ERASEABLE bool isInvisibleString(string s)
Definition string.qh:387
void SUB_SetFade(entity ent, float vanish_time, float fading_time)
Definition subs.qc:77
const int DAMAGE_NO
Definition subs.qh:79
const int DAMAGE_AIM
Definition subs.qh:81
float takedamage
Definition subs.qh:78
entity enemy
Definition sv_ctf.qh:153
bool MinigameImpulse(entity this, int imp)
void part_minigame(entity player)
void monsters_setstatus(entity this)
bool monster_attack
IntrusiveList g_monster_targets
int oldskin
float g_nexball_meter_period
Definition sv_nexball.qh:54
float GetResourceLimit(entity e, Resource res_type)
Returns the maximum amount of the given resource.
Header file that describes the resource system.
float autocvar_g_balance_armor_rotlinear
int autocvar_g_balance_fuel_rotstable
float autocvar_g_balance_fuel_regen
float autocvar_g_balance_armor_regen
float autocvar_g_balance_fuel_regenlinear
float autocvar_g_balance_health_rotstable
float autocvar_g_balance_health_regenstable
int autocvar_g_balance_armor_regenstable
float autocvar_g_balance_health_rotlinear
float autocvar_g_balance_health_regenlinear
float autocvar_g_balance_fuel_rotlinear
int autocvar_g_balance_fuel_regenstable
float autocvar_g_balance_armor_rot
float autocvar_g_balance_health_regen
int autocvar_g_balance_armor_rotstable
float autocvar_g_balance_health_rot
float autocvar_g_balance_fuel_rot
float autocvar_g_balance_armor_regenlinear
#define INGAME(it)
Definition sv_rules.qh:24
#define GameRules_scoring_add(client, fld, value)
Definition sv_rules.qh:85
void vehicles_enter(entity pl, entity veh)
void vehicles_exit(entity vehic, bool eject)
const float vehicle_shield
If ent is player this is 0..100 indicating precentage of energy left on vehicle. If ent is vehicle,...
const float vehicle_reload2
If ent is player this is 0..100 indicating percentage of secondary ammo left. If ent is vehicle,...
const float vehicle_ammo1
If ent is player this is 0..100 indicating precentage of shield left on vehicle. If ent is vehicle,...
const float vehicle_health
const float vehicle_energy
If ent is player this is 0..100 indicating precentage of health left on vehicle. Vehicle's value is t...
const int VHEF_NORMAL
const int VHEF_RELEASE
User pressed exit key 3 times fast (not implemented) or vehicle is dying.
entity vehicle
Entity to disply the shild effect on damage.
const float vehicle_ammo2
If ent is player this is 0..100 indicating percentage of primary reload status. If ent is vehicle,...
float autocvar_g_vehicles_enter_radius
const float vehicle_reload1
If ent is player this is 0..100 indicating percentage of primary ammo left UNLESS value is already st...
entity swampslug
Definition swamp.qh:7
float swamp_interval
Definition swamp.qh:9
IntrusiveList g_swamped
Definition swamp.qh:4
bool QueuedPlayersReady(entity this, bool checkspecificteam)
Returns true when enough players are queued that the next will join directly to the only available te...
Definition teamplay.qc:238
bool TeamBalance_QueuedPlayersTagIn(entity ignore)
Joins queued player(s) to team(s) with a shortage, this should be more robust than only replacing the...
Definition teamplay.qc:775
void TeamBalance_Destroy(entity balance)
Destroy the team balance entity.
Definition teamplay.qc:599
void TeamBalance_RemoveExcessPlayers(entity ignore)
Definition teamplay.qc:712
void Player_DetermineForcedTeam(entity player)
Determines the forced team of the player using current global config.
Definition teamplay.qc:348
void TeamBalance_JoinBestTeam(entity player)
Assigns the given player to a team that will make the game most balanced.
Definition teamplay.qc:423
bool Player_HasRealForcedTeam(entity player)
Returns whether player has real forced team.
Definition teamplay.qc:313
bool QueueNeeded(entity ignore)
Definition teamplay.qc:1325
bool SetPlayerTeam(entity player, int team_index, int type)
Sets the team of the player.
Definition teamplay.qc:255
int Player_GetForcedTeamIndex(entity player)
Returns the index of the forced team of the given player.
Definition teamplay.qc:318
int TeamBalance_GetAllowedTeams(entity balance)
Returns the bitmask of allowed teams.
Definition teamplay.qc:612
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings.
Definition teamplay.qc:459
bool TeamBalance_AreEqual(entity ignore, bool would_leave)
Definition teamplay.qc:656
string autocvar_g_forced_team_otherwise
Definition teamplay.qh:13
@ TEAM_FORCE_SPECTATOR
Force the player to spectator team.
Definition teamplay.qh:137
bool autocvar_g_balance_teams_remove
Definition teamplay.qh:10
@ TEAM_CHANGE_MANUAL
Player has manually selected their team.
Definition teamplay.qh:115
@ TEAM_CHANGE_SPECTATOR
Player is joining spectators. //TODO: Remove?
Definition teamplay.qh:116
bool autocvar_g_balance_teams
Definition teamplay.qh:7
bool lockteams
Definition teamplay.qh:15
#define SAME_TEAM(a, b)
Definition teams.qh:241
const int NUM_TEAM_2
Definition teams.qh:14
const int NUM_TEAM_4
Definition teams.qh:16
const int NUM_TEAM_3
Definition teams.qh:15
int Team_IndexToTeam(int index)
Converts team index into team value.
Definition teams.qh:169
bool teamplay
Definition teams.qh:59
const int NUM_TEAM_1
Definition teams.qh:13
const int TELEPORT_NORMAL
float teleportable
const int TELEPORT_SIMPLE
void WarpZone_crosshair_trace_plusvisibletriggers(entity pl)
Definition tracing.qc:559
float autocvar_g_trueaim_minrange
Definition tracing.qh:17
float autocvar_g_ballistics_density_player
Definition tracing.qh:7
#define IS_OBSERVER(v)
Definition utils.qh:11
#define IS_SPEC(v)
Definition utils.qh:10
const string STR_PLAYER
Definition utils.qh:5
#define IS_REAL_CLIENT(v)
Definition utils.qh:17
#define FOREACH_CLIENT(cond, body)
Definition utils.qh:50
#define IS_VEHICLE(v)
Definition utils.qh:22
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition utils.qh:15
#define vlen2(v)
Definition vector.qh:4
#define vec2(...)
Definition vector.qh:90
const int VHF_MULTISLOT
Add random head angles each frame if health < 50%.
Definition vehicle.qh:96
int cursor_active
Definition view.qh:112
float dmg_take
Definition view.qh:123
void target_voicescript_next(entity pl)
void target_voicescript_clear(entity pl)
Definition voicescript.qc:8
void W_Vortex_Charge(entity actor,.entity weaponentity, float dt)
Definition vortex.qc:173
float vortex_charge_rottime
Definition vortex.qh:88
bool waypointeditor_enabled
Definition waypoints.qh:3
entity wp_aimed
Definition waypoints.qh:47
void WaypointSprite_PlayerGone(entity this)
void WaypointSprite_PlayerDead(entity this)
void WaypointSprite_UpdateHealth(entity e, float f)
entity waypointsprite_attachedforcarrier
void W_PROP_reload(int chan, entity to)
Definition all.qh:112
#define WEPSET(id)
Definition all.qh:45
string autocvar_g_shootfromfixedorigin
Definition all.qh:417
entity exteriorweaponentity
Definition all.qh:377
#define WEP_CVAR(wep, name)
Definition all.qh:321
WepSet WEPSET_SUPERWEAPONS
Definition all.qh:329
vector spawnorigin
Definition all.qh:391
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
void W_WeaponFrame(Player actor,.entity weaponentity)
void CL_SpawnWeaponentity(entity actor,.entity weaponentity)
void W_ResetGunAlign(entity player, int preferred_alignment)
const int W_TICSPERFRAME
float weapon_load[REGISTRY_MAX(Weapons)]
float vortex_charge
Definition wepent.qh:6
Weapon m_weapon
Definition wepent.qh:26
WepSet start_weapons
Definition world.qh:80
float warmup_start_ammo_cells
Definition world.qh:105
string clientstuff
Definition world.qh:61
#define WARMUP_START_WEAPONS
Definition world.qh:101
entity random_start_ammo
Entity that contains amount of ammo to give with random start weapons.
Definition world.qh:95
string autocvar_g_random_start_weapons
Holds a list of possible random start weapons.
Definition world.qh:92
bool autocvar_g_jetpack
Definition world.qh:8
float start_ammo_shells
Definition world.qh:84
float warmup_start_ammo_rockets
Definition world.qh:104
float warmup_start_ammo_shells
Definition world.qh:102
float start_ammo_fuel
Definition world.qh:88
int start_items
Definition world.qh:83
bool autocvar_sv_mapformat_is_quake3
Definition world.qh:32
int random_start_weapons_count
Number of random start weapons to give to players.
Definition world.qh:90
float warmup_start_ammo_nails
Definition world.qh:103
float default_weapon_alpha
Definition world.qh:73
WepSet g_weaponarena_weapons
Definition world.qh:76
float default_player_alpha
Definition world.qh:72
float start_ammo_cells
Definition world.qh:87
string cache_lastmutatormsg
Definition world.qh:70
float g_weaponarena
Definition world.qh:75
float warmup_start_health
Definition world.qh:107
bool autocvar_sv_dedicated
Definition world.qh:41
float start_ammo_rockets
Definition world.qh:86
float g_weapon_stay
Definition world.qh:109
float start_armorvalue
Definition world.qh:97
int autocvar_g_warmup
Definition world.qh:9
bool observe_blocked_if_eliminated
Definition world.qh:160
float warmup_start_ammo_fuel
Definition world.qh:106
string g_weaponarena_list
Definition world.qh:78
float start_health
Definition world.qh:96
bool sv_ready_restart_after_countdown
Definition world.qh:116
float warmup_start_armorvalue
Definition world.qh:108
float start_ammo_nails
Definition world.qh:85
string cache_mutatormsg
Definition world.qh:69