]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/client.qc
Don't attempt to network more than the maximum number of shown spectators, fixes...
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / client.qc
index 1211e8988ea98b65c5fb90ac8f952a3c0e540067..99aa86d24f82d7d233fc12f6fff56e2661252376 100644 (file)
@@ -1,6 +1,7 @@
 #include "client.qh"
 
-#include <server/defs.qh>
+#include <common/weapons/_all.qh>
+#include <common/stats.qh>
 #include <server/miscfunctions.qh>
 #include <common/effects/all.qh>
 #include "anticheat.qh"
@@ -22,6 +23,7 @@
 #include "g_world.qh"
 #include <server/gamelog.qh>
 #include "race.qh"
+#include <server/sv_main.qh>
 #include "antilag.qh"
 #include "campaign.qh"
 #include "command/common.qh"
@@ -48,6 +50,7 @@
 #include "../common/vehicles/all.qh"
 
 #include "weapons/hitplot.qh"
+#include "weapons/selection.qh"
 #include "weapons/weaponsystem.qh"
 
 #include "../common/net_notice.qh"
@@ -58,6 +61,8 @@
 
 #include "../common/items/_mod.qh"
 
+#include <common/gamemodes/gamemode/nexball/sv_nexball.qh>
+
 #include "../common/mutators/mutator/waypoints/all.qh"
 #include "../common/mutators/mutator/instagib/sv_instagib.qh"
 #include <common/gamemodes/_mod.qh>
@@ -76,6 +81,8 @@
 
 #include <common/mutators/mutator/overkill/oknex.qh>
 
+#include <common/weapons/weapon/vortex.qh>
+
 STATIC_METHOD(Client, Add, void(Client this, int _team))
 {
     ClientConnect(this);
@@ -114,9 +121,13 @@ void WriteSpectators(entity player, entity to)
 {
        if(!player) { return; } // not sure how, but best to be safe
 
+       int spec_count = 0;
        FOREACH_CLIENT(IS_REAL_CLIENT(it) && IS_SPEC(it) && it != to && it.enemy == player,
        {
+               if(spec_count >= MAX_SPECTATORS)
+                       break;
                WriteByte(MSG_ENTITY, num_for_edict(it));
+               ++spec_count;
        });
 }
 
@@ -334,12 +345,11 @@ void PutObserverInServer(entity this)
        this.alpha = 0;
        this.scale = 0;
        this.fade_time = 0;
-       this.pain_frame = 0;
        this.pain_finished = 0;
        STAT(STRENGTH_FINISHED, this) = 0;
        STAT(INVINCIBLE_FINISHED, this) = 0;
        STAT(SUPERWEAPONS_FINISHED, this) = 0;
-       this.air_finished = 0;
+       STAT(AIR_FINISHED, this) = 0;
        //this.dphitcontentsmask = 0;
        this.dphitcontentsmask = DPCONTENTS_SOLID;
        if (autocvar_g_playerclip_collisions)
@@ -349,7 +359,7 @@ void PutObserverInServer(entity this)
        setthink(this, func_null);
        this.nextthink = 0;
        this.deadflag = DEAD_NO;
-       this.crouch = false;
+       UNSET_DUCKED(this);
        STAT(REVIVE_PROGRESS, this) = 0;
        this.revival_time = 0;
        this.draggable = drag_undraggable;
@@ -617,7 +627,6 @@ void PutPlayerInServer(entity this)
        bool q3dfcompat = autocvar_sv_q3defragcompat && autocvar_sv_q3defragcompat_changehitbox;
        this.scale = ((q3dfcompat) ? 0.9 : autocvar_sv_player_scale);
        this.fade_time = 0;
-       this.pain_frame = 0;
        this.pain_finished = 0;
        this.pushltime = 0;
        setthink(this, func_null); // players have no think function
@@ -650,7 +659,7 @@ void PutPlayerInServer(entity this)
        STAT(BUFFS, this) = 0;
        STAT(BUFF_TIME, this) = 0;
 
-       this.air_finished = 0;
+       STAT(AIR_FINISHED, this) = 0;
        this.waterlevel = WATERLEVEL_NONE;
        this.watertype = CONTENT_EMPTY;
 
@@ -678,7 +687,7 @@ void PutPlayerInServer(entity this)
 
        this.spawnpoint_targ = NULL;
 
-       this.crouch = false;
+       UNSET_DUCKED(this);
        this.view_ofs = STAT(PL_VIEW_OFS, this);
        setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
        this.spawnorigin = spot.origin;
@@ -1309,6 +1318,91 @@ void UpdateChatBubble(entity this)
        }
 }
 
+void calculate_player_respawn_time(entity this)
+{
+       if(MUTATOR_CALLHOOK(CalculateRespawnTime, this))
+               return;
+
+       float gametype_setting_tmp;
+       float sdelay_max = GAMETYPE_DEFAULTED_SETTING(respawn_delay_max);
+       float sdelay_small = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small);
+       float sdelay_large = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large);
+       float sdelay_small_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_small_count);
+       float sdelay_large_count = GAMETYPE_DEFAULTED_SETTING(respawn_delay_large_count);
+       float waves = GAMETYPE_DEFAULTED_SETTING(respawn_waves);
+
+       float pcount = 1;  // Include myself whether or not team is already set right and I'm a "player".
+       if (teamplay)
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
+                       if(it.team == this.team)
+                               ++pcount;
+               });
+               if (sdelay_small_count == 0)
+                       sdelay_small_count = 1;
+               if (sdelay_large_count == 0)
+                       sdelay_large_count = 1;
+       }
+       else
+       {
+               FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
+                       ++pcount;
+               });
+               if (sdelay_small_count == 0)
+               {
+                       if (IS_INDEPENDENT_PLAYER(this))
+                       {
+                               // Players play independently. No point in requiring enemies.
+                               sdelay_small_count = 1;
+                       }
+                       else
+                       {
+                               // Players play AGAINST each other. Enemies required.
+                               sdelay_small_count = 2;
+                       }
+               }
+               if (sdelay_large_count == 0)
+               {
+                       if (IS_INDEPENDENT_PLAYER(this))
+                       {
+                               // Players play independently. No point in requiring enemies.
+                               sdelay_large_count = 1;
+                       }
+                       else
+                       {
+                               // Players play AGAINST each other. Enemies required.
+                               sdelay_large_count = 2;
+                       }
+               }
+       }
+
+       float sdelay;
+
+       if (pcount <= sdelay_small_count)
+               sdelay = sdelay_small;
+       else if (pcount >= sdelay_large_count)
+               sdelay = sdelay_large;
+       else  // NOTE: this case implies sdelay_large_count > sdelay_small_count.
+               sdelay = sdelay_small + (sdelay_large - sdelay_small) * (pcount - sdelay_small_count) / (sdelay_large_count - sdelay_small_count);
+
+       if(waves)
+               this.respawn_time = ceil((time + sdelay) / waves) * waves;
+       else
+               this.respawn_time = time + sdelay;
+
+       if(sdelay < sdelay_max)
+               this.respawn_time_max = time + sdelay_max;
+       else
+               this.respawn_time_max = this.respawn_time;
+
+       if((sdelay + waves >= 5.0) && (this.respawn_time - time > 1.75))
+               this.respawn_countdown = 10; // first number to count down from is 10
+       else
+               this.respawn_countdown = -1; // do not count down
+
+       if(autocvar_g_forced_respawn)
+               this.respawn_flags = this.respawn_flags | RESPAWN_FORCE;
+}
 
 // LordHavoc: this hack will be removed when proper _pants/_shirt layers are
 // added to the model skins
@@ -1723,7 +1817,7 @@ void SpectateCopy(entity this, entity spectatee)
        STAT(STRENGTH_FINISHED, this) = STAT(STRENGTH_FINISHED, spectatee);
        STAT(INVINCIBLE_FINISHED, this) = STAT(INVINCIBLE_FINISHED, spectatee);
        STAT(SUPERWEAPONS_FINISHED, this) = STAT(SUPERWEAPONS_FINISHED, spectatee);
-       this.air_finished = spectatee.air_finished;
+       STAT(AIR_FINISHED, this) = STAT(AIR_FINISHED, spectatee);
        STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
        STAT(WEAPONS, this) = STAT(WEAPONS, spectatee);
        this.punchangle = spectatee.punchangle;
@@ -2267,7 +2361,6 @@ bool PlayerThink(entity this)
                this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
        }
 
-       secrets_setstatus(this);
        monsters_setstatus(this);
 
        return true;
@@ -2612,21 +2705,21 @@ void DrownPlayer(entity this)
        if(IS_DEAD(this) || game_stopped || time < game_starttime || this.vehicle
                || STAT(FROZEN, this) || this.watertype != CONTENT_WATER)
        {
-               this.air_finished = 0;
+               STAT(AIR_FINISHED, this) = 0;
                return;
        }
 
        if (this.waterlevel != WATERLEVEL_SUBMERGED)
        {
-               if(this.air_finished && this.air_finished < time)
+               if(STAT(AIR_FINISHED, this) && STAT(AIR_FINISHED, this) < time)
                        PlayerSound(this, playersound_gasp, CH_PLAYER, VOL_BASE, VOICETYPE_PLAYERSOUND);
-               this.air_finished = 0;
+               STAT(AIR_FINISHED, this) = 0;
        }
        else
        {
-               if (!this.air_finished)
-                       this.air_finished = time + autocvar_g_balance_contents_drowndelay;
-               if (this.air_finished < time)
+               if (!STAT(AIR_FINISHED, this))
+                       STAT(AIR_FINISHED, this) = time + autocvar_g_balance_contents_drowndelay;
+               if (STAT(AIR_FINISHED, this) < time)
                {       // drown!
                        if (this.pain_finished < time)
                        {