]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/client.qc
Show a welcome window with MOTD on server connection
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / client.qc
index edefc0d28b0f72086d11ba12ff75224460716d5d..3d0fffe0a0a538f3f850d48b5a8d762e42fd89e0 100644 (file)
@@ -30,6 +30,7 @@
 #include <common/notifications/all.qh>
 #include <common/physics/player.qh>
 #include <common/playerstats.qh>
+#include <common/resources/sv_resources.qh>
 #include <common/state.qh>
 #include <common/stats.qh>
 #include <common/vehicles/all.qh>
@@ -65,7 +66,6 @@
 #include <server/player.qh>
 #include <server/portals.qh>
 #include <server/race.qh>
-#include <server/resources.qh>
 #include <server/scores.qh>
 #include <server/scores_rules.qh>
 #include <server/spawnpoints.qh>
@@ -235,9 +235,10 @@ void setplayermodel(entity e, string modelname)
 }
 
 /** putting a client as observer in the server */
-void PutObserverInServer(entity this, bool is_forced)
+void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint)
 {
        bool mutator_returnvalue = MUTATOR_CALLHOOK(MakePlayerObserver, this, is_forced);
+       bool recount_ready = false;
        PlayerState_detach(this);
 
        if (IS_PLAYER(this))
@@ -252,17 +253,24 @@ void PutObserverInServer(entity this, bool is_forced)
                if(IS_REAL_CLIENT(this))
                {
                        if (vote_called) { VoteCount(false); }
-                       ReadyCount();
+                       this.ready = false;
+                       recount_ready = true;
                }
                entcs_update_players(this);
        }
 
-       entity spot = SelectSpawnPoint(this, true);
-       if (!spot) LOG_FATAL("No spawnpoints for observers?!?");
-       this.angles = vec2(spot.angles);
+       if (use_spawnpoint)
+       {
+               entity spot = SelectSpawnPoint(this, true);
+               if (!spot) LOG_FATAL("No spawnpoints for observers?!?");
+               this.angles = vec2(spot.angles);
+               // offset it so that the spectator spawns higher off the ground, looks better this way
+               setorigin(this, spot.origin + STAT(PL_VIEW_OFS, this));
+       }
+       else // change origin to restore previous view origin
+               setorigin(this, this.origin + STAT(PL_VIEW_OFS, this) - STAT(PL_CROUCH_VIEW_OFS, this));
        this.fixangle = true;
-       // offset it so that the spectator spawns higher off the ground, looks better this way
-       setorigin(this, spot.origin + STAT(PL_VIEW_OFS, this));
+
        if (IS_REAL_CLIENT(this))
        {
                msg_entity = this;
@@ -295,13 +303,16 @@ void PutObserverInServer(entity this, bool is_forced)
 
        if (this.vehicle) vehicles_exit(this.vehicle, VHEF_RELEASE);
 
+       TRANSMUTE(Observer, this);
+
+       if(recount_ready) ReadyCount();
+
        WaypointSprite_PlayerDead(this);
+       accuracy_resend(this);
 
        if (CS(this).killcount != FRAGS_SPECTATOR && !game_stopped && CHAT_NOSPECTATORS())
                Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
 
-       accuracy_resend(this);
-
        CS(this).spectatortime = time;
        if(this.bot_attack)
                IL_REMOVE(g_bot_targets, this);
@@ -310,7 +321,6 @@ void PutObserverInServer(entity this, bool is_forced)
                IL_REMOVE(g_monster_targets, this);
        this.monster_attack = false;
        STAT(HUD, this) = HUD_NORMAL;
-       TRANSMUTE(Observer, this);
        this.iscreature = false;
        this.teleportable = TELEPORT_SIMPLE;
        if(this.damagedbycontents)
@@ -351,6 +361,7 @@ void PutObserverInServer(entity this, bool is_forced)
        this.revival_time = 0;
        this.draggable = drag_undraggable;
 
+       player_powerups_remove_all(this);
        this.items = 0;
        STAT(WEAPONS, this) = '0 0 0';
        this.drawonlytoclient = this;
@@ -809,6 +820,7 @@ void PutClientInServer(entity this)
        if (game_stopped)
                TRANSMUTE(Observer, this);
 
+       bool use_spawnpoint = (!this.enemy); // check this.enemy here since SetSpectatee will clear it
        SetSpectatee(this, NULL);
 
        // reset player keys
@@ -818,7 +830,7 @@ void PutClientInServer(entity this)
        MUTATOR_CALLHOOK(PutClientInServer, this);
 
        if (IS_OBSERVER(this)) {
-               PutObserverInServer(this, false);
+               PutObserverInServer(this, false, use_spawnpoint);
        } else if (IS_PLAYER(this)) {
                PutPlayerInServer(this);
        }
@@ -935,7 +947,6 @@ void DecodeLevelParms(entity this)
 void FixClientCvars(entity e)
 {
        // send prediction settings to the client
-       stuffcmd(e, "\nin_bindmap 0 0\n");
        if(autocvar_g_antilag == 3) // client side hitscan
                stuffcmd(e, "cl_cmd settemp cl_prydoncursor_notrace 0\n");
        if(autocvar_sv_gentle)
@@ -1044,10 +1055,9 @@ string getwelcomemessage(entity this)
                modifications = strcat(modifications, ", Jet pack");
        modifications = substring(modifications, 2, strlen(modifications) - 2);
 
-       string versionmessage = GetClientVersionMessage(this);
-       string s = strcat(versionmessage, "^8\n^8\nserver is ^9", autocvar_hostname, "^8\n");
+       string s = GetClientVersionMessage(this);
 
-       s = strcat(s, "^8\nmatch type is ^1", gamemode_name, "^8\n");
+       s = strcat(s, "^8\n\nmatch type is ^1", gamemode_name, "^8\n");
 
        if(modifications != "")
                s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n");
@@ -1075,6 +1085,14 @@ string getwelcomemessage(entity this)
        return s;
 }
 
+void serverinfo_welcomemessage_send(entity this)
+{
+       msg_entity = this;
+       WriteHeader(MSG_ONE, TE_CSQC_SERVERINFO);
+       WriteString(MSG_ONE, autocvar_hostname);
+       WriteString(MSG_ONE, getwelcomemessage(this));
+}
+
 /**
 =============
 ClientConnect
@@ -1162,7 +1180,11 @@ void ClientConnect(entity this)
        CS(this).model_randomizer = random();
 
        if (IS_REAL_CLIENT(this))
+       {
+               if (!autocvar_g_campaign)
+                       serverinfo_welcomemessage_send(this);
                sv_notice_join(this);
+       }
 
        this.move_qcphysics = autocvar_sv_qcphysics;
 
@@ -1442,15 +1464,17 @@ void play_countdown(entity this, float finished, Sound samp)
                                sound (this, CH_INFO, samp, VOL_BASE, ATTEN_NORM);
 }
 
+// it removes special powerups not handled by StatusEffects
 void player_powerups_remove_all(entity this)
 {
-       if (this.items & IT_SUPERWEAPON)
+       if (this.items & (IT_SUPERWEAPON | IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS))
        {
                // don't play the poweroff sound when the game restarts or the player disconnects
                if (time > game_starttime + 1 && IS_CLIENT(this))
                        sound(this, CH_INFO, SND_POWEROFF, VOL_BASE, ATTEN_NORM);
-               stopsound(this, CH_TRIGGER_SINGLE); // get rid of the pickup sound
-               this.items -= (this.items & IT_SUPERWEAPON);
+               if (this.items & (IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS))
+                       stopsound(this, CH_TRIGGER_SINGLE); // get rid of the pickup sound
+               this.items -= (this.items & (IT_SUPERWEAPON | IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS));
        }
 }
 
@@ -1554,7 +1578,7 @@ float CalcRot(float current, float stable, float rotfactor, float rotframetime)
                return max(stable, current + (stable - current) * rotfactor * rotframetime);
 }
 
-void RotRegen(entity this, int res, float limit_mod,
+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)
 {
@@ -1798,7 +1822,7 @@ bool SpectateSet(entity this)
        accuracy_resend(this);
 
        if(!SpectateUpdate(this))
-               PutObserverInServer(this, false);
+               PutObserverInServer(this, false, true);
 
        return true;
 }
@@ -1840,18 +1864,18 @@ void SetSpectatee(entity this, entity spectatee)
                                old_spectatee.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
                }
        }
-       if(this.enemy)
+       if(spectatee)
        {
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                        .entity weaponentity = weaponentities[slot];
-                       if(this.enemy.(weaponentity).arc_beam)
-                               this.enemy.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
+                       if(spectatee.(weaponentity).arc_beam)
+                               spectatee.(weaponentity).arc_beam.SendFlags |= ARC_SF_SETTINGS;
                }
        }
 
-       if (this.enemy)
-               SetSpectatee_status(this, etof(this.enemy));
+       if (spectatee)
+               SetSpectatee_status(this, etof(spectatee));
 
        // needed to update spectator list
        if(old_spectatee) { ClientData_Touch(old_spectatee); }
@@ -2301,7 +2325,7 @@ void ObserverOrSpectatorThink(entity this)
                                TRANSMUTE(Observer, this);
                                PutClientInServer(this);
                        } else if(!SpectateUpdate(this) && !SpectateNext(this)) {
-                               PutObserverInServer(this, false);
+                               PutObserverInServer(this, false, true);
                                this.would_spectate = true;
                        }
                }
@@ -2327,7 +2351,7 @@ void ObserverOrSpectatorThink(entity this)
                        }
                }
                if(is_spec && !SpectateUpdate(this))
-                       PutObserverInServer(this, false);
+                       PutObserverInServer(this, false, true);
        }
        if (is_spec)
                this.flags |= FL_CLIENT | FL_NOTARGET;
@@ -2511,12 +2535,9 @@ void PlayerPreThink (entity this)
                this.last_vehiclecheck = time + 1;
        }
 
-       if(!CS_CVAR(this).cvar_cl_newusekeysupported) // FIXME remove this - it was a stupid idea to begin with, we can JUST use the button
-       {
-               if(PHYS_INPUT_BUTTON_USE(this) && !CS(this).usekeypressed)
-                       PlayerUseKey(this);
-               CS(this).usekeypressed = PHYS_INPUT_BUTTON_USE(this);
-       }
+       if(PHYS_INPUT_BUTTON_USE(this) && !CS(this).usekeypressed)
+               PlayerUseKey(this);
+       CS(this).usekeypressed = PHYS_INPUT_BUTTON_USE(this);
 
        if (IS_REAL_CLIENT(this))
                PrintWelcomeMessage(this);
@@ -2701,7 +2722,7 @@ void PlayerPostThink (entity this)
                                if (IS_PLAYER(this) && autocvar_sv_maxidle_playertospectator > 0)
                                {
                                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_MOVETOSPEC_IDLING, this.netname, maxidle_time);
-                                       PutObserverInServer(this, true);
+                                       PutObserverInServer(this, true, true);
                                }
                                else
                                {