X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fxonotic-data.pk3dir.git;a=blobdiff_plain;f=qcsrc%2Fserver%2Fclient.qc;h=08f9ff664e1627c453ed479475d15d65f9b7f06c;hp=3af147c21374c52f3cec6aa3cc2e3c1d09b432f0;hb=18bd49fa931fff143ba3cfff468774aea65bd882;hpb=f04de7c7c59718cb668dde161acb25d1d74651e3 diff --git a/qcsrc/server/client.qc b/qcsrc/server/client.qc index 3af147c213..08f9ff664e 100644 --- a/qcsrc/server/client.qc +++ b/qcsrc/server/client.qc @@ -137,7 +137,8 @@ bool ClientData_Send(entity this, entity to, int sf) if (CS(e).race_completed) sf |= BIT(0); // forced scoreboard if (CS(to).spectatee_status) sf |= BIT(1); // spectator ent number follows if (CS(e).zoomstate) sf |= BIT(2); // zoomed - if (autocvar_sv_showspectators) sf |= BIT(4); // show spectators + if (autocvar_sv_showspectators == 1 || (autocvar_sv_showspectators && IS_SPEC(to))) + sf |= BIT(4); // show spectators WriteHeader(MSG_ENTITY, ENT_CLIENT_CLIENTDATA); WriteByte(MSG_ENTITY, sf); @@ -238,6 +239,7 @@ void setplayermodel(entity e, string modelname) 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,7 +254,8 @@ void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint) if(IS_REAL_CLIENT(this)) { if (vote_called) { VoteCount(false); } - ReadyCount(); + this.ready = false; + recount_ready = true; } entcs_update_players(this); } @@ -301,13 +304,16 @@ void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint) 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); @@ -316,7 +322,6 @@ void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint) 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) @@ -357,6 +362,7 @@ void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint) 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; @@ -395,7 +401,7 @@ void PutObserverInServer(entity this, bool is_forced, bool use_spawnpoint) } else { - SetPlayerTeam(this, -1, TEAM_CHANGE_SPECTATOR); + SetPlayerTeam(this, -1, TEAM_CHANGE_SPECTATOR); // clears scores too in game modes without teams this.frags = FRAGS_SPECTATOR; } @@ -534,6 +540,9 @@ void PutPlayerInServer(entity this) PlayerState_attach(this); accuracy_resend(this); + if (teamplay && this.bot_forced_team) + SetPlayerTeam(this, this.bot_forced_team, TEAM_CHANGE_MANUAL); + if (this.team < 0) TeamBalance_JoinBestTeam(this); @@ -755,7 +764,6 @@ void PutPlayerInServer(entity this) Unfreeze(this, false); MUTATOR_CALLHOOK(PlayerSpawn, this, spot); - { string s = spot.target; if(g_assault || g_race) // TODO: make targeting work in assault & race without this hack @@ -805,9 +813,7 @@ void PutPlayerInServer(entity this) /** Called when a client spawns in the server */ void PutClientInServer(entity this) { - if (IS_BOT_CLIENT(this)) { - TRANSMUTE(Player, this); - } else if (IS_REAL_CLIENT(this)) { + if (IS_REAL_CLIENT(this)) { msg_entity = this; WriteByte(MSG_ONE, SVC_SETVIEW); WriteEntity(MSG_ONE, this); @@ -1013,50 +1019,48 @@ void ClientPreConnect(entity this) } #endif -string GetClientVersionMessage(entity this) +void SendWelcomemessage(entity this, bool force_centerprint) { - if (CS(this).version_mismatch) { - if(CS(this).version < autocvar_gameversion) { - return strcat("This is Xonotic ", autocvar_g_xonoticversion, - "\n^3Your client version is outdated.\n\n\n### YOU WON'T BE ABLE TO PLAY ON THIS SERVER ###\n\n\nPlease update!!!^8"); - } else { - return strcat("This is Xonotic ", autocvar_g_xonoticversion, - "\n^3This server is using an outdated Xonotic version.\n\n\n ### THIS SERVER IS INCOMPATIBLE AND THUS YOU CANNOT JOIN ###.^8"); - } - } else { - return strcat("Welcome to Xonotic ", autocvar_g_xonoticversion); - } + msg_entity = this; + WriteHeader(MSG_ONE, TE_CSQC_SERVERWELCOME); + SendWelcomemessage_msg_type(this, force_centerprint, MSG_ONE); } -string getwelcomemessage(entity this) +// NOTE csqc uses the active mutators list sent by this function +// to understand which mutators are enabled +// also note that they aren't all registered mutators, e.g. jetpack, low gravity +void SendWelcomemessage_msg_type(entity this, bool force_centerprint, int msg_type) { + WriteByte(msg_type, boolean(autocvar_g_campaign)); + if (boolean(autocvar_g_campaign)) + { + WriteString(msg_type, Campaign_GetTitle()); + WriteByte(msg_type, Campaign_GetLevelNum()); + WriteString(msg_type, Campaign_GetMessage()); + return; + } + WriteByte(msg_type, force_centerprint); + WriteString(msg_type, autocvar_hostname); + WriteString(msg_type, autocvar_g_xonoticversion); + WriteByte(msg_type, CS(this).version_mismatch); + WriteByte(msg_type, (CS(this).version < autocvar_gameversion)); + MUTATOR_CALLHOOK(BuildMutatorsPrettyString, ""); string modifications = M_ARGV(0, string); - if(g_weaponarena) - { - if(g_weaponarena_random) - modifications = strcat(modifications, ", ", ftos(g_weaponarena_random), " of ", g_weaponarena_list, " Arena"); - else - modifications = strcat(modifications, ", ", g_weaponarena_list, " Arena"); - } - else if(cvar("g_balance_blaster_weaponstartoverride") == 0) + if (!g_weaponarena && cvar("g_balance_blaster_weaponstartoverride") == 0) modifications = strcat(modifications, ", No start weapons"); if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity"))) modifications = strcat(modifications, ", Low gravity"); if(g_weapon_stay && !g_cts) modifications = strcat(modifications, ", Weapons stay"); if(autocvar_g_jetpack) - modifications = strcat(modifications, ", Jet pack"); + modifications = strcat(modifications, ", Jetpack"); 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"); - - s = strcat(s, "^8\nmatch type is ^1", gamemode_name, "^8\n"); + WriteString(msg_type, modifications); - if(modifications != "") - s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n"); + WriteString(msg_type, g_weaponarena_list); if(cache_lastmutatormsg != autocvar_g_mutatormsg) { @@ -1064,21 +1068,9 @@ string getwelcomemessage(entity this) strcpy(cache_mutatormsg, cache_lastmutatormsg); } - if (cache_mutatormsg != "") { - s = strcat(s, "\n\n^8special gameplay tips: ^7", cache_mutatormsg); - } - - string mutator_msg = ""; - MUTATOR_CALLHOOK(BuildGameplayTipsString, mutator_msg); - mutator_msg = M_ARGV(0, string); + WriteString(msg_type, cache_mutatormsg); - s = strcat(s, mutator_msg); // trust that the mutator will do proper formatting - - string motd = autocvar_sv_motd; - if (motd != "") { - s = strcat(s, "\n\n^8MOTD: ^7", strreplace("\\n", "\n", motd)); - } - return s; + WriteString(msg_type, strreplace("\\n", "\n", autocvar_sv_motd)); } /** @@ -1183,14 +1175,8 @@ void ClientConnect(entity this) MUTATOR_CALLHOOK(ClientConnect, this); - if (IS_REAL_CLIENT(this)) - { - if (!autocvar_g_campaign && !IS_PLAYER(this)) - { - CS(this).motd_actived_time = -1; - Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this)); - } - } + if (player_count == 1) + localcmd("\nsv_hook_firstjoin\n"); } /* ============= @@ -1257,6 +1243,9 @@ void ClientDisconnect(entity this) player_powerups_remove_all(this); // stop powerup sound ONREMOVE(this); + + if (player_count == 0) + localcmd("\nsv_hook_lastleave\n"); } void ChatBubbleThink(entity this) @@ -1442,21 +1431,25 @@ void respawn(entity this) void play_countdown(entity this, float finished, Sound samp) { TC(Sound, samp); - if(IS_REAL_CLIENT(this)) - if(floor(finished - time - frametime) != floor(finished - time)) - if(finished - time < 6) - sound (this, CH_INFO, samp, VOL_BASE, ATTEN_NORM); + float time_left = finished - time; + if(IS_REAL_CLIENT(this) && time_left < 6 && floor(time_left - frametime) != floor(time_left)) + 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)) + if (time > game_starttime + 1 && IS_CLIENT(this) + && !(start_items & (IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS))) + { 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)); } } @@ -1958,6 +1951,9 @@ bool ShowTeamSelection(entity this) } void Join(entity this) { + if (autocvar_g_campaign && !campaign_bots_may_start && !game_stopped && time >= game_starttime) + ReadyRestart(true); + TRANSMUTE(Player, this); if(!this.team_selected) @@ -2039,65 +2035,6 @@ int nJoinAllowed(entity this, entity ignore) return free_slots; } -void PrintWelcomeMessage(entity this) -{ - if(CS(this).motd_actived_time == 0) - { - if (autocvar_g_campaign) { - if ((IS_PLAYER(this) && PHYS_INPUT_BUTTON_INFO(this)) || (!IS_PLAYER(this))) { - CS(this).motd_actived_time = time; - Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_CAMPAIGN_MESSAGE, Campaign_GetMessage(), Campaign_GetLevelNum()); - } - } else { - if (PHYS_INPUT_BUTTON_INFO(this)) { - CS(this).motd_actived_time = time; - Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_MOTD, getwelcomemessage(this)); - } - } - } - else if(CS(this).motd_actived_time > 0) // showing MOTD or campaign message - { - if (autocvar_g_campaign) { - if (PHYS_INPUT_BUTTON_INFO(this)) - CS(this).motd_actived_time = time; - else if ((time - CS(this).motd_actived_time > 2) && IS_PLAYER(this)) { // hide it some seconds after BUTTON_INFO has been released - CS(this).motd_actived_time = 0; - Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_CAMPAIGN_MESSAGE); - } - } else { - if (PHYS_INPUT_BUTTON_INFO(this)) - CS(this).motd_actived_time = time; - else if (time - CS(this).motd_actived_time > 2) { // hide it some seconds after BUTTON_INFO has been released - CS(this).motd_actived_time = 0; - Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD); - } - } - } - else //if(CS(this).motd_actived_time < 0) // just connected, motd is active - { - if(PHYS_INPUT_BUTTON_INFO(this)) // BUTTON_INFO hides initial MOTD - CS(this).motd_actived_time = -2; // wait until BUTTON_INFO gets released - else if (CS(this).motd_actived_time == -2) - { - // instantly hide MOTD - CS(this).motd_actived_time = 0; - if (autocvar_g_campaign) - Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_CAMPAIGN_MESSAGE); - else - Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD); - } - else if (IS_PLAYER(this) || IS_SPEC(this)) - { - // FIXME occasionally for some reason MOTD never goes away - // delay MOTD removal a little bit in the hope it fixes this bug - if (CS(this).motd_actived_time == -1) // MOTD marked to fade away as soon as client becomes player or spectator - CS(this).motd_actived_time = -(5 + floor(random() * 10)); // add small delay - else //if (CS(this).motd_actived_time < -2) - CS(this).motd_actived_time++; - } - } -} - bool joinAllowed(entity this) { if (CS(this).version_mismatch) return false; @@ -2274,6 +2211,14 @@ void ObserverOrSpectatorThink(entity this) } } + if (IS_BOT_CLIENT(this) && !CS(this).autojoin_checked) + { + CS(this).autojoin_checked = true; + TRANSMUTE(Player, this); + PutClientInServer(this); + return; + } + if (this.flags & FL_JUMPRELEASED) { if (PHYS_INPUT_BUTTON_JUMP(this) && (joinAllowed(this) || time < CS(this).jointime + MIN_SPEC_TIME)) { this.flags &= ~FL_JUMPRELEASED; @@ -2521,9 +2466,6 @@ void PlayerPreThink (entity this) PlayerUseKey(this); CS(this).usekeypressed = PHYS_INPUT_BUTTON_USE(this); - if (IS_REAL_CLIENT(this)) - PrintWelcomeMessage(this); - if (IS_PLAYER(this)) { if (IS_REAL_CLIENT(this) && time < CS(this).jointime + MIN_SPEC_TIME) error("Client can't be spawned as player on connection!"); @@ -2545,7 +2487,6 @@ void PlayerPreThink (entity this) || (!(autocvar_sv_spectate || autocvar_g_campaign || (Player_GetForcedTeamIndex(this) == TEAM_FORCE_SPECTATOR)) && (!teamplay || autocvar_g_balance_teams))) { - campaign_bots_may_start = true; if(joinAllowed(this)) Join(this); return;