using System; using System.Linq; namespace Barotrauma.Networking { partial class RespawnManager { private DateTime lastShuttleLeavingWarningTime; public int PendingRespawnCount { get; private set; } public int RequiredRespawnCount { get; private set; } public bool ForceSpawnInMainSub { get; private set; } partial void UpdateTransportingProjSpecific(float deltaTime) { if (GameMain.Client?.Character == null || GameMain.Client.Character.Submarine != RespawnShuttle) { return; } if (!ReturnCountdownStarted) { return; } //show a warning when there's 20 seconds until the shuttle leaves if ((ReturnTime - DateTime.Now).TotalSeconds < 20.0f && (DateTime.Now - lastShuttleLeavingWarningTime).TotalSeconds > 30.0f) { lastShuttleLeavingWarningTime = DateTime.Now; GameMain.Client.AddChatMessage("ServerMessage.ShuttleLeaving", ChatMessageType.Server); } } private CoroutineHandle respawnPromptCoroutine; public void ShowRespawnPromptIfNeeded(float delay = 5.0f) { if (!UseRespawnPrompt) { return; } if (CoroutineManager.IsCoroutineRunning(respawnPromptCoroutine) || GUIMessageBox.MessageBoxes.Any(mb => mb.UserData as string == "respawnquestionprompt")) { return; } respawnPromptCoroutine = CoroutineManager.Invoke(() => { if (Character.Controlled != null || (GameMain.GameSession is not { IsRunning: true })) { return; } LocalizedString text; GUIMessageBox respawnPrompt; if (SkillLossPercentageOnImmediateRespawn > 0) { // Respawn asap with extra skill loss? text = TextManager.GetWithVariable("respawnquestionprompt", "[percentage]", ((int)Math.Round(SkillLossPercentageOnImmediateRespawn)).ToString()); respawnPrompt = new GUIMessageBox( TextManager.Get("tutorial.tryagainheader"), text, new LocalizedString[] { TextManager.Get("respawnquestionpromptrespawn"), TextManager.Get("respawnquestionpromptwait") }) { UserData = "respawnquestionprompt" }; } else { // Respawn asap? text = TextManager.Get("respawnquestionpromptnoloss"); respawnPrompt = new GUIMessageBox( TextManager.Get("tutorial.tryagainheader"), text, new LocalizedString[] { TextManager.Get("respawnquestionpromptrespawnnoloss"), TextManager.Get("respawnquestionpromptwait") }) { UserData = "respawnquestionprompt" }; } if (SkillLossPercentageOnDeath > 0) { // You have died... etc added BEFORE the above text text = TextManager.GetWithVariable("respawnskillpenalty", "[percentage]", ((int)SkillLossPercentageOnDeath).ToString()) + "\n\n" + text; }; respawnPrompt.Buttons[0].OnClicked += (btn, userdata) => { GameMain.Client?.SendRespawnPromptResponse(waitForNextRoundRespawn: false); respawnPrompt.Close(); return true; }; respawnPrompt.Buttons[1].OnClicked += (btn, userdata) => { GameMain.Client?.SendRespawnPromptResponse(waitForNextRoundRespawn: true); respawnPrompt.Close(); return true; }; }, delay: delay); } public void ClientEventRead(IReadMessage msg, float sendingTime) { bool respawnPromptPending = false; var newState = (State)msg.ReadRangedInteger(0, Enum.GetNames(typeof(State)).Length); ForceSpawnInMainSub = false; switch (newState) { case State.Transporting: ReturnCountdownStarted = msg.ReadBoolean(); maxTransportTime = msg.ReadSingle(); float transportTimeLeft = msg.ReadSingle(); ReturnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(transportTimeLeft * 1000.0f)); RespawnCountdownStarted = false; if (CurrentState != newState) { CoroutineManager.StopCoroutines("forcepos"); } break; case State.Waiting: PendingRespawnCount = msg.ReadUInt16(); RequiredRespawnCount = msg.ReadUInt16(); respawnPromptPending = msg.ReadBoolean(); RespawnCountdownStarted = msg.ReadBoolean(); ForceSpawnInMainSub = msg.ReadBoolean(); ResetShuttle(); float newRespawnTime = msg.ReadSingle(); RespawnTime = DateTime.Now + new TimeSpan(0, 0, 0, 0, milliseconds: (int)(newRespawnTime * 1000.0f)); break; case State.Returning: RespawnCountdownStarted = false; break; } CurrentState = newState; if (respawnPromptPending) { GameMain.Client.HasSpawned = true; ShowRespawnPromptIfNeeded(delay: 1.0f); } msg.ReadPadBits(); } } }