Unstable 0.15.15.0 (and the one before it I forgor)

This commit is contained in:
Markus Isberg
2021-11-18 21:34:30 +09:00
parent 10e5fd5f3e
commit 80f39cd2a3
257 changed files with 4916 additions and 2582 deletions

View File

@@ -17,7 +17,7 @@ namespace Barotrauma
fadeOutRoutine = CoroutineManager.StartCoroutine(FadeOutColors(Config.DeadEntityColorFadeOutTime));
}
private IEnumerable<object> FadeOutColors(float time)
private IEnumerable<CoroutineStatus> FadeOutColors(float time)
{
float timer = 0;
while (timer < time)

View File

@@ -36,7 +36,7 @@ namespace Barotrauma
CharacterStateInfo serverPos = character.MemState.Last();
if (!character.isSynced)
{
SetPosition(serverPos.Position, false);
SetPosition(serverPos.Position, lerp: false);
Collider.LinearVelocity = Vector2.Zero;
character.MemLocalState.Clear();
character.LastNetworkUpdateID = serverPos.ID;
@@ -159,7 +159,7 @@ namespace Barotrauma
if (!character.isSynced)
{
SetPosition(serverPos.Position, false);
SetPosition(serverPos.Position, lerp: false);
Collider.LinearVelocity = Vector2.Zero;
character.MemLocalState.Clear();
character.LastNetworkUpdateID = serverPos.ID;
@@ -581,10 +581,10 @@ namespace Barotrauma
if (this is HumanoidAnimController humanoid)
{
Vector2 pos = ConvertUnits.ToDisplayUnits(humanoid.RightHandIKPos);
if (humanoid.character.Submarine != null) { pos += humanoid.character.Submarine.Position; }
if (humanoid.character.Submarine != null) { pos += humanoid.character.Submarine.DrawPosition; }
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), GUI.Style.Green, true);
pos = ConvertUnits.ToDisplayUnits(humanoid.LeftHandIKPos);
if (humanoid.character.Submarine != null) { pos += humanoid.character.Submarine.Position; }
if (humanoid.character.Submarine != null) { pos += humanoid.character.Submarine.DrawPosition; }
GUI.DrawRectangle(spriteBatch, new Rectangle((int)pos.X, (int)-pos.Y, 4, 4), GUI.Style.Green, true);
Vector2 aimPos = humanoid.AimSourceWorldPos;

View File

@@ -447,28 +447,7 @@ namespace Barotrauma
if (GameMain.Client != null) { chatMessage += " " + TextManager.Get("DeathChatNotification"); }
if (GameMain.NetworkMember.RespawnManager?.UseRespawnPrompt ?? false)
{
CoroutineManager.Invoke(() =>
{
if (controlled != null || (!(GameMain.GameSession?.IsRunning ?? false))) { return; }
var respawnPrompt = new GUIMessageBox(
TextManager.Get("tutorial.tryagainheader"), TextManager.Get("respawnquestionprompt"),
new string[] { TextManager.Get("respawnquestionpromptrespawn"), TextManager.Get("respawnquestionpromptwait") });
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: 5.0f);
}
GameMain.NetworkMember.RespawnManager?.ShowRespawnPromptIfNeeded();
GameMain.NetworkMember.AddChatMessage(chatMessage, ChatMessageType.Dead);
GameMain.LightManager.LosEnabled = false;

View File

@@ -235,7 +235,7 @@ namespace Barotrauma
foreach (Item item in Item.ItemList)
{
if (item.Submarine == null || item.Submarine.TeamID != character.TeamID || item.Submarine.Info.IsWreck) { continue; }
if (!item.Repairables.Any(r => item.ConditionPercentage <= r.RepairIconThreshold)) { continue; }
if (!item.Repairables.Any(r => r.IsBelowRepairIconThreshold)) { continue; }
if (Submarine.VisibleEntities != null && !Submarine.VisibleEntities.Contains(item)) { continue; }
Vector2 diff = item.WorldPosition - character.WorldPosition;

View File

@@ -790,10 +790,7 @@ namespace Barotrauma
return false;
}
};
//force update twice because the listbox is insanely janky
//TODO: fix all of the UI :)
listBox.ForceUpdate();
listBox.ForceUpdate();
listBox.ForceLayoutRecalculation();
foreach (var childLayoutGroup in listBox.Content.GetAllChildren<GUILayoutGroup>())
{
childLayoutGroup.Recalculate();

View File

@@ -371,21 +371,22 @@ namespace Barotrauma
if (attackLimbIndex == 255 || Removed) { break; }
if (attackLimbIndex >= AnimController.Limbs.Length)
{
DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})");
DebugConsole.ThrowError($"Received invalid {(eventType == 4 ? "SetAttackTarget" : "ExecuteAttack")} message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})");
break;
}
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
Limb targetLimb = null;
if (!(FindEntityByID(targetEntityID) is IDamageable targetEntity))
IDamageable targetEntity = FindEntityByID(targetEntityID) as IDamageable;
if (targetEntity == null && eventType == 4)
{
DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target entity not found (ID {targetEntityID})");
DebugConsole.ThrowError($"Received invalid SetAttackTarget message. Target entity not found (ID {targetEntityID})");
break;
}
if (targetEntity is Character targetCharacter)
{
if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
{
DebugConsole.ThrowError($"Received invalid SetAttack/ExecuteAttack message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
DebugConsole.ThrowError($"Received invalid {(eventType == 4 ? "SetAttackTarget" : "ExecuteAttack")} message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
break;
}
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];

View File

@@ -805,7 +805,27 @@ namespace Barotrauma
{
var treatmentButton = component.GetChild<GUIButton>();
if (!(treatmentButton?.UserData is ItemPrefab itemPrefab)) { continue; }
treatmentButton.Enabled = Character.Controlled.Inventory.AllItems.Any(it => it.prefab == itemPrefab);
var matchingItem = Character.Controlled.Inventory.FindItem(it => it.prefab == itemPrefab, recursive: true);
treatmentButton.Enabled = matchingItem != null;
if (treatmentButton.Enabled && treatmentButton.State == GUIComponent.ComponentState.Hover)
{
//highlight the slot the treatment item is in
var rootContainer = matchingItem.GetRootContainer() ?? matchingItem;
var index = Character.Controlled.Inventory.FindIndex(rootContainer);
if (Character.Controlled.Inventory.visualSlots != null && index > -1 && index < Character.Controlled.Inventory.visualSlots.Length &&
Character.Controlled.Inventory.visualSlots[index].HighlightTimer <= 0.0f)
{
Character.Controlled.Inventory.visualSlots[index].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f);
}
}
if (matchingItem != null && !string.IsNullOrEmpty(treatmentButton.ToolTip)) { continue; }
treatmentButton.ToolTip = $"‖color:255,255,255,255‖{itemPrefab.Name}‖color:end‖" + '\n' + itemPrefab.Description;
if (treatmentButton.Enabled)
{
treatmentButton.ToolTip =
$"‖color:gui.green‖[{TextManager.Get(PlayerInput.MouseButtonsSwapped() ? "input.rightmouse" : "input.leftmouse")}] {TextManager.Get("quickuseaction.usetreatment")}‖color:end‖" + '\n'
+ treatmentButton.RawToolTip;
}
foreach (GUIComponent child in treatmentButton.Children)
{
child.Enabled = treatmentButton.Enabled;
@@ -1249,7 +1269,7 @@ namespace Barotrauma
foreach (string treatment in treatmentSuitability.Keys.ToList())
{
//prefer suggestions for items the player has
if (Character.Controlled.Inventory.FindItemByIdentifier(treatment) != null)
if (Character.Controlled.Inventory.FindItemByIdentifier(treatment, recursive: true) != null)
{
treatmentSuitability[treatment] *= 10.0f;
}
@@ -1288,12 +1308,11 @@ namespace Barotrauma
var innerFrame = new GUIButton(new RectTransform(Vector2.One, itemSlot.RectTransform, Anchor.Center, Pivot.Center, scaleBasis: ScaleBasis.Smallest), style: "SubtreeHeader")
{
UserData = item,
ToolTip = $"‖color:255,255,255,255‖{item.Name}‖color:end‖" + '\n' + item.Description,
DisabledColor = Color.White * 0.1f,
OnClicked = (btn, userdata) =>
{
if (!(userdata is ItemPrefab itemPrefab)) { return false; }
var item = Character.Controlled.Inventory.AllItems.FirstOrDefault(it => it.prefab == itemPrefab);
var item = Character.Controlled.Inventory.FindItem(it => it.prefab == itemPrefab, recursive: true);
if (item == null) { return false; }
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == selectedLimbIndex);
item.ApplyTreatment(Character.Controlled, Character, targetLimb);
@@ -1445,7 +1464,7 @@ namespace Barotrauma
var potentialTreatment = Inventory.DraggingItems.FirstOrDefault();
if (potentialTreatment == null && GUI.MouseOn?.UserData is ItemPrefab itemPrefab)
{
potentialTreatment = Character.Controlled.Inventory.AllItems.FirstOrDefault(it => it.prefab == itemPrefab);
potentialTreatment = Character.Controlled.Inventory.FindItem(it => it.prefab == itemPrefab, recursive: true);
}
potentialTreatment ??= Inventory.SelectedSlot?.Item;

View File

@@ -30,7 +30,7 @@ namespace Barotrauma
foreach (SkillPrefab skill in Skills)
{
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillContainer.RectTransform),
" - " + TextManager.AddPunctuation(':', TextManager.Get("SkillName." + skill.Identifier), (int)skill.LevelRange.X + " - " + (int)skill.LevelRange.Y),
" - " + TextManager.AddPunctuation(':', TextManager.Get("SkillName." + skill.Identifier), (int)skill.LevelRange.Start + " - " + (int)skill.LevelRange.End),
font: GUI.SmallFont);
}

View File

@@ -730,8 +730,6 @@ namespace Barotrauma
}
}
body.Dir = Dir;
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
bool hideLimb = Hide ||

View File

@@ -138,7 +138,7 @@ namespace Barotrauma
var newMsg = queuedMessages.Dequeue();
AddMessage(newMsg);
if (GameSettings.SaveDebugConsoleLogs)
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging)
{
unsavedMessages.Add(newMsg);
if (unsavedMessages.Count >= messagesPerFile)
@@ -274,7 +274,10 @@ namespace Barotrauma
AddMessage(newMsg);
}
if (GameSettings.SaveDebugConsoleLogs) unsavedMessages.Add(newMsg);
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging)
{
unsavedMessages.Add(newMsg);
}
}
}
}
@@ -537,7 +540,21 @@ namespace Barotrauma
return;
}
GameMain.MainMenuScreen.QuickStart(fixedSeed: false, subName);
float difficulty = 40;
if (args.Length > 1)
{
float.TryParse(args[1], out difficulty);
}
LevelGenerationParams levelGenerationParams = null;
if (args.Length > 2)
{
string levelGenerationIdentifier = args[2];
levelGenerationParams = LevelGenerationParams.LevelParams.FirstOrDefault(p => p.Identifier == levelGenerationIdentifier);
}
GameMain.MainMenuScreen.QuickStart(fixedSeed: false, subName, difficulty, levelGenerationParams);
}, getValidArgs: () => new[] { SubmarineInfo.SavedSubmarines.Select(s => s.Name).Distinct().ToArray() }));
commands.Add(new Command("steamnetdebug", "steamnetdebug: Toggles Steamworks networking debug logging.", (string[] args) =>
@@ -734,13 +751,10 @@ namespace Barotrauma
AssignOnExecute("teleportcharacter|teleport", (string[] args) =>
{
Character tpCharacter = (args.Length == 0) ? Character.Controlled : FindMatchingCharacter(args, false);
if (tpCharacter == null) return;
var cam = GameMain.GameScreen.Cam;
tpCharacter.AnimController.CurrentHull = null;
tpCharacter.Submarine = null;
tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cam.ScreenToWorld(PlayerInput.MousePosition)));
tpCharacter.AnimController.FindHull(cam.ScreenToWorld(PlayerInput.MousePosition), true);
if (tpCharacter != null)
{
tpCharacter.TeleportTo(GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition));
}
});
AssignOnExecute("spawn|spawncharacter", (string[] args) =>
@@ -1413,7 +1427,7 @@ namespace Barotrauma
commands.Add(new Command("analyzeitem", "analyzeitem: Analyzes one item for exploits.", (string[] args) =>
{
if (args.Length < 1) return;
if (args.Length < 1) { return; }
List<FabricationRecipe> fabricableItems = new List<FabricationRecipe>();
foreach (ItemPrefab iPrefab in ItemPrefab.Prefabs)
@@ -1792,7 +1806,7 @@ namespace Barotrauma
foreach (var talentTree in TalentTree.JobTalentTrees)
{
foreach (var talentSubTree in talentTree.Value.TalentSubTrees)
foreach (var talentSubTree in talentTree.TalentSubTrees)
{
string nameIdentifier = "talenttree." + talentSubTree.Identifier;
if (!tags[language].Contains(nameIdentifier))
@@ -1857,7 +1871,21 @@ namespace Barotrauma
commands.Add(new Command("eventstats", "", (string[] args) =>
{
var debugLines = EventSet.GetDebugStatistics();
List<string> debugLines;
if (args.Length > 0)
{
if (!Enum.TryParse(args[0], ignoreCase: true, out Level.PositionType spawnType))
{
var enums = Enum.GetNames(typeof(Level.PositionType));
ThrowError($"\"{args[0]}\" is not a valid Level.PositionType. Available options are: {string.Join(", ", enums)}");
return;
}
debugLines = EventSet.GetDebugStatistics(filter: monsterEvent => monsterEvent.SpawnPosType.HasFlag(spawnType));
}
else
{
debugLines = EventSet.GetDebugStatistics();
}
string filePath = "eventstats.txt";
Barotrauma.IO.Validation.SkipValidationInDebugBuilds = true;
File.WriteAllLines(filePath, debugLines);

View File

@@ -14,7 +14,8 @@ namespace Barotrauma
{
private Graph intensityGraph;
private Graph targetIntensityGraph;
private float intensityGraphUpdateInterval;
private Graph monsterStrengthGraph;
private const float intensityGraphUpdateInterval = 10;
private float lastIntensityUpdate;
private Vector2 pinnedPosition = new Vector2(256, 128);
@@ -22,6 +23,8 @@ namespace Barotrauma
public Event? PinnedEvent { get; set; }
private bool isGraphSelected;
public void DebugDraw(SpriteBatch spriteBatch)
{
foreach (Event ev in activeEvents)
@@ -42,17 +45,25 @@ namespace Barotrauma
DrawEventTargetTags(spriteBatch, scriptedEvent);
}
float theoreticalMaxMonsterStrength = 10000;
float relativeMaxMonsterStrength = theoreticalMaxMonsterStrength * GameMain.GameSession.LevelData.Difficulty / 100;
float absoluteMonsterStrength = monsterStrength / theoreticalMaxMonsterStrength;
float relativeMonsterStrength = monsterStrength / relativeMaxMonsterStrength;
GUI.DrawString(spriteBatch, new Vector2(10, y), "EventManager", Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 20), "Event cooldown: " + (int)Math.Max(eventCoolDown, 0), Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 35), "Current intensity: " + (int)Math.Round(currentIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, currentIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 50), "Target intensity: " + (int)Math.Round(targetIntensity * 100), Color.Lerp(Color.White, GUI.Style.Red, targetIntensity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "AvgHealth: " + (int)Math.Round(avgCrewHealth * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "AvgHullIntegrity: " + (int)Math.Round(avgHullIntegrity * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "FloodingAmount: " + (int)Math.Round(floodingAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "FireAmount: " + (int)Math.Round(fireAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "EnemyDanger: " + (int)Math.Round(enemyDanger * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 140), "MonsterTotalStrength: " + (int)Math.Round(monsterTotalStrength), Color.Lerp(GUI.Style.Green, GUI.Style.Red, monsterTotalStrength / 5000f), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 65), "Crew health: " + (int)Math.Round(avgCrewHealth * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgCrewHealth), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 80), "Hull integrity: " + (int)Math.Round(avgHullIntegrity * 100), Color.Lerp(GUI.Style.Red, GUI.Style.Green, avgHullIntegrity), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 95), "Flooding amount: " + (int)Math.Round(floodingAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, floodingAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 110), "Fire amount: " + (int)Math.Round(fireAmount * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, fireAmount), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 125), "Enemy danger: " + (int)Math.Round(enemyDanger * 100), Color.Lerp(GUI.Style.Green, GUI.Style.Red, enemyDanger), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 140), "Current monster strength (total): " + (int)Math.Round(monsterStrength), Color.Lerp(GUI.Style.Green, GUI.Style.Red, relativeMonsterStrength), Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 155), "Main events: " + (int)Math.Round(CumulativeMonsterStrengthMain), Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 170), "Ruin events: " + (int)Math.Round(CumulativeMonsterStrengthRuins), Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 185), "Wreck events: " + (int)Math.Round(CumulativeMonsterStrengthWrecks), Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
GUI.DrawString(spriteBatch, new Vector2(15, y + 200), "Cave events: " + (int)Math.Round(CumulativeMonsterStrengthCaves), Color.White, Color.Black * 0.6f, 0, GUI.SmallFont);
#if DEBUG
if (PlayerInput.KeyDown(Microsoft.Xna.Framework.Input.Keys.LeftAlt) &&
@@ -64,29 +75,103 @@ namespace Barotrauma
if (intensityGraph == null)
{
intensityGraph = new Graph();
targetIntensityGraph = new Graph();
int graphDensity = 360; // 60 min
intensityGraph = new Graph(graphDensity);
targetIntensityGraph = new Graph(graphDensity);
monsterStrengthGraph = new Graph(graphDensity);
}
intensityGraphUpdateInterval = 5.0f;
if (Timing.TotalTime > lastIntensityUpdate + intensityGraphUpdateInterval)
{
intensityGraph.Update(currentIntensity);
targetIntensityGraph.Update(targetIntensity);
lastIntensityUpdate = (float) Timing.TotalTime;
monsterStrengthGraph.Update(relativeMonsterStrength);
lastIntensityUpdate = (float)Timing.TotalTime;
}
Rectangle graphRect = new Rectangle(15, y + 165, 150, 50);
Rectangle graphRect = new Rectangle(15, y + 240, (int)(200 * GUI.xScale), (int)(100 * GUI.yScale));
bool isGraphHovered = graphRect.Contains(PlayerInput.MousePosition);
bool leftMousePressed = PlayerInput.PrimaryMouseButtonDown() || PlayerInput.PrimaryMouseButtonHeld();
bool rightMousePressed = PlayerInput.SecondaryMouseButtonHeld() || PlayerInput.SecondaryMouseButtonDown();
if (!isGraphSelected && isGraphHovered && leftMousePressed)
{
isGraphSelected = true;
}
if (isGraphSelected && rightMousePressed)
{
isGraphSelected = false;
}
Color intensityColor = Color.Lerp(Color.White, GUI.Style.Red, currentIntensity);
if (isGraphHovered || isGraphSelected)
{
graphRect.Size = new Point(GameMain.GraphicsWidth - 30, (int)(GameMain.GraphicsHeight * 0.35f));
intensityColor = Color.Red;
GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.95f, isFilled: true);
}
else
{
GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.6f, isFilled: true);
}
intensityGraph.Draw(spriteBatch, graphRect, maxValue: 1.0f, xOffset: 0, intensityColor, (sBatch, value, order, pos) =>
{
if (isGraphHovered || isGraphSelected)
{
Vector2 bottomPoint = new Vector2(pos.X, graphRect.Bottom);
float height = 3 * GUI.yScale;
if (order % 6 == 0)
{
height *= 3;
string text = (order / 6).ToString();
var font = GUI.SmallFont;
Vector2 textSize = font.MeasureString(text);
Vector2 textPos = new Vector2(bottomPoint.X - textSize.X / 2, bottomPoint.Y + height * 1.5f);
GUI.DrawString(sBatch, textPos, text, Color.White, font: font);
}
GUI.DrawLine(sBatch, bottomPoint, bottomPoint + Vector2.UnitY * height, Color.White, width: Math.Max(GUI.Scale, 1));
DrawTimeStamps(sBatch, Color.Red, pos, order);
}
});
targetIntensityGraph.Draw(spriteBatch, graphRect, maxValue: 1.0f, xOffset: 0, intensityColor * 0.5f);
if (isGraphHovered || isGraphSelected)
{
float? maxValue = 1;
Color color = Color.White;
if (relativeMonsterStrength > 1)
{
maxValue = null;
color = Color.Yellow;
}
monsterStrengthGraph.Draw(spriteBatch, graphRect, maxValue, color: color, doForEachValue: (sBatch, value, order, pos) => DrawTimeStamps(sBatch, color, pos, order));
}
GUI.DrawRectangle(spriteBatch, graphRect, Color.Black * 0.5f, true);
intensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, GUI.Style.Red, currentIntensity));
targetIntensityGraph.Draw(spriteBatch, graphRect, 1.0f, 0.0f, Color.Lerp(Color.White, GUI.Style.Red, targetIntensity) * 0.5f);
void DrawTimeStamps(SpriteBatch sBatch, Color color, Vector2 pos, int order)
{
if (isGraphHovered || isGraphSelected)
{
foreach (var timeStamp in timeStamps)
{
int t = (int)Math.Abs(Math.Round((timeStamp.Time - lastIntensityUpdate) / intensityGraphUpdateInterval));
if (t == order)
{
float size = 6;
Vector2 p = new Vector2(pos.X - size / 2, pos.Y - size / 2);
ShapeExtensions.DrawPoint(sBatch, p, color, size);
break;
}
}
}
}
GUI.DrawLine(spriteBatch,
new Vector2(graphRect.Right, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)),
new Vector2(graphRect.Right + 5, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)), Color.Orange, 0, 1);
new Vector2(graphRect.Right + 5, graphRect.Y + graphRect.Height * (1.0f - eventThreshold)), Color.Orange, width: 3);
y = graphRect.Bottom + 20;
int yStep = (int)(20 * GUI.yScale);
y = graphRect.Bottom + yStep;
if (isGraphHovered || isGraphSelected)
{
y += yStep;
}
int x = graphRect.X;
if (isCrewAway && crewAwayDuration < settings.FreezeDurationWhenCrewAway)
{
@@ -143,7 +228,7 @@ namespace Barotrauma
if (CurrentIntensity < eventSet.MinIntensity || CurrentIntensity > eventSet.MaxIntensity)
{
GUI.DrawString(spriteBatch, new Vector2(x, y),
" intensity between " + ((int) eventSet.MinIntensity) + " and " + ((int) eventSet.MaxIntensity),
" intensity between " + eventSet.MinIntensity.FormatDoubleDecimal() + " and " + eventSet.MaxIntensity.FormatDoubleDecimal(),
Color.Orange * 0.8f, null, 0, GUI.SmallFont);
y += 12;
}
@@ -159,13 +244,13 @@ namespace Barotrauma
if (y > GameMain.GraphicsHeight * 0.9f)
{
y = graphRect.Bottom + 35;
x += 250;
y = graphRect.Bottom + yStep * 2;
x += 300;
}
}
GUI.DrawString(spriteBatch, new Vector2(x, y), "Current events: ", Color.White * 0.9f, null, 0, GUI.SmallFont);
y += 15;
y += yStep;
foreach (Event ev in activeEvents.Where(ev => !ev.IsFinished || PlayerInput.IsShiftDown()))
{
@@ -182,17 +267,15 @@ namespace Barotrauma
{
GUI.MouseCursor = CursorState.Hand;
GUI.DrawRectangle(spriteBatch, outlineRect, Color.White);
if (ev != PinnedEvent)
{
DrawEvent(spriteBatch, ev, rect);
}
else if (PlayerInput.SecondaryMouseButtonHeld() || PlayerInput.SecondaryMouseButtonDown())
else if (rightMousePressed)
{
PinnedEvent = null;
}
if (PlayerInput.PrimaryMouseButtonHeld() || PlayerInput.PrimaryMouseButtonDown())
if (leftMousePressed)
{
PinnedEvent = ev;
}
@@ -201,8 +284,8 @@ namespace Barotrauma
y += 18;
if (y > GameMain.GraphicsHeight * 0.9f)
{
y = graphRect.Bottom + 35;
x += 250;
y = graphRect.Bottom + yStep * 2;
x += 300;
}
}
}
@@ -352,9 +435,11 @@ namespace Barotrauma
return DrawInfoRectangle(spriteBatch, scriptedEvent, text, parentRect, positions);
}
private readonly List<DebugLine> debugPositions = new List<DebugLine>();
private Rectangle DrawArtifactEvent(SpriteBatch spriteBatch, ArtifactEvent artifactEvent, Rectangle? parentRect = null)
{
List<DebugLine> positions = new List<DebugLine>();
debugPositions.Clear();
string text = $"Finished: {artifactEvent.IsFinished.ColorizeObject()}\n" +
$"Item: {artifactEvent.Item.ColorizeObject()}\n" +
@@ -364,15 +449,15 @@ namespace Barotrauma
if (artifactEvent.Item != null && !artifactEvent.Item.Removed)
{
Vector2 pos = artifactEvent.Item.WorldPosition;
positions.Add(new DebugLine(pos, Color.White));
debugPositions.Add(new DebugLine(pos, Color.White));
}
return DrawInfoRectangle(spriteBatch, artifactEvent, text, parentRect, positions);
return DrawInfoRectangle(spriteBatch, artifactEvent, text, parentRect, debugPositions);
}
private Rectangle DrawMonsterEvent(SpriteBatch spriteBatch, MonsterEvent monsterEvent, Rectangle? parentRect = null)
{
List<DebugLine> positions = new List<DebugLine>();
debugPositions.Clear();
string text = $"Finished: {monsterEvent.IsFinished.ColorizeObject()}\n" +
$"Amount: {monsterEvent.MinAmount.ColorizeObject()} - {monsterEvent.MaxAmount.ColorizeObject()}\n" +
@@ -383,7 +468,7 @@ namespace Barotrauma
{
Vector2 pos = monsterEvent.SpawnPos.Value;
text += $"Distance from submarine: {Vector2.Distance(pos, Submarine.MainSub.WorldPosition).ColorizeObject()}\n";
positions.Add(new DebugLine(pos, Color.White));
debugPositions.Add(new DebugLine(pos, Color.White));
}
if (monsterEvent.Monsters != null)
@@ -394,11 +479,10 @@ namespace Barotrauma
{
text += $" {monster.ColorizeObject()} -> (Dead: {monster.IsDead.ColorizeObject()}, Health: {monster.HealthPercentage.ColorizeObject()}%, AIState: {(monster.AIController is EnemyAIController enemyAI ? enemyAI.State : AIState.Idle ).ColorizeObject()})\n";
if (monster.Removed) { continue; }
positions.Add(new DebugLine(monster.WorldPosition, Color.Red));
debugPositions.Add(new DebugLine(monster.WorldPosition, Color.Red));
}
}
return DrawInfoRectangle(spriteBatch, monsterEvent, text, parentRect, positions);
return DrawInfoRectangle(spriteBatch, monsterEvent, text, parentRect, debugPositions);
}
private Rectangle DrawInfoRectangle(SpriteBatch spriteBatch, Event @event, string text, Rectangle? parentRect = null, List<DebugLine>? drawPoints = null)

View File

@@ -78,7 +78,7 @@ namespace Barotrauma
CoroutineManager.StartCoroutine(ShowMessageBoxAfterRoundSummary(header, message));
}
private IEnumerable<object> ShowMessageBoxAfterRoundSummary(string header, string message)
private IEnumerable<CoroutineStatus> ShowMessageBoxAfterRoundSummary(string header, string message)
{
while (GUIMessageBox.VisibleBox?.UserData is RoundSummary)
{

View File

@@ -51,16 +51,30 @@ namespace Barotrauma
}
}
public float LineHeight => baseHeight * 1.8f;
private uint[] charRanges;
private int texDims;
private uint baseChar;
private struct GlyphData
private readonly struct GlyphData
{
public int texIndex;
public Vector2 drawOffset;
public float advance;
public Rectangle texCoords;
public readonly int TexIndex;
public readonly Vector2 DrawOffset;
public readonly float Advance;
public readonly Rectangle TexCoords;
public GlyphData(
int texIndex = default,
Vector2 drawOffset = default,
float advance = default,
Rectangle texCoords = default)
{
TexIndex = texIndex;
DrawOffset = drawOffset;
Advance = advance;
TexCoords = texCoords;
}
}
public ScalableFont(XElement element, GraphicsDevice gd = null)
@@ -167,9 +181,10 @@ namespace Barotrauma
if (face.Glyph.Metrics.HorizontalAdvance > 0)
{
//glyph is empty, but char still applies advance
GlyphData blankData = new GlyphData();
blankData.advance = (float)face.Glyph.Metrics.HorizontalAdvance;
blankData.texIndex = -1; //indicates no texture because the glyph is empty
GlyphData blankData = new GlyphData(
advance: (float)face.Glyph.Metrics.HorizontalAdvance,
texIndex: -1); //indicates no texture because the glyph is empty
texCoords.Add(j, blankData);
}
continue;
@@ -211,13 +226,12 @@ namespace Barotrauma
}
}
GlyphData newData = new GlyphData
{
advance = (float)face.Glyph.Metrics.HorizontalAdvance,
texIndex = texIndex,
texCoords = new Rectangle((int)currentCoords.X, (int)currentCoords.Y, glyphWidth, glyphHeight),
drawOffset = new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop)
};
GlyphData newData = new GlyphData(
advance: (float)face.Glyph.Metrics.HorizontalAdvance,
texIndex: texIndex,
texCoords: new Rectangle((int)currentCoords.X, (int)currentCoords.Y, glyphWidth, glyphHeight),
drawOffset: new Vector2(face.Glyph.BitmapLeft, baseHeight * 14 / 10 - face.Glyph.BitmapTop)
);
texCoords.Add(j, newData);
for (int y = 0; y < glyphHeight; y++)
@@ -278,9 +292,9 @@ namespace Barotrauma
if (face.Glyph.Metrics.HorizontalAdvance > 0)
{
//glyph is empty, but char still applies advance
GlyphData blankData = new GlyphData();
blankData.advance = (float)face.Glyph.Metrics.HorizontalAdvance;
blankData.texIndex = -1; //indicates no texture because the glyph is empty
GlyphData blankData = new GlyphData(
advance: (float)face.Glyph.Metrics.HorizontalAdvance,
texIndex: -1); //indicates no texture because the glyph is empty
texCoords.Add(character, blankData);
}
return;
@@ -316,19 +330,18 @@ namespace Barotrauma
currentDynamicPixelBuffer = null;
}
GlyphData newData = new GlyphData
{
advance = (float)horizontalAdvance,
texIndex = textures.Count - 1,
texCoords = new Rectangle((int)currentDynamicAtlasCoords.X, (int)currentDynamicAtlasCoords.Y, glyphWidth, glyphHeight),
drawOffset = drawOffset
};
GlyphData newData = new GlyphData(
advance: (float)horizontalAdvance,
texIndex: textures.Count - 1,
texCoords: new Rectangle((int)currentDynamicAtlasCoords.X, (int)currentDynamicAtlasCoords.Y, glyphWidth, glyphHeight),
drawOffset: drawOffset
);
texCoords.Add(character, newData);
if (currentDynamicPixelBuffer == null)
{
currentDynamicPixelBuffer = new uint[texDims * texDims];
textures[newData.texIndex].GetData<uint>(currentDynamicPixelBuffer, 0, texDims * texDims);
textures[newData.TexIndex].GetData<uint>(currentDynamicPixelBuffer, 0, texDims * texDims);
}
for (int y = 0; y < glyphHeight; y++)
@@ -339,12 +352,25 @@ namespace Barotrauma
currentDynamicPixelBuffer[((int)currentDynamicAtlasCoords.X + x) + ((int)currentDynamicAtlasCoords.Y + y) * texDims] = (uint)(byteColor << 24 | 0x00ffffff);
}
}
textures[newData.texIndex].SetData<uint>(currentDynamicPixelBuffer);
textures[newData.TexIndex].SetData<uint>(currentDynamicPixelBuffer);
currentDynamicAtlasCoords.X += glyphWidth + 2;
}
}
private GlyphData GetGlyphData(uint charIndex)
{
const uint DEFAULT_INDEX = 0x25A1; //U+25A1 = white square
if (texCoords.TryGetValue(charIndex, out GlyphData gd) ||
texCoords.TryGetValue(DEFAULT_INDEX, out gd))
{
return gd;
}
return new GlyphData(texIndex: -1);
}
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth)
{
if (textures.Count == 0 && !DynamicLoading) { return; }
@@ -358,8 +384,8 @@ namespace Barotrauma
{
lineNum++;
currentPos = position;
currentPos.X -= baseHeight * 1.8f * lineNum * advanceUnit.Y * scale.Y;
currentPos.Y += baseHeight * 1.8f * lineNum * advanceUnit.X * scale.Y;
currentPos.X -= LineHeight * lineNum * advanceUnit.Y * scale.Y;
currentPos.Y += LineHeight * lineNum * advanceUnit.X * scale.Y;
continue;
}
@@ -369,19 +395,17 @@ namespace Barotrauma
DynamicRenderAtlas(graphicsDevice, charIndex);
}
if (texCoords.TryGetValue(charIndex, out GlyphData gd) || texCoords.TryGetValue(9633, out gd)) //9633 = white square
GlyphData gd = GetGlyphData(charIndex);
if (gd.TexIndex >= 0)
{
if (gd.texIndex >= 0)
{
Texture2D tex = textures[gd.texIndex];
Vector2 drawOffset;
drawOffset.X = gd.drawOffset.X * advanceUnit.X * scale.X - gd.drawOffset.Y * advanceUnit.Y * scale.Y;
drawOffset.Y = gd.drawOffset.X * advanceUnit.Y * scale.Y + gd.drawOffset.Y * advanceUnit.X * scale.X;
Texture2D tex = textures[gd.TexIndex];
Vector2 drawOffset;
drawOffset.X = gd.DrawOffset.X * advanceUnit.X * scale.X - gd.DrawOffset.Y * advanceUnit.Y * scale.Y;
drawOffset.Y = gd.DrawOffset.X * advanceUnit.Y * scale.Y + gd.DrawOffset.Y * advanceUnit.X * scale.X;
sb.Draw(tex, currentPos + drawOffset, gd.texCoords, color, rotation, origin, scale, se, layerDepth);
}
currentPos += gd.advance * advanceUnit * scale.X;
sb.Draw(tex, currentPos + drawOffset, gd.TexCoords, color, rotation, origin, scale, se, layerDepth);
}
currentPos += gd.Advance * advanceUnit * scale.X;
}
}
@@ -400,7 +424,7 @@ namespace Barotrauma
if (text[i] == '\n')
{
currentPos.X = position.X;
currentPos.Y += baseHeight * 1.8f;
currentPos.Y += LineHeight;
continue;
}
@@ -410,15 +434,13 @@ namespace Barotrauma
DynamicRenderAtlas(graphicsDevice, charIndex);
}
if (texCoords.TryGetValue(charIndex, out GlyphData gd) || texCoords.TryGetValue(9633, out gd)) //9633 = white square
GlyphData gd = GetGlyphData(charIndex);
if (gd.TexIndex >= 0)
{
if (gd.texIndex >= 0)
{
Texture2D tex = textures[gd.texIndex];
sb.Draw(tex, currentPos + gd.drawOffset, gd.texCoords, color);
}
currentPos.X += gd.advance;
Texture2D tex = textures[gd.TexIndex];
sb.Draw(tex, currentPos + gd.DrawOffset, gd.TexCoords, color);
}
currentPos.X += gd.Advance;
}
}
@@ -444,8 +466,8 @@ namespace Barotrauma
{
lineNum++;
currentPos = position;
currentPos.X -= baseHeight * 1.8f * lineNum * advanceUnit.Y * scale.Y;
currentPos.Y += baseHeight * 1.8f * lineNum * advanceUnit.X * scale.Y;
currentPos.X -= LineHeight * lineNum * advanceUnit.Y * scale.Y;
currentPos.Y += LineHeight * lineNum * advanceUnit.X * scale.Y;
continue;
}
@@ -476,22 +498,116 @@ namespace Barotrauma
currentTextColor = color;
}
if (texCoords.TryGetValue(charIndex, out GlyphData gd) || texCoords.TryGetValue(9633, out gd)) //9633 = white square
GlyphData gd = GetGlyphData(charIndex);
if (gd.TexIndex >= 0)
{
if (gd.texIndex >= 0)
{
Texture2D tex = textures[gd.texIndex];
Vector2 drawOffset;
drawOffset.X = gd.drawOffset.X * advanceUnit.X * scale.X - gd.drawOffset.Y * advanceUnit.Y * scale.Y;
drawOffset.Y = gd.drawOffset.X * advanceUnit.Y * scale.Y + gd.drawOffset.Y * advanceUnit.X * scale.X;
Texture2D tex = textures[gd.TexIndex];
Vector2 drawOffset;
drawOffset.X = gd.DrawOffset.X * advanceUnit.X * scale.X - gd.DrawOffset.Y * advanceUnit.Y * scale.Y;
drawOffset.Y = gd.DrawOffset.X * advanceUnit.Y * scale.Y + gd.DrawOffset.Y * advanceUnit.X * scale.X;
sb.Draw(tex, currentPos + drawOffset, gd.texCoords, currentTextColor, rotation, origin, scale, se, layerDepth);
}
currentPos += gd.advance * advanceUnit * scale.X;
sb.Draw(tex, currentPos + drawOffset, gd.TexCoords, currentTextColor, rotation, origin, scale, se, layerDepth);
}
currentPos += gd.Advance * advanceUnit * scale.X;
}
}
public string WrapText(string text, float width)
=> WrapText(text, width, requestCharPos: 0, out _, returnAllCharPositions: false, out _);
public string WrapText(string text, float width, int requestCharPos, out Vector2 requestedCharPos)
=> WrapText(text, width, requestCharPos, out requestedCharPos, returnAllCharPositions: false, out _);
public string WrapText(string text, float width, out Vector2[] allCharPositions)
=> WrapText(text, width, requestCharPos: 0, out _, returnAllCharPositions: true, out allCharPositions);
/// <summary>
/// Wraps a string of text to fit within a given width.
/// Optionally returns the caret position of a certain character,
/// or all of them.
/// </summary>
private string WrapText(string text,
float width,
int requestCharPos,
out Vector2 requestedCharPos,
bool returnAllCharPositions,
out Vector2[] allCharPositions)
{
int currLineStart = 0;
Vector2 currentPos = Vector2.Zero;
Vector2 foundCharPos = Vector2.Zero;
int? lastBreakerIndex = null;
string result = "";
var allCharPos = returnAllCharPositions ? new Vector2[text.Length+1] : null;
for (int i = 0; i < text.Length; i++)
{
//Records the caret position of the current character
void recordCurrentPos()
{
if (i == requestCharPos) { foundCharPos = currentPos; }
if (allCharPos != null) { allCharPos[i] = currentPos; }
}
recordCurrentPos();
//Appends a newline to the result and resets the caret position's X value
void nextLine()
{
result += text[currLineStart..i].Remove("\n") + "\n";
lastBreakerIndex = null;
currentPos.X = 0.0f;
currentPos.Y += LineHeight;
currLineStart = i;
}
//If a newline is found in the source, split immediately
if (text[i] == '\n')
{
nextLine();
continue;
}
//Otherwise, advance based on the width of the current character
GlyphData gd = GetGlyphData(text[i]);
float advance = gd.Advance;
if (currentPos.X + advance >= width)
{
//Advancing based on the last character
//would put us past the max width!
if (i > 0 && char.IsWhiteSpace(text[i]) && !char.IsWhiteSpace(text[i - 1]))
{
//Whitespace immediately after a visible
//character can be shrunk down to fit
advance = width - currentPos.X;
}
else
{
if (lastBreakerIndex.HasValue)
{
//A breaker (whitespace or CJK) was found earlier
//in this line, so let's break the line there
i = lastBreakerIndex.Value + 1;
}
nextLine();
recordCurrentPos(); //must re-record current caret position since we are on a new line now
}
}
currentPos.X += advance;
if (char.IsWhiteSpace(text[i]) || TextManager.IsCJK($"{text[i]}"))
{
lastBreakerIndex = i;
}
}
if (requestCharPos >= text.Length) { foundCharPos = currentPos; }
if (allCharPos != null) { allCharPos[text.Length] = currentPos; }
allCharPositions = allCharPos;
result += text[currLineStart..].Remove("\n");
requestedCharPos = foundCharPos;
return result;
}
public Vector2 MeasureString(string text, bool removeExtraSpacing = false)
{
if (text == null)
@@ -504,7 +620,7 @@ namespace Barotrauma
if (!removeExtraSpacing)
{
retVal.Y = baseHeight * 1.8f;
retVal.Y = LineHeight;
}
else
{
@@ -516,7 +632,7 @@ namespace Barotrauma
if (text[i] == '\n')
{
currentLineX = 0.0f;
retVal.Y += baseHeight * 1.8f;
retVal.Y += LineHeight;
continue;
}
uint charIndex = text[i];
@@ -524,10 +640,9 @@ namespace Barotrauma
{
DynamicRenderAtlas(graphicsDevice, charIndex);
}
if (texCoords.TryGetValue(charIndex, out GlyphData gd))
{
currentLineX += gd.advance;
}
GlyphData gd = GetGlyphData(charIndex);
currentLineX += gd.Advance;
retVal.X = Math.Max(retVal.X, currentLineX);
}
return retVal;
@@ -536,15 +651,14 @@ namespace Barotrauma
public Vector2 MeasureChar(char c)
{
Vector2 retVal = Vector2.Zero;
retVal.Y = baseHeight * 1.8f;
retVal.Y = LineHeight;
if (DynamicLoading && !texCoords.ContainsKey(c))
{
DynamicRenderAtlas(graphicsDevice, c);
}
if (texCoords.TryGetValue(c, out GlyphData gd))
{
retVal.X = gd.advance;
}
GlyphData gd = GetGlyphData(c);
retVal.X = gd.Advance;
return retVal;
}

View File

@@ -494,7 +494,7 @@ namespace Barotrauma
GUIFrame.Parent.Visible = visible;
}
private IEnumerable<object> UpdateMessageAnimation(GUIComponent message, float animDuration)
private IEnumerable<CoroutineStatus> UpdateMessageAnimation(GUIComponent message, float animDuration)
{
float timer = 0.0f;
while (timer < animDuration)

View File

@@ -399,7 +399,7 @@ namespace Barotrauma
" Max: " + GameMain.PerformanceCounter.DrawTimeGraph.LargestValue().ToString("0.00") + " ms",
GUI.Style.Green, Color.Black * 0.8f, font: SmallFont);
y += 15;
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, GUI.Style.Green);
GameMain.PerformanceCounter.DrawTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), color: Style.Green);
y += 50;
DrawString(spriteBatch, new Vector2(300, y),
@@ -407,8 +407,8 @@ namespace Barotrauma
" Max: " + GameMain.PerformanceCounter.UpdateTimeGraph.LargestValue().ToString("0.00") + " ms",
Color.LightBlue, Color.Black * 0.8f, font: SmallFont);
y += 15;
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), null, 0, Color.LightBlue);
GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), 20, 0, GUI.Style.Red);
GameMain.PerformanceCounter.UpdateTimeGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), color: Color.LightBlue);
GameMain.PerformanceCounter.UpdateIterationsGraph.Draw(spriteBatch, new Rectangle(300, y, 170, 50), maxValue: 20, color: Style.Red);
y += 50;
foreach (string key in GameMain.PerformanceCounter.GetSavedIdentifiers)
{
@@ -941,7 +941,8 @@ namespace Barotrauma
inventoryIndex = updateList.IndexOf(CharacterHUD.HUDFrame);
}
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) || (prevMouseOn == null && !PlayerInput.SecondaryMouseButtonHeld()))
if ((!PlayerInput.PrimaryMouseButtonHeld() && !PlayerInput.PrimaryMouseButtonClicked()) ||
(prevMouseOn == null && !PlayerInput.SecondaryMouseButtonHeld() && !Inventory.DraggingItems.Any()))
{
for (var i = updateList.Count - 1; i > inventoryIndex; i--)
{
@@ -1052,10 +1053,10 @@ namespace Barotrauma
// Children in list boxes can be interacted with despite not having
// a GUIButton inside of them so instead of hard coding we check if
// the children can be interacted with by checking their hover state
if (parent is GUIListBox listBox)
if (parent is GUIListBox listBox && c.Parent == listBox.Content)
{
if (listBox.DraggedElement != null) { return CursorState.Dragging; }
if (listBox.CanDragElements) { return CursorState.Move; }
if (listBox.CurrentDragMode != GUIListBox.DragMode.NoDragging) { return CursorState.Move; }
if (listBox.HoverCursor != CursorState.Default)
{
@@ -1148,7 +1149,7 @@ namespace Barotrauma
{
CoroutineManager.StartCoroutine(WaitCursorCoroutine(), "WaitCursorTimeout");
IEnumerable<object> WaitCursorCoroutine()
IEnumerable<CoroutineStatus> WaitCursorCoroutine()
{
MouseCursor = CursorState.Waiting;
var timeOut = DateTime.Now + new TimeSpan(0, 0, waitSeconds);
@@ -1360,7 +1361,7 @@ namespace Barotrauma
float symbolScale = Math.Min(64.0f / sprite.size.X, 1.0f) * scaleMultiplier * Scale;
if (overrideAlpha.HasValue || (dist > visibleRange.Start && dist < visibleRange.End))
if (overrideAlpha.HasValue || visibleRange.Contains(dist))
{
float alpha = overrideAlpha ?? MathUtils.Min((dist - visibleRange.Start) / 100.0f, 1.0f - ((dist - visibleRange.End + 100f) / 100.0f), 1.0f);
Vector2 targetScreenPos = cam.WorldToScreen(worldPosition);
@@ -2254,8 +2255,8 @@ namespace Barotrauma
#region Misc
public static void TogglePauseMenu()
{
if (Screen.Selected == GameMain.MainMenuScreen) return;
if (PreventPauseMenuToggle) return;
if (Screen.Selected == GameMain.MainMenuScreen) { return; }
if (PreventPauseMenuToggle) { return; }
settingsMenuOpen = false;
@@ -2276,162 +2277,121 @@ namespace Barotrauma
Stretch = true,
RelativeSpacing = 0.05f
};
new GUIButton(new RectTransform(new Vector2(0.1f, 0.1f), pauseMenuInner.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point((int)(15 * GUI.Scale)) },
new GUIButton(new RectTransform(new Vector2(0.1f, 0.1f), pauseMenuInner.RectTransform, Anchor.TopRight) { AbsoluteOffset = new Point((int)(15 * GUI.Scale)) },
"", style: "GUIBugButton")
{
IgnoreLayoutGroups = true,
ToolTip = TextManager.Get("bugreportbutton"),
ToolTip = TextManager.Get("bugreportbutton") + $" (v{GameMain.Version})",
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
};
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuResume"))
{
OnClicked = TogglePauseMenu
};
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSettings"))
{
OnClicked = (btn, userData) =>
{
TogglePauseMenu();
settingsMenuOpen = !settingsMenuOpen;
return true;
}
};
CreateButton("PauseMenuResume", buttonContainer, null);
CreateButton("PauseMenuSettings", buttonContainer, () => { settingsMenuOpen = !settingsMenuOpen; });
bool IsOutpostLevel() => GameMain.GameSession != null && Level.IsLoadedOutpost;
if (Screen.Selected == GameMain.GameScreen && GameMain.GameSession != null)
{
if (GameMain.GameSession.GameMode is SinglePlayerCampaign spMode)
{
var retryButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuRetry"));
retryButton.OnClicked += (btn, userData) =>
CreateButton("PauseMenuRetry", buttonContainer, verificationTextTag: "PauseMenuRetryVerification", action: () =>
{
var msgBox = new GUIMessageBox("", TextManager.Get("PauseMenuRetryVerification"), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
if (GameMain.GameSession.RoundSummary?.Frame != null)
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (_, userdata) =>
{
if (GameMain.GameSession.RoundSummary?.Frame != null)
{
GUIMessageBox.MessageBoxes.Remove(GameMain.GameSession.RoundSummary.Frame);
}
GUIMessageBox.MessageBoxes.Remove(GameMain.GameSession.RoundSummary.Frame);
}
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "ConversationAction");
GameMain.GameSession.LoadPreviousSave();
});
GUIMessageBox.MessageBoxes.RemoveAll(mb => mb.UserData as string == "ConversationAction");
TogglePauseMenu(btn, userData);
GameMain.GameSession.LoadPreviousSave();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = (_, userdata) =>
{
TogglePauseMenu(btn, userData);
msgBox.Close();
return true;
};
return true;
};
if (IsOutpostLevel())
{
var saveAndQuitButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuSaveQuit"))
CreateButton("PauseMenuSaveQuit", buttonContainer, verificationTextTag: "PauseMenuSaveAndReturnToMainMenuVerification", action: () =>
{
UserData = "save",
OnClicked = (btn, userData) =>
{
pauseMenuOpen = false;
if (IsOutpostLevel())
{
GameMain.QuitToMainMenu(save: true);
}
return true;
}
};
if (IsOutpostLevel()) { GameMain.QuitToMainMenu(save: true); }
});
}
}
else if (GameMain.GameSession.GameMode is TestGameMode)
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), text: TextManager.Get("PauseMenuReturnToEditor"))
CreateButton("PauseMenuReturnToEditor", buttonContainer, action: () =>
{
OnClicked = (btn, userdata) =>
{
GameMain.GameSession.EndRound("");
pauseMenuOpen = false;
return true;
}
};
GameMain.GameSession?.EndRound("");
});
}
else if (!GameMain.GameSession.GameMode.IsSinglePlayer && GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.ManageRound))
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform),
text: TextManager.Get(GameMain.GameSession.GameMode is CampaignMode ? "ReturnToServerlobby": "EndRound"))
bool canSave = GameMain.GameSession.GameMode is CampaignMode && IsOutpostLevel();
if (canSave)
{
OnClicked = (btn, userdata) =>
CreateButton("PauseMenuSaveQuit", buttonContainer, verificationTextTag: "PauseMenuSaveAndReturnToServerLobbyVerification", action: () =>
{
if (!GameMain.Client.HasPermission(ClientPermissions.ManageRound)) { return false; }
if (GameMain.GameSession.GameMode is CampaignMode && !IsOutpostLevel() || (!Submarine.MainSub.AtStartExit && !Submarine.MainSub.AtEndExit))
{
var msgBox = new GUIMessageBox("",
TextManager.Get(GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd"),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (_, __) =>
{
pauseMenuOpen = false;
GameMain.Client.RequestRoundEnd();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += msgBox.Close;
}
else
{
pauseMenuOpen = false;
GameMain.Client.RequestRoundEnd();
}
return true;
}
};
GameMain.Client?.RequestRoundEnd(save: true);
});
}
CreateButton(GameMain.GameSession.GameMode is CampaignMode ? "ReturnToServerlobby" : "EndRound", buttonContainer,
verificationTextTag: GameMain.GameSession.GameMode is CampaignMode ? "PauseMenuReturnToServerLobbyVerification" : "EndRoundSubNotAtLevelEnd",
action: () =>
{
GameMain.Client?.RequestRoundEnd(save: false);
});
}
}
var quitButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), buttonContainer.RectTransform), TextManager.Get("PauseMenuQuit"));
quitButton.OnClicked += (btn, userData) =>
if (GameMain.GameSession != null || Screen.Selected is CharacterEditorScreen || Screen.Selected is SubEditorScreen)
{
if (GameMain.GameSession != null || (Screen.Selected is CharacterEditorScreen || Screen.Selected is SubEditorScreen))
{
string text = GameMain.GameSession == null ? "PauseMenuQuitVerificationEditor" : "PauseMenuQuitVerification";
var msgBox = new GUIMessageBox("", TextManager.Get(text), new string[] { TextManager.Get("Yes"), TextManager.Get("Cancel") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (yesBtn, userdata) =>
CreateButton("PauseMenuQuit", buttonContainer,
verificationTextTag: GameMain.GameSession == null ? "PauseMenuQuitVerificationEditor" : "PauseMenuQuitVerification",
action: () =>
{
GameMain.QuitToMainMenu(save: false);
pauseMenuOpen = false;
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked = (_, userdata) =>
{
pauseMenuOpen = false;
msgBox.Close();
return true;
};
}
else
{
GameMain.QuitToMainMenu(save: false);
pauseMenuOpen = false;
}
return true;
};
});
}
else
{
CreateButton("PauseMenuQuit", buttonContainer, action: () => { GameMain.QuitToMainMenu(save: false); });
}
GUITextBlock.AutoScaleAndNormalize(buttonContainer.Children.Where(c => c is GUIButton).Select(c => ((GUIButton)c).TextBlock));
}
void CreateButton(string textTag, GUIComponent parent, Action action, string verificationTextTag = null)
{
new GUIButton(new RectTransform(new Vector2(1.0f, 0.1f), parent.RectTransform), TextManager.Get(textTag))
{
OnClicked = (btn, userData) =>
{
if (string.IsNullOrEmpty(verificationTextTag))
{
pauseMenuOpen = false;
action?.Invoke();
}
else
{
CreateVerificationPrompt(verificationTextTag, action);
}
return true;
}
};
}
void CreateVerificationPrompt(string textTag, Action confirmAction)
{
var msgBox = new GUIMessageBox("", TextManager.Get(textTag),
new string[] { TextManager.Get("Yes"), TextManager.Get("No") })
{
UserData = "verificationprompt"
};
msgBox.Buttons[0].OnClicked = (_, __) =>
{
pauseMenuOpen = false;
confirmAction?.Invoke();
return true;
};
msgBox.Buttons[0].OnClicked += msgBox.Close;
msgBox.Buttons[1].OnClicked += msgBox.Close;
}
}
private static bool TogglePauseMenu(GUIButton button, object obj)

View File

@@ -531,6 +531,17 @@ namespace Barotrauma
}
}
public virtual void ForceLayoutRecalculation()
{
//This is very ugly but it gets the job done, it
//would be real nice to un-jank this some day
ForceUpdate();
ForceUpdate();
foreach (var child in Children) { child.ForceLayoutRecalculation(); }
}
public void ForceUpdate() => Update((float)Timing.Step);
/// <summary>
/// Updates all the children manually.
/// </summary>
@@ -831,7 +842,7 @@ namespace Barotrauma
CoroutineManager.StartCoroutine(SlideToPosition(duration, 0.0f, targetPos));
}
private IEnumerable<object> SlideToPosition(float duration, float wait, Vector2 target)
private IEnumerable<CoroutineStatus> SlideToPosition(float duration, float wait, Vector2 target)
{
float t = 0.0f;
var (startX, startY) = RectTransform.ScreenSpaceOffset.ToVector2();
@@ -855,7 +866,7 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
private IEnumerable<object> LerpAlpha(float to, float duration, bool removeAfter, float wait = 0.0f)
private IEnumerable<CoroutineStatus> LerpAlpha(float to, float duration, bool removeAfter, float wait = 0.0f)
{
State = ComponentState.None;
float t = 0.0f;
@@ -894,7 +905,7 @@ namespace Barotrauma
pulsateCoroutine = CoroutineManager.StartCoroutine(DoPulsate(startScale, endScale, duration), "Pulsate" + ToString());
}
private IEnumerable<object> DoPulsate(Vector2 startScale, Vector2 endScale, float duration)
private IEnumerable<CoroutineStatus> DoPulsate(Vector2 startScale, Vector2 endScale, float duration)
{
float t = 0.0f;
while (t < duration)

View File

@@ -34,7 +34,7 @@ namespace Barotrauma
public GUIScrollBar ScrollBar { get; private set; }
private readonly Dictionary<GUIComponent, bool> childVisible = new Dictionary<GUIComponent, bool>();
private int totalSize;
private bool childrenNeedsRecalculation;
private bool scrollBarNeedsRecalculation;
@@ -53,7 +53,23 @@ namespace Barotrauma
}
}
public bool SelectMultiple;
public enum SelectMode
{
SelectSingle,
SelectMultiple,
RequireShiftToSelectMultiple
}
public SelectMode CurrentSelectMode = SelectMode.SelectSingle;
public bool SelectMultiple
{
get { return CurrentSelectMode != SelectMode.SelectSingle; }
set
{
CurrentSelectMode = value ? SelectMode.SelectMultiple : SelectMode.SelectSingle;
}
}
public bool HideChildrenOutsideFrame = true;
@@ -103,7 +119,7 @@ namespace Barotrauma
/// <summary>
/// true if mouse down should select elements instead of mouse up
/// </summary>
private bool useMouseDownToSelect = false;
private readonly bool useMouseDownToSelect = false;
private Vector4? overridePadding;
public Vector4 Padding
@@ -132,10 +148,7 @@ namespace Barotrauma
// TODO: fix implicit hiding
public bool Selected { get; set; }
public List<GUIComponent> AllSelected
{
get { return selected; }
}
public IReadOnlyList<GUIComponent> AllSelected => selected;
public object SelectedData
{
@@ -214,25 +227,34 @@ namespace Barotrauma
public bool AutoHideScrollBar { get; set; } = true;
private bool IsScrollBarOnDefaultSide { get; set; }
public bool CanDragElements
public enum DragMode
{
NoDragging,
DragWithinBox,
DragOutsideBox
}
private DragMode currentDragMode = DragMode.NoDragging;
public DragMode CurrentDragMode
{
get
{
return canDragElements;
return currentDragMode;
}
set
{
if (value == false && canDragElements && draggedElement != null)
if (value == DragMode.NoDragging && currentDragMode != DragMode.NoDragging && isDraggingElement)
{
DraggedElement = null;
}
canDragElements = value;
currentDragMode = value;
}
}
private bool canDragElements = false;
private GUIComponent draggedElement;
private Rectangle draggedReferenceRectangle;
private Point draggedReferenceOffset;
private Point dragMousePosRelativeToTopLeftCorner;
private bool isDraggingElement => draggedElement != null;
public bool HasDraggedElementIndexChanged { get; private set; }
public GUIComponent DraggedElement
@@ -246,8 +268,24 @@ namespace Barotrauma
if (value == draggedElement) { return; }
draggedElement = value;
HasDraggedElementIndexChanged = false;
if (value == null) { return; }
dragMousePosRelativeToTopLeftCorner = PlayerInput.MousePosition.ToPoint() - value.Rect.Location;
if (SelectMultiple)
{
if (!AllSelected.Contains(DraggedElement))
{
Select(DraggedElement.ToEnumerable());
}
}
}
}
//This exists to work around the fact that rendering child
//elements on top of the listbox's siblings is a clusterfuck.
public bool HideDraggedElement = false;
private readonly bool isHorizontal;
@@ -354,7 +392,7 @@ namespace Barotrauma
(child.UserData == null && userData == null))
{
Select(i, force, autoScroll);
if (!SelectMultiple) return;
if (!SelectMultiple) { return; }
}
i++;
}
@@ -363,9 +401,10 @@ namespace Barotrauma
private Point CalculateFrameSize(bool isHorizontal, int scrollBarSize)
=> isHorizontal ? new Point(Rect.Width, Rect.Height - scrollBarSize) : new Point(Rect.Width - scrollBarSize, Rect.Height);
private void RepositionChildren()
public Vector2 CalculateTopOffset()
{
int x = 0, y = 0;
int x = 0;
int y = 0;
if (ScrollBar.BarSize < 1.0f)
{
if (ScrollBar.IsHorizontal)
@@ -378,53 +417,59 @@ namespace Barotrauma
}
}
return new Vector2(x, y);
}
private void CalculateChildrenOffsets(Action<int, Point> callback)
{
Vector2 topOffset = CalculateTopOffset();
int x = (int)topOffset.X;
int y = (int)topOffset.Y;
for (int i = 0; i < Content.CountChildren; i++)
{
GUIComponent child = Content.GetChild(i);
if (!child.Visible) { continue; }
if (RectTransform != null)
{
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
callback(i, new Point(x, y));
}
if (useGridLayout)
{
void advanceGridLayout(
ref int primaryCoord,
ref int secondaryCoord,
int primaryChildDimension,
int secondaryChildDimension,
int primaryParentDimension)
{
if (primaryCoord + primaryChildDimension + Spacing > primaryParentDimension)
{
primaryCoord = 0;
secondaryCoord += secondaryChildDimension + Spacing;
callback(i, new Point(x, y));
}
primaryCoord += primaryChildDimension + Spacing;
}
if (ScrollBar.IsHorizontal)
{
if (y + child.Rect.Height + Spacing > Content.Rect.Height)
{
y = 0;
x += child.Rect.Width + Spacing;
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
y += child.Rect.Height + Spacing;
}
else
{
y += child.Rect.Height + Spacing;
}
advanceGridLayout(
primaryCoord: ref y,
secondaryCoord: ref x,
primaryChildDimension: child.Rect.Height,
secondaryChildDimension: child.Rect.Width,
primaryParentDimension: Content.Rect.Height);
}
else
{
if (x + child.Rect.Width + Spacing > Content.Rect.Width)
{
x = 0;
y += child.Rect.Height + Spacing;
if (child != draggedElement && (child.RectTransform.AbsoluteOffset.X != x || child.RectTransform.AbsoluteOffset.Y != y))
{
child.RectTransform.AbsoluteOffset = new Point(x, y);
}
x += child.Rect.Width + Spacing;
}
else
{
x += child.Rect.Width + Spacing;
}
advanceGridLayout(
primaryCoord: ref x,
secondaryCoord: ref y,
primaryChildDimension: child.Rect.Width,
secondaryChildDimension: child.Rect.Height,
primaryParentDimension: Content.Rect.Width);
}
}
else
@@ -440,6 +485,18 @@ namespace Barotrauma
}
}
}
private void RepositionChildren()
{
CalculateChildrenOffsets((index, offset) =>
{
var child = Content.GetChild(index);
if (child != draggedElement && child.RectTransform.AbsoluteOffset != offset)
{
child.RectTransform.AbsoluteOffset = offset;
}
});
}
/// <summary>
/// Scrolls the list to the specific element, currently only works when smooth scrolling and PadBottom are enabled.
@@ -466,7 +523,7 @@ namespace Barotrauma
{
CoroutineManager.StartCoroutine(ScrollCoroutine());
IEnumerable<object> ScrollCoroutine()
IEnumerable<CoroutineStatus> ScrollCoroutine()
{
if (BarSize >= 1.0f)
{
@@ -490,68 +547,122 @@ namespace Barotrauma
}
}
private void UpdateChildrenRect()
private void StartDraggingElement(GUIComponent child)
{
//dragging
if (CanDragElements && draggedElement != null)
DraggedElement = child;
}
private bool UpdateDragging()
{
if (CurrentDragMode == DragMode.NoDragging || !isDraggingElement) { return false; }
if (!PlayerInput.PrimaryMouseButtonHeld())
{
if (!PlayerInput.PrimaryMouseButtonHeld())
var draggedElem = draggedElement;
OnRearranged?.Invoke(this, draggedElem.UserData);
DraggedElement = null;
RepositionChildren();
if (AllSelected.Contains(draggedElem)) { return true; }
}
else
{
Vector2 topOffset = CalculateTopOffset();
var mousePos = PlayerInput.MousePosition.ToPoint();
draggedElement.RectTransform.AbsoluteOffset = mousePos - Content.Rect.Location - dragMousePosRelativeToTopLeftCorner;
if (CurrentDragMode != DragMode.DragOutsideBox)
{
OnRearranged?.Invoke(this, draggedElement.UserData);
DraggedElement = null;
RepositionChildren();
var offset = draggedElement.RectTransform.AbsoluteOffset;
draggedElement.RectTransform.AbsoluteOffset =
isHorizontal ? new Point(offset.X, 0) : new Point(0, offset.Y);
}
int index = Content.RectTransform.GetChildIndex(draggedElement.RectTransform);
int newIndex = index;
Point draggedOffsetWhenReleased = Point.Zero;
CalculateChildrenOffsets((i, offset) =>
{
if (index != i) { return; }
draggedOffsetWhenReleased = offset;
});
Rectangle draggedRectWhenReleased = new Rectangle(Content.Rect.Location + draggedOffsetWhenReleased, draggedElement.Rect.Size);
void shiftIndices(
float mousePos,
ref int draggedRectWhenReleasedLocation,
int draggedRectWhenReleasedSize)
{
while (mousePos > (draggedRectWhenReleasedLocation + draggedRectWhenReleasedSize) && newIndex < Content.CountChildren-1)
{
newIndex++;
draggedRectWhenReleasedLocation += draggedRectWhenReleasedSize;
}
while (mousePos < draggedRectWhenReleasedLocation && newIndex > 0)
{
newIndex--;
draggedRectWhenReleasedLocation -= draggedRectWhenReleasedSize;
}
if (newIndex != index && AllSelected.Count > 1)
{
this.selected.Sort((a, b) => Content.GetChildIndex(a) - Content.GetChildIndex(b));
int draggedPos = AllSelected.IndexOf(draggedElement);
if (newIndex < draggedPos)
{
newIndex = draggedPos;
}
if (newIndex >= Content.CountChildren - (AllSelected.Count - draggedPos))
{
int max = Content.CountChildren - (AllSelected.Count - draggedPos);
newIndex = max;
}
}
}
if (isHorizontal)
{
shiftIndices(
mousePos.X,
ref draggedRectWhenReleased.X,
draggedRectWhenReleased.Width);
}
else
{
draggedElement.RectTransform.AbsoluteOffset = isHorizontal ?
draggedReferenceOffset + new Point((int)PlayerInput.MousePosition.X - draggedReferenceRectangle.Center.X, 0) :
draggedReferenceOffset + new Point(0, (int)PlayerInput.MousePosition.Y - draggedReferenceRectangle.Center.Y);
shiftIndices(
mousePos.Y,
ref draggedRectWhenReleased.Y,
draggedRectWhenReleased.Height);
}
int index = Content.RectTransform.GetChildIndex(draggedElement.RectTransform);
int currIndex = index;
if (isHorizontal)
if (newIndex != index)
{
if (AllSelected.Count > 1)
{
while (currIndex > 0 && PlayerInput.MousePosition.X < draggedReferenceRectangle.Left)
this.selected.Sort((a, b) => Content.GetChildIndex(a) - Content.GetChildIndex(b));
int indexOfDraggedElem = AllSelected.IndexOf(draggedElement);
IEnumerable<GUIComponent> allSelected = AllSelected;
if (newIndex > index) { allSelected = allSelected.Reverse(); }
foreach (var elem in allSelected)
{
currIndex--;
draggedReferenceRectangle.X -= draggedReferenceRectangle.Width;
draggedReferenceOffset.X -= draggedReferenceRectangle.Width;
}
while (currIndex < Content.CountChildren - 1 && PlayerInput.MousePosition.X > draggedReferenceRectangle.Right)
{
currIndex++;
draggedReferenceRectangle.X += draggedReferenceRectangle.Width;
draggedReferenceOffset.X += draggedReferenceRectangle.Width;
elem.RectTransform.RepositionChildInHierarchy(newIndex + AllSelected.IndexOf(elem) - indexOfDraggedElem);
}
}
else
{
while (currIndex > 0 && PlayerInput.MousePosition.Y < draggedReferenceRectangle.Top)
{
currIndex--;
draggedReferenceRectangle.Y -= draggedReferenceRectangle.Height;
draggedReferenceOffset.Y -= draggedReferenceRectangle.Height;
}
while (currIndex < Content.CountChildren - 1 && PlayerInput.MousePosition.Y > draggedReferenceRectangle.Bottom)
{
currIndex++;
draggedReferenceRectangle.Y += draggedReferenceRectangle.Height;
draggedReferenceOffset.Y += draggedReferenceRectangle.Height;
}
draggedElement.RectTransform.RepositionChildInHierarchy(newIndex);
}
if (currIndex != index)
{
draggedElement.RectTransform.RepositionChildInHierarchy(currIndex);
HasDraggedElementIndexChanged = true;
}
return;
HasDraggedElementIndexChanged = true;
}
return true;
}
return false;
}
private void UpdateChildrenRect()
{
if (UpdateDragging()) { return; }
if (SelectTop)
{
foreach (GUIComponent child in Content.Children)
@@ -581,7 +692,7 @@ namespace Barotrauma
for (int i = 0; i < Content.CountChildren; i++)
{
var child = Content.RectTransform.GetChild(i)?.GUIComponent;
if (child == null || !child.Visible) { continue; }
if (!(child is { Visible: true })) { continue; }
// selecting
if (Enabled && (CanBeFocused || CanInteractWhenUnfocusable) && child.CanBeFocused && child.Rect.Contains(PlayerInput.MousePosition) && GUI.IsMouseOn(child))
@@ -595,19 +706,15 @@ namespace Barotrauma
if (SelectTop)
{
ScrollToElement(child);
Select(i, autoScroll: false, takeKeyBoardFocus: true);
}
else
{
Select(i, autoScroll: false, takeKeyBoardFocus: true);
}
Select(i, autoScroll: false, takeKeyBoardFocus: true);
}
if (CanDragElements && PlayerInput.PrimaryMouseButtonDown() && GUI.MouseOn == child)
if (CurrentDragMode != DragMode.NoDragging
&& (CurrentSelectMode != SelectMode.RequireShiftToSelectMultiple || (!PlayerInput.IsShiftDown() && !PlayerInput.IsCtrlDown()))
&& PlayerInput.PrimaryMouseButtonDown() && GUI.MouseOn == child)
{
DraggedElement = child;
draggedReferenceRectangle = child.Rect;
draggedReferenceOffset = child.RectTransform.AbsoluteOffset;
StartDraggingElement(child);
}
}
else if (selected.Contains(child))
@@ -686,6 +793,13 @@ namespace Barotrauma
OnAddedToGUIUpdateList?.Invoke(this);
}
public override void ForceLayoutRecalculation()
{
base.ForceLayoutRecalculation();
Content.ForceLayoutRecalculation();
ScrollBar.ForceLayoutRecalculation();
}
public void RecalculateChildren()
{
foreach (GUIComponent child in Content.Children)
@@ -709,8 +823,6 @@ namespace Barotrauma
}
}
public void ForceUpdate() => Update((float)Timing.Step);
protected override void Update(float deltaTime)
{
if (!Visible) { return; }
@@ -805,7 +917,7 @@ namespace Barotrauma
}
else
{
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * ScrollBar.UnclampedBarSize;
}
}
@@ -870,6 +982,7 @@ namespace Barotrauma
if (childIndex >= Content.CountChildren || childIndex < 0) { return; }
GUIComponent child = Content.GetChild(childIndex);
if (child is null) { return; }
bool wasSelected = true;
if (OnSelected != null)
@@ -880,7 +993,8 @@ namespace Barotrauma
if (!wasSelected) { return; }
if (SelectMultiple)
if (CurrentSelectMode == SelectMode.SelectMultiple ||
(CurrentSelectMode == SelectMode.RequireShiftToSelectMultiple && PlayerInput.IsCtrlDown()))
{
if (selected.Contains(child))
{
@@ -891,6 +1005,23 @@ namespace Barotrauma
selected.Add(child);
}
}
else if (CurrentSelectMode == SelectMode.RequireShiftToSelectMultiple && PlayerInput.IsShiftDown())
{
var first = SelectedComponent ?? child;
var last = child;
int firstIndex = Content.GetChildIndex(first);
int lastIndex = Content.GetChildIndex(last);
int sgn = Math.Sign(lastIndex - firstIndex);
selected.Clear(); selected.Add(first);
for (int i = firstIndex + sgn; i != lastIndex; i += sgn)
{
if (Content.GetChild(i) is { Visible: true } interChild)
{
selected.Add(interChild);
}
}
if (first != last) { selected.Add(last); }
}
else
{
selected.Clear();
@@ -937,6 +1068,14 @@ namespace Barotrauma
}
}
public void Select(IEnumerable<GUIComponent> children)
{
Selected = true;
selected.Clear();
selected.AddRange(children.Where(c => Content.Children.Contains(c)));
foreach (var child in selected) { OnSelected?.Invoke(child, child.UserData); }
}
public void Deselect()
{
Selected = false;
@@ -1007,9 +1146,12 @@ namespace Barotrauma
}
float minScrollBarSize = 20.0f;
ScrollBar.UnclampedBarSize = ScrollBar.IsHorizontal ?
Math.Min(Content.Rect.Width / (float)totalSize, 1.0f) :
Math.Min(Content.Rect.Height / (float)totalSize, 1.0f);
ScrollBar.BarSize = ScrollBar.IsHorizontal ?
Math.Max(Math.Min(Content.Rect.Width / (float)totalSize, 1.0f), minScrollBarSize / Content.Rect.Width) :
Math.Max(Math.Min(Content.Rect.Height / (float)totalSize, 1.0f), minScrollBarSize / Content.Rect.Height);
Math.Max(ScrollBar.UnclampedBarSize, minScrollBarSize / Content.Rect.Width) :
Math.Max(ScrollBar.UnclampedBarSize, minScrollBarSize / Content.Rect.Height);
}
public override void ClearChildren()
@@ -1052,10 +1194,11 @@ namespace Barotrauma
int i = 0;
foreach (GUIComponent child in Content.Children)
{
if (!child.Visible) continue;
if (!child.Visible) { continue; }
if (child == draggedElement && CurrentDragMode == DragMode.DragOutsideBox) { continue; }
if (!IsChildInsideFrame(child))
{
if (lastVisible > 0) break;
if (lastVisible > 0) { break; }
continue;
}
lastVisible = i;
@@ -1070,6 +1213,11 @@ namespace Barotrauma
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
}
if (isDraggingElement && CurrentDragMode == DragMode.DragOutsideBox && !HideDraggedElement)
{
draggedElement.DrawManually(spriteBatch, alsoChildren: true, recursive: true);
}
if (ScrollBarVisible)
{
ScrollBar.DrawManually(spriteBatch, alsoChildren: true, recursive: true);

View File

@@ -183,6 +183,11 @@ namespace Barotrauma
}
}
/// <summary>
/// ListBoxes with lots of content in them clamp the size of the scrollbar above a certain minimum size; this is the relative bar size without the clamping applied.
/// </summary>
public float UnclampedBarSize;
public float BarSize
{
get { return barSize; }
@@ -299,9 +304,15 @@ namespace Barotrauma
}
else
{
float barScale = 1.0f;
if (UnclampedBarSize > 0.0f)
{
barScale = (UnclampedBarSize / BarSize);
}
MoveButton(new Vector2(
Math.Sign(PlayerInput.MousePosition.X - Bar.Rect.Center.X) * Bar.Rect.Width,
Math.Sign(PlayerInput.MousePosition.Y - Bar.Rect.Center.Y) * Bar.Rect.Height));
Math.Sign(PlayerInput.MousePosition.X - Bar.Rect.Center.X) * Bar.Rect.Width * barScale,
Math.Sign(PlayerInput.MousePosition.Y - Bar.Rect.Center.Y) * Bar.Rect.Height * barScale));
}
}
}

View File

@@ -44,6 +44,8 @@ namespace Barotrauma
public UISprite PingCircle { get; private set; }
public UISprite YouAreHereCircle { get; private set; }
public UISprite UIGlowCircular { get; private set; }
public UISprite UIGlowSolidCircular { get; private set; }
@@ -253,6 +255,9 @@ namespace Barotrauma
case "pingcircle":
PingCircle = new UISprite(subElement);
break;
case "youareherecircle":
YouAreHereCircle = new UISprite(subElement);
break;
case "radiation":
RadiationSprite = new UISprite(subElement);
break;

View File

@@ -2,6 +2,7 @@
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
namespace Barotrauma
@@ -376,6 +377,7 @@ namespace Barotrauma
public void SetTextPos()
{
cachedCaretPositions = ImmutableArray<Vector2>.Empty;
if (text == null) { return; }
censoredText = string.IsNullOrEmpty(text) ? "" : new string('\u2022', text.Length);
@@ -389,7 +391,7 @@ namespace Barotrauma
if (Wrap && rect.Width > 0)
{
wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale, playerInput);
wrappedText = ToolBox.WrapText(text, rect.Width - padding.X - padding.Z, Font, textScale);
TextSize = MeasureText(wrappedText);
}
else if (OverflowClip)
@@ -477,108 +479,49 @@ namespace Barotrauma
disabledTextColor = color;
}
protected List<Tuple<Vector2, int>> GetAllPositions()
private ImmutableArray<Vector2> cachedCaretPositions = ImmutableArray<Vector2>.Empty;
public ImmutableArray<Vector2> GetAllCaretPositions()
{
float halfHeight = Font.MeasureString("T").Y * 0.5f * textScale;
string textDrawn = Censor ? CensoredText : WrappedText;
var positions = new List<Tuple<Vector2, int>>();
if (textDrawn.Contains("\n"))
if (cachedCaretPositions.Any())
{
string[] lines = textDrawn.Split('\n');
int index = 0;
int totalIndex = 0;
for (int i = 0; i < lines.Length; i++)
{
string line = lines[i];
totalIndex += line.Length;
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y * textScale;
for (int j = 0; j <= line.Length; j++)
{
Vector2 lineTextSize = Font.MeasureString(line.Substring(0, j)) * textScale;
Vector2 indexPos = new Vector2(lineTextSize.X, totalTextHeight - halfHeight) + TextPos - Origin * textScale;
//DebugConsole.NewMessage($"index: {index}, pos: {indexPos}", Color.AliceBlue);
positions.Add(new Tuple<Vector2, int>(indexPos, index + j));
}
index = totalIndex;
}
return cachedCaretPositions;
}
else
{
textDrawn = Censor ? CensoredText : Text;
for (int i = 0; i <= Text.Length; i++)
{
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, i)) * textScale;
Vector2 indexPos = new Vector2(textSize.X, textSize.Y - halfHeight) + TextPos - Origin * textScale;
//DebugConsole.NewMessage($"index: {i}, pos: {indexPos}", Color.WhiteSmoke);
positions.Add(new Tuple<Vector2, int>(indexPos, i));
}
}
return positions;
string textDrawn = Censor ? CensoredText : Text;
float w = Wrap
? (Rect.Width - Padding.X - Padding.Z) / TextScale
: float.PositiveInfinity;
Font.WrapText(textDrawn, w, out Vector2[] positions);
cachedCaretPositions = positions.Select(p => p * TextScale + TextPos - Origin * TextScale).ToImmutableArray();
return cachedCaretPositions;
}
public int GetCaretIndexFromScreenPos(Vector2 pos)
public int GetCaretIndexFromScreenPos(in Vector2 pos)
{
return GetCaretIndexFromLocalPos(pos - Rect.Location.ToVector2());
}
public int GetCaretIndexFromLocalPos(Vector2 pos)
public int GetCaretIndexFromLocalPos(in Vector2 pos)
{
var positions = GetAllPositions();
if (positions.Count == 0) { return 0; }
float halfHeight = Font.MeasureString("T").Y * 0.5f * textScale;
var positions = GetAllCaretPositions();
if (positions.Length == 0) { return 0; }
var currPosition = positions[0];
float topY = positions.Min(p => p.Item1.Y);
for (int i = 1; i < positions.Count; i++)
float closestXDist = float.PositiveInfinity;
float closestYDist = float.PositiveInfinity;
int closestIndex = -1;
for (int i = 0; i < positions.Length; i++)
{
var p1 = positions[i];
var p2 = currPosition;
float diffY = Math.Abs(p1.Item1.Y - pos.Y) - Math.Abs(p2.Item1.Y - pos.Y);
if (diffY < -3.0f)
float xDist = Math.Abs(pos.X - positions[i].X);
float yDist = Math.Abs(pos.Y - (positions[i].Y + Font.LineHeight * 0.5f));
if (yDist < closestYDist || (MathUtils.NearlyEqual(yDist, closestYDist) && xDist < closestXDist))
{
currPosition = p1;
continue;
}
else if (diffY > 3.0f)
{
continue;
}
else
{
diffY = Math.Abs(p1.Item1.Y - pos.Y);
if (diffY < halfHeight || (p1.Item1.Y == topY && pos.Y < topY))
{
//we are on this line, select the nearest character
float diffX = Math.Abs(p1.Item1.X - pos.X) - Math.Abs(p2.Item1.X - pos.X);
if (diffX < -1.0f)
{
currPosition = p1; continue;
}
else
{
continue;
}
}
else
{
//we are on a different line, preserve order
if (p1.Item2 < p2.Item2)
{
if (p1.Item1.Y > pos.Y) { currPosition = p1; }
}
else if (p1.Item2 > p2.Item2)
{
if (p1.Item1.Y < pos.Y) { currPosition = p1; }
}
continue;
}
closestIndex = i;
closestXDist = xDist;
closestYDist = yDist;
}
}
//GUI.AddMessage($"index: {posIndex.Item2}, pos: {posIndex.Item1}", Color.WhiteSmoke);
return currPosition != null ? currPosition.Item2 : Text.Length;
return closestIndex >= 0 ? closestIndex : Text.Length;
}
protected override void Update(float deltaTime)

View File

@@ -44,7 +44,7 @@ namespace Barotrauma
private int? maxTextLength;
private int _caretIndex;
private int CaretIndex
public int CaretIndex
{
get { return _caretIndex; }
set
@@ -343,34 +343,23 @@ namespace Barotrauma
private void CalculateCaretPos()
{
string textDrawn = Censor ? textBlock.CensoredText : textBlock.WrappedText;
if (textDrawn.Contains("\n"))
if (Censor || !Wrap)
{
string[] lines = textDrawn.Split('\n');
int totalIndex = 0;
for (int i = 0; i < lines.Length; i++)
{
int currentLineLength = lines[i].Length;
totalIndex += currentLineLength;
// The caret is on this line
if (CaretIndex < totalIndex || totalIndex == textBlock.Text.Length)
{
int diff = totalIndex - CaretIndex;
int index = currentLineLength - diff;
Vector2 lineTextSize = Font.MeasureString(lines[i].Substring(0, index)) * TextBlock.TextScale;
Vector2 lastLineSize = Font.MeasureString(lines[i]) * TextBlock.TextScale;
float totalTextHeight = Font.MeasureString(textDrawn.Substring(0, totalIndex)).Y * TextBlock.TextScale;
caretPos = new Vector2(lineTextSize.X, totalTextHeight - lastLineSize.Y) + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
break;
}
}
string textDrawn = textBlock.CensoredText;
CaretIndex = Math.Min(CaretIndex, textDrawn.Length);
textDrawn = Censor ? textBlock.CensoredText : textBlock.Text;
Vector2 textSize = Font.MeasureString(textDrawn[..CaretIndex]) * TextBlock.TextScale;
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
}
else
{
CaretIndex = Math.Min(CaretIndex, textDrawn.Length);
textDrawn = Censor ? textBlock.CensoredText : textBlock.Text;
Vector2 textSize = Font.MeasureString(textDrawn.Substring(0, CaretIndex)) * TextBlock.TextScale;
caretPos = new Vector2(textSize.X, 0) + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
CaretIndex = Math.Min(CaretIndex, textBlock.Text.Length);
textBlock.Font.WrapText(
textBlock.Text,
(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z) / TextBlock.TextScale,
CaretIndex,
out Vector2 requestedCharPos);
caretPos = requestedCharPos * TextBlock.TextScale + textBlock.TextPos - textBlock.Origin * TextBlock.TextScale;
}
caretPosDirty = false;
}
@@ -383,6 +372,7 @@ namespace Barotrauma
memento.Store(Text);
}
CaretIndex = forcedCaretIndex == - 1 ? textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition) : forcedCaretIndex;
CalculateCaretPos();
ClearSelection();
selected = true;
GUI.KeyboardDispatcher.Subscriber = this;
@@ -538,59 +528,37 @@ namespace Barotrauma
if (textBlock.WrappedText.Contains("\n"))
{
// Multiline selection
string[] lines = textBlock.WrappedText.Split('\n');
int totalIndex = 0;
int previousCharacters = 0;
Vector2 offset = textBlock.TextPos - textBlock.Origin;
for (int i = 0; i < lines.Length; i++)
var characterPositions = textBlock.GetAllCaretPositions();
(int startIndex, int endIndex) = selectionStartIndex < selectionEndIndex
? (selectionStartIndex, selectionEndIndex)
: (selectionEndIndex, selectionStartIndex);
endIndex--;
void drawRect(Vector2 topLeft, Vector2 bottomRight)
{
string currentLine = lines[i];
int currentLineLength = currentLine.Length;
totalIndex += currentLineLength;
bool containsSelection = IsLeftToRight
? selectionStartIndex < totalIndex && selectionEndIndex > previousCharacters
: selectionEndIndex < totalIndex && selectionStartIndex > previousCharacters;
if (containsSelection)
{
Vector2 currentLineSize = Font.MeasureString(currentLine) * TextBlock.TextScale;
if ((IsLeftToRight && selectionStartIndex < previousCharacters && selectionEndIndex > totalIndex)
|| !IsLeftToRight && selectionEndIndex < previousCharacters && selectionStartIndex > totalIndex)
{
// select the whole line
Vector2 topLeft = offset + new Vector2(0, currentLineSize.Y * i);
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, currentLineSize, SelectionColor, isFilled: true);
}
else
{
if (IsLeftToRight)
{
bool selectFromTheBeginning = selectionStartIndex <= previousCharacters;
int startIndex = selectFromTheBeginning ? 0 : Math.Abs(selectionStartIndex - previousCharacters);
int endIndex = Math.Abs(selectionEndIndex - previousCharacters);
int characters = Math.Min(endIndex - startIndex, currentLineLength - startIndex);
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(startIndex, characters)) * TextBlock.TextScale;
Vector2 topLeft = selectFromTheBeginning
? new Vector2(offset.X, offset.Y + currentLineSize.Y * i)
: new Vector2(selectionStartPos.X, offset.Y + currentLineSize.Y * i);
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, selectedTextSize, SelectionColor, isFilled: true);
}
else
{
bool selectFromTheBeginning = selectionStartIndex >= totalIndex;
bool selectFromTheStart = selectionEndIndex <= previousCharacters;
int startIndex = selectFromTheBeginning ? currentLineLength : Math.Abs(selectionStartIndex - previousCharacters);
int endIndex = selectFromTheStart ? 0 : Math.Abs(selectionEndIndex - previousCharacters);
int characters = Math.Min(Math.Abs(endIndex - startIndex), currentLineLength);
Vector2 selectedTextSize = Font.MeasureString(currentLine.Substring(endIndex, characters)) * TextBlock.TextScale;
Vector2 topLeft = selectFromTheBeginning
? new Vector2(offset.X + currentLineSize.X - selectedTextSize.X, offset.Y + currentLineSize.Y * i)
: new Vector2(selectionStartPos.X - selectedTextSize.X, offset.Y + currentLineSize.Y * i);
GUI.DrawRectangle(spriteBatch, Rect.Location.ToVector2() + topLeft, selectedTextSize, SelectionColor, isFilled: true);
}
}
}
previousCharacters = totalIndex;
int minWidth = GUI.IntScale(5);
if (bottomRight.X - topLeft.X < minWidth) { bottomRight.X = topLeft.X + minWidth; }
GUI.DrawRectangle(spriteBatch,
Rect.Location.ToVector2() + topLeft,
bottomRight - topLeft,
SelectionColor, isFilled: true);
}
Vector2 topLeft = characterPositions[startIndex];
for (int i = startIndex+1; i <= endIndex; i++)
{
Vector2 currPos = characterPositions[i];
if (!MathUtils.NearlyEqual(topLeft.Y, currPos.Y))
{
Vector2 bottomRight = characterPositions[i - 1];
bottomRight += Font.MeasureChar(Text[i - 1]);
drawRect(topLeft, bottomRight);
topLeft = currPos;
}
}
Vector2 finalBottomRight = characterPositions[endIndex];
finalBottomRight += Font.MeasureChar(Text[endIndex]);
drawRect(topLeft, finalBottomRight);
}
else
{
@@ -728,8 +696,15 @@ namespace Barotrauma
{
InitSelectionStart();
}
float lineHeight = Font.MeasureString("T").Y * TextBlock.TextScale;
int newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y - lineHeight));
float lineHeight = Font.LineHeight * TextBlock.TextScale;
int newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y - lineHeight * 0.5f));
textBlock.Font.WrapText(
textBlock.Text,
(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z) / TextBlock.TextScale,
newIndex,
out Vector2 requestedCharPos);
requestedCharPos *= TextBlock.TextScale;
if (MathUtils.NearlyEqual(requestedCharPos.Y, caretPos.Y)) { newIndex = 0; }
CaretIndex = newIndex;
caretTimer = 0;
HandleSelection();
@@ -739,8 +714,15 @@ namespace Barotrauma
{
InitSelectionStart();
}
lineHeight = Font.MeasureString("T").Y * TextBlock.TextScale;
newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y + lineHeight));
lineHeight = Font.LineHeight * TextBlock.TextScale;
newIndex = textBlock.GetCaretIndexFromLocalPos(new Vector2(caretPos.X, caretPos.Y + lineHeight * 1.5f));
textBlock.Font.WrapText(
textBlock.Text,
(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z) / TextBlock.TextScale,
newIndex,
out Vector2 requestedCharPos2);
requestedCharPos2 *= TextBlock.TextScale;
if (MathUtils.NearlyEqual(requestedCharPos2.Y, caretPos.Y)) { newIndex = Text.Length; }
CaretIndex = newIndex;
caretTimer = 0;
HandleSelection();
@@ -803,6 +785,7 @@ namespace Barotrauma
}
break;
}
if (caretPosDirty) { CalculateCaretPos(); }
OnKeyHit?.Invoke(this, key);
void HandleSelection()
{

View File

@@ -1,5 +1,6 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using System.Linq;
namespace Barotrauma
@@ -37,39 +38,44 @@ namespace Barotrauma
values[0] = newValue;
}
public void Draw(SpriteBatch spriteBatch, Rectangle rect, float? maxVal, float xOffset, Color color)
public delegate void GraphDelegate(SpriteBatch spriteBatch, float value, int order, Vector2 position);
public void Draw(SpriteBatch spriteBatch, Rectangle rect, float? maxValue = null, float xOffset = 0, Color? color = null, GraphDelegate doForEachValue = null)
{
color ??= Color.White;
float graphMaxVal = 1.0f;
if (maxVal == null)
if (maxValue == null)
{
graphMaxVal = LargestValue();
}
else if (maxVal > 0.0f)
else if (maxValue > 0.0f)
{
graphMaxVal = (float)maxVal;
graphMaxVal = (float)maxValue;
}
GUI.DrawRectangle(spriteBatch, rect, Color.White);
if (values.Length == 0) return;
if (values.Length == 0) { return; }
float lineWidth = (float)rect.Width / (float)(values.Length - 2);
float yScale = (float)rect.Height / graphMaxVal;
float lineWidth = rect.Width / (float)(values.Length - 2);
float yScale = rect.Height / graphMaxVal;
Vector2 prevPoint = new Vector2(rect.Right, rect.Bottom - (values[1] + (values[0] - values[1]) * xOffset) * yScale);
float currX = rect.Right - ((xOffset - 1.0f) * lineWidth);
for (int i = 1; i < values.Length - 1; i++)
{
float value = values[i];
currX -= lineWidth;
Vector2 newPoint = new Vector2(currX, rect.Bottom - values[i] * yScale);
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color);
Vector2 newPoint = new Vector2(currX, rect.Bottom - value * yScale);
GUI.DrawLine(spriteBatch, prevPoint, newPoint - new Vector2(1.0f, 0), color.Value);
prevPoint = newPoint;
doForEachValue?.Invoke(spriteBatch, value, i, newPoint);
}
Vector2 lastPoint = new Vector2(rect.X,
rect.Bottom - (values[values.Length - 1] + (values[values.Length - 2] - values[values.Length - 1]) * xOffset) * yScale);
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color);
int lastIndex = values.Length - 1;
float lastValue = values[lastIndex];
Vector2 lastPoint = new Vector2(rect.X, rect.Bottom - (lastValue + (values[values.Length - 2] - lastValue) * xOffset) * yScale);
GUI.DrawLine(spriteBatch, prevPoint, lastPoint, color.Value);
doForEachValue?.Invoke(spriteBatch, lastValue, lastIndex, lastPoint);
}
}
}

View File

@@ -379,11 +379,42 @@ namespace Barotrauma
if (currSplashScreen.IsPlaying)
{
graphics.Clear(Color.Black);
float videoAspectRatio = (float)currSplashScreen.Width / (float)currSplashScreen.Height;
int width; int height;
if (GameMain.GraphicsHeight * videoAspectRatio > GameMain.GraphicsWidth)
{
width = GameMain.GraphicsWidth;
height = (int)(GameMain.GraphicsWidth / videoAspectRatio);
}
else
{
width = (int)(GameMain.GraphicsHeight * videoAspectRatio);
height = GameMain.GraphicsHeight;
}
spriteBatch.Begin();
spriteBatch.Draw(currSplashScreen.GetTexture(), new Rectangle(0, 0, GameMain.GraphicsWidth, GameMain.GraphicsHeight), Color.White);
spriteBatch.Draw(
currSplashScreen.GetTexture(),
destinationRectangle: new Rectangle(
GameMain.GraphicsWidth / 2 - width / 2,
GameMain.GraphicsHeight / 2 - height / 2,
width,
height),
sourceRectangle: new Rectangle(0, 0, currSplashScreen.Width, currSplashScreen.Height),
Color.White,
rotation: 0.0f,
origin: Vector2.Zero,
SpriteEffects.None,
layerDepth: 0.0f);
spriteBatch.End();
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500) && GameMain.WindowActive && (PlayerInput.KeyHit(Keys.Escape) || PlayerInput.KeyHit(Keys.Space) || PlayerInput.KeyHit(Keys.Enter) || PlayerInput.PrimaryMouseButtonDown()))
if (DateTime.Now > videoStartTime + new TimeSpan(0, 0, 0, 0, milliseconds: 500)
&& GameMain.WindowActive
&& (PlayerInput.KeyHit(Keys.Escape)
|| PlayerInput.KeyHit(Keys.Space)
|| PlayerInput.KeyHit(Keys.Enter)
|| PlayerInput.PrimaryMouseButtonDown()))
{
currSplashScreen.Dispose(); currSplashScreen = null;
}
@@ -395,7 +426,7 @@ namespace Barotrauma
}
bool drawn;
public IEnumerable<object> DoLoading(IEnumerable<object> loader)
public IEnumerable<CoroutineStatus> DoLoading(IEnumerable<CoroutineStatus> loader)
{
drawn = false;
LoadState = null;

View File

@@ -732,7 +732,7 @@ namespace Barotrauma
CoroutineManager.StartCoroutine(DoScaleAnimation(targetSize, duration));
}
private IEnumerable<object> DoMoveAnimation(Point targetPos, float duration)
private IEnumerable<CoroutineStatus> DoMoveAnimation(Point targetPos, float duration)
{
Vector2 startPos = AbsoluteOffset.ToVector2();
float t = 0.0f;
@@ -746,7 +746,7 @@ namespace Barotrauma
animTargetPos = null;
yield return CoroutineStatus.Success;
}
private IEnumerable<object> DoScaleAnimation(Point targetSize, float duration)
private IEnumerable<CoroutineStatus> DoScaleAnimation(Point targetSize, float duration)
{
Vector2 startSize = NonScaledSize.ToVector2();
float t = 0.0f;

View File

@@ -151,9 +151,8 @@ namespace Barotrauma
/// </summary>
public static void DrawPoint(this SpriteBatch spriteBatch, Vector2 position, Color color, float size = 1f)
{
var scale = Vector2.One * size;
var offset = new Vector2(0.5f) - new Vector2(size * 0.5f);
spriteBatch.Draw(GetTexture(spriteBatch), position + offset, null, color, 0.0f, Vector2.Zero, Vector2.One, SpriteEffects.None, 0);
spriteBatch.Draw(GetTexture(spriteBatch), position + offset, null, color, 0.0f, Vector2.Zero, new Vector2(size), SpriteEffects.None, 0);
}
public static void DrawCircle(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, Color color,

View File

@@ -266,7 +266,7 @@ namespace Barotrauma
};
if (balanceAfterTransaction != CurrentLocation.StoreCurrentBalance)
{
var newStatus = Location.GetStoreBalanceStatus(balanceAfterTransaction);
var newStatus = CurrentLocation.GetStoreBalanceStatus(balanceAfterTransaction);
if (CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier != newStatus.SellPriceModifier)
{
string tooltipTag = newStatus.SellPriceModifier > CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier ?

View File

@@ -471,7 +471,7 @@ namespace Barotrauma
}
// Initial submarine selection needs a slight wait to allow the layoutgroups to place content properly
private IEnumerable<object> SelectOwnSubmarineWithDelay(SubmarineInfo info, SubmarineDisplayContent display)
private IEnumerable<CoroutineStatus> SelectOwnSubmarineWithDelay(SubmarineInfo info, SubmarineDisplayContent display)
{
yield return new WaitForSeconds(0.05f);
SelectSubmarine(info, display.background.Rect);

View File

@@ -1541,13 +1541,41 @@ namespace Barotrauma
GUITextBlock.AutoScaleAndNormalize(skillNames);
}
private bool HasUnlockedAllTalents(Character controlledCharacter)
{
if (TalentTree.JobTalentTrees.TryGetValue(controlledCharacter.Info.Job.Prefab.Identifier, out TalentTree talentTree))
{
foreach (TalentSubTree talentSubTree in talentTree.TalentSubTrees)
{
foreach (TalentOption talentOption in talentSubTree.TalentOptionStages)
{
if (talentOption.Talents.None(t => controlledCharacter.HasTalent(t.Identifier)))
{
return false;
}
}
}
}
return true;
}
private void UpdateTalentButtons()
{
Character controlledCharacter = Character.Controlled;
if (controlledCharacter?.Info == null) { return; }
experienceText.Text = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
experienceBar.BarSize = controlledCharacter.Info.GetProgressTowardsNextLevel();
//experienceBar.ToolTip = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
bool unlockedAllTalents = HasUnlockedAllTalents(controlledCharacter);
if (unlockedAllTalents)
{
experienceText.Text = string.Empty;
experienceBar.BarSize = 1f;
}
else
{
experienceText.Text = $"{controlledCharacter.Info.ExperiencePoints - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()} / {controlledCharacter.Info.GetExperienceRequiredToLevelUp() - controlledCharacter.Info.GetExperienceRequiredForCurrentLevel()}";
experienceBar.BarSize = controlledCharacter.Info.GetProgressTowardsNextLevel();
}
selectedTalents = TalentTree.CheckTalentSelection(controlledCharacter, selectedTalents);
@@ -1555,7 +1583,11 @@ namespace Barotrauma
int talentCount = selectedTalents.Count - controlledCharacter.Info.GetUnlockedTalentsInTree().Count();
if (talentCount > 0)
if (unlockedAllTalents)
{
talentPointText.SetRichText($"‖color:{XMLExtensions.ToStringHex(Color.Gray)}‖{TextManager.Get("talentmenu.alltalentsunlocked")}‖color:end‖");
}
else if (talentCount > 0)
{
string pointsUsed = $"‖color:{XMLExtensions.ColorToString(GUI.Style.Red)}‖{-talentCount}‖color:end‖";
string localizedString = TextManager.GetWithVariables("talentmenu.points.spending", new []{ "[amount]", "[used]" }, new []{ pointsLeft, pointsUsed});

View File

@@ -436,7 +436,7 @@ namespace Barotrauma
}
}
private IEnumerable<object> Load(bool isSeparateThread)
private IEnumerable<CoroutineStatus> Load(bool isSeparateThread)
{
if (GameSettings.VerboseLogging)
{
@@ -534,9 +534,8 @@ namespace Barotrauma
Debug.WriteLine("sounds");
int i = 0;
foreach (object crObj in SoundPlayer.Init())
foreach (CoroutineStatus status in SoundPlayer.Init())
{
CoroutineStatus status = (CoroutineStatus)crObj;
if (status == CoroutineStatus.Success) break;
i++;
@@ -1000,11 +999,11 @@ namespace Barotrauma
}
}
NetworkMember?.Update((float)Timing.Step);
GUI.Update((float)Timing.Step);
}
NetworkMember?.Update((float)Timing.Step);
CoroutineManager.Update((float)Timing.Step, Paused ? 0.0f : (float)Timing.Step);
SteamManager.Update((float)Timing.Step);
@@ -1231,7 +1230,7 @@ namespace Barotrauma
}
static bool waitForKeyHit = true;
public CoroutineHandle ShowLoading(IEnumerable<object> loader, bool waitKeyHit = true)
public CoroutineHandle ShowLoading(IEnumerable<CoroutineStatus> loader, bool waitKeyHit = true)
{
waitForKeyHit = waitKeyHit;
loadingScreenOpen = true;
@@ -1256,7 +1255,7 @@ namespace Barotrauma
}
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
if (GameSettings.SaveDebugConsoleLogs) { DebugConsole.SaveLogs(); }
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
base.OnExiting(sender, args);
}

View File

@@ -40,12 +40,13 @@ namespace Barotrauma
private List<SoldEntity> SoldEntities { get; } = new List<SoldEntity>();
// The bag slot is intentionally left out since we want to be able to sell items from there
private readonly List<InvSlotType> equipmentSlots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.InnerClothes, InvSlotType.OuterClothes, InvSlotType.Headset, InvSlotType.Card };
public IEnumerable<Item> GetSellableItems(Character character)
{
if (character == null) { return new List<Item>(); }
var confirmedSoldEntities = GetConfirmedSoldEntities();
// The bag slot is intentionally left out since we want to be able to sell items from there
var equipmentSlots = new List<InvSlotType>() { InvSlotType.Head, InvSlotType.InnerClothes, InvSlotType.OuterClothes, InvSlotType.Headset, InvSlotType.Card };
return character.Inventory.FindAllItems(item =>
{
if (!IsItemSellable(item, confirmedSoldEntities)) { return false; }
@@ -73,6 +74,7 @@ namespace Barotrauma
return Submarine.MainSub.GetItems(true).FindAll(item =>
{
if (!IsItemSellable(item, confirmedSoldEntities)) { return false; }
if (item.GetRootInventoryOwner() is Character) { return false; }
if (!item.Components.All(c => !(c is Holdable h) || !h.Attachable || !h.Attached)) { return false; }
if (!item.Components.All(c => !(c is Wire w) || w.Connections.All(c => c == null))) { return false; }
if (!ItemAndAllContainersInteractable(item)) { return false; }
@@ -101,7 +103,7 @@ namespace Barotrauma
private bool IsItemSellable(Item item, IEnumerable<SoldEntity> confirmedSoldEntities)
{
if (!item.Prefab.CanBeSold) { return false; }
if (item.SpawnedInOutpost) { return false; }
if (item.SpawnedInCurrentOutpost) { return false; }
if (!item.Prefab.AllowSellingWhenBroken && item.ConditionPercentage < 90.0f) { return false; }
if (confirmedSoldEntities.Any(it => it.Item == item)) { return false; }
if (item.OwnInventory?.Container is ItemContainer itemContainer)

View File

@@ -100,7 +100,7 @@ namespace Barotrauma
{
AutoHideScrollBar = false,
CanBeFocused = false,
CanDragElements = true,
CurrentDragMode = GUIListBox.DragMode.DragWithinBox,
CanInteractWhenUnfocusable = true,
OnSelected = (component, userData) => false,
SelectMultiple = false,
@@ -359,34 +359,41 @@ namespace Barotrauma
CanBeFocused = false
};
var jobIconBackground = new GUIImage(
// Hide the icon to make more space for the name if the crew list's width is small enough
bool isJobIconVisible = crewListEntrySize.X >= 220;
if (isJobIconVisible)
{
var jobIconBackground = new GUIImage(
new RectTransform(new Vector2(0.8f * iconRelativeWidth, 0.8f), layoutGroup.RectTransform),
jobIndicatorBackground,
scaleToFit: true)
{
CanBeFocused = false,
UserData = "job"
};
if (character?.Info?.Job.Prefab?.Icon != null)
{
new GUIImage(
new RectTransform(Vector2.One, jobIconBackground.RectTransform),
character.Info.Job.Prefab.Icon,
scaleToFit: true)
{
CanBeFocused = false,
Color = character.Info.Job.Prefab.UIColor,
HoverColor = character.Info.Job.Prefab.UIColor,
PressedColor = character.Info.Job.Prefab.UIColor,
SelectedColor = character.Info.Job.Prefab.UIColor
UserData = "job"
};
if (character?.Info?.Job.Prefab?.Icon != null)
{
new GUIImage(
new RectTransform(Vector2.One, jobIconBackground.RectTransform),
character.Info.Job.Prefab.Icon,
scaleToFit: true)
{
CanBeFocused = false,
Color = character.Info.Job.Prefab.UIColor,
HoverColor = character.Info.Job.Prefab.UIColor,
PressedColor = character.Info.Job.Prefab.UIColor,
SelectedColor = character.Info.Job.Prefab.UIColor
};
}
}
int iconsVisible = isJobIconVisible ? 5 : 4;
var nameRelativeWidth = 1.0f
// Start padding
- paddingRelativeWidth
// 5 icons (job, 3 orders, sound)
- (5 * 0.8f * iconRelativeWidth)
// icons (job, active orders, current task / voip)
- (iconsVisible * 0.8f * iconRelativeWidth)
// Vertical line
- (0.1f * iconRelativeWidth)
// Spacing
@@ -425,7 +432,7 @@ namespace Barotrauma
var currentOrderList = new GUIListBox(new RectTransform(new Vector2(0.0f, 1.0f), parent: orderGroup.RectTransform), isHorizontal: true, style: null)
{
AllowMouseWheelScroll = false,
CanDragElements = true,
CurrentDragMode = GUIListBox.DragMode.DragWithinBox,
HideChildrenOutsideFrame = false,
KeepSpaceForScrollBar = false,
OnRearranged = OnOrdersRearranged,
@@ -439,7 +446,9 @@ namespace Barotrauma
if (component is GUIListBox list)
{
list.CanBeFocused = CanIssueOrders;
list.CanDragElements = CanIssueOrders && list.Content.CountChildren > 1;
list.CurrentDragMode = CanIssueOrders && list.Content.CountChildren > 1
? GUIListBox.DragMode.DragWithinBox
: GUIListBox.DragMode.NoDragging;
}
};
@@ -507,8 +516,11 @@ namespace Barotrauma
{
if (!(characterComponent?.UserData is Character character)) { return; }
if (character.Info?.Job?.Prefab == null) { return; }
string tooltip = TextManager.GetWithVariables("crewlistelementtooltip",
new string[] { "[name]", "[job]" },
new string[] { character.Name, character.Info.Job.Name });
string color = XMLExtensions.ColorToString(character.Info.Job.Prefab.UIColor);
string tooltip = $"‖color:{color}‖{character.Name} ({character.Info.Job.Name})‖color:end‖";
tooltip = $"‖color:{color}‖{tooltip}‖color:end‖";
var richTextData = RichTextData.GetRichTextData(tooltip, out string sanitizedTooltip);
characterComponent.ToolTip = sanitizedTooltip;
characterComponent.TooltipRichTextData = richTextData;
@@ -546,7 +558,7 @@ namespace Barotrauma
RemoveCharacter(killedCharacter);
}
private IEnumerable<object> KillCharacterAnim(GUIComponent component)
private IEnumerable<CoroutineStatus> KillCharacterAnim(GUIComponent component)
{
List<GUIComponent> components = component.GetAllChildren().ToList();
components.Add(component);
@@ -1648,7 +1660,7 @@ namespace Barotrauma
}
if (characterComponent.Visible)
{
if (character == Character.Controlled && characterComponent.State != GUIComponent.ComponentState.Selected)
if (character == Character.Controlled && crewList.SelectedComponent != characterComponent)
{
crewList.Select(character, force: true);
}
@@ -2637,7 +2649,7 @@ namespace Barotrauma
// If targeting a repairable item with condition below the repair threshold, show the 'repairsystems' order
orderIdentifier = "repairsystems";
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Repairables.Any(r => itemContext.ConditionPercentage < r.RepairThreshold))
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Repairables.Any(r => r.IsBelowRepairThreshold))
{
if (itemContext.Repairables.Any(r => r != null && r.requiredSkills.Any(s => s != null && s.Identifier.Equals("electrical"))))
{
@@ -2758,11 +2770,11 @@ namespace Barotrauma
if (AIObjectiveCleanupItems.IsValidTarget(item, Character.Controlled, checkInventory: false)) { return true; }
if (AIObjectiveCleanupItems.IsValidContainer(item, Character.Controlled)) { return true; }
if (item.Repairables.Any(r => item.ConditionPercentage < r.RepairThreshold)) { return true; }
if (item.Repairables.Any(r => r.IsBelowRepairThreshold)) { return true; }
var operateWeaponsPrefab = Order.GetPrefab("operateweapons");
return item.Components.Any(c => c is Controller) &&
(item.GetConnectedComponents<Turret>().Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)) ||
item.GetConnectedComponents<Turret>(recursive: true).Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)));
item.GetConnectedComponents<Turret>(recursive: true).Any(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)));
}
/// <param name="hotkey">Use a negative value (e.g. -1) if there should be no hotkey associated with the node</param>
@@ -2781,7 +2793,7 @@ namespace Barotrauma
disableNode = !CanCharacterBeHeard();
}
var mustSetOptionOrTarget = order.HasOptions;
bool mustSetOptionOrTarget = order.HasOptions;
Item orderTargetEntity = null;
// If the order doesn't have options, but must set a target,
@@ -2804,14 +2816,14 @@ namespace Barotrauma
{
if (disableNode || !CanIssueOrders) { return false; }
var o = userData as Order;
if (o.MustManuallyAssign && characterContext == null)
{
CreateAssignmentNodes(node);
}
else if (mustSetOptionOrTarget)
if (mustSetOptionOrTarget)
{
NavigateForward(button, userData);
}
else if (o.MustManuallyAssign && characterContext == null)
{
CreateAssignmentNodes(node);
}
else
{
if (orderTargetEntity != null)
@@ -2925,6 +2937,10 @@ namespace Barotrauma
{
NavigateForward(button, userData);
}
else if (o.Item1.MustManuallyAssign && characterContext == null)
{
CreateAssignmentNodes(button);
}
else
{
SetCharacterOrder(characterContext ?? GetCharacterForQuickAssignment(o.Item1), o.Item1, o.Item2, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
@@ -2987,12 +3003,19 @@ namespace Barotrauma
var node = new GUIButton(new RectTransform(size, parent: parent, anchor: Anchor.Center), style: null)
{
UserData = new Tuple<Order, string>(order, option),
OnClicked = (_, userData) =>
OnClicked = (button, userData) =>
{
if (!CanIssueOrders) { return false; }
var o = userData as Tuple<Order, string>;
SetCharacterOrder(characterContext ?? GetCharacterForQuickAssignment(o.Item1), o.Item1, o.Item2, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
DisableCommandUI();
if (o.Item1.MustManuallyAssign && characterContext == null)
{
CreateAssignmentNodes(button);
}
else
{
SetCharacterOrder(characterContext ?? GetCharacterForQuickAssignment(o.Item1), o.Item1, o.Item2, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
DisableCommandUI();
}
return true;
}
};

View File

@@ -188,7 +188,7 @@ namespace Barotrauma
}
private IEnumerable<object> DoInitialCameraTransition()
private IEnumerable<CoroutineStatus> DoInitialCameraTransition()
{
while (GameMain.Instance.LoadingScreenOpen)
{
@@ -310,12 +310,12 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
protected override IEnumerable<object> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults = null)
protected override IEnumerable<CoroutineStatus> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults = null)
{
yield return CoroutineStatus.Success;
}
private IEnumerable<object> DoLevelTransition()
private IEnumerable<CoroutineStatus> DoLevelTransition()
{
SoundPlayer.OverrideMusicType = CrewManager.GetCharacters().Any(c => !c.IsDead) ? "endround" : "crewdead";
SoundPlayer.OverrideMusicDuration = 18.0f;
@@ -361,7 +361,7 @@ namespace Barotrauma
//--------------------------------------
//wait for the new level to be loaded
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, seconds: 30);
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, seconds: 60);
while (Level.Loaded == prevLevel || Level.Loaded == null)
{
if (DateTime.Now > timeOut || Screen.Selected != GameMain.GameScreen) { break; }
@@ -480,8 +480,6 @@ namespace Barotrauma
{
IsFirstRound = false;
CoroutineManager.StartCoroutine(DoLevelTransition(), "LevelTransition");
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
GUI.SetSavingIndicatorState(success && (Level.IsLoadedOutpost || transitionType != TransitionType.None));
}
}
@@ -500,7 +498,7 @@ namespace Barotrauma
};
}
private IEnumerable<object> DoEndCampaignCameraTransition()
private IEnumerable<CoroutineStatus> DoEndCampaignCameraTransition()
{
Character controlled = Character.Controlled;
if (controlled != null)

View File

@@ -243,7 +243,7 @@ namespace Barotrauma
mirror: map.CurrentLocation != map.SelectedConnection?.Locations[0]));
}
private IEnumerable<object> DoLoadInitialLevel(LevelData level, bool mirror)
private IEnumerable<CoroutineStatus> DoLoadInitialLevel(LevelData level, bool mirror)
{
GameMain.GameSession.StartRound(level,
mirrorLevel: mirror);
@@ -254,7 +254,7 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
private IEnumerable<object> DoInitialCameraTransition()
private IEnumerable<CoroutineStatus> DoInitialCameraTransition()
{
while (GameMain.Instance.LoadingScreenOpen)
{
@@ -378,7 +378,7 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
protected override IEnumerable<object> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults = null)
protected override IEnumerable<CoroutineStatus> DoLevelTransition(TransitionType transitionType, LevelData newLevel, Submarine leavingSub, bool mirror, List<TraitorMissionResult> traitorResults = null)
{
NextLevel = newLevel;
bool success = CrewManager.GetCharacters().Any(c => !c.IsDead);
@@ -515,7 +515,7 @@ namespace Barotrauma
};
}
private IEnumerable<object> DoEndCampaignCameraTransition()
private IEnumerable<CoroutineStatus> DoEndCampaignCameraTransition()
{
if (Character.Controlled != null)
{

View File

@@ -15,7 +15,7 @@ namespace Barotrauma.Tutorials
{
}
public override IEnumerable<object> UpdateState()
public override IEnumerable<CoroutineStatus> UpdateState()
{
Character Controlled = Character.Controlled;
if (Controlled == null) yield return CoroutineStatus.Success;
@@ -634,7 +634,7 @@ namespace Barotrauma.Tutorials
return Character.Controlled.Inventory.FindItemByIdentifier(itemIdentifier) != null;
}
protected IEnumerable<object> KeepReactorRunning(Reactor reactor)
protected IEnumerable<CoroutineStatus> KeepReactorRunning(Reactor reactor)
{
do
{
@@ -652,7 +652,7 @@ namespace Barotrauma.Tutorials
/// <summary>
/// keeps the enemy away from the sub until the capacitors are loaded
/// </summary>
private IEnumerable<object> KeepEnemyAway(Character enemy, PowerContainer[] capacitors)
private IEnumerable<CoroutineStatus> KeepEnemyAway(Character enemy, PowerContainer[] capacitors)
{
do
{

View File

@@ -141,7 +141,7 @@ namespace Barotrauma.Tutorials
captain_mechanic.AIController.Enabled = captain_security.AIController.Enabled = captain_engineer.AIController.Enabled = false;
}
public override IEnumerable<object> UpdateState()
public override IEnumerable<CoroutineStatus> UpdateState()
{
while (GameMain.Instance.LoadingScreenOpen) yield return null;

View File

@@ -139,7 +139,7 @@ namespace Barotrauma.Tutorials
reactorItem.GetComponent<Reactor>().AutoTemp = true;
}
public override IEnumerable<object> UpdateState()
public override IEnumerable<CoroutineStatus> UpdateState()
{
while (GameMain.Instance.LoadingScreenOpen) yield return null;
@@ -446,7 +446,7 @@ namespace Barotrauma.Tutorials
CoroutineManager.StartCoroutine(TutorialCompleted());
}
public IEnumerable<object> KeepPatientAlive(Character patient)
public IEnumerable<CoroutineStatus> KeepPatientAlive(Character patient)
{
while (patient != null && !patient.Removed)
{

View File

@@ -10,7 +10,7 @@ namespace Barotrauma.Tutorials
{
}
public override IEnumerable<object> UpdateState()
public override IEnumerable<CoroutineStatus> UpdateState()
{
/*infoBox = CreateInfoFrame("Use the mouse wheel to zoom in and out, and WASD to move the camera around.", true);

View File

@@ -206,7 +206,7 @@ namespace Barotrauma.Tutorials
engineer_submarineJunctionBox_3.Condition = 0f;
}
public override IEnumerable<object> UpdateState()
public override IEnumerable<CoroutineStatus> UpdateState()
{
while (GameMain.Instance.LoadingScreenOpen) yield return null;
@@ -378,7 +378,7 @@ namespace Barotrauma.Tutorials
}
}
yield return null;
} while (engineer_brokenJunctionBox.Condition < repairableJunctionBoxComponent.RepairThreshold); // Wait until repaired
} while (repairableJunctionBoxComponent.IsBelowRepairThreshold); // Wait until repaired
SetHighlight(engineer_brokenJunctionBox, false);
RemoveCompletedObjective(segments[3]);
SetDoorAccess(engineer_thirdDoor, engineer_thirdDoorLight, true);
@@ -422,7 +422,7 @@ namespace Barotrauma.Tutorials
Repairable repairableJunctionBoxComponent3 = engineer_submarineJunctionBox_3.GetComponent<Repairable>();
// Remove highlights when each individual machine is repaired
do { CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3); yield return null; } while (engineer_submarineJunctionBox_1.Condition < repairableJunctionBoxComponent1.RepairThreshold || engineer_submarineJunctionBox_2.Condition < repairableJunctionBoxComponent2.RepairThreshold || engineer_submarineJunctionBox_3.Condition < repairableJunctionBoxComponent3.RepairThreshold);
do { CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3); yield return null; } while (repairableJunctionBoxComponent1.IsBelowRepairThreshold || repairableJunctionBoxComponent2.IsBelowRepairThreshold || repairableJunctionBoxComponent3.IsBelowRepairThreshold);
CheckJunctionBoxHighlights(repairableJunctionBoxComponent1, repairableJunctionBoxComponent2, repairableJunctionBoxComponent3);
RemoveCompletedObjective(segments[5]);
yield return new WaitForSeconds(2f, false);
@@ -462,7 +462,7 @@ namespace Barotrauma.Tutorials
return engineer?.SelectedConstruction == item;
}
private IEnumerable<object> ReactorOperatedProperly()
private IEnumerable<CoroutineStatus> ReactorOperatedProperly()
{
float timer;
@@ -566,17 +566,17 @@ namespace Barotrauma.Tutorials
private void CheckJunctionBoxHighlights(Repairable comp1, Repairable comp2, Repairable comp3)
{
if (engineer_submarineJunctionBox_1.Condition > comp1.RepairThreshold && engineer_submarineJunctionBox_1.ExternalHighlight)
if (!comp1.IsBelowRepairThreshold && engineer_submarineJunctionBox_1.ExternalHighlight)
{
SetHighlight(engineer_submarineJunctionBox_1, false);
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_1);
}
if (engineer_submarineJunctionBox_2.Condition > comp2.RepairThreshold && engineer_submarineJunctionBox_2.ExternalHighlight)
if (!comp2.IsBelowRepairThreshold && engineer_submarineJunctionBox_2.ExternalHighlight)
{
SetHighlight(engineer_submarineJunctionBox_2, false);
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_2);
}
if (engineer_submarineJunctionBox_3.Condition > comp3.RepairThreshold && engineer_submarineJunctionBox_3.ExternalHighlight)
if (!comp3.IsBelowRepairThreshold && engineer_submarineJunctionBox_3.ExternalHighlight)
{
SetHighlight(engineer_submarineJunctionBox_3, false);
engineer.RemoveActiveObjectiveEntity(engineer_submarineJunctionBox_3);

View File

@@ -225,7 +225,7 @@ namespace Barotrauma.Tutorials
base.Update(deltaTime);
}
public override IEnumerable<object> UpdateState()
public override IEnumerable<CoroutineStatus> UpdateState()
{
while (GameMain.Instance.LoadingScreenOpen) yield return null;
@@ -550,7 +550,7 @@ namespace Barotrauma.Tutorials
do
{
yield return null;
if (mechanic_brokenPump.Item.Condition < repairablePumpComponent.RepairThreshold)
if (repairablePumpComponent.IsBelowRepairThreshold)
{
if (!mechanic.HasEquippedItem("wrench"))
{
@@ -574,7 +574,7 @@ namespace Barotrauma.Tutorials
}
}
}
} while (mechanic_brokenPump.Item.Condition < repairablePumpComponent.RepairThreshold || mechanic_brokenPump.FlowPercentage >= 0 || !mechanic_brokenPump.IsActive);
} while (repairablePumpComponent.IsBelowRepairThreshold || mechanic_brokenPump.FlowPercentage >= 0 || !mechanic_brokenPump.IsActive);
RemoveCompletedObjective(segments[9]);
SetHighlight(mechanic_brokenPump.Item, false);
do { yield return null; } while (mechanic_brokenhull_2.WaterPercentage > waterVolumeBeforeOpening);
@@ -597,7 +597,7 @@ namespace Barotrauma.Tutorials
Repairable repairableEngineComponent = mechanic_submarineEngine.Item.GetComponent<Repairable>();
// Remove highlights when each individual machine is repaired
do { CheckHighlights(repairablePumpComponent1, repairablePumpComponent2, repairableEngineComponent); yield return null; } while (mechanic_ballastPump_1.Item.Condition < repairablePumpComponent1.RepairThreshold || mechanic_ballastPump_2.Item.Condition < repairablePumpComponent2.RepairThreshold || mechanic_submarineEngine.Item.Condition < repairableEngineComponent.RepairThreshold);
do { CheckHighlights(repairablePumpComponent1, repairablePumpComponent2, repairableEngineComponent); yield return null; } while (repairablePumpComponent1.IsBelowRepairThreshold || repairablePumpComponent2.IsBelowRepairThreshold || repairableEngineComponent.IsBelowRepairThreshold);
CheckHighlights(repairablePumpComponent1, repairablePumpComponent2, repairableEngineComponent);
RemoveCompletedObjective(segments[10]);
GameMain.GameSession?.CrewManager.AddSinglePlayerChatMessage(radioSpeakerName, TextManager.Get("Mechanic.Radio.Complete"), ChatMessageType.Radio, null);
@@ -623,17 +623,17 @@ namespace Barotrauma.Tutorials
private void CheckHighlights(Repairable comp1, Repairable comp2, Repairable comp3)
{
if (mechanic_ballastPump_1.Item.Condition > comp1.RepairThreshold && mechanic_ballastPump_1.Item.ExternalHighlight)
if (!comp1.IsBelowRepairThreshold && mechanic_ballastPump_1.Item.ExternalHighlight)
{
SetHighlight(mechanic_ballastPump_1.Item, false);
mechanic.RemoveActiveObjectiveEntity(mechanic_ballastPump_1.Item);
}
if (mechanic_ballastPump_2.Item.Condition > comp2.RepairThreshold && mechanic_ballastPump_2.Item.ExternalHighlight)
if (!comp2.IsBelowRepairThreshold && mechanic_ballastPump_2.Item.ExternalHighlight)
{
SetHighlight(mechanic_ballastPump_2.Item, false);
mechanic.RemoveActiveObjectiveEntity(mechanic_ballastPump_2.Item);
}
if (mechanic_submarineEngine.Item.Condition > comp3.RepairThreshold && mechanic_submarineEngine.Item.ExternalHighlight)
if (!comp3.IsBelowRepairThreshold && mechanic_submarineEngine.Item.ExternalHighlight)
{
SetHighlight(mechanic_submarineEngine.Item, false);
mechanic.RemoveActiveObjectiveEntity(mechanic_submarineEngine.Item);

View File

@@ -201,7 +201,7 @@ namespace Barotrauma.Tutorials
SetDoorAccess(tutorial_submarineDoor, tutorial_submarineDoorLight, true);
}
public override IEnumerable<object> UpdateState()
public override IEnumerable<CoroutineStatus> UpdateState()
{
while (GameMain.Instance.LoadingScreenOpen) yield return null;

View File

@@ -54,7 +54,7 @@ namespace Barotrauma.Tutorials
GameMain.Instance.ShowLoading(Loading());
}
private IEnumerable<object> Loading()
private IEnumerable<CoroutineStatus> Loading()
{
SubmarineInfo subInfo = new SubmarineInfo(submarinePath);
@@ -259,7 +259,7 @@ namespace Barotrauma.Tutorials
base.Stop();
}
private IEnumerable<object> Dead()
private IEnumerable<CoroutineStatus> Dead()
{
GUI.PreventPauseMenuToggle = true;
Character.Controlled = character = null;
@@ -279,7 +279,7 @@ namespace Barotrauma.Tutorials
yield return CoroutineStatus.Success;
}
protected IEnumerable<object> TutorialCompleted()
protected IEnumerable<CoroutineStatus> TutorialCompleted()
{
GUI.PreventPauseMenuToggle = true;

View File

@@ -247,7 +247,7 @@ namespace Barotrauma.Tutorials
}
}
public virtual IEnumerable<object> UpdateState()
public virtual IEnumerable<CoroutineStatus> UpdateState()
{
yield return CoroutineStatus.Success;
}
@@ -470,7 +470,7 @@ namespace Barotrauma.Tutorials
CoroutineManager.StartCoroutine(WaitForObjectiveEnd(segment));
}
private IEnumerable<object> WaitForObjectiveEnd(TutorialSegment objective)
private IEnumerable<CoroutineStatus> WaitForObjectiveEnd(TutorialSegment objective)
{
yield return new WaitForSeconds(2.0f);
objectiveFrame.RemoveChild(objective.ReplayButton);

View File

@@ -24,7 +24,7 @@ namespace Barotrauma
foreach (Item item in Item.ItemList)
{
//don't consider the items to belong in the outpost to prevent the stealing icon from showing
item.SpawnedInOutpost = false;
item.SpawnedInCurrentOutpost = false;
}
}

View File

@@ -106,7 +106,8 @@ namespace Barotrauma
respawnButtonContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), respawnInfoFrame.RectTransform, Anchor.CenterRight), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
AbsoluteSpacing = HUDLayoutSettings.Padding,
Stretch = true
Stretch = true,
Visible = false
};
respawnTickBox = new GUITickBox(new RectTransform(Vector2.One * 0.9f, respawnButtonContainer.RectTransform, Anchor.Center), TextManager.Get("respawnquestionpromptrespawn"))
{

View File

@@ -133,7 +133,7 @@ namespace Barotrauma
string hintIdentifierBase = "onstartedinteracting";
// onstartedinteracting.brokenitem
if (item.Repairables.Any(r => item.ConditionPercentage < r.RepairThreshold))
if (item.Repairables.Any(r => r.IsBelowRepairThreshold))
{
if (DisplayHint($"{hintIdentifierBase}.brokenitem")) { return; }
}
@@ -192,7 +192,7 @@ namespace Barotrauma
if (!CanDisplayHints(requireGameScreen: false, requireControllingCharacter: false)) { return; }
CoroutineManager.StartCoroutine(DisplayRoundStartedHints(initRoundHandle), "HintManager.DisplayRoundStartedHints");
static IEnumerable<object> InitRound()
static IEnumerable<CoroutineStatus> InitRound()
{
while (Character.Controlled == null) { yield return CoroutineStatus.Running; }
// Get the ballast hulls on round start not to find them again and again later
@@ -211,7 +211,7 @@ namespace Barotrauma
yield return CoroutineStatus.Success;
}
static IEnumerable<object> DisplayRoundStartedHints(CoroutineHandle initRoundHandle)
static IEnumerable<CoroutineStatus> DisplayRoundStartedHints(CoroutineHandle initRoundHandle)
{
while (GameMain.Instance.LoadingScreenOpen || Screen.Selected != GameMain.GameScreen ||
CoroutineManager.IsCoroutineRunning(initRoundHandle) ||

View File

@@ -480,7 +480,7 @@ namespace Barotrauma
"\n" + string.Join("\n", contentPackage.ErrorMessages);
}
}
contentPackageList.CanDragElements = CanHotswapPackages(false);
contentPackageList.CurrentDragMode = CanHotswapPackages(false) ? GUIListBox.DragMode.DragWithinBox : GUIListBox.DragMode.NoDragging;
contentPackageList.CanBeFocused = CanHotswapPackages(false);
contentPackageList.OnRearranged = OnContentPackagesRearranged;
@@ -1767,7 +1767,7 @@ namespace Barotrauma
return true;
}
private IEnumerable<object> WaitForKeyPress(GUITextBox keyBox, KeyOrMouse[] keyArray)
private IEnumerable<CoroutineStatus> WaitForKeyPress(GUITextBox keyBox, KeyOrMouse[] keyArray)
{
yield return CoroutineStatus.Running;

View File

@@ -949,16 +949,17 @@ namespace Barotrauma
//player has selected the inventory of another item -> attempt to move the item there
return QuickUseAction.PutToContainer;
}
else if (character.SelectedCharacter != null &&
character.SelectedCharacter.Inventory != null &&
else if (character.SelectedCharacter?.Inventory != null &&
!character.SelectedCharacter.Inventory.Locked &&
allowInventorySwap)
{
//player has selected the inventory of another character -> attempt to move the item there
return QuickUseAction.PutToCharacter;
}
else if (character.SelectedBy != null && Character.Controlled == character.SelectedBy &&
character.SelectedBy.Inventory != null && !character.SelectedBy.Inventory.Locked && allowInventorySwap)
else if (character.SelectedBy?.Inventory != null &&
Character.Controlled == character.SelectedBy &&
!character.SelectedBy.Inventory.Locked &&
allowInventorySwap)
{
return QuickUseAction.TakeFromCharacter;
}

View File

@@ -108,7 +108,7 @@ namespace Barotrauma.Items.Components
float sizeMultiplier = Math.Clamp(chargeRatio, 0.1f, 1f);
foreach (ParticleEmitter emitter in particleEmitterCharges)
{
emitter.Emit(deltaTime, particlePos, hullGuess: null, sizeMultiplier: sizeMultiplier, colorMultiplier: emitter.Prefab.Properties.ColorMultiplier);
emitter.Emit(deltaTime, particlePos, hullGuess: item.CurrentHull, sizeMultiplier: sizeMultiplier, colorMultiplier: emitter.Prefab.Properties.ColorMultiplier);
}
if (chargeSoundChannel == null || !chargeSoundChannel.IsPlaying)
@@ -157,6 +157,14 @@ namespace Barotrauma.Items.Components
crosshairSprite?.Draw(spriteBatch, crosshairPos, Color.White, 0, currentCrossHairScale);
crosshairPointerSprite?.Draw(spriteBatch, crosshairPointerPos, 0, currentCrossHairPointerScale);
}
if (GameMain.DebugDraw)
{
Vector2 barrelPos = item.DrawPosition + ConvertUnits.ToDisplayUnits(TransformedBarrelPos);
barrelPos = Screen.Selected.Cam.WorldToScreen(barrelPos);
GUI.DrawLine(spriteBatch, barrelPos - Vector2.UnitY * 3, barrelPos + Vector2.UnitY * 3, Color.Red);
GUI.DrawLine(spriteBatch, barrelPos - Vector2.UnitX * 3, barrelPos + Vector2.UnitX * 3, Color.Red);
}
}
partial void LaunchProjSpecific()
@@ -166,7 +174,7 @@ namespace Barotrauma.Items.Components
if (item.body.Dir < 0.0f) { rotation += MathHelper.Pi; }
foreach (ParticleEmitter emitter in particleEmitters)
{
emitter.Emit(1.0f, particlePos, hullGuess: null, angle: rotation, particleRotation: rotation);
emitter.Emit(1.0f, particlePos, hullGuess: item.CurrentHull, angle: rotation, particleRotation: rotation);
}
}

View File

@@ -576,7 +576,7 @@ namespace Barotrauma.Items.Components
delayedCorrectionCoroutine = CoroutineManager.StartCoroutine(DoDelayedCorrection(type, buffer, sendingTime, waitForMidRoundSync));
}
private IEnumerable<object> DoDelayedCorrection(ServerNetObject type, IReadMessage buffer, float sendingTime, bool waitForMidRoundSync)
private IEnumerable<CoroutineStatus> DoDelayedCorrection(ServerNetObject type, IReadMessage buffer, float sendingTime, bool waitForMidRoundSync)
{
while (GameMain.Client != null &&
(correctionTimer > 0.0f || (waitForMidRoundSync && GameMain.Client.MidRoundSyncing)))

View File

@@ -14,6 +14,8 @@ namespace Barotrauma.Items.Components
private CoroutineHandle resetPredictionCoroutine;
private float resetPredictionTimer;
private float currentBrightness;
public Vector2 DrawSize
{
get { return new Vector2(Light.Range * 2, Light.Range * 2); }
@@ -31,12 +33,40 @@ namespace Barotrauma.Items.Components
{
if (Light == null) { return; }
Light.Enabled = enabled;
currentBrightness = brightness;
if (enabled)
{
Light.Color = LightColor.Multiply(brightness);
}
}
partial void SetLightSourceTransform()
{
if (ParentBody != null)
{
Light.Position = ParentBody.Position;
}
else if (turret != null)
{
Light.Position = new Vector2(item.Rect.X + turret.TransformedBarrelPos.X, item.Rect.Y - turret.TransformedBarrelPos.Y);
}
else
{
Light.Position = item.Position;
}
PhysicsBody body = ParentBody ?? item.body;
if (body != null)
{
Light.Rotation = body.Dir > 0.0f ? body.DrawRotation : body.DrawRotation - MathHelper.Pi;
Light.LightSpriteEffect = (body.Dir > 0.0f) ? SpriteEffects.None : SpriteEffects.FlipVertically;
}
else
{
Light.Rotation = -Rotation - MathHelper.ToRadians(item.Rotation);
Light.LightSpriteEffect = item.SpriteEffects;
}
}
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
{
if (Light.LightSprite != null && (item.body == null || item.body.Enabled) && lightBrightness > 0.0f && IsOn && Light.Enabled)
@@ -71,7 +101,7 @@ namespace Barotrauma.Items.Components
/// <summary>
/// Reset client-side prediction of the light's state to the last known state sent by the server after resetPredictionTimer runs out
/// </summary>
private IEnumerable<object> ResetPredictionAfterDelay()
private IEnumerable<CoroutineStatus> ResetPredictionAfterDelay()
{
while (resetPredictionTimer > 0.0f)
{

View File

@@ -259,7 +259,9 @@ namespace Barotrauma.Items.Components
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
SetActive(msg.ReadBoolean());
ushort userID = msg.ReadUInt16();
Character user = userID == Entity.NullEntityID ? null : Entity.FindEntityByID(userID) as Character;
SetActive(msg.ReadBoolean(), user);
progressTimer = msg.ReadSingle();
}
}

View File

@@ -329,8 +329,6 @@ namespace Barotrauma.Items.Components
var missingCounts = missingItems.GroupBy(missingItem => missingItem).ToDictionary(x => x.Key, x => x.Count());
missingItems = missingItems.Distinct().ToList();
var availableIngredients = GetAvailableIngredients();
foreach (FabricationRecipe.RequiredItem requiredItem in missingItems)
{
while (slotIndex < inputContainer.Capacity && inputContainer.Inventory.GetItemAt(slotIndex) != null)
@@ -341,23 +339,23 @@ namespace Barotrauma.Items.Components
requiredItem.ItemPrefabs
.Where(requiredPrefab => availableIngredients.ContainsKey(requiredPrefab.Identifier))
.ForEach(requiredPrefab => {
var availablePrefabs = availableIngredients[requiredPrefab.Identifier];
availablePrefabs
.Where(availablePrefab => availablePrefab.ParentInventory != inputContainer.Inventory)
.Where(availablePrefab => availablePrefab.ParentInventory.visualSlots != null) //slots are null if the inventory has never been displayed
.ForEach(availablePrefab => { //(linked item, but the UI is not set to be displayed at the same time)
int availableSlotIndex = availablePrefab.ParentInventory.FindIndex(availablePrefab);
if (availablePrefab.ParentInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
var availableItems = availableIngredients[requiredPrefab.Identifier];
foreach (Item it in availableItems)
{
if (it.ParentInventory == inputContainer.Inventory) { continue; }
var rootContainer = it.GetRootContainer();
if (rootContainer?.OwnInventory?.visualSlots == null) { continue; }
int availableSlotIndex = rootContainer.OwnInventory.FindIndex(it.Container == rootContainer ? it : it.Container);
if (availableSlotIndex < 0) { continue; }
if (rootContainer.OwnInventory.visualSlots[availableSlotIndex].HighlightTimer <= 0.0f)
{
rootContainer.OwnInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
if (slotIndex < inputContainer.Capacity)
{
availablePrefab.ParentInventory.visualSlots[availableSlotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
if (slotIndex < inputContainer.Capacity)
{
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
}
inputContainer.Inventory.visualSlots[slotIndex].ShowBorderHighlight(GUI.Style.Green, 0.5f, 0.5f, 0.2f);
}
});
}
}
});
if (slotIndex >= inputContainer.Capacity) { break; }
@@ -676,7 +674,17 @@ namespace Barotrauma.Items.Components
activateButton.Enabled = false;
inSufficientPowerWarning.Visible = currPowerConsumption > 0 && !hasPower;
var availableIngredients = GetAvailableIngredients();
if (!IsActive)
{
//only check ingredients if the fabricator isn't active (if it is, this is done in Update)
if (refreshIngredientsTimer <= 0.0f)
{
RefreshAvailableIngredients();
refreshIngredientsTimer = RefreshIngredientsInterval;
}
refreshIngredientsTimer -= deltaTime;
}
if (character != null)
{
foreach (GUIComponent child in itemList.Content.Children)

View File

@@ -183,6 +183,7 @@ namespace Barotrauma.Items.Components
private ImmutableDictionary<MapEntity, MiniMapGUIComponent> electricalMapComponents;
private ImmutableDictionary<MiniMapGUIComponent, GUIComponent> electricalChildren;
private ImmutableDictionary<MiniMapGUIComponent, GUIComponent> doorChildren;
private ImmutableDictionary<MiniMapGUIComponent, GUIComponent> weaponChildren;
private ImmutableHashSet<ItemPrefab>? itemsFoundOnSub;
@@ -366,8 +367,8 @@ namespace Barotrauma.Items.Components
hullInfoFrame = new GUIFrame(new RectTransform(new Vector2(0.13f, 0.13f), GUI.Canvas, minSize: new Point(250, 150)), style: "GUIToolTip")
{
CanBeFocused = false
CanBeFocused = false,
Visible = false
};
var hullInfoContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.9f), hullInfoFrame.RectTransform, Anchor.Center))
@@ -431,7 +432,7 @@ namespace Barotrauma.Items.Components
scissorComponent = new GUIScissorComponent(new RectTransform(Vector2.One, submarineContainer.RectTransform, Anchor.Center));
miniMapContainer = new GUIFrame(new RectTransform(Vector2.One, scissorComponent.Content.RectTransform, Anchor.Center), style: null) { CanBeFocused = false };
ImmutableHashSet<Item> hullPointsOfInterest = Item.ItemList.Where(it => it.Submarine == item.Submarine && !it.HiddenInGame && !it.NonInteractable && it.Prefab.ShowInStatusMonitor && it.GetComponent<Door>() != null).ToImmutableHashSet();
ImmutableHashSet<Item> hullPointsOfInterest = Item.ItemList.Where(it => it.Submarine == item.Submarine && !it.HiddenInGame && !it.NonInteractable && it.Prefab.ShowInStatusMonitor && (it.GetComponent<Door>() != null || it.GetComponent<Turret>() != null)).ToImmutableHashSet();
miniMapFrame = CreateMiniMap(item.Submarine, submarineContainer, MiniMapSettings.Default, hullPointsOfInterest, out hullStatusComponents);
IEnumerable<Item> electrialPointsOfInterest = Item.ItemList.Where(it => it.Submarine == item.Submarine && !it.HiddenInGame && !it.NonInteractable && it.GetComponent<Repairable>() != null);
@@ -460,29 +461,63 @@ namespace Barotrauma.Items.Components
electricalChildren = electricChildren.ToImmutableDictionary();
Dictionary<MiniMapGUIComponent, GUIComponent> doorChilds = new Dictionary<MiniMapGUIComponent, GUIComponent>();
Dictionary<MiniMapGUIComponent, GUIComponent> weaponChilds = new Dictionary<MiniMapGUIComponent, GUIComponent>();
foreach (var (entity, component) in hullStatusComponents)
{
if (!hullPointsOfInterest.Contains(entity)) { continue; }
const int minSize = 8;
if (!(entity is Item it)) { continue; }
const int borderMaxSize = 2;
Point size = component.BorderComponent.Rect.Size;
size.X = Math.Max(size.X, minSize);
size.Y = Math.Max(size.Y, minSize);
float width = Math.Min(borderMaxSize, Math.Min(size.X, size.Y) / 8f);
GUIFrame frame = new GUIFrame(new RectTransform(size, component.RectComponent.RectTransform, anchor: Anchor.Center), style: "ScanLines", color: DoorIndicatorColor)
if (it.GetComponent<Door>() is { })
{
OutlineColor = GUI.Style.Green,
OutlineThickness = width
};
doorChilds.Add(component, frame);
const int minSize = 8;
Point size = component.BorderComponent.Rect.Size;
size.X = Math.Max(size.X, minSize);
size.Y = Math.Max(size.Y, minSize);
float width = Math.Min(borderMaxSize, Math.Min(size.X, size.Y) / 8f);
GUIFrame frame = new GUIFrame(new RectTransform(size, component.RectComponent.RectTransform, anchor: Anchor.Center), style: "ScanLines", color: DoorIndicatorColor)
{
OutlineColor = DoorIndicatorColor,
OutlineThickness = width
};
doorChilds.Add(component, frame);
}
else if (it.GetComponent<Turret>() is { } turret)
{
int parentWidth = (int) (submarineContainer.Rect.Width / 16f);
GUICustomComponent frame = new GUICustomComponent(new RectTransform(new Point(parentWidth, parentWidth), component.RectComponent.RectTransform, anchor: Anchor.Center), (batch, customComponent) =>
{
Vector2 center = customComponent.Center;
float rotation = turret.Rotation;
if (!hasPower)
{
float minRotation = MathHelper.ToRadians(Math.Min(turret.RotationLimits.X, turret.RotationLimits.Y)),
maxRotation = MathHelper.ToRadians(Math.Max(turret.RotationLimits.X, turret.RotationLimits.Y));
rotation = (minRotation + maxRotation) / 2;
}
if (turret.WeaponIndicatorSprite is { } weaponSprite)
{
Vector2 origin = weaponSprite.Origin;
float scale = parentWidth / Math.Max(weaponSprite.size.X, weaponSprite.size.Y);
Color color = !hasPower ? NoPowerColor : turret.ActiveUser is null ? GUI.Style.Red : GUI.Style.Green;
weaponSprite.Draw(batch, center, color, origin, rotation, scale, it.SpriteEffects);
}
});
weaponChilds.Add(component, frame);
}
}
doorChildren = doorChilds.ToImmutableDictionary();
weaponChildren = weaponChilds.ToImmutableDictionary();
Rectangle parentRect = miniMapFrame.Rect;
@@ -655,7 +690,7 @@ namespace Barotrauma.Items.Components
worldBorders.Location += item.Submarine.WorldPosition.ToPoint();
foreach (Gap gap in Gap.GapList)
{
if (gap.IsRoomToRoom || gap.Submarine != item.Submarine || gap.ConnectedDoor != null) { continue; }
if (gap.IsRoomToRoom || gap.Submarine != item.Submarine || gap.ConnectedDoor != null || gap.HiddenInGame) { continue; }
RectangleF entityRect = ScaleRectToUI(gap, miniMapFrame.Rect, worldBorders);
Vector2 scale = new Vector2(entityRect.Size.X / spriteSize.X, entityRect.Size.Y / spriteSize.Y) * 2.0f;
@@ -668,13 +703,33 @@ namespace Barotrauma.Items.Components
}
}
if (currentMode == MiniMapMode.HullStatus)
if (currentMode == MiniMapMode.HullStatus && hullStatusComponents != null)
{
foreach (var (entity, component) in hullStatusComponents)
{
if (!(entity is Hull hull)) { continue; }
if (!hullDatas.TryGetValue(hull, out HullData? hullData) || hullData is null) { continue; }
DrawHullCards(spriteBatch, hull, hullData, component.RectComponent);
if (item.CurrentHull is { } currentHull && currentHull == hull)
{
Sprite pingCircle = GUI.Style.YouAreHereCircle.Sprite;
if (pingCircle is null) { continue; }
Vector2 charPos = item.WorldPosition;
Vector2 hullPos = hull.WorldRect.Location.ToVector2(),
hullSize = hull.WorldRect.Size.ToVector2();
Vector2 relativePos = (charPos - hullPos) / hullSize * component.RectComponent.Rect.Size.ToVector2();
relativePos.Y = -relativePos.Y;
float parentWidth = submarineContainer.Rect.Width / 64f;
float spriteSize = pingCircle.size.X * (parentWidth / pingCircle.size.X);
Vector2 drawPos = component.RectComponent.Rect.Location.ToVector2() + relativePos;
drawPos -= new Vector2(spriteSize, spriteSize) / 2f;
pingCircle.Draw(spriteBatch, drawPos, GUI.Style.Red * 0.8f, Vector2.Zero, 0f, parentWidth / pingCircle.size.X);
}
}
}
@@ -944,7 +999,7 @@ namespace Barotrauma.Items.Components
if (ShowHullIntegrity)
{
float amount = 1f + hullData.LinkedHulls.Count;
gapOpenSum = hull.ConnectedGaps.Concat(hullData.LinkedHulls.SelectMany(h => h.ConnectedGaps)).Where(g => !g.IsRoomToRoom).Sum(g => g.Open) / amount;
gapOpenSum = hull.ConnectedGaps.Concat(hullData.LinkedHulls.SelectMany(h => h.ConnectedGaps)).Where(g => !g.IsRoomToRoom && !g.HiddenInGame).Sum(g => g.Open) / amount;
borderColor = Color.Lerp(neutralColor, GUI.Style.Red, Math.Min(gapOpenSum, 1.0f));
}
@@ -1039,10 +1094,9 @@ namespace Barotrauma.Items.Components
}
else if (it.GetComponent<PowerTransfer>() is { } powerTransfer)
{
int current = (int) -powerTransfer.CurrPowerConsumption,
load = (int) powerTransfer.PowerLoad;
int current = (int)-powerTransfer.CurrPowerConsumption, load = (int)powerTransfer.PowerLoad;
line1 = TextManager.GetWithVariable("statusmonitor.junctioncurrent.tooltip", "[amount]", current.ToString());
line1 = TextManager.GetWithVariable("statusmonitor.junctionpower.tooltip", "[amount]", current.ToString(), fallBackTag: "statusmonitor.junctioncurrent.tooltip");
line2 = TextManager.GetWithVariable("statusmonitor.junctionload.tooltip", "[amount]", load.ToString());
}
@@ -1086,38 +1140,41 @@ namespace Barotrauma.Items.Components
}
else
{
bool hullsVisible = currentMode == MiniMapMode.HullStatus;
bool hullsVisible = currentMode == MiniMapMode.HullStatus && item.Submarine != null;
foreach (var (entity, component) in hullStatusComponents)
if (hullStatusComponents != null)
{
if (!(entity is Hull hull)) { continue; }
if (!hullDatas.TryGetValue(hull, out HullData? hullData) || hullData is null) { continue; }
if (hullData.Distort) { continue; }
GUIComponent hullFrame = component.RectComponent;
if (hullsVisible && hullData.HullWaterAmount is { } waterAmount)
foreach (var (entity, component) in hullStatusComponents)
{
if (hullFrame.Rect.Height * waterAmount > 3.0f)
if (!(entity is Hull hull)) { continue; }
if (!hullDatas.TryGetValue(hull, out HullData? hullData) || hullData is null) { continue; }
if (hullData.Distort) { continue; }
GUIComponent hullFrame = component.RectComponent;
if (hullsVisible && hullData.HullWaterAmount is { } waterAmount)
{
RectangleF waterRect = new RectangleF(hullFrame.Rect.X, hullFrame.Rect.Y + hullFrame.Rect.Height * (1.0f - waterAmount), hullFrame.Rect.Width, hullFrame.Rect.Height * waterAmount);
const float width = 1f;
GUI.DrawFilledRectangle(spriteBatch, waterRect, HullWaterColor);
if (!MathUtils.NearlyEqual(waterAmount, 1.0f))
if (hullFrame.Rect.Height * waterAmount > 3.0f)
{
Vector2 offset = new Vector2(0, width);
GUI.DrawLine(spriteBatch, waterRect.Location + offset, new Vector2(waterRect.Right, waterRect.Y) + offset, HullWaterLineColor, width: width);
RectangleF waterRect = new RectangleF(hullFrame.Rect.X, hullFrame.Rect.Y + hullFrame.Rect.Height * (1.0f - waterAmount), hullFrame.Rect.Width, hullFrame.Rect.Height * waterAmount);
const float width = 1f;
GUI.DrawFilledRectangle(spriteBatch, waterRect, HullWaterColor);
if (!MathUtils.NearlyEqual(waterAmount, 1.0f))
{
Vector2 offset = new Vector2(0, width);
GUI.DrawLine(spriteBatch, waterRect.Location + offset, new Vector2(waterRect.Right, waterRect.Y) + offset, HullWaterLineColor, width: width);
}
}
}
}
if (hullsVisible && hullData.HullOxygenAmount is { } oxygenAmount)
{
GUI.DrawRectangle(spriteBatch, hullFrame.Rect, Color.Lerp(GUI.Style.Red * 0.5f, GUI.Style.Green * 0.3f, oxygenAmount / 100.0f), true);
if (hullsVisible && hullData.HullOxygenAmount is { } oxygenAmount)
{
GUI.DrawRectangle(spriteBatch, hullFrame.Rect, Color.Lerp(GUI.Style.Red * 0.5f, GUI.Style.Green * 0.3f, oxygenAmount / 100.0f), true);
}
}
}
}
@@ -1221,7 +1278,7 @@ namespace Barotrauma.Items.Components
Vector2 spriteScale = new Vector2(entityRect.Size.X / sprite.size.X, entityRect.Size.Y / sprite.size.Y);
Vector2 origin = new Vector2(sprite.Origin.X * spriteScale.X, sprite.Origin.Y * spriteScale.Y);
if (item.GetComponent<Turret>() is { } turret)
if (!item.Prefab.ShowInStatusMonitor && item.GetComponent<Turret>() is { } turret)
{
Vector2 drawPos = turret.GetDrawPos();
drawPos.Y = -drawPos.Y;

View File

@@ -158,7 +158,7 @@ namespace Barotrauma.Items.Components
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.01f), columnLeft.RectTransform), style: "HorizontalLine");
float relativeYMargin = 0.02f;
Vector2 relativeTextSize = new Vector2(0.9f, 0.2f);
Vector2 relativeTextSize = new Vector2(0.9f, 0.15f);
Vector2 sliderSize = new Vector2(1.0f, 0.125f);
Vector2 meterSize = new Vector2(1, 1 - relativeTextSize.Y - relativeYMargin - sliderSize.Y - 0.1f);
@@ -198,7 +198,7 @@ namespace Barotrauma.Items.Components
FissionRateScrollBar = new GUIScrollBar(new RectTransform(sliderSize, leftArea.RectTransform, Anchor.TopCenter)
{
RelativeOffset = new Vector2(0, fissionMeter.RectTransform.RelativeOffset.Y + meterSize.Y)
RelativeOffset = new Vector2(0, fissionMeter.RectTransform.RelativeOffset.Y + meterSize.Y + relativeYMargin)
},
style: "DeviceSlider", barSize: 0.15f)
{
@@ -208,7 +208,7 @@ namespace Barotrauma.Items.Components
{
LastUser = Character.Controlled;
unsentChanges = true;
targetFissionRate = scrollAmount * 100.0f;
TargetFissionRate = scrollAmount * 100.0f;
return false;
}
@@ -216,7 +216,7 @@ namespace Barotrauma.Items.Components
TurbineOutputScrollBar = new GUIScrollBar(new RectTransform(sliderSize, rightArea.RectTransform, Anchor.TopCenter)
{
RelativeOffset = new Vector2(0, turbineMeter.RectTransform.RelativeOffset.Y + meterSize.Y)
RelativeOffset = new Vector2(0, turbineMeter.RectTransform.RelativeOffset.Y + meterSize.Y + relativeYMargin)
},
style: "DeviceSlider", barSize: 0.15f, isHorizontal: true)
{
@@ -226,7 +226,7 @@ namespace Barotrauma.Items.Components
{
LastUser = Character.Controlled;
unsentChanges = true;
targetTurbineOutput = scrollAmount * 100.0f;
TargetTurbineOutput = scrollAmount * 100.0f;
return false;
}
@@ -370,7 +370,7 @@ namespace Barotrauma.Items.Components
};
string loadStr = TextManager.Get("ReactorLoad");
string kW = TextManager.Get("kilowatt");
loadText.TextGetter += () => $"{loadStr.Replace("[kw]", ((int)load).ToString())} {kW}";
loadText.TextGetter += () => $"{loadStr.Replace("[kw]", ((int)Load).ToString())} {kW}";
var graph = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.9f), graphArea.RectTransform), style: "InnerFrameRed");
new GUICustomComponent(new RectTransform(new Vector2(0.9f, 0.98f), graph.RectTransform, Anchor.Center), DrawGraph, null);
@@ -387,8 +387,8 @@ namespace Barotrauma.Items.Components
public override void OnItemLoaded()
{
base.OnItemLoaded();
TurbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
FissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
TurbineOutputScrollBar.BarScroll = TargetTurbineOutput / 100.0f;
FissionRateScrollBar.BarScroll = TargetFissionRate / 100.0f;
var itemContainer = item.GetComponent<ItemContainer>();
if (itemContainer != null)
{
@@ -462,7 +462,7 @@ namespace Barotrauma.Items.Components
if (graphTimer > updateGraphInterval)
{
UpdateGraph(outputGraph, -currPowerConsumption);
UpdateGraph(loadGraph, load);
UpdateGraph(loadGraph, Load);
graphTimer = 0.0f;
}
@@ -487,7 +487,7 @@ namespace Barotrauma.Items.Components
float jitter = 0.0f;
if (FissionRate > allowedFissionRate.Y - 5.0f)
{
float jitterAmount = Math.Min(targetFissionRate - allowedFissionRate.Y, 10.0f);
float jitterAmount = Math.Min(TargetFissionRate - allowedFissionRate.Y, 10.0f);
float t = graphTimer / updateGraphInterval;
jitter = (PerlinNoise.GetPerlin(t * 0.5f, t * 0.1f) - 0.5f) * jitterAmount;
@@ -525,12 +525,12 @@ namespace Barotrauma.Items.Components
criticalHeatWarning.Selected = temperature > allowedTemperature.Y && lightOn;
lowTemperatureWarning.Selected = temperature < allowedTemperature.X && lightOn;
criticalOutputWarning.Selected = -currPowerConsumption > load * 1.5f && lightOn;
criticalOutputWarning.Selected = -currPowerConsumption > Load * 1.5f && lightOn;
warningButtons["ReactorWarningOverheating"].Selected = temperature > optimalTemperature.Y && lightOn;
warningButtons["ReactorWarningHighOutput"].Selected = -currPowerConsumption > load * 1.1f && lightOn;
warningButtons["ReactorWarningHighOutput"].Selected = -currPowerConsumption > Load * 1.1f && lightOn;
warningButtons["ReactorWarningLowTemp"].Selected = temperature < optimalTemperature.X && lightOn;
warningButtons["ReactorWarningLowOutput"].Selected = -currPowerConsumption < load * 0.9f && lightOn;
warningButtons["ReactorWarningLowOutput"].Selected = -currPowerConsumption < Load * 0.9f && lightOn;
warningButtons["ReactorWarningFuelOut"].Selected = prevAvailableFuel < fissionRate * 0.01f && lightOn;
warningButtons["ReactorWarningLowFuel"].Selected = prevAvailableFuel < fissionRate && lightOn;
warningButtons["ReactorWarningMeltdown"].Selected = meltDownTimer > MeltdownDelay * 0.5f || item.Condition == 0.0f && lightOn;
@@ -571,12 +571,12 @@ namespace Barotrauma.Items.Components
unsentChanges = true;
if (input.X != 0.0f && GUIScrollBar.DraggingBar != FissionRateScrollBar)
{
targetFissionRate = MathHelper.Clamp(targetFissionRate + input.X, 0.0f, 100.0f);
TargetFissionRate = MathHelper.Clamp(TargetFissionRate + input.X, 0.0f, 100.0f);
FissionRateScrollBar.BarScroll += input.X / 100.0f;
}
if (input.Y != 0.0f && GUIScrollBar.DraggingBar != TurbineOutputScrollBar)
{
targetTurbineOutput = MathHelper.Clamp(targetTurbineOutput + input.Y, 0.0f, 100.0f);
TargetTurbineOutput = MathHelper.Clamp(TargetTurbineOutput + input.Y, 0.0f, 100.0f);
TurbineOutputScrollBar.BarScroll += input.Y / 100.0f;
}
}
@@ -596,7 +596,7 @@ namespace Barotrauma.Items.Components
MathHelper.Clamp((allowedRange.X - range.X) / (range.Y - range.X), 0.0f, 0.95f),
MathHelper.Clamp((allowedRange.Y - range.X) / (range.Y - range.X), 0.0f, 1.0f));
Vector2 sectorRad = new Vector2(-1.57f, 1.57f);
Vector2 sectorRad = new Vector2(-1.35f, 1.35f);
Vector2 optimalSectorRad = new Vector2(
MathHelper.Lerp(sectorRad.X, sectorRad.Y, optimalRangeNormalized.X),
@@ -606,23 +606,25 @@ namespace Barotrauma.Items.Components
MathHelper.Lerp(sectorRad.X, sectorRad.Y, allowedRangeNormalized.X),
MathHelper.Lerp(sectorRad.X, sectorRad.Y, allowedRangeNormalized.Y));
Vector2 pointerPos = pos - new Vector2(0, 30) * scale;
if (optimalRangeNormalized.X == optimalRangeNormalized.Y)
{
sectorSprite.Draw(spriteBatch, pos, GUI.Style.Red, MathHelper.PiOver2, scale);
sectorSprite.Draw(spriteBatch, pointerPos, GUI.Style.Red, MathHelper.PiOver2, scale);
}
else
{
spriteBatch.End();
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0, 0, GameMain.GraphicsWidth, (int)(pos.Y + (meterSprite.size.Y - meterSprite.Origin.Y) * scale) - 3);
spriteBatch.GraphicsDevice.ScissorRectangle = new Rectangle(0, 0, GameMain.GraphicsWidth, (int)(pointerPos.Y + (meterSprite.size.Y - meterSprite.Origin.Y) * scale) - 3);
spriteBatch.Begin(SpriteSortMode.Deferred, rasterizerState: GameMain.ScissorTestEnable);
float scaleMultiplier = 0.95f;
sectorSprite.Draw(spriteBatch, pos, optimalRangeColor, MathHelper.PiOver2 + (allowedSectorRad.X + allowedSectorRad.Y) / 2.0f, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pos, offRangeColor, optimalSectorRad.X, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pos, warningColor, allowedSectorRad.X, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pos, offRangeColor, MathHelper.Pi + optimalSectorRad.Y, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pos, warningColor, MathHelper.Pi + allowedSectorRad.Y, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pointerPos, optimalRangeColor, MathHelper.PiOver2 + (allowedSectorRad.X + allowedSectorRad.Y) / 2.0f, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pointerPos, offRangeColor, optimalSectorRad.X, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pointerPos, warningColor, allowedSectorRad.X, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pointerPos, offRangeColor, MathHelper.Pi + optimalSectorRad.Y, scale * scaleMultiplier);
sectorSprite.Draw(spriteBatch, pointerPos, warningColor, MathHelper.Pi + allowedSectorRad.Y, scale * scaleMultiplier);
spriteBatch.End();
spriteBatch.GraphicsDevice.ScissorRectangle = prevScissorRect;
@@ -634,7 +636,7 @@ namespace Barotrauma.Items.Components
float normalizedValue = (value - range.X) / (range.Y - range.X);
float valueRad = MathHelper.Lerp(sectorRad.X, sectorRad.Y, normalizedValue);
Vector2 offset = new Vector2(0, 40) * scale;
meterPointer.Draw(spriteBatch, pos - offset, valueRad, scale);
meterPointer.Draw(spriteBatch, pointerPos, valueRad, scale);
}
static void UpdateGraph<T>(IList<T> graph, T newValue)
@@ -713,8 +715,8 @@ namespace Barotrauma.Items.Components
{
msg.Write(autoTemp);
msg.Write(PowerOn);
msg.WriteRangedSingle(targetFissionRate, 0.0f, 100.0f, 8);
msg.WriteRangedSingle(targetTurbineOutput, 0.0f, 100.0f, 8);
msg.WriteRangedSingle(TargetFissionRate, 0.0f, 100.0f, 8);
msg.WriteRangedSingle(TargetTurbineOutput, 0.0f, 100.0f, 8);
correctionTimer = CorrectionDelay;
}
@@ -730,17 +732,17 @@ namespace Barotrauma.Items.Components
AutoTemp = msg.ReadBoolean();
PowerOn = msg.ReadBoolean();
Temperature = msg.ReadRangedSingle(0.0f, 100.0f, 8);
targetFissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
targetTurbineOutput = msg.ReadRangedSingle(0.0f, 100.0f, 8);
TargetFissionRate = msg.ReadRangedSingle(0.0f, 100.0f, 8);
TargetTurbineOutput = msg.ReadRangedSingle(0.0f, 100.0f, 8);
degreeOfSuccess = msg.ReadRangedSingle(0.0f, 1.0f, 8);
if (Math.Abs(FissionRateScrollBar.BarScroll - targetFissionRate / 100.0f) > 0.01f)
if (Math.Abs(FissionRateScrollBar.BarScroll - TargetFissionRate / 100.0f) > 0.01f)
{
FissionRateScrollBar.BarScroll = targetFissionRate / 100.0f;
FissionRateScrollBar.BarScroll = TargetFissionRate / 100.0f;
}
if (Math.Abs(TurbineOutputScrollBar.BarScroll - targetTurbineOutput / 100.0f) > 0.01f)
if (Math.Abs(TurbineOutputScrollBar.BarScroll - TargetTurbineOutput / 100.0f) > 0.01f)
{
TurbineOutputScrollBar.BarScroll = targetTurbineOutput / 100.0f;
TurbineOutputScrollBar.BarScroll = TargetTurbineOutput / 100.0f;
}
IsActive = true;

View File

@@ -456,7 +456,7 @@ namespace Barotrauma.Items.Components
}
}
float distort = 1.0f - item.Condition / item.MaxCondition;
float distort = MathHelper.Clamp(1.0f - item.Condition / item.MaxCondition, 0.0f, 1.0f);
for (int i = sonarBlips.Count - 1; i >= 0; i--)
{
sonarBlips[i].FadeTimer -= deltaTime * MathHelper.Lerp(0.5f, 2.0f, distort);

View File

@@ -56,7 +56,9 @@ namespace Barotrauma.Items.Components
if (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition) { return true; }
float maxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(character);
if (item.Condition / maxRepairConditionMultiplier < RepairThreshold) { return true; }
float defaultMaxCondition = item.MaxCondition / maxRepairConditionMultiplier;
if (MathUtils.Percentage(item.Condition, defaultMaxCondition) < RepairThreshold) { return true; }
if (CurrentFixer == character)
{
@@ -280,14 +282,14 @@ namespace Barotrauma.Items.Components
progressBarOverlayText.Visible = false;
}
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition && item.ConditionPercentage < RepairThreshold;
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
repairButtonText :
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition && IsBelowRepairThreshold;
RepairButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Repair) ?
repairButtonText :
repairingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);
SabotageButton.Visible = character.IsTraitor;
SabotageButton.IgnoreLayoutGroups = !SabotageButton.Visible;
SabotageButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Sabotage)) && character.IsTraitor && item.ConditionPercentage > MinSabotageCondition;
SabotageButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Sabotage)) && character.IsTraitor && IsBelowRepairThreshold;
SabotageButton.Text = (currentFixerAction == FixActions.None || CurrentFixer != character || currentFixerAction != FixActions.Sabotage || !character.IsTraitor) ?
sabotageButtonText :
sabotagingText + new string('.', ((int)(Timing.TotalTime * 2.0f) % 3) + 1);

View File

@@ -35,7 +35,7 @@ namespace Barotrauma.Items.Components
new GUIFrame(new RectTransform(new Vector2(0.9f, 0.01f), layoutGroup.RectTransform), style: "HorizontalLine");
inputBox = new GUITextBox(new RectTransform(new Vector2(1, .1f), layoutGroup.RectTransform), textColor: Color.LimeGreen)
inputBox = new GUITextBox(new RectTransform(new Vector2(1, .1f), layoutGroup.RectTransform), textColor: TextColor)
{
MaxTextLength = MaxMessageLength,
OverflowClip = true,
@@ -63,15 +63,15 @@ namespace Barotrauma.Items.Components
}
OutputValue = input;
ShowOnDisplay(input, addToHistory: true);
ShowOnDisplay(input, addToHistory: true, TextColor);
item.SendSignal(input, "signal_out");
}
partial void ShowOnDisplay(string input, bool addToHistory)
partial void ShowOnDisplay(string input, bool addToHistory, Color color)
{
if (addToHistory)
{
messageHistory.Add(input);
messageHistory.Add(new TerminalMessage(input, color));
while (messageHistory.Count > MaxMessages)
{
messageHistory.RemoveAt(0);
@@ -85,7 +85,7 @@ namespace Barotrauma.Items.Components
GUITextBlock newBlock = new GUITextBlock(
new RectTransform(new Vector2(1, 0), historyBox.Content.RectTransform, anchor: Anchor.TopCenter),
"> " + input,
textColor: Color.LimeGreen, wrap: true, font: UseMonospaceFont ? GUI.MonospacedFont : GUI.GlobalFont)
textColor: color, wrap: true, font: UseMonospaceFont ? GUI.MonospacedFont : GUI.GlobalFont)
{
CanBeFocused = false
};

View File

@@ -0,0 +1,12 @@
using Barotrauma.Networking;
namespace Barotrauma.Items.Components
{
partial class TriggerComponent : ItemComponent, IServerSerializable
{
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
{
CurrentForceFluctuation = msg.ReadRangedSingle(0.0f, 1.0f, 8);
}
}
}

View File

@@ -14,6 +14,7 @@ namespace Barotrauma.Items.Components
partial class Turret : Powered, IDrawableComponent, IServerSerializable
{
private Sprite crosshairSprite, crosshairPointerSprite;
public Sprite WeaponIndicatorSprite;
private GUIProgressBar powerIndicator;
@@ -134,6 +135,9 @@ namespace Barotrauma.Items.Components
case "crosshair":
crosshairSprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.FilePath));
break;
case "weaponindicator":
WeaponIndicatorSprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.FilePath));
break;
case "crosshairpointer":
crosshairPointerSprite = new Sprite(subElement, texturePath.Contains("/") ? "" : Path.GetDirectoryName(item.Prefab.FilePath));
break;

View File

@@ -101,7 +101,7 @@ namespace Barotrauma
private float currentHighlightState, fadeInDuration, fadeOutDuration;
private Color currentHighlightColor;
private IEnumerable<object> UpdateBorderHighlight()
private IEnumerable<CoroutineStatus> UpdateBorderHighlight()
{
HighlightTimer = 1.0f;
while (currentHighlightState < fadeInDuration + fadeOutDuration)
@@ -1255,9 +1255,18 @@ namespace Barotrauma
else
{
bool anySuccess = false;
bool allowCombine = true;
//if we're dragging a stack of partial items or trying to drag to a stack of partial items
//(which should not normally exist, but can happen when e.g. fire damages a stack of items)
//don't allow combining because it leads to weird behavior (stack of items of mixed quality)
if (DraggingItems.Count(it => !it.IsFullCondition && it.Condition > 0.0f) > 1 ||
selectedInventory.GetItemsAt(slotIndex).Count(it => !it.IsFullCondition && it.Condition > 0.0f) > 1)
{
allowCombine = false;
}
foreach (Item item in DraggingItems)
{
bool success = selectedInventory.TryPutItem(item, slotIndex, allowSwapping: !anySuccess, true, Character.Controlled);
bool success = selectedInventory.TryPutItem(item, slotIndex, allowSwapping: !anySuccess, allowCombine, Character.Controlled);
anySuccess |= success;
if (!success) { break; }
}
@@ -1673,7 +1682,7 @@ namespace Barotrauma
}
sprite.Draw(spriteBatch, itemPos, spriteColor, rotation, scale);
if ((!item.AllowStealing || (inventory != null && inventory.slots[slotIndex].Items.Any(it => !it.AllowStealing))) && CharacterInventory.LimbSlotIcons.ContainsKey(InvSlotType.LeftHand))
if (((item.SpawnedInCurrentOutpost && !item.AllowStealing) || (inventory != null && inventory.slots[slotIndex].Items.Any(it => it.SpawnedInCurrentOutpost && !it.AllowStealing))) && CharacterInventory.LimbSlotIcons.ContainsKey(InvSlotType.LeftHand))
{
var stealIcon = CharacterInventory.LimbSlotIcons[InvSlotType.LeftHand];
Vector2 iconSize = new Vector2(25 * GUI.Scale);
@@ -1818,7 +1827,7 @@ namespace Barotrauma
}
}
private IEnumerable<object> SyncItemsAfterDelay(UInt16 lastEventID)
private IEnumerable<CoroutineStatus> SyncItemsAfterDelay(UInt16 lastEventID)
{
while (syncItemsDelay > 0.0f ||
//don't apply inventory updates until

View File

@@ -175,12 +175,12 @@ namespace Barotrauma
}
}
float displayCondition = FakeBroken ? 0.0f : condition;
float displayCondition = FakeBroken ? 0.0f : ConditionPercentage;
for (int i = 0; i < Prefab.BrokenSprites.Count;i++)
{
if (Prefab.BrokenSprites[i].FadeIn) { continue; }
float minCondition = i > 0 ? Prefab.BrokenSprites[i - i].MaxCondition : 0.0f;
if (displayCondition <= minCondition || displayCondition <= Prefab.BrokenSprites[i].MaxCondition)
float minCondition = i > 0 ? Prefab.BrokenSprites[i - i].MaxConditionPercentage : 0.0f;
if (displayCondition <= minCondition || displayCondition <= Prefab.BrokenSprites[i].MaxConditionPercentage)
{
activeSprite = Prefab.BrokenSprites[i].Sprite;
break;
@@ -284,8 +284,8 @@ namespace Barotrauma
{
if (Prefab.BrokenSprites[i].FadeIn)
{
float min = i > 0 ? Prefab.BrokenSprites[i - i].MaxCondition : 0.0f;
float max = Prefab.BrokenSprites[i].MaxCondition;
float min = i > 0 ? Prefab.BrokenSprites[i - i].MaxConditionPercentage : 0.0f;
float max = Prefab.BrokenSprites[i].MaxConditionPercentage;
fadeInBrokenSpriteAlpha = 1.0f - ((displayCondition - min) / (max - min));
if (fadeInBrokenSpriteAlpha > 0.0f && fadeInBrokenSpriteAlpha <= 1.0f)
{
@@ -293,7 +293,7 @@ namespace Barotrauma
}
continue;
}
if (displayCondition <= Prefab.BrokenSprites[i].MaxCondition)
if (displayCondition <= Prefab.BrokenSprites[i].MaxConditionPercentage)
{
activeSprite = Prefab.BrokenSprites[i].Sprite;
drawOffset = Prefab.BrokenSprites[i].Offset.ToVector2() * Scale;
@@ -1632,7 +1632,7 @@ namespace Barotrauma
{
item = new Item(itemPrefab, pos, sub, id: itemId)
{
SpawnedInOutpost = spawnedInOutpost,
SpawnedInCurrentOutpost = spawnedInOutpost,
AllowStealing = allowStealing,
Quality = quality
};

View File

@@ -11,7 +11,7 @@ namespace Barotrauma
class BrokenItemSprite
{
//sprite will be rendered if the condition of the item is below this
public readonly float MaxCondition;
public readonly float MaxConditionPercentage;
public readonly Sprite Sprite;
public readonly bool FadeIn;
public readonly Point Offset;
@@ -19,7 +19,7 @@ namespace Barotrauma
public BrokenItemSprite(Sprite sprite, float maxCondition, bool fadeIn, Point offset)
{
Sprite = sprite;
MaxCondition = MathHelper.Clamp(maxCondition, 0.0f, 100.0f);
MaxConditionPercentage = MathHelper.Clamp(maxCondition, 0.0f, 100.0f);
FadeIn = fadeIn;
Offset = offset;
}

View File

@@ -95,7 +95,7 @@ namespace Barotrauma
MathHelper.Clamp(particlePos.Y, hull.WorldRect.Y - hull.WorldRect.Height, hull.WorldRect.Y));
}
private IEnumerable<object> DimLight(LightSource light)
private IEnumerable<CoroutineStatus> DimLight(LightSource light)
{
float currBrightness = 1.0f;
while (light.Color.A > 0.0f && flashDuration > 0.0f)

View File

@@ -438,7 +438,7 @@ namespace Barotrauma
for (int i = 0; i < Bodies.Count; i++)
{
Vector2 pos = FarseerPhysics.ConvertUnits.ToDisplayUnits(Bodies[i].Position);
if (Submarine != null) pos += Submarine.Position;
if (Submarine != null) { pos += Submarine.DrawPosition; }
pos.Y = -pos.Y;
GUI.DrawRectangle(spriteBatch,
pos,

View File

@@ -202,6 +202,7 @@ namespace Barotrauma
}
}
GUITextBlock.AutoScaleAndNormalize(parent.Content.GetAllChildren<GUITextBlock>().Where(c => c != submarineNameText && c != descBlock));
parent.ForceLayoutRecalculation();
}
}
}

View File

@@ -160,7 +160,7 @@ namespace Barotrauma.Networking
public TransferInDelegate OnTransferFailed;
private readonly List<FileTransferIn> activeTransfers;
private readonly List<Pair<int, double>> finishedTransfers;
private readonly List<(int transferId, double finishedTime)> finishedTransfers;
private readonly Dictionary<FileTransferType, string> downloadFolders = new Dictionary<FileTransferType, string>()
{
@@ -176,7 +176,7 @@ namespace Barotrauma.Networking
public FileReceiver()
{
activeTransfers = new List<FileTransferIn>();
finishedTransfers = new List<Pair<int, double>>();
finishedTransfers = new List<(int transferId, double finishedTime)>();
}
public void ReadMessage(IReadMessage inc)
@@ -193,8 +193,8 @@ namespace Barotrauma.Networking
case (byte)FileTransferMessageType.Initiate:
{
byte transferId = inc.ReadByte();
var existingTransfer = activeTransfers.Find(t => t.ID == transferId);
finishedTransfers.RemoveAll(t => t.First == transferId);
var existingTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.EndPointString) && t.ID == transferId);
finishedTransfers.RemoveAll(t => t.transferId == transferId);
byte fileType = inc.ReadByte();
//ushort chunkLen = inc.ReadUInt16();
int fileSize = inc.ReadInt32();
@@ -211,7 +211,7 @@ namespace Barotrauma.Networking
}
else //resend acknowledgement packet
{
GameMain.Client.UpdateFileTransfer(transferId, 0);
GameMain.Client.UpdateFileTransfer(transferId, existingTransfer.Received);
}
return;
}
@@ -316,14 +316,14 @@ namespace Barotrauma.Networking
{
byte transferId = inc.ReadByte();
var activeTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
var activeTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.EndPointString) && t.ID == transferId);
if (activeTransfer == null)
{
//it's possible for the server to send some extra data
//before it acknowledges that the download is finished,
//so let's suppress the error message in that case
finishedTransfers.RemoveAll(t => t.Second + 5.0 < Timing.TotalTime);
if (!finishedTransfers.Any(t => t.First == transferId))
finishedTransfers.RemoveAll(t => t.finishedTime + 5.0 < Timing.TotalTime);
if (!finishedTransfers.Any(t => t.transferId == transferId))
{
GameMain.Client.CancelFileTransfer(transferId);
DebugConsole.ThrowError("File transfer error: received data without a transfer initiation message");
@@ -373,7 +373,7 @@ namespace Barotrauma.Networking
if (ValidateReceivedData(activeTransfer, out string errorMessage))
{
finishedTransfers.Add(new Pair<int, double>(transferId, Timing.TotalTime));
finishedTransfers.Add((transferId, Timing.TotalTime));
StopTransfer(activeTransfer);
Md5Hash.RemoveFromCache(activeTransfer.FilePath);
OnFinished(activeTransfer);
@@ -391,7 +391,7 @@ namespace Barotrauma.Networking
case (byte)FileTransferMessageType.Cancel:
{
byte transferId = inc.ReadByte();
var matchingTransfer = activeTransfers.Find(t => t.Connection == inc.Sender && t.ID == transferId);
var matchingTransfer = activeTransfers.Find(t => t.Connection.EndpointMatches(t.Connection.EndPointString) && t.ID == transferId);
if (matchingTransfer != null)
{
new GUIMessageBox("File transfer cancelled", "The server has cancelled the transfer of the file \"" + matchingTransfer.FileName + "\".");
@@ -528,7 +528,7 @@ namespace Barotrauma.Networking
transfer.Status = FileTransferStatus.Canceled;
}
if (activeTransfers.Contains(transfer)) activeTransfers.Remove(transfer);
if (activeTransfers.Contains(transfer)) { activeTransfers.Remove(transfer); }
transfer.Dispose();
if (deleteFile && File.Exists(transfer.FilePath))

View File

@@ -460,7 +460,7 @@ namespace Barotrauma.Networking
private bool wrongPassword;
// Before main looping starts, we loop here and wait for approval message
private IEnumerable<object> WaitForStartingInfo()
private IEnumerable<CoroutineStatus> WaitForStartingInfo()
{
GUI.SetCursorWaiting();
requiresPw = false;
@@ -861,8 +861,8 @@ namespace Barotrauma.Networking
if (roundInitStatus == RoundInitStatus.WaitingForStartGameFinalize)
{
//waiting for a save file
if (campaign != null &&
campaign.PendingSaveID > campaign.LastSaveID &&
if (campaign != null &&
NetIdUtils.IdMoreRecent(campaign.PendingSaveID, campaign.LastSaveID) &&
fileReceiver.ActiveTransfers.Any(t => t.FileType == FileTransferType.CampaignSave))
{
return;
@@ -872,6 +872,7 @@ namespace Barotrauma.Networking
break;
case ServerPacketHeader.ENDGAME:
CampaignMode.TransitionType transitionType = (CampaignMode.TransitionType)inc.ReadByte();
bool save = inc.ReadBoolean();
string endMessage = string.Empty;
endMessage = inc.ReadString();
@@ -905,6 +906,7 @@ namespace Barotrauma.Networking
roundInitStatus = RoundInitStatus.Interrupted;
CoroutineManager.StartCoroutine(EndGame(endMessage, traitorResults, transitionType), "EndGame");
GUI.SetSavingIndicatorState(save);
break;
case ServerPacketHeader.CAMPAIGN_SETUP_INFO:
UInt16 saveCount = inc.ReadUInt16();
@@ -1236,7 +1238,7 @@ namespace Barotrauma.Networking
}
}
private IEnumerable<object> WaitInServerQueue()
private IEnumerable<CoroutineStatus> WaitInServerQueue()
{
waitInServerQueueBox = new GUIMessageBox(
TextManager.Get("ServerQueuePleaseWait"),
@@ -1424,7 +1426,7 @@ namespace Barotrauma.Networking
GameMain.NetLobbyScreen.RefreshEnabledElements();
}
private IEnumerable<object> StartGame(IReadMessage inc)
private IEnumerable<CoroutineStatus> StartGame(IReadMessage inc)
{
Character?.Remove();
Character = null;
@@ -1562,31 +1564,47 @@ namespace Barotrauma.Networking
if (GameMain.GameSession?.CrewManager != null) { GameMain.GameSession.CrewManager.Reset(); }
byte campaignID = inc.ReadByte();
UInt16 campaignSaveID = inc.ReadUInt16();
int nextLocationIndex = inc.ReadInt32();
int nextConnectionIndex = inc.ReadInt32();
int selectedLocationIndex = inc.ReadInt32();
bool mirrorLevel = inc.ReadBoolean();
if (campaign.CampaignID != campaignID)
{
string errorMsg = "Failed to start campaign round (campaign ID does not match).";
gameStarted = true;
DebugConsole.ThrowError(errorMsg);
DebugConsole.ThrowError("Failed to start campaign round (campaign ID does not match).");
GameMain.NetLobbyScreen.Select();
roundInitStatus = RoundInitStatus.Interrupted;
yield return CoroutineStatus.Failure;
}
else if (campaign.Map == null)
{
string errorMsg = "Failed to start campaign round (campaign map not loaded yet).";
gameStarted = true;
DebugConsole.ThrowError(errorMsg);
DebugConsole.ThrowError("Failed to start campaign round (campaign map not loaded yet).");
GameMain.NetLobbyScreen.Select();
roundInitStatus = RoundInitStatus.Interrupted;
yield return CoroutineStatus.Failure;
}
if (NetIdUtils.IdMoreRecent(campaignSaveID, campaign.PendingSaveID))
{
campaign.PendingSaveID = campaignSaveID;
DateTime saveFileTimeOut = DateTime.Now + new TimeSpan(0,0,60);
while (NetIdUtils.IdMoreRecent(campaignSaveID, campaign.LastSaveID))
{
if (DateTime.Now > saveFileTimeOut)
{
gameStarted = true;
DebugConsole.ThrowError("Failed to start campaign round (timed out while waiting for the up-to-date save file).");
GameMain.NetLobbyScreen.Select();
roundInitStatus = RoundInitStatus.Interrupted;
yield return CoroutineStatus.Failure;
}
yield return new WaitForSeconds(0.1f);
}
}
campaign.Map.SelectLocation(selectedLocationIndex);
LevelData levelData = nextLocationIndex > -1 ?
@@ -1665,10 +1683,6 @@ namespace Barotrauma.Networking
}
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize) { break; }
clientPeer.Update((float)Timing.Step);
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize) { break; }
}
catch (Exception e)
{
@@ -1744,7 +1758,7 @@ namespace Barotrauma.Networking
yield return CoroutineStatus.Success;
}
public IEnumerable<object> EndGame(string endMessage, List<TraitorMissionResult> traitorResults = null, CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
public IEnumerable<CoroutineStatus> EndGame(string endMessage, List<TraitorMissionResult> traitorResults = null, CampaignMode.TransitionType transitionType = CampaignMode.TransitionType.None)
{
//round starting up, wait for it to finish
DateTime timeOut = DateTime.Now + new TimeSpan(0, 0, 60);
@@ -1854,8 +1868,7 @@ namespace Barotrauma.Networking
GameMain.GameSession.OwnedSubmarines = new List<SubmarineInfo>();
for (int i = 0; i < ownedIndexes.Length; i++)
{
int index;
if (int.TryParse(ownedIndexes[i], out index))
if (int.TryParse(ownedIndexes[i], out int index))
{
SubmarineInfo sub = GameMain.Client.ServerSubmarines[index];
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, "owned"))
@@ -2670,8 +2683,11 @@ namespace Barotrauma.Networking
public override void CreateEntityEvent(INetSerializable entity, object[] extraData)
{
if (!(entity is IClientSerializable)) throw new InvalidCastException("Entity is not IClientSerializable");
entityEventManager.CreateEvent(entity as IClientSerializable, extraData);
if (!(entity is IClientSerializable clientSerializable))
{
throw new InvalidCastException($"Entity is not {nameof(IClientSerializable)}");
}
entityEventManager.CreateEvent(clientSerializable, extraData);
}
public bool HasPermission(ClientPermissions permission)
@@ -3013,12 +3029,13 @@ namespace Barotrauma.Networking
/// <summary>
/// Tell the server to end the round (permission required)
/// </summary>
public void RequestRoundEnd()
public void RequestRoundEnd(bool save)
{
IWriteMessage msg = new WriteOnlyMessage();
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
msg.Write((UInt16)ClientPermissions.ManageRound);
msg.Write(true); //indicates round end
msg.Write(save);
clientPeer.Send(msg, DeliveryMethod.Reliable);
}
@@ -3321,7 +3338,9 @@ namespace Barotrauma.Networking
if (respawnManager.RespawnCountdownStarted)
{
float timeLeft = (float)(respawnManager.RespawnTime - DateTime.Now).TotalSeconds;
respawnText = TextManager.GetWithVariable(respawnManager.UsingShuttle ? "RespawnShuttleDispatching" : "RespawningIn", "[time]", ToolBox.SecondsToReadableTime(timeLeft));
respawnText = TextManager.GetWithVariable(
respawnManager.UsingShuttle && !respawnManager.ForceSpawnInMainSub ?
"RespawnShuttleDispatching" : "RespawningIn", "[time]", ToolBox.SecondsToReadableTime(timeLeft));
}
else if (respawnManager.PendingRespawnCount > 0)
{
@@ -3437,7 +3456,7 @@ namespace Barotrauma.Networking
}
// Need a delayed selection due to the inputbox being deselected when a left click occurs outside of it
IEnumerable<object> selectCoroutine()
IEnumerable<CoroutineStatus> selectCoroutine()
{
yield return new WaitForSeconds(0.01f, true);
chatBox.InputBox.Select(chatBox.InputBox.Text.Length);

View File

@@ -72,6 +72,9 @@ namespace Barotrauma
{
CreateLabeledTickBox(parent, nameof(DangerousItemStealBots));
}
CreateLabeledSlider(parent, 0.0f, 30.0f, 0.5f, nameof(DangerousItemContainKarmaDecrease));
CreateLabeledTickBox(parent, nameof(IsDangerousItemContainKarmaDecreaseIncremental));
CreateLabeledSlider(parent, 0.0f, 100.0f, 1.0f, nameof(MaxDangerousItemContainKarmaDecrease));
}
private void CreateLabeledSlider(GUIComponent parent, float min, float max, float step, string propertyName)

View File

@@ -43,24 +43,9 @@ namespace Barotrauma.Networking
public void CreateEvent(IClientSerializable entity, object[] extraData = null)
{
if (GameMain.Client == null || GameMain.Client.Character == null) return;
if (GameMain.Client?.Character == null) { return; }
if (!(entity is Entity))
{
DebugConsole.ThrowError("Can't create an entity event for " + entity + "!");
return;
}
if (((Entity)entity).Removed)
{
DebugConsole.ThrowError("Can't create an entity event for " + entity + " - the entity has been removed.\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
if (((Entity)entity).IdFreed)
{
DebugConsole.ThrowError("Can't create an entity event for " + entity + " - the ID of the entity has been freed.\n" + Environment.StackTrace.CleanupStackTrace());
return;
}
if (!ValidateEntity(entity)) { return; }
var newEvent = new ClientEntityEvent(entity, (UInt16)(ID + 1))
{
@@ -161,7 +146,7 @@ namespace Barotrauma.Networking
UInt16 firstEventID = msg.ReadUInt16();
int eventCount = msg.ReadByte();
for (int i = 0; i < eventCount; i++)
{
//16 = entity ID, 8 = msg length
@@ -179,7 +164,7 @@ namespace Barotrauma.Networking
UInt16 thisEventID = (UInt16)(firstEventID + (UInt16)i);
UInt16 entityID = msg.ReadUInt16();
if (entityID == Entity.NullEntityID)
{
if (GameSettings.VerboseLogging)
@@ -240,8 +225,11 @@ namespace Barotrauma.Networking
if (msg.BitPosition != msgPosition + msgLength * 8)
{
string errorMsg = "Message byte position incorrect after reading an event for the entity \"" + entity.ToString()
+ "\". Read " + (msg.BitPosition - msgPosition) + " bits, expected message length was " + (msgLength * 8) + " bits.";
var prevEntity = entities.Count >= 2 ? entities[entities.Count - 2] : null;
ushort prevId = prevEntity is Entity p ? p.ID : (ushort)0;
string errorMsg = $"Message byte position incorrect after reading an event for the entity \"{entity}\" (ID {(entity is Entity e ? e.ID : 0)}). "
+$"The previous entity was \"{prevEntity}\" (ID {prevId}) "
+$"Read {msg.BitPosition - msgPosition} bits, expected message length was {msgLength * 8} bits.";
DebugConsole.ThrowError(errorMsg);

View File

@@ -60,11 +60,11 @@ namespace Barotrauma.Networking
{
GUI.DrawRectangle(spriteBatch, rect, Color.Black * 0.4f, true);
graphs[(int)NetStatType.ReceivedBytes].Draw(spriteBatch, rect, null, 0.0f, Color.Cyan);
graphs[(int)NetStatType.SentBytes].Draw(spriteBatch, rect, null, 0.0f, GUI.Style.Orange);
graphs[(int)NetStatType.ReceivedBytes].Draw(spriteBatch, rect, color: Color.Cyan);
graphs[(int)NetStatType.SentBytes].Draw(spriteBatch, rect, null, color: GUI.Style.Orange);
if (graphs[(int)NetStatType.ResentMessages].Average() > 0)
{
graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, null, 0.0f, GUI.Style.Red);
graphs[(int)NetStatType.ResentMessages].Draw(spriteBatch, rect, color: GUI.Style.Red);
GUI.SmallFont.DrawString(spriteBatch, "Peak resent: " + graphs[(int)NetStatType.ResentMessages].LargestValue() + " messages/s",
new Vector2(rect.Right + 10, rect.Y + 50), GUI.Style.Red);
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Linq;
namespace Barotrauma.Networking
{
@@ -17,6 +18,11 @@ namespace Barotrauma.Networking
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; }
@@ -30,10 +36,46 @@ namespace Barotrauma.Networking
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?.IsRunning ?? false))) { return; }
var respawnPrompt = new GUIMessageBox(
TextManager.Get("tutorial.tryagainheader"), TextManager.Get("respawnquestionprompt"),
new string[] { TextManager.Get("respawnquestionpromptrespawn"), TextManager.Get("respawnquestionpromptwait") })
{
UserData = "respawnquestionprompt"
};
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 ClientRead(ServerNetObject type, 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:
@@ -46,13 +88,14 @@ namespace Barotrauma.Networking
if (CurrentState != newState)
{
CoroutineManager.StopCoroutines("forcepos");
//CoroutineManager.StartCoroutine(ForceShuttleToPos(Level.Loaded.StartPosition - Vector2.UnitY * Level.ShaftHeight, 100.0f), "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));
@@ -63,6 +106,12 @@ namespace Barotrauma.Networking
}
CurrentState = newState;
if (respawnPromptPending)
{
GameMain.Client.HasSpawned = true;
ShowRespawnPromptIfNeeded(delay: 1.0f);
}
msg.ReadPadBits();
}
}

View File

@@ -106,10 +106,10 @@ namespace Barotrauma.Networking
public void CreatePreviewWindow(GUIFrame frame)
{
frame.ClearChildren();
if (frame == null) { return; }
frame.ClearChildren();
var title = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), frame.RectTransform), ServerName, font: GUI.LargeFont)
{
ToolTip = ServerName

View File

@@ -141,6 +141,10 @@ namespace Barotrauma.Networking
ReadExtraCargo(incMsg);
ReadHiddenSubs(incMsg);
GameMain.NetLobbyScreen.UpdateSubVisibility();
Voting.ClientRead(incMsg);
bool isAdmin = incMsg.ReadBoolean();
@@ -202,6 +206,11 @@ namespace Barotrauma.Networking
Whitelist.ClientAdminWrite(outMsg);
}
if (dataToSend.HasFlag(NetFlags.HiddenSubs))
{
WriteHiddenSubs(outMsg);
}
if (dataToSend.HasFlag(NetFlags.Misc))
{
outMsg.WriteRangedInteger(missionTypeOr ?? (int)Barotrauma.MissionType.None, 0, (int)Barotrauma.MissionType.All);
@@ -288,7 +297,7 @@ namespace Barotrauma.Networking
};
//center frames
GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.4f, 0.8f), settingsFrame.RectTransform, Anchor.Center) { MinSize = new Point(400, 430) });
GUIFrame innerFrame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.85f), settingsFrame.RectTransform, Anchor.Center) { MinSize = new Point(400, 430) });
GUILayoutGroup paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), innerFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
{
Stretch = true,
@@ -363,7 +372,7 @@ namespace Barotrauma.Networking
selectionFrame.RectTransform.NonScaledSize = new Point(selectionFrame.Rect.Width, selectionFrame.Children.First().Rect.Height);
selectionFrame.RectTransform.IsFixedSize = true;
GetPropertyData("SubSelectionMode").AssignGUIComponent(selectionMode);
GetPropertyData(nameof(SubSelectionMode)).AssignGUIComponent(selectionMode);
// Mode Selection
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), serverTab.RectTransform), TextManager.Get("ServerSettingsModeSelection"), font: GUI.SubHeadingFont);
@@ -381,7 +390,7 @@ namespace Barotrauma.Networking
}
selectionFrame.RectTransform.NonScaledSize = new Point(selectionFrame.Rect.Width, selectionFrame.Children.First().Rect.Height);
selectionFrame.RectTransform.IsFixedSize = true;
GetPropertyData("ModeSelectionMode").AssignGUIComponent(selectionMode);
GetPropertyData(nameof(ModeSelectionMode)).AssignGUIComponent(selectionMode);
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.02f), serverTab.RectTransform), style: "HorizontalLine");
@@ -389,7 +398,7 @@ namespace Barotrauma.Networking
var voiceChatEnabled = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform),
TextManager.Get("ServerSettingsVoiceChatEnabled"));
GetPropertyData("VoiceChatEnabled").AssignGUIComponent(voiceChatEnabled);
GetPropertyData(nameof(VoiceChatEnabled)).AssignGUIComponent(voiceChatEnabled);
//***********************************************
@@ -407,14 +416,14 @@ namespace Barotrauma.Networking
}
};
startIntervalSlider.Range = new Vector2(10.0f, 300.0f);
GetPropertyData("AutoRestartInterval").AssignGUIComponent(startIntervalSlider);
GetPropertyData(nameof(AutoRestartInterval)).AssignGUIComponent(startIntervalSlider);
startIntervalSlider.OnMoved(startIntervalSlider, startIntervalSlider.BarScroll);
//***********************************************
var startWhenClientsReady = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform),
TextManager.Get("ServerSettingsStartWhenClientsReady"));
GetPropertyData("StartWhenClientsReady").AssignGUIComponent(startWhenClientsReady);
GetPropertyData(nameof(StartWhenClientsReady)).AssignGUIComponent(startWhenClientsReady);
CreateLabeledSlider(serverTab, "ServerSettingsStartWhenClientsReadyRatio", out GUIScrollBar slider, out GUITextBlock sliderLabel);
string clientsReadyRequiredLabel = sliderLabel.Text;
@@ -425,19 +434,19 @@ namespace Barotrauma.Networking
((GUITextBlock)scrollBar.UserData).Text = clientsReadyRequiredLabel.Replace("[percentage]", ((int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f)).ToString());
return true;
};
GetPropertyData("StartWhenClientsReadyRatio").AssignGUIComponent(slider);
GetPropertyData(nameof(StartWhenClientsReadyRatio)).AssignGUIComponent(slider);
slider.OnMoved(slider, slider.BarScroll);
//***********************************************
var allowSpecBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsAllowSpectating"));
GetPropertyData("AllowSpectating").AssignGUIComponent(allowSpecBox);
GetPropertyData(nameof(AllowSpectating)).AssignGUIComponent(allowSpecBox);
var shareSubsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsShareSubFiles"));
GetPropertyData("AllowFileTransfers").AssignGUIComponent(shareSubsBox);
GetPropertyData(nameof(AllowFileTransfers)).AssignGUIComponent(shareSubsBox);
var randomizeLevelBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsRandomizeSeed"));
GetPropertyData("RandomizeSeed").AssignGUIComponent(randomizeLevelBox);
GetPropertyData(nameof(RandomizeSeed)).AssignGUIComponent(randomizeLevelBox);
var saveLogsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), serverTab.RectTransform), TextManager.Get("ServerSettingsSaveLogs"))
{
@@ -448,7 +457,7 @@ namespace Barotrauma.Networking
return true;
}
};
GetPropertyData("SaveServerLogs").AssignGUIComponent(saveLogsBox);
GetPropertyData(nameof(SaveServerLogs)).AssignGUIComponent(saveLogsBox);
//--------------------------------------------------------------------------------
// game settings
@@ -480,20 +489,20 @@ namespace Barotrauma.Networking
selectionPlayStyle.AddRadioButton((int)playStyle, selectionTick);
playStyleTickBoxes.Add(selectionTick);
}
GetPropertyData("PlayStyle").AssignGUIComponent(selectionPlayStyle);
GetPropertyData(nameof(PlayStyle)).AssignGUIComponent(selectionPlayStyle);
GUITextBlock.AutoScaleAndNormalize(playStyleTickBoxes.Select(t => t.TextBlock));
playstyleList.RectTransform.MinSize = new Point(0, (int)(playstyleList.Content.Children.First().Rect.Height * 2.0f + playstyleList.Padding.Y + playstyleList.Padding.W));
var endVoteBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
TextManager.Get("ServerSettingsEndRoundVoting"));
GetPropertyData("AllowEndVoting").AssignGUIComponent(endVoteBox);
GetPropertyData(nameof(AllowEndVoting)).AssignGUIComponent(endVoteBox);
CreateLabeledSlider(roundsTab, "ServerSettingsEndRoundVotesRequired", out slider, out sliderLabel);
string endRoundLabel = sliderLabel.Text;
slider.Step = 0.2f;
slider.Range = new Vector2(0.5f, 1.0f);
GetPropertyData("EndVoteRequiredRatio").AssignGUIComponent(slider);
GetPropertyData(nameof(EndVoteRequiredRatio)).AssignGUIComponent(slider);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
((GUITextBlock)scrollBar.UserData).Text = endRoundLabel + " " + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
@@ -503,13 +512,13 @@ namespace Barotrauma.Networking
var respawnBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
TextManager.Get("ServerSettingsAllowRespawning"));
GetPropertyData("AllowRespawn").AssignGUIComponent(respawnBox);
GetPropertyData(nameof(AllowRespawn)).AssignGUIComponent(respawnBox);
CreateLabeledSlider(roundsTab, "ServerSettingsRespawnInterval", out slider, out sliderLabel);
string intervalLabel = sliderLabel.Text;
slider.Range = new Vector2(10.0f, 600.0f);
slider.StepValue = 10.0f;
GetPropertyData("RespawnInterval").AssignGUIComponent(slider);
GetPropertyData(nameof(RespawnInterval)).AssignGUIComponent(slider);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
GUITextBlock text = scrollBar.UserData as GUITextBlock;
@@ -518,18 +527,26 @@ namespace Barotrauma.Networking
};
slider.OnMoved(slider, slider.BarScroll);
var minRespawnText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), "")
var respawnLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), roundsTab.RectTransform),
isHorizontal: true);
var minRespawnLayout
= new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), respawnLayout.RectTransform));
var minRespawnText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), minRespawnLayout.RectTransform), "")
{
ToolTip = TextManager.Get("ServerSettingsMinRespawnToolTip")
};
string minRespawnLabel = TextManager.Get("ServerSettingsMinRespawn") + " ";
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
CreateLabeledSlider(minRespawnLayout, "", out slider, out sliderLabel);
sliderLabel.RectTransform.RelativeSize = Vector2.Zero;
slider.RectTransform.RelativeSize = new Vector2(1.0f, 0.5f);
slider.ToolTip = minRespawnText.RawToolTip;
slider.UserData = minRespawnText;
slider.Step = 0.1f;
slider.Range = new Vector2(0.0f, 1.0f);
GetPropertyData("MinRespawnRatio").AssignGUIComponent(slider);
GetPropertyData(nameof(MinRespawnRatio)).AssignGUIComponent(slider);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
((GUITextBlock)scrollBar.UserData).Text = minRespawnLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
@@ -537,13 +554,18 @@ namespace Barotrauma.Networking
};
slider.OnMoved(slider, MinRespawnRatio);
var respawnDurationText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), "")
var respawnDurationLayout
= new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), respawnLayout.RectTransform));
var respawnDurationText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), respawnDurationLayout.RectTransform), "")
{
ToolTip = TextManager.Get("ServerSettingsRespawnDurationToolTip")
};
string respawnDurationLabel = TextManager.Get("ServerSettingsRespawnDuration") + " ";
CreateLabeledSlider(roundsTab, "", out slider, out sliderLabel);
CreateLabeledSlider(respawnDurationLayout, "", out slider, out sliderLabel);
sliderLabel.RectTransform.RelativeSize = Vector2.Zero;
slider.RectTransform.RelativeSize = new Vector2(1.0f, 0.5f);
slider.ToolTip = respawnDurationText.RawToolTip;
slider.UserData = respawnDurationText;
slider.Step = 0.1f;
@@ -556,7 +578,7 @@ namespace Barotrauma.Networking
{
return value <= 0.0f ? 1.0f : (value - scrollBar.Range.X) / (scrollBar.Range.Y - scrollBar.Range.X);
};
GetPropertyData("MaxTransportTime").AssignGUIComponent(slider);
GetPropertyData(nameof(MaxTransportTime)).AssignGUIComponent(slider);
slider.OnMoved = (GUIScrollBar scrollBar, float barScroll) =>
{
if (barScroll == 1.0f)
@@ -572,14 +594,34 @@ namespace Barotrauma.Networking
};
slider.OnMoved(slider, slider.BarScroll);
var losModeLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform),
TextManager.Get("LosEffect"));
var losModeRadioButtonLayout
= new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), roundsTab.RectTransform),
isHorizontal: true)
{
Stretch = true
};
var losModeRadioButtonGroup = new GUIRadioButtonGroup();
LosMode[] losModes = (LosMode[])Enum.GetValues(typeof(LosMode));
for (int i = 0; i < losModes.Length; i++)
{
var losTick = new GUITickBox(new RectTransform(new Vector2(0.3f, 1.0f), losModeRadioButtonLayout.RectTransform), TextManager.Get($"LosMode{losModes[i]}"), font: GUI.SmallFont, style: "GUIRadioButton");
losModeRadioButtonGroup.AddRadioButton(i, losTick);
}
GetPropertyData(nameof(LosMode)).AssignGUIComponent(losModeRadioButtonGroup);
var traitorsMinPlayerCount = CreateLabeledNumberInput(roundsTab, "ServerSettingsTraitorsMinPlayerCount", 1, 16, "ServerSettingsTraitorsMinPlayerCountToolTip");
GetPropertyData("TraitorsMinPlayerCount").AssignGUIComponent(traitorsMinPlayerCount);
GetPropertyData(nameof(TraitorsMinPlayerCount)).AssignGUIComponent(traitorsMinPlayerCount);
var ragdollButtonBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsAllowRagdollButton"));
GetPropertyData("AllowRagdollButton").AssignGUIComponent(ragdollButtonBox);
GetPropertyData(nameof(AllowRagdollButton)).AssignGUIComponent(ragdollButtonBox);
var disableBotConversationsBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), roundsTab.RectTransform), TextManager.Get("ServerSettingsDisableBotConversations"));
GetPropertyData("DisableBotConversations").AssignGUIComponent(disableBotConversationsBox);
GetPropertyData(nameof(DisableBotConversations)).AssignGUIComponent(disableBotConversationsBox);
var buttonHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.07f), roundsTab.RectTransform), isHorizontal: true)
{
@@ -729,35 +771,35 @@ namespace Barotrauma.Networking
var allowFriendlyFire = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
TextManager.Get("ServerSettingsAllowFriendlyFire"));
GetPropertyData("AllowFriendlyFire").AssignGUIComponent(allowFriendlyFire);
GetPropertyData(nameof(AllowFriendlyFire)).AssignGUIComponent(allowFriendlyFire);
var killableNPCs = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
TextManager.Get("ServerSettingsKillableNPCs"));
GetPropertyData("KillableNPCs").AssignGUIComponent(killableNPCs);
GetPropertyData(nameof(KillableNPCs)).AssignGUIComponent(killableNPCs);
var destructibleOutposts = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
TextManager.Get("ServerSettingsDestructibleOutposts"));
GetPropertyData("DestructibleOutposts").AssignGUIComponent(destructibleOutposts);
GetPropertyData(nameof(DestructibleOutposts)).AssignGUIComponent(destructibleOutposts);
var lockAllDefaultWires = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
TextManager.Get("ServerSettingsLockAllDefaultWires"));
GetPropertyData("LockAllDefaultWires").AssignGUIComponent(lockAllDefaultWires);
GetPropertyData(nameof(LockAllDefaultWires)).AssignGUIComponent(lockAllDefaultWires);
var allowRewiring = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
TextManager.Get("ServerSettingsAllowRewiring"));
GetPropertyData("AllowRewiring").AssignGUIComponent(allowRewiring);
GetPropertyData(nameof(AllowRewiring)).AssignGUIComponent(allowRewiring);
var allowWifiChatter = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
TextManager.Get("ServerSettingsAllowWifiChat"));
GetPropertyData("AllowLinkingWifiToChat").AssignGUIComponent(allowWifiChatter);
GetPropertyData(nameof(AllowLinkingWifiToChat)).AssignGUIComponent(allowWifiChatter);
var allowDisguises = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
TextManager.Get("ServerSettingsAllowDisguises"));
GetPropertyData("AllowDisguises").AssignGUIComponent(allowDisguises);
GetPropertyData(nameof(AllowDisguises)).AssignGUIComponent(allowDisguises);
var voteKickBox = new GUITickBox(new RectTransform(new Vector2(0.48f, 0.05f), tickBoxContainer.Content.RectTransform),
TextManager.Get("ServerSettingsAllowVoteKick"));
GetPropertyData("AllowVoteKick").AssignGUIComponent(voteKickBox);
GetPropertyData(nameof(AllowVoteKick)).AssignGUIComponent(voteKickBox);
GUITextBlock.AutoScaleAndNormalize(tickBoxContainer.Content.Children.Select(c => ((GUITickBox)c).TextBlock));
@@ -772,7 +814,7 @@ namespace Barotrauma.Networking
((GUITextBlock)scrollBar.UserData).Text = votesRequiredLabel + (int)MathUtils.Round(scrollBar.BarScrollValue * 100.0f, 10.0f) + " %";
return true;
};
GetPropertyData("KickVoteRequiredRatio").AssignGUIComponent(slider);
GetPropertyData(nameof(KickVoteRequiredRatio)).AssignGUIComponent(slider);
slider.OnMoved(slider, slider.BarScroll);
CreateLabeledSlider(antigriefingTab, "ServerSettingsAutobanTime", out slider, out sliderLabel);
@@ -784,13 +826,13 @@ namespace Barotrauma.Networking
((GUITextBlock)scrollBar.UserData).Text = autobanLabel + ToolBox.SecondsToReadableTime(scrollBar.BarScrollValue);
return true;
};
GetPropertyData("AutoBanTime").AssignGUIComponent(slider);
GetPropertyData(nameof(AutoBanTime)).AssignGUIComponent(slider);
slider.OnMoved(slider, slider.BarScroll);
var wrongPasswordBanBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform), TextManager.Get("ServerSettingsBanAfterWrongPassword"));
GetPropertyData("BanAfterWrongPassword").AssignGUIComponent(wrongPasswordBanBox);
GetPropertyData(nameof(BanAfterWrongPassword)).AssignGUIComponent(wrongPasswordBanBox);
var allowedPasswordRetries = CreateLabeledNumberInput(antigriefingTab, "ServerSettingsPasswordRetriesBeforeBan", 0, 10);
GetPropertyData("MaxPasswordRetriesBeforeBan").AssignGUIComponent(allowedPasswordRetries);
GetPropertyData(nameof(MaxPasswordRetriesBeforeBan)).AssignGUIComponent(allowedPasswordRetries);
wrongPasswordBanBox.OnSelected += (tb) =>
{
allowedPasswordRetries.Enabled = tb.Selected;
@@ -800,7 +842,7 @@ namespace Barotrauma.Networking
// karma --------------------------------------------------------------------------
var karmaBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform), TextManager.Get("ServerSettingsUseKarma"));
GetPropertyData("KarmaEnabled").AssignGUIComponent(karmaBox);
GetPropertyData(nameof(KarmaEnabled)).AssignGUIComponent(karmaBox);
karmaPresetDD = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), antigriefingTab.RectTransform));
foreach (string karmaPreset in GameMain.NetworkMember.KarmaManager.Presets.Keys)

View File

@@ -935,7 +935,7 @@ namespace Barotrauma.Steam
return workshopPublishStatus;
}
private static IEnumerable<object> PublishItem(WorkshopPublishStatus workshopPublishStatus)
private static IEnumerable<CoroutineStatus> PublishItem(WorkshopPublishStatus workshopPublishStatus)
{
if (!isInitialized)
{

View File

@@ -66,10 +66,10 @@ namespace Barotrauma
if (clients == null) { return; }
List<Pair<object, int>> voteList = GetVoteList(voteType, clients);
foreach (Pair<object, int> votable in voteList)
IReadOnlyDictionary<object, int> voteList = GetVoteCounts<object>(voteType, clients);
foreach (KeyValuePair<object, int> votable in voteList)
{
SetVoteText(listBox, votable.First, votable.Second);
SetVoteText(listBox, votable.Key, votable.Value);
}
break;
case VoteType.StartRound:

View File

@@ -106,8 +106,12 @@ namespace Barotrauma.Particles
public void Init(ParticlePrefab prefab, Vector2 position, Vector2 speed, float rotation, Hull hullGuess = null, bool drawOnTop = false, float collisionIgnoreTimer = 0f, Tuple<Vector2, Vector2> tracerPoints = null)
{
this.prefab = prefab;
#if DEBUG
debugName = $"Particle ({prefab.Name})";
#else
//don't instantiate new string objects in release builds
debugName = prefab.Name;
#endif
spriteIndex = Rand.Int(prefab.Sprites.Count);
animState = 0;

View File

@@ -188,11 +188,14 @@ namespace Barotrauma.Particles
var particlePrefab = overrideParticle ?? Prefab.ParticlePrefab;
if (particlePrefab == null) { return; }
angle += Rand.Range(Prefab.Properties.AngleMinRad, Prefab.Properties.AngleMaxRad);
Vector2 dir = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
Vector2 velocity = dir * Rand.Range(Prefab.Properties.VelocityMin, Prefab.Properties.VelocityMax) * velocityMultiplier;
position += dir * Rand.Range(Prefab.Properties.DistanceMin, Prefab.Properties.DistanceMax);
Vector2 velocity = Vector2.Zero;
if (!MathUtils.NearlyEqual(Prefab.Properties.VelocityMax * velocityMultiplier, 0.0f) || !MathUtils.NearlyEqual(Prefab.Properties.DistanceMax, 0.0f))
{
angle += Rand.Range(Prefab.Properties.AngleMinRad, Prefab.Properties.AngleMaxRad);
Vector2 dir = new Vector2((float)Math.Cos(angle), (float)Math.Sin(angle));
velocity = dir * Rand.Range(Prefab.Properties.VelocityMin, Prefab.Properties.VelocityMax) * velocityMultiplier;
position += dir * Rand.Range(Prefab.Properties.DistanceMin, Prefab.Properties.DistanceMax);
}
var particle = GameMain.ParticleManager.CreateParticle(particlePrefab, position, velocity, particleRotation, hullGuess, Prefab.DrawOnTop, tracerPoints: tracerPoints);

View File

@@ -167,8 +167,8 @@ namespace Barotrauma.Particles
if (minPos.X > expandedViewRect.Right || maxPos.X < expandedViewRect.X) { return null; }
if (minPos.Y > expandedViewRect.Y || maxPos.Y < expandedViewRect.Y - expandedViewRect.Height) { return null; }
if (particles[particleCount] == null) particles[particleCount] = new Particle();
if (particles[particleCount] == null) { particles[particleCount] = new Particle(); }
particles[particleCount].Init(prefab, position, velocity, rotation, hullGuess, drawOnTop, collisionIgnoreTimer, tracerPoints: tracerPoints);

View File

@@ -255,7 +255,7 @@ namespace Barotrauma
File.WriteAllText(filePath, crashReport);
if (GameSettings.SaveDebugConsoleLogs) DebugConsole.SaveLogs();
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
if (GameSettings.SendUserStatistics)
{

View File

@@ -271,7 +271,7 @@ namespace Barotrauma
}
}
private IEnumerable<object> WaitForCampaignSetup()
private IEnumerable<CoroutineStatus> WaitForCampaignSetup()
{
GUI.SetCursorWaiting();
string headerText = TextManager.Get("CampaignStartingPleaseWait");

View File

@@ -1802,9 +1802,11 @@ namespace Barotrauma.CharacterEditor
{
case AnimationType.Walk:
case AnimationType.Run:
case AnimationType.Crouch:
if (!ragdollParams.CanWalk) { continue; }
break;
case AnimationType.Crouch:
if (!ragdollParams.CanWalk || !isHumanoid) { continue; }
break;
case AnimationType.SwimSlow:
case AnimationType.SwimFast:
break;
@@ -2690,7 +2692,15 @@ namespace Barotrauma.CharacterEditor
characterDropDown.SelectItem(currentCharacterConfig);
characterDropDown.OnSelected = (component, data) =>
{
SpawnCharacter((string)data);
string configFile = (string)data;
try
{
SpawnCharacter(configFile);
}
catch (Exception e)
{
HandleSpawnException(configFile, e);
}
return true;
};
if (currentCharacterConfig == CharacterPrefab.HumanConfigFile)
@@ -2719,19 +2729,48 @@ namespace Barotrauma.CharacterEditor
prevCharacterButton.TextBlock.AutoScaleHorizontal = true;
prevCharacterButton.OnClicked += (b, obj) =>
{
SpawnCharacter(GetPreviousConfigFile());
string configFile = GetPreviousConfigFile();
try
{
SpawnCharacter(configFile);
}
catch (Exception e)
{
HandleSpawnException(configFile, e);
}
return true;
};
var nextCharacterButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), charButtons.RectTransform, Anchor.TopRight), GetCharacterEditorTranslation("NextCharacter"));
prevCharacterButton.TextBlock.AutoScaleHorizontal = true;
nextCharacterButton.OnClicked += (b, obj) =>
{
SpawnCharacter(GetNextConfigFile());
string configFile = GetNextConfigFile();
try
{
SpawnCharacter(configFile);
}
catch (Exception e)
{
HandleSpawnException(configFile, e);
}
return true;
};
charButtons.RectTransform.MinSize = new Point(0, prevCharacterButton.RectTransform.MinSize.Y);
characterPanelToggle = new ToggleButton(new RectTransform(new Vector2(0.08f, 1), characterSelectionPanel.RectTransform, Anchor.CenterLeft, Pivot.CenterRight), Direction.Right);
characterSelectionPanel.RectTransform.MinSize = new Point(0, (int)(content.RectTransform.Children.Sum(c => c.MinSize.Y) * 1.2f));
void HandleSpawnException(string configFile, Exception e)
{
if (configFile != CharacterPrefab.HumanConfigFile)
{
DebugConsole.ThrowError($"Failed to spawn the character \"{configFile}\".", e);
SpawnCharacter(CharacterPrefab.HumanConfigFile);
}
else
{
throw new Exception($"Failed to spawn the character \"{configFile}\".", innerException: e);
}
}
}
private void CreateFileEditPanel()

View File

@@ -143,9 +143,33 @@ namespace Barotrauma
editorContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 1.0f), paddedRightPanel.RectTransform));
var seedContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), isHorizontal: true);
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), TextManager.Get("leveleditor.levelseed"));
seedBox = new GUITextBox(new RectTransform(new Vector2(0.5f, 1.0f), seedContainer.RectTransform), ToolBox.RandomSeed(8));
var seedContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.04f), paddedRightPanel.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
Vector2 randomizeButtonRelativeSize = GetRandomizeButtonRelativeSize();
Vector2 elementRelativeSize = GetSeedElementRelativeSize();
var seedLabel = new GUITextBlock(new RectTransform(elementRelativeSize, seedContainer.RectTransform), TextManager.Get("leveleditor.levelseed"));
seedBox = new GUITextBox(new RectTransform(elementRelativeSize, seedContainer.RectTransform), GetLevelSeed());
var seedButton = new GUIButton(new RectTransform(randomizeButtonRelativeSize, seedContainer.RectTransform), style: "RandomizeButton")
{
OnClicked = (button, userData) =>
{
if(seedBox == null) { return false; }
seedBox.Text = GetLevelSeed();
return true;
}
};
seedContainer.RectTransform.SizeChanged += () =>
{
Vector2 randomizeButtonRelativeSize = GetRandomizeButtonRelativeSize();
Vector2 elementRelativeSize = GetSeedElementRelativeSize();
seedLabel.RectTransform.RelativeSize = elementRelativeSize;
seedBox.RectTransform.RelativeSize = elementRelativeSize;
seedButton.RectTransform.RelativeSize = randomizeButtonRelativeSize;
};
Vector2 GetRandomizeButtonRelativeSize() => 0.2f * seedContainer.Rect.Width > seedContainer.Rect.Height ?
new Vector2(Math.Min((float)seedContainer.Rect.Height / seedContainer.Rect.Width, 0.2f), 1.0f) :
new Vector2(0.15f, Math.Min((0.2f * seedContainer.Rect.Width) / seedContainer.Rect.Height, 1.0f));
Vector2 GetSeedElementRelativeSize() => new Vector2(0.5f * (1.0f - randomizeButtonRelativeSize.X), 1.0f);
static string GetLevelSeed() => ToolBox.RandomSeed(8);
mirrorLevel = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), TextManager.Get("mirrorentityx"));

View File

@@ -679,7 +679,7 @@ namespace Barotrauma
return true;
}
private IEnumerable<object> SelectScreenWithWaitCursor(Screen screen)
private IEnumerable<CoroutineStatus> SelectScreenWithWaitCursor(Screen screen)
{
GUI.SetCursorWaiting();
//tiny delay to get the cursor to render
@@ -719,7 +719,7 @@ namespace Barotrauma
}
#endregion
public void QuickStart(bool fixedSeed = false, string sub = null)
public void QuickStart(bool fixedSeed = false, string sub = null, float difficulty = 40, LevelGenerationParams levelGenerationParams = null)
{
if (fixedSeed)
{
@@ -751,7 +751,7 @@ namespace Barotrauma
GameModePreset.DevSandbox,
missionPrefabs: null);
//(gamesession.GameMode as SinglePlayerCampaign).GenerateMap(ToolBox.RandomSeed(8));
gamesession.StartRound(fixedSeed ? "abcd" : ToolBox.RandomSeed(8), difficulty: 40);
gamesession.StartRound(fixedSeed ? "abcd" : ToolBox.RandomSeed(8), difficulty, levelGenerationParams);
GameMain.GameScreen.Select();
// TODO: modding support
string[] jobIdentifiers = new string[] { "captain", "engineer", "mechanic", "securityofficer", "medicaldoctor" };
@@ -890,7 +890,7 @@ namespace Barotrauma
}
}
private IEnumerable<object> WaitForSubmarineHashCalculations(GUIMessageBox messageBox)
private IEnumerable<CoroutineStatus> WaitForSubmarineHashCalculations(GUIMessageBox messageBox)
{
string originalText = messageBox.Text.Text;
int doneCount = 0;
@@ -1452,7 +1452,7 @@ namespace Barotrauma
}
}
private IEnumerable<object> WairForRemoteContentReceived()
private IEnumerable<CoroutineStatus> WairForRemoteContentReceived()
{
while (true)
{

View File

@@ -18,9 +18,7 @@ namespace Barotrauma
private readonly GUILayoutGroup infoFrameContent;
private readonly GUIFrame myCharacterFrame;
private readonly GUIListBox subList, modeList;
private readonly GUIListBox chatBox, playerList;
private readonly GUIListBox chatBox;
private readonly GUIButton serverLogReverseButton;
private readonly GUIListBox serverLogBox, serverLogFilterTicks;
@@ -73,7 +71,8 @@ namespace Barotrauma
private readonly GUIComponent gameModeContainer;
private readonly GUIButton spectateButton;
private readonly GUILayoutGroup roundControlsHolder;
public GUIButton SettingsButton { get; private set; }
public readonly GUIButton SettingsButton;
public static GUIButton JobInfoFrame;
private readonly GUITickBox spectateBox;
@@ -85,12 +84,15 @@ namespace Barotrauma
private bool createPendingChangesText = true;
public GUIButton PlayerFrame;
public readonly GUIButton SubVisibilityButton;
private readonly GUITextBox subSearchBox;
private readonly GUIComponent subPreviewContainer;
private readonly GUITickBox autoRestartBox;
private readonly GUITextBlock autoRestartText;
private readonly GUIDropDown shuttleList;
private readonly GUITickBox shuttleTickBox;
private readonly GUIComponent settingsBlocker;
@@ -161,20 +163,11 @@ namespace Barotrauma
private readonly GUITextBlock publicOrPrivate;
public GUIListBox SubList
{
get { return subList; }
}
public readonly GUIListBox SubList;
public GUIDropDown ShuttleList
{
get { return shuttleList; }
}
public readonly GUIDropDown ShuttleList;
public GUIListBox ModeList
{
get { return modeList; }
}
public readonly GUIListBox ModeList;
private int selectedModeIndex;
public int SelectedModeIndex
@@ -184,7 +177,7 @@ namespace Barotrauma
{
if (HighlightedModeIndex == selectedModeIndex)
{
modeList.Select(value);
ModeList.Select(value);
}
selectedModeIndex = value;
}
@@ -192,17 +185,14 @@ namespace Barotrauma
public int HighlightedModeIndex
{
get { return modeList.SelectedIndex; }
get { return ModeList.SelectedIndex; }
set
{
modeList.Select(value, true);
ModeList.Select(value, true);
}
}
public GUIListBox PlayerList
{
get { return playerList; }
}
public readonly GUIListBox PlayerList;
public GUITextBox CharacterNameBox
{
@@ -228,16 +218,9 @@ namespace Barotrauma
private set;
}
public SubmarineInfo SelectedSub
{
get { return subList.SelectedData as SubmarineInfo; }
set { subList.Select(value); }
}
public SubmarineInfo SelectedSub => SubList.SelectedData as SubmarineInfo;
public SubmarineInfo SelectedShuttle
{
get { return shuttleList.SelectedData as SubmarineInfo; }
}
public SubmarineInfo SelectedShuttle => ShuttleList.SelectedData as SubmarineInfo;
public MultiPlayerCampaignSetupUI CampaignSetupUI;
public List<SubmarineInfo> CampaignSubmarines = new List<SubmarineInfo>();
@@ -253,7 +236,7 @@ namespace Barotrauma
public GameModePreset SelectedMode
{
get { return modeList.SelectedData as GameModePreset; }
get { return ModeList.SelectedData as GameModePreset; }
}
public MissionType MissionType
@@ -529,7 +512,7 @@ namespace Barotrauma
//player list ------------------------------------------------------------------
playerList = new GUIListBox(new RectTransform(new Vector2(0.4f, 1.0f), socialHolderHorizontal.RectTransform))
PlayerList = new GUIListBox(new RectTransform(new Vector2(0.4f, 1.0f), socialHolderHorizontal.RectTransform))
{
OnSelected = (component, userdata) => { SelectPlayer(userdata as Client); return true; }
};
@@ -737,25 +720,65 @@ namespace Barotrauma
};
var serverMessageContainer = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.75f), serverInfoHolder.RectTransform));
ServerMessage = new GUITextBox(new RectTransform(Vector2.One, serverMessageContainer.Content.RectTransform), style: "GUITextBoxNoBorder")
ServerMessage = new GUITextBox(new RectTransform(Vector2.One, serverMessageContainer.Content.RectTransform),
style: "GUITextBoxNoBorder", wrap: true, textAlignment: Alignment.TopLeft);
var serverMessageHint = new GUITextBlock(new RectTransform(Vector2.One, ServerMessage.RectTransform),
textColor: Color.DarkGray * 0.6f, textAlignment: Alignment.TopLeft, font: GUI.Style.Font, text: TextManager.Get("ClickToWriteServerMessage"));
void updateServerMessageScrollBasedOnCaret()
{
Wrap = true
float caretY = ServerMessage.CaretScreenPos.Y;
float bottomCaretExtent = ServerMessage.Font.LineHeight * 1.5f;
float topCaretExtent = -ServerMessage.Font.LineHeight * 0.5f;
if (caretY + bottomCaretExtent > serverMessageContainer.Rect.Bottom)
{
serverMessageContainer.ScrollBar.BarScroll
= (caretY - ServerMessage.Rect.Top - serverMessageContainer.Rect.Height + bottomCaretExtent)
/ (ServerMessage.Rect.Height - serverMessageContainer.Rect.Height);
}
else if (caretY + topCaretExtent < serverMessageContainer.Rect.Top)
{
serverMessageContainer.ScrollBar.BarScroll
= (caretY - ServerMessage.Rect.Top + topCaretExtent)
/ (ServerMessage.Rect.Height - serverMessageContainer.Rect.Height);
}
}
ServerMessage.OnSelected += (textBox, key) =>
{
serverMessageHint.Visible = false;
updateServerMessageScrollBasedOnCaret();
};
ServerMessage.OnTextChanged += (textBox, text) =>
{
Vector2 textSize = textBox.Font.MeasureString(textBox.WrappedText);
textBox.RectTransform.NonScaledSize = new Point(textBox.RectTransform.NonScaledSize.X, Math.Max(serverMessageContainer.Content.Rect.Height, (int)textSize.Y + 10));
serverMessageContainer.UpdateScrollBarSize();
serverMessageContainer.BarScroll = 1.0f;
serverMessageHint.Visible = !textBox.Selected && !textBox.Readonly && string.IsNullOrWhiteSpace(textBox.Text);
return true;
};
ServerMessage.OnEnterPressed += (textBox, text) =>
{
string str = textBox.Text;
int caretIndex = textBox.CaretIndex;
textBox.Text = $"{str[..caretIndex]}\n{str[caretIndex..]}";
textBox.CaretIndex = caretIndex + 1;
return true;
};
ServerMessage.OnDeselected += (textBox, key) =>
{
if (!textBox.Readonly)
{
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Message);
GameMain.Client?.ServerSettings?.ClientAdminWrite(ServerSettings.NetFlags.Message);
}
serverMessageHint.Visible = !textBox.Readonly && string.IsNullOrWhiteSpace(textBox.Text);
};
ServerMessage.OnKeyHit += (sender, key) => updateServerMessageScrollBasedOnCaret();
clientHiddenElements.Add(serverMessageHint);
clientReadonlyElements.Add(ServerMessage);
//submarine list ------------------------------------------------------------------
@@ -768,26 +791,36 @@ namespace Barotrauma
var subLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.055f), subHolder.RectTransform) { MinSize = new Point(0, 25) }, TextManager.Get("Submarine"), font: GUI.SubHeadingFont);
SubVisibilityButton
= new GUIButton(
new RectTransform(Vector2.One * 1.2f, subLabel.RectTransform, anchor: Anchor.CenterRight,
scaleBasis: ScaleBasis.BothHeight),
style: "EyeButton")
{
OnClicked = (button, o) =>
{
CreateSubmarineVisibilityMenu();
return false;
}
};
clientHiddenElements.Add(SubVisibilityButton);
var filterContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), subHolder.RectTransform), isHorizontal: true)
{
Stretch = true
};
var searchTitle = new GUITextBlock(new RectTransform(new Vector2(0.001f, 1.0f), filterContainer.RectTransform), TextManager.Get("serverlog.filter"), textAlignment: Alignment.CenterLeft, font: GUI.Font);
var searchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
filterContainer.RectTransform.MinSize = searchBox.RectTransform.MinSize;
searchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
searchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
searchBox.OnTextChanged += (textBox, text) =>
subSearchBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 1.0f), filterContainer.RectTransform, Anchor.CenterRight), font: GUI.Font, createClearButton: true);
filterContainer.RectTransform.MinSize = subSearchBox.RectTransform.MinSize;
subSearchBox.OnSelected += (sender, userdata) => { searchTitle.Visible = false; };
subSearchBox.OnDeselected += (sender, userdata) => { searchTitle.Visible = true; };
subSearchBox.OnTextChanged += (textBox, text) =>
{
foreach (GUIComponent child in subList.Content.Children)
{
if (!(child.UserData is SubmarineInfo sub)) { continue; }
child.Visible = string.IsNullOrEmpty(text) || sub.DisplayName.ToLower().Contains(text.ToLower());
}
UpdateSubVisibility();
return true;
};
subList = new GUIListBox(new RectTransform(Vector2.One, subHolder.RectTransform))
SubList = new GUIListBox(new RectTransform(Vector2.One, subHolder.RectTransform))
{
OnSelected = VotableClicked
};
@@ -832,7 +865,7 @@ namespace Barotrauma
shuttleTickBox.TextBlock.TextScale = 1.0f;
}
};
shuttleList = new GUIDropDown(new RectTransform(Vector2.One, shuttleHolder.RectTransform), elementCount: 10)
ShuttleList = new GUIDropDown(new RectTransform(Vector2.One, shuttleHolder.RectTransform), elementCount: 10)
{
OnSelected = (component, obj) =>
{
@@ -840,8 +873,8 @@ namespace Barotrauma
return true;
}
};
shuttleList.ListBox.RectTransform.MinSize = new Point(250, 0);
shuttleHolder.RectTransform.MinSize = new Point(0, shuttleList.RectTransform.Children.Max(c => c.MinSize.Y));
ShuttleList.ListBox.RectTransform.MinSize = new Point(250, 0);
shuttleHolder.RectTransform.MinSize = new Point(0, ShuttleList.RectTransform.Children.Max(c => c.MinSize.Y));
subPreviewContainer = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.9f), rightColumn.RectTransform), style: null);
subPreviewContainer.RectTransform.SizeChanged += () =>
@@ -871,7 +904,7 @@ namespace Barotrauma
UserData = "modevotes",
Visible = false
};
modeList = new GUIListBox(new RectTransform(Vector2.One, gameModeHolder.RectTransform))
ModeList = new GUIListBox(new RectTransform(Vector2.One, gameModeHolder.RectTransform))
{
OnSelected = VotableClicked
};
@@ -880,7 +913,7 @@ namespace Barotrauma
{
if (mode.IsSinglePlayer) { continue; }
var modeFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.15f), modeList.Content.RectTransform), style: null)
var modeFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.15f), ModeList.Content.RectTransform), style: null)
{
UserData = mode
};
@@ -938,7 +971,7 @@ namespace Barotrauma
{
OnClicked = (_, __) =>
{
GameMain.Client.RequestSelectMode(modeList.Content.GetChildIndex(modeList.Content.GetChildByUserData(GameModePreset.Sandbox)));
GameMain.Client.RequestSelectMode(ModeList.Content.GetChildIndex(ModeList.Content.GetChildByUserData(GameModePreset.Sandbox)));
return true;
}
};
@@ -1221,7 +1254,7 @@ namespace Barotrauma
GUI.ClearCursorWait();
}
public IEnumerable<object> WaitForStartRound(GUIButton startButton)
public IEnumerable<CoroutineStatus> WaitForStartRound(GUIButton startButton)
{
GUI.SetCursorWaiting();
string headerText = TextManager.Get("RoundStartingPleaseWait");
@@ -1264,6 +1297,8 @@ namespace Barotrauma
{
if (GameMain.NetworkMember == null) { return; }
visibilityMenuOrder.Clear();
CharacterAppearanceCustomizationMenu?.Dispose();
JobSelectionFrame = null;
@@ -1362,7 +1397,7 @@ namespace Barotrauma
ServerMessage.Readonly = !GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
shuttleTickBox.Enabled = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
SubList.Enabled = !CampaignFrame.Visible && (GameMain.Client.ServerSettings.Voting.AllowSubVoting || GameMain.Client.HasPermission(ClientPermissions.SelectSub));
shuttleList.Enabled = shuttleList.ButtonEnabled = GameMain.Client.HasPermission(ClientPermissions.SelectSub);
ShuttleList.Enabled = ShuttleList.ButtonEnabled = GameMain.Client.HasPermission(ClientPermissions.SelectSub);
ModeList.Enabled = GameMain.Client.ServerSettings.Voting.AllowModeVoting || GameMain.Client.HasPermission(ClientPermissions.SelectMode);
LogButtons.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
GameMain.Client.ShowLogButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ServerLog);
@@ -1370,6 +1405,8 @@ namespace Barotrauma
roundControlsHolder.Children.ForEach(c => c.RectTransform.RelativeSize = Vector2.One);
roundControlsHolder.Recalculate();
SubVisibilityButton.Visible = GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
ReadyToStartBox.Parent.Visible = !GameMain.Client.GameStarted;
RefreshGameModeContent();
@@ -1557,7 +1594,7 @@ namespace Barotrauma
};
}
UpdateJobPreferences();
UpdateJobPreferences(characterInfo);
appearanceFrame = new GUIFrame(new RectTransform(Vector2.One, characterInfoFrame.RectTransform), style: "GUIFrameListBox")
{
@@ -1853,7 +1890,7 @@ namespace Barotrauma
}
else
{
if (subList == shuttleList || subList == shuttleList.ListBox || subList == shuttleList.ListBox.Content)
if (subList == ShuttleList || subList == ShuttleList.ListBox || subList == ShuttleList.ListBox.Content)
{
subTextBlock.TextColor = new Color(subTextBlock.TextColor, sub.HasTag(SubmarineTag.Shuttle) ? 1.0f : 0.6f);
}
@@ -1865,9 +1902,22 @@ namespace Barotrauma
frame.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + frame.RawToolTip;
}
CreateSubmarineClassText(
frame,
sub,
subTextBlock,
subList);
}
private void CreateSubmarineClassText(
GUIComponent parent,
SubmarineInfo sub,
GUITextBlock subTextBlock,
GUIComponent subList)
{
if (sub.HasTag(SubmarineTag.Shuttle))
{
var shuttleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(GUI.IntScale(20), 0) },
var shuttleText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), parent.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(GUI.IntScale(20), 0) },
TextManager.Get("Shuttle", fallBackTag: "RespawnShuttle"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
{
TextColor = subTextBlock.TextColor * 0.8f,
@@ -1875,10 +1925,10 @@ namespace Barotrauma
CanBeFocused = false
};
//make shuttles more dim in the sub list (selecting a shuttle as the main sub is allowed but not recommended)
if (subList == this.subList.Content)
if (subList == this.SubList.Content)
{
subTextBlock.TextColor *= 0.8f;
foreach (GUIComponent child in frame.Children)
foreach (GUIComponent child in parent.Children)
{
child.Color *= 0.8f;
}
@@ -1886,17 +1936,17 @@ namespace Barotrauma
}
else
{
var classText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(GUI.IntScale(20), 0) },
TextManager.Get($"submarineclass.{sub.SubmarineClass}"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
var classText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), parent.RectTransform, Anchor.CenterRight) { AbsoluteOffset = new Point(GUI.IntScale(20), 0) },
TextManager.Get($"submarineclass.{sub.SubmarineClass}"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
{
UserData = "classtext",
TextColor = subTextBlock.TextColor * 0.8f,
ToolTip = subTextBlock.RawToolTip
ToolTip = subTextBlock.RawToolTip,
CanBeFocused = false
};
}
}
public bool VotableClicked(GUIComponent component, object userData)
{
if (GameMain.Client == null) { return false; }
@@ -1995,7 +2045,7 @@ namespace Barotrauma
public void AddPlayer(Client client)
{
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), playerList.Content.RectTransform) { MinSize = new Point(0, (int)(30 * GUI.Scale)) },
GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), PlayerList.Content.RectTransform) { MinSize = new Point(0, (int)(30 * GUI.Scale)) },
client.Name, textAlignment: Alignment.CenterLeft, font: GUI.SmallFont, style: null)
{
Padding = Vector4.One * 10.0f * GUI.Scale,
@@ -2109,8 +2159,8 @@ namespace Barotrauma
public void RemovePlayer(Client client)
{
GUIComponent child = playerList.Content.GetChildByUserData(client);
if (child != null) { playerList.RemoveChild(child); }
GUIComponent child = PlayerList.Content.GetChildByUserData(client);
if (child != null) { PlayerList.RemoveChild(child); }
}
public void SelectPlayer(GUITextBlock component, GUITextBlock.ClickableArea area)
@@ -2459,7 +2509,7 @@ namespace Barotrauma
private bool ClosePlayerFrame(GUIButton button, object userData)
{
PlayerFrame = null;
playerList.Deselect();
PlayerList.Deselect();
return true;
}
@@ -2520,7 +2570,7 @@ namespace Barotrauma
GUI.Style.Apply(micIcon, targetMicStyle);
}
foreach (GUIComponent child in playerList.Content.Children)
foreach (GUIComponent child in PlayerList.Content.Children)
{
if (child.UserData is Client client)
{
@@ -2752,13 +2802,13 @@ namespace Barotrauma
appearanceFrame.ClearChildren();
var info = GameMain.Client.CharacterInfo;
var info = GameMain.Client.CharacterInfo ?? Character.Controlled?.Info;
CharacterAppearanceCustomizationMenu = new CharacterInfo.AppearanceCustomizationMenu(info, appearanceFrame)
{
OnHeadSwitch = menu =>
{
StoreHead(true);
UpdateJobPreferences();
UpdateJobPreferences(info);
SelectAppearanceTab(button, _);
},
OnSliderMoved = (bar, scroll) =>
@@ -2818,7 +2868,7 @@ namespace Barotrauma
}
}
UpdateJobPreferences();
UpdateJobPreferences(GameMain.Client.CharacterInfo ?? Character.Controlled?.Info);
if (moveToNext)
{
@@ -3014,16 +3064,16 @@ namespace Barotrauma
public void SelectMode(int modeIndex)
{
if (modeIndex < 0 || modeIndex >= modeList.Content.CountChildren) { return; }
if (modeIndex < 0 || modeIndex >= ModeList.Content.CountChildren) { return; }
if ((GameModePreset)modeList.Content.GetChild(modeIndex).UserData != GameModePreset.MultiPlayerCampaign)
if ((GameModePreset)ModeList.Content.GetChild(modeIndex).UserData != GameModePreset.MultiPlayerCampaign)
{
ToggleCampaignMode(false);
}
var prevMode = modeList.Content.GetChild(selectedModeIndex).UserData as GameModePreset;
var prevMode = ModeList.Content.GetChild(selectedModeIndex).UserData as GameModePreset;
if ((HighlightedModeIndex == selectedModeIndex || HighlightedModeIndex < 0) && modeList.SelectedIndex != modeIndex) { modeList.Select(modeIndex, true); }
if ((HighlightedModeIndex == selectedModeIndex || HighlightedModeIndex < 0) && ModeList.SelectedIndex != modeIndex) { ModeList.Select(modeIndex, true); }
selectedModeIndex = modeIndex;
if ((prevMode == GameModePreset.PvP) != (SelectedMode == GameModePreset.PvP))
@@ -3043,7 +3093,7 @@ namespace Barotrauma
public void HighlightMode(int modeIndex)
{
if (modeIndex < 0 || modeIndex >= modeList.Content.CountChildren) { return; }
if (modeIndex < 0 || modeIndex >= ModeList.Content.CountChildren) { return; }
HighlightedModeIndex = modeIndex;
RefreshGameModeContent();
@@ -3139,7 +3189,7 @@ namespace Barotrauma
RefreshEnabledElements();
if (enabled)
{
modeList.Select(GameModePreset.MultiPlayerCampaign, true);
ModeList.Select(GameModePreset.MultiPlayerCampaign, true);
}
}
@@ -3147,17 +3197,17 @@ namespace Barotrauma
{
string name = submarine?.Name;
bool displayed = false;
subList.OnSelected -= VotableClicked;
subList.Deselect();
SubList.OnSelected -= VotableClicked;
SubList.Deselect();
subPreviewContainer.ClearChildren();
foreach (GUIComponent child in subList.Content.Children)
foreach (GUIComponent child in SubList.Content.Children)
{
if (!(child.UserData is SubmarineInfo sub)) { continue; }
//just check the name, even though the campaign sub may not be the exact same version
//we're selecting the sub just for show, the selection is not actually used for anything
if (sub.Name == name)
{
subList.Select(sub);
SubList.Select(sub);
if (SubmarineInfo.SavedSubmarines.Contains(sub))
{
CreateSubPreview(sub);
@@ -3166,7 +3216,7 @@ namespace Barotrauma
break;
}
}
subList.OnSelected += VotableClicked;
SubList.OnSelected += VotableClicked;
if (!displayed)
{
CreateSubPreview(submarine);
@@ -3194,11 +3244,13 @@ namespace Barotrauma
return true;
}
private void UpdateJobPreferences()
private void UpdateJobPreferences(CharacterInfo characterInfo)
{
if (characterInfo == null) { return; }
GUICustomComponent characterIcon = JobPreferenceContainer.GetChild<GUICustomComponent>();
JobPreferenceContainer.RemoveChild(characterIcon);
GameMain.Client.CharacterInfo.CreateIcon(new RectTransform(new Vector2(1.0f, 0.4f), JobPreferenceContainer.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.025f) });
characterInfo.CreateIcon(new RectTransform(new Vector2(1.0f, 0.4f), JobPreferenceContainer.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.025f) });
GUIListBox listBox = JobPreferenceContainer.GetChild<GUIListBox>();
/*foreach (Sprite sprite in jobPreferenceSprites) { sprite.Remove(); }
@@ -3231,7 +3283,7 @@ namespace Barotrauma
variantButton.OnClicked = (btn, obj) =>
{
btn.Parent.UserData = obj;
UpdateJobPreferences();
UpdateJobPreferences(characterInfo);
return false;
};
}
@@ -3340,7 +3392,7 @@ namespace Barotrauma
//matching sub found and already selected, all good
if (sub != null)
{
if (subList == this.subList)
if (subList == this.SubList)
{
CreateSubPreview(sub);
}
@@ -3533,6 +3585,249 @@ namespace Barotrauma
}
}
private List<SubmarineInfo> visibilityMenuOrder = new List<SubmarineInfo>();
private void CreateSubmarineVisibilityMenu()
{
var messageBox = new GUIMessageBox(TextManager.Get("SubmarineVisibility"), "",
buttons: Array.Empty<string>(),
relativeSize: new Vector2(0.75f, 0.75f));
messageBox.Content.ChildAnchor = Anchor.TopCenter;
var columns = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.9f), messageBox.Content.RectTransform), isHorizontal: true);
GUILayoutGroup createColumn(float width)
=> new GUILayoutGroup(new RectTransform(new Vector2(width, 1.0f), columns.RectTransform))
{ Stretch = true };
GUIListBox createColumnListBox(string labelTag)
{
var column = createColumn(0.45f);
var label = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.1f), column.RectTransform),
TextManager.Get(labelTag), textAlignment: Alignment.Center);
return new GUIListBox(new RectTransform(new Vector2(1.0f, 0.9f), column.RectTransform))
{
CurrentSelectMode = GUIListBox.SelectMode.RequireShiftToSelectMultiple,
CurrentDragMode = GUIListBox.DragMode.DragOutsideBox,
HideDraggedElement = true
};
}
void handleDraggingAcrossLists(GUIListBox from, GUIListBox to)
{
//TODO: put this in a static class once modding-refactor gets merged
if (to.Rect.Contains(PlayerInput.MousePosition) && from.DraggedElement != null)
{
//move the dragged elements to the index determined previously
var draggedElement = from.DraggedElement;
var selected = from.AllSelected.ToList();
selected.Sort((a, b) => from.Content.GetChildIndex(a) - from.Content.GetChildIndex(b));
float oldCount = to.Content.CountChildren;
float newCount = oldCount + selected.Count;
var offset = draggedElement.RectTransform.AbsoluteOffset;
offset += from.Content.Rect.Location;
offset -= to.Content.Rect.Location;
for (int i = 0; i < selected.Count; i++)
{
var c = selected[i];
c.Parent.RemoveChild(c);
c.RectTransform.Parent = to.Content.RectTransform;
c.RectTransform.RepositionChildInHierarchy((int)oldCount+i);
}
from.DraggedElement = null;
from.Deselect();
from.RecalculateChildren();
from.RectTransform.RecalculateScale(true);
to.RecalculateChildren();
to.RectTransform.RecalculateScale(true);
to.Select(selected);
//recalculate the dragged element's offset so it doesn't jump around
draggedElement.RectTransform.AbsoluteOffset = offset;
to.DraggedElement = draggedElement;
to.BarScroll = to.BarScroll * (oldCount / newCount);
}
}
var visibleSubsList = createColumnListBox("VisibleSubmarines");
var centerColumn = createColumn(0.1f);
void centerSpacing()
{
new GUIFrame(new RectTransform(new Vector2(1.0f, 0.4f), centerColumn.RectTransform), style: null);
}
GUIButton centerButton(string style)
=> new GUIButton(
new RectTransform(new Vector2(1.0f, 0.1f), centerColumn.RectTransform),
style: style);
var hiddenSubsList = createColumnListBox("HiddenSubmarines");
void addSubToList(SubmarineInfo sub, GUIListBox list)
{
var modFrame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.08f), list.Content.RectTransform),
style: "ListBoxElement")
{
UserData = sub
};
var frameContent = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.9f), modFrame.RectTransform, Anchor.Center), isHorizontal: true, childAnchor: Anchor.CenterLeft)
{
Stretch = true,
RelativeSpacing = 0.02f
};
var dragIndicator = new GUIButton(new RectTransform(new Vector2(0.1f, 0.5f), frameContent.RectTransform, scaleBasis: ScaleBasis.BothHeight),
style: "GUIDragIndicator")
{
CanBeFocused = false
};
var subName = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), frameContent.RectTransform),
text: sub.Name)
{
CanBeFocused = false
};
CreateSubmarineClassText(
frameContent,
sub,
subName,
list.Content);
}
foreach (var sub in GameMain.Client.ServerSubmarines
.OrderBy(s => visibilityMenuOrder.Contains(s))
.ThenBy(s => visibilityMenuOrder.IndexOf(s)))
{
addSubToList(sub,
GameMain.Client.ServerSettings.HiddenSubs.Contains(sub.Name) ? hiddenSubsList : visibleSubsList);
}
void onRearranged(GUIListBox listBox, object userData)
{
visibilityMenuOrder.Clear();
visibilityMenuOrder.AddRange(visibleSubsList.Content.Children.Select(c => c.UserData as SubmarineInfo));
visibilityMenuOrder.AddRange(hiddenSubsList.Content.Children.Select(c => c.UserData as SubmarineInfo));
}
visibleSubsList.OnRearranged = onRearranged;
hiddenSubsList.OnRearranged = onRearranged;
void swapListItems(GUIListBox from, GUIListBox to)
{
to.Deselect();
var selected = from.AllSelected.ToArray();
int lastIndex = from.Content.GetChildIndex(selected.LastOrDefault());
int nextIndex = lastIndex + 1;
GUIComponent nextComponent = null;
if (lastIndex >= 0 && nextIndex < from.Content.CountChildren)
{
nextComponent = from.Content.GetChild(nextIndex);
}
foreach (var frame in selected)
{
frame.Parent.RemoveChild(frame);
frame.RectTransform.Parent = to.Content.RectTransform;
}
from.RecalculateChildren();
from.RectTransform.RecalculateScale(true);
to.RecalculateChildren();
to.RectTransform.RecalculateScale(true);
to.Select(selected);
if (nextComponent != null) { from.Select(nextComponent.ToEnumerable()); }
}
centerSpacing();
var visibleToHidden = centerButton("GUIButtonToggleRight");
visibleToHidden.OnClicked = (button, o) =>
{
swapListItems(visibleSubsList, hiddenSubsList);
return false;
};
var hiddenToVisible = centerButton("GUIButtonToggleLeft");
hiddenToVisible.OnClicked = (button, o) =>
{
swapListItems(hiddenSubsList, visibleSubsList);
return false;
};
centerSpacing();
var buttonLayout
= new GUILayoutGroup(new RectTransform(new Vector2(0.7f, 0.1f), messageBox.Content.RectTransform),
isHorizontal: true)
{
RelativeSpacing = 0.01f
};
var cancelButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonLayout.RectTransform),
TextManager.Get("Cancel"))
{
OnClicked = (button, o) =>
{
messageBox.Close();
return false;
}
};
var okButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonLayout.RectTransform),
TextManager.Get("OK"))
{
OnClicked = (button, o) =>
{
var hiddenSubs = GameMain.Client.ServerSettings.HiddenSubs;
hiddenSubs.Clear();
hiddenSubs.UnionWith(hiddenSubsList.Content.Children.Select(c => (c.UserData as SubmarineInfo).Name));
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.HiddenSubs);
messageBox.Close();
return false;
}
};
new GUICustomComponent(new RectTransform(Vector2.Zero, messageBox.RectTransform),
onUpdate: (f, component) =>
{
handleDraggingAcrossLists(visibleSubsList, hiddenSubsList);
handleDraggingAcrossLists(hiddenSubsList, visibleSubsList);
if (PlayerInput.PrimaryMouseButtonClicked()
&& !GUI.IsMouseOn(visibleToHidden)
&& !GUI.IsMouseOn(hiddenToVisible))
{
if (!GUI.IsMouseOn(hiddenSubsList)
|| !hiddenSubsList.Content.IsParentOf(GUI.MouseOn))
{
hiddenSubsList.Deselect();
}
if (!GUI.IsMouseOn(visibleSubsList)
|| !visibleSubsList.Content.IsParentOf(GUI.MouseOn))
{
visibleSubsList.Deselect();
}
}
},
onDraw: (spriteBatch, component) =>
{
visibleSubsList.DraggedElement?.DrawManually(spriteBatch, true, true);
hiddenSubsList.DraggedElement?.DrawManually(spriteBatch, true, true);
});
}
public void UpdateSubVisibility()
{
foreach (GUIComponent child in SubList.Content.Children)
{
if (!(child.UserData is SubmarineInfo sub)) { continue; }
child.Visible = !GameMain.Client.ServerSettings.HiddenSubs.Contains(sub.Name)
&& (string.IsNullOrEmpty(subSearchBox.Text) || sub.DisplayName.Contains(subSearchBox.Text, StringComparison.OrdinalIgnoreCase));
}
}
public void OnRoundEnded()
{
CampaignCharacterDiscarded = false;

View File

@@ -43,7 +43,7 @@ namespace Barotrauma
CoroutineManager.StartCoroutine(UpdateColorFade(from, to, duration));
}
private IEnumerable<object> UpdateColorFade(Color from, Color to, float duration)
private IEnumerable<CoroutineStatus> UpdateColorFade(Color from, Color to, float duration)
{
while (Selected != this)
{

View File

@@ -578,6 +578,7 @@ namespace Barotrauma
RecalculateHolder();
}
serverInfo.CreatePreviewWindow(serverPreview.Content);
serverPreview.ForceLayoutRecalculation();
btn.Children.ForEach(c => c.SpriteEffects = serverPreviewContainer.Visible ? SpriteEffects.None : SpriteEffects.FlipHorizontally);
}
return true;
@@ -1715,7 +1716,7 @@ namespace Barotrauma
CoroutineManager.StartCoroutine(WaitForRefresh());
}
private IEnumerable<object> WaitForRefresh()
private IEnumerable<CoroutineStatus> WaitForRefresh()
{
waitingForRefresh = true;
if (refreshDisableTimer > DateTime.Now)
@@ -2058,7 +2059,7 @@ namespace Barotrauma
FilterServers();
}
private IEnumerable<object> EstimateLobbyPing(ServerInfo serverInfo, GUITextBlock serverPingText)
private IEnumerable<CoroutineStatus> EstimateLobbyPing(ServerInfo serverInfo, GUITextBlock serverPingText)
{
while (!steamPingInfoReady)
{
@@ -2096,7 +2097,7 @@ namespace Barotrauma
waitingForRefresh = false;
}
private IEnumerable<object> SendMasterServerRequest()
private IEnumerable<CoroutineStatus> SendMasterServerRequest()
{
RestClient client = null;
try
@@ -2271,7 +2272,7 @@ namespace Barotrauma
return true;
}
private IEnumerable<object> ConnectToServer(string endpoint, string serverName)
private IEnumerable<CoroutineStatus> ConnectToServer(string endpoint, string serverName)
{
string serverIP = null;
UInt64 serverSteamID = SteamManager.SteamIDStringToUInt64(endpoint);

View File

@@ -304,7 +304,7 @@ namespace Barotrauma
float subscribePollAdditionalWait = 0.0f;
private IEnumerable<object> PollSubscribedItems()
private IEnumerable<CoroutineStatus> PollSubscribedItems()
{
if (!SteamManager.IsInitialized) { yield return CoroutineStatus.Success; }
@@ -364,7 +364,7 @@ namespace Barotrauma
}
}
public IEnumerable<object> RefreshDownloadState()
public IEnumerable<CoroutineStatus> RefreshDownloadState()
{
bool isDownloading = true;
while (true)
@@ -831,7 +831,7 @@ namespace Barotrauma
}
}
private IEnumerable<object> WaitForItemPreviewDownloaded(Steamworks.Ugc.Item? item, GUIListBox listBox, string previewImagePath)
private IEnumerable<CoroutineStatus> WaitForItemPreviewDownloaded(Steamworks.Ugc.Item? item, GUIListBox listBox, string previewImagePath)
{
while (true)
{
@@ -1835,7 +1835,7 @@ namespace Barotrauma
}
private IEnumerable<object> WaitForPublish(SteamManager.WorkshopPublishStatus workshopPublishStatus)
private IEnumerable<CoroutineStatus> WaitForPublish(SteamManager.WorkshopPublishStatus workshopPublishStatus)
{
var item = workshopPublishStatus.Item;
var coroutine = workshopPublishStatus.Coroutine;

View File

@@ -369,11 +369,20 @@ namespace Barotrauma
{
ToolTip = TextManager.Get("AddSubToolTip")
};
List<(string Name, SubmarineInfo Sub)> subs = new List<(string Name, SubmarineInfo Sub)>();
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
{
if (sub.Type != SubmarineType.Player) { continue; }
linkedSubBox.AddItem(sub.Name, sub);
subs.Add((sub.Name, sub));
}
foreach (var (name, sub) in subs.OrderBy(tuple => tuple.Name))
{
linkedSubBox.AddItem(name, sub);
}
linkedSubBox.OnSelected += SelectLinkedSub;
linkedSubBox.OnDropped += (component, obj) =>
{
@@ -1220,11 +1229,19 @@ namespace Barotrauma
string downloadFolder = Path.GetFullPath(SaveUtil.SubmarineDownloadFolder);
linkedSubBox.ClearChildren();
List<(string Name, SubmarineInfo Sub)> subs = new List<(string Name, SubmarineInfo Sub)>();
foreach (SubmarineInfo sub in SubmarineInfo.SavedSubmarines)
{
if (sub.Type != SubmarineType.Player) { continue; }
if (Path.GetDirectoryName(Path.GetFullPath(sub.FilePath)) == downloadFolder) { continue; }
linkedSubBox.AddItem(sub.Name, sub);
subs.Add((sub.Name, sub));
}
foreach (var (subName, sub) in subs.OrderBy(tuple => tuple.Name))
{
linkedSubBox.AddItem(subName, sub);
}
cam.UpdateTransform();
@@ -1294,7 +1311,7 @@ namespace Barotrauma
/// </summary>
/// <see cref="AutoSave"/>
/// <returns></returns>
private static IEnumerable<object> AutoSaveCoroutine()
private static IEnumerable<CoroutineStatus> AutoSaveCoroutine()
{
DateTime target = DateTime.Now.AddMinutes(GameSettings.AutoSaveIntervalSeconds);
DateTime tempTarget = DateTime.Now;
@@ -1998,14 +2015,21 @@ namespace Barotrauma
var gapPositionDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), gapPositionGroup.RectTransform),
text: "", selectMultiple: true);
Submarine.MainSub.Info?.OutpostModuleInfo?.DetermineGapPositions(Submarine.MainSub);
foreach (var gapPos in Enum.GetValues(typeof(OutpostModuleInfo.GapPosition)))
var outpostModuleInfo = Submarine.MainSub.Info?.OutpostModuleInfo;
if (outpostModuleInfo != null)
{
if ((OutpostModuleInfo.GapPosition)gapPos == OutpostModuleInfo.GapPosition.None) { continue; }
gapPositionDropDown.AddItem(TextManager.Capitalize(gapPos.ToString()), gapPos);
if (Submarine.MainSub.Info?.OutpostModuleInfo?.GapPositions.HasFlag((OutpostModuleInfo.GapPosition)gapPos) ?? false)
if (outpostModuleInfo.GapPositions == OutpostModuleInfo.GapPosition.None)
{
gapPositionDropDown.SelectItem(gapPos);
outpostModuleInfo.DetermineGapPositions(Submarine.MainSub);
}
foreach (var gapPos in Enum.GetValues(typeof(OutpostModuleInfo.GapPosition)))
{
if ((OutpostModuleInfo.GapPosition)gapPos == OutpostModuleInfo.GapPosition.None) { continue; }
gapPositionDropDown.AddItem(TextManager.Capitalize(gapPos.ToString()), gapPos);
if (outpostModuleInfo.GapPositions.HasFlag((OutpostModuleInfo.GapPosition)gapPos))
{
gapPositionDropDown.SelectItem(gapPos);
}
}
}
@@ -4774,7 +4798,7 @@ namespace Barotrauma
if (dummyCharacter != null)
{
dummyCharacter.AnimController.FindHull(dummyCharacter.CursorWorldPosition, false);
dummyCharacter.AnimController.FindHull(dummyCharacter.CursorWorldPosition, setSubmarine: false);
foreach (Item item in dummyCharacter.Inventory.AllItems)
{

View File

@@ -221,7 +221,7 @@ namespace Barotrauma.Sounds
{
if (!MathUtils.IsValid(value)) { return; }
gain = Math.Clamp(value, 0.0f, 1.0f);
gain = Math.Max(value, 0.0f);
if (ALSourceIndex < 0) { return; }
@@ -525,6 +525,8 @@ namespace Barotrauma.Sounds
throw new Exception("Failed to bind buffer to source (" + ALSourceIndex.ToString() + ":" + sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex) + "," + alBuffer.ToString() + "): " + debugName + ", " + Al.GetErrorString(alError));
}
SetProperties();
Al.SourcePlay(sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex));
alError = Al.GetError();
if (alError != Al.NoError)
@@ -570,16 +572,9 @@ namespace Barotrauma.Sounds
}
}
Sound.Owner.InitStreamThread();
SetProperties();
}
}
this.Position = position;
this.Gain = gain;
this.FrequencyMultiplier = freqMult;
this.Looping = false;
this.Near = near;
this.Far = far;
this.Category = category;
#if !DEBUG
}
catch
@@ -594,6 +589,17 @@ namespace Barotrauma.Sounds
}
#endif
void SetProperties()
{
this.Position = position;
this.Gain = gain;
this.FrequencyMultiplier = freqMult;
this.Looping = false;
this.Near = near;
this.Far = far;
this.Category = category;
}
Sound.Owner.Update();
}

View File

@@ -147,7 +147,7 @@ namespace Barotrauma
MathUtils.NearlyEqual(rangeA, rangeB);
}
public static IEnumerable<object> Init()
public static IEnumerable<CoroutineStatus> Init()
{
OverrideMusicType = null;
@@ -826,7 +826,7 @@ namespace Barotrauma
//find appropriate music for the current situation
string currentMusicType = GetCurrentMusicType();
float currentIntensity = GameMain.GameSession?.EventManager != null ?
GameMain.GameSession.EventManager.CurrentIntensity * 100.0f : 0.0f;
GameMain.GameSession.EventManager.MusicIntensity * 100.0f : 0.0f;
IEnumerable<BackgroundMusic> suitableMusic = GetSuitableMusicClips(currentMusicType, currentIntensity);
int mainTrackIndex = 0;

View File

@@ -84,7 +84,7 @@ namespace Barotrauma
Vector4 sourceVector = Vector4.Zero;
bool temp2 = false;
int maxLoadRetries = 3;
int maxLoadRetries = File.Exists(FilePath) ? 3 : 0;
for (int i = 0; i <= maxLoadRetries; i++)
{
try
@@ -169,7 +169,8 @@ namespace Barotrauma
}
else
{
DebugConsole.ThrowError($"Sprite \"{file}\" not found! {Environment.StackTrace.CleanupStackTrace()}");
DebugConsole.ThrowError($"Sprite \"{file}\" not found!");
DebugConsole.Log(Environment.StackTrace.CleanupStackTrace());
}
return null;

View File

@@ -434,130 +434,8 @@ namespace Barotrauma
return Color.Lerp(gradient[(int)scaledT], gradient[(int)Math.Min(scaledT + 1, gradient.Length - 1)], (scaledT - (int)scaledT));
}
public static string WrapText(string text, float lineLength, ScalableFont font, float textScale = 1.0f, bool playerInput = false) //TODO: could integrate this into the ScalableFont class directly
{
Vector2 textSize = font.MeasureString(text);
if (textSize.X <= lineLength) { return text; }
if (!playerInput)
{
text = text.Replace("\n", " \n ");
}
List<string> words = new List<string>();
string currWord = "";
for (int i = 0; i < text.Length; i++)
{
if (TextManager.IsCJK(text[i].ToString()))
{
if (currWord.Length > 0)
{
words.Add(currWord);
currWord = "";
}
words.Add(text[i].ToString());
}
else if (text[i] == ' ')
{
if (currWord.Length > 0)
{
words.Add(currWord);
currWord = "";
}
words.Add(string.Empty);
}
else
{
currWord += text[i];
}
}
if (currWord.Length > 0)
{
words.Add(currWord);
currWord = "";
}
StringBuilder wrappedText = new StringBuilder();
float linePos = 0f;
Vector2 spaceSize = font.MeasureString(" ") * textScale;
for (int i = 0; i < words.Count; ++i)
{
string currentWord = words[i];
if (currentWord.Length == 0)
{
// space
currentWord = " ";
}
else if (string.IsNullOrWhiteSpace(currentWord) && currentWord != "\n")
{
continue;
}
Vector2 size = words[i].Length == 0 ? spaceSize : font.MeasureString(currentWord) * textScale;
if (size.X > lineLength)
{
float splitSize = 0.0f;
List<string> splitWord = new List<string>() { string.Empty };
int k = 0;
for (int j = 0; j < currentWord.Length; j++)
{
splitWord[k] += currentWord[j];
splitSize += (font.MeasureString(currentWord[j].ToString()) * textScale).X;
if (splitSize + linePos > lineLength)
{
linePos = splitSize = 0.0f;
splitWord[k] = splitWord[k].Remove(splitWord[k].Length - 1) + "\n";
if (splitWord[k].Length <= 1) { break; }
j--;
splitWord.Add(string.Empty);
k++;
}
}
for (int j = 0; j < splitWord.Count; j++)
{
wrappedText.Append(splitWord[j]);
}
linePos = splitSize;
}
else
{
if (linePos + size.X < lineLength)
{
wrappedText.Append(currentWord);
if (currentWord == "\n")
{
linePos = 0.0f;
}
else
{
linePos += size.X;
}
}
else
{
wrappedText.Append("\n");
wrappedText.Append(currentWord);
linePos = size.X;
}
}
}
if (!playerInput)
{
return wrappedText.ToString().Replace(" \n ", "\n");
}
else
{
return wrappedText.ToString();
}
}
public static string WrapText(string text, float lineLength, ScalableFont font, float textScale = 1.0f)
=> font.WrapText(text, lineLength / textScale);
public static void ParseConnectCommand(string[] args, out string name, out string endpoint, out UInt64 lobbyId)
{

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.15.13.0</Version>
<Version>0.15.15.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
@@ -122,7 +122,7 @@
<ItemGroup>
<PackageReference Include="NVorbis" Version="0.8.6" />
<PackageReference Include="RestSharp" Version="106.6.10" />
<PackageReference Include="RestSharp" Version="106.12.0" />
</ItemGroup>
<!-- Sourced from https://stackoverflow.com/a/45248069 -->

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.15.13.0</Version>
<Version>0.15.15.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
@@ -123,7 +123,7 @@
<ItemGroup>
<PackageReference Include="NVorbis" Version="0.8.6" />
<PackageReference Include="RestSharp" Version="106.6.10" />
<PackageReference Include="RestSharp" Version="106.12.0" />
</ItemGroup>
<!-- Sourced from https://stackoverflow.com/a/45248069 -->

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma</Product>
<Version>0.15.13.0</Version>
<Version>0.15.15.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>Barotrauma</AssemblyName>
@@ -126,7 +126,7 @@
<ItemGroup>
<PackageReference Include="NVorbis" Version="0.8.6" />
<PackageReference Include="RestSharp" Version="106.6.10" />
<PackageReference Include="RestSharp" Version="106.12.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.15.13.0</Version>
<Version>0.15.15.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -6,7 +6,7 @@
<RootNamespace>Barotrauma</RootNamespace>
<Authors>FakeFish, Undertow Games</Authors>
<Product>Barotrauma Dedicated Server</Product>
<Version>0.15.13.0</Version>
<Version>0.15.15.0</Version>
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
<Platforms>AnyCPU;x64</Platforms>
<AssemblyName>DedicatedServer</AssemblyName>

View File

@@ -60,5 +60,10 @@ namespace Barotrauma
{
GameMain.NetworkMember.CreateEntityEvent(this, new object[] { NetEntityEvent.Type.UpdateMoney });
}
partial void OnTalentGiven(string talentIdentifier)
{
GameServer.Log($"{GameServer.CharacterLogName(this)} has gained the talent '{talentIdentifier}'", ServerLog.MessageType.Talent);
}
}
}

View File

@@ -29,6 +29,7 @@ namespace Barotrauma
if (Character == null || Character.Removed) { return; }
if (prevAmount != newAmount)
{
GameServer.Log($"{GameServer.CharacterLogName(Character)} has gained {newAmount - prevAmount} experience ({prevAmount} -> {newAmount})", ServerLog.MessageType.Talent);
GameMain.NetworkMember.CreateEntityEvent(Character, new object[] { NetEntityEvent.Type.UpdateExperience });
}
}

View File

@@ -98,7 +98,7 @@ namespace Barotrauma
{
ColoredText msg = queuedMessages.Dequeue();
Messages.Add(msg);
if (GameSettings.SaveDebugConsoleLogs)
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging)
{
unsavedMessages.Add(msg);
if (unsavedMessages.Count >= messagesPerFile)
@@ -281,7 +281,7 @@ namespace Barotrauma
{
var msg = queuedMessages.Dequeue();
Messages.Add(msg);
if (GameSettings.SaveDebugConsoleLogs)
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging)
{
unsavedMessages.Add(msg);
if (unsavedMessages.Count >= messagesPerFile)
@@ -1315,7 +1315,7 @@ namespace Barotrauma
commands.Add(new Command("sub|submarine", "submarine [name]: Select the submarine for the next round.", (string[] args) =>
{
SubmarineInfo sub = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.ToLower() == string.Join(" ", args).ToLower());
SubmarineInfo sub = GameMain.NetLobbyScreen.GetSubList().Find(s => s.Name.Equals(string.Join(" ", args), StringComparison.OrdinalIgnoreCase));
if (sub != null)
{
@@ -1377,7 +1377,7 @@ namespace Barotrauma
commands.Add(new Command("endgame|endround|end", "end/endgame/endround: End the current round.", (string[] args) =>
{
if (Screen.Selected == GameMain.NetLobbyScreen) return;
if (Screen.Selected == GameMain.NetLobbyScreen) { return; }
GameMain.Server.EndGame();
}));
@@ -1399,11 +1399,18 @@ namespace Barotrauma
commands.Add(new Command("eventdata", "", (string[] args) =>
{
if (args.Length == 0) return;
ServerEntityEvent ev = GameMain.Server.EntityEventManager.Events[Convert.ToUInt16(args[0])];
if (args.Length == 0) { return; }
if (!UInt16.TryParse(args[0], NumberStyles.Any, CultureInfo.InvariantCulture, out ushort eventId)) { return; }
ServerEntityEvent ev = GameMain.Server.EntityEventManager.Events.Find(ev => ev.ID == eventId);
if (ev != null)
{
NewMessage(ev.StackTrace.CleanupStackTrace(), Color.Lime);
string entityData = "";
if (ev.Entity is { ID: var entityId, Removed: var removed, IdFreed: var idFreed })
{
entityData = $"Entity ID: {entityId}; Entity removed: {removed}; Entity ID freed: {idFreed}";
}
NewMessage($"EventData {eventId}\n{entityData}", Color.Lime);
//NewMessage(ev.StackTrace.CleanupStackTrace(), Color.Lime);
}
}));
@@ -1578,16 +1585,13 @@ namespace Barotrauma
(Client client, Vector2 cursorWorldPos, string[] args) =>
{
Character tpCharacter = (args.Length == 0) ? client.Character : FindMatchingCharacter(args, false);
if (tpCharacter == null) return;
//var cam = GameMain.GameScreen.Cam;
tpCharacter.AnimController.CurrentHull = null;
tpCharacter.Submarine = null;
tpCharacter.AnimController.SetPosition(ConvertUnits.ToSimUnits(cursorWorldPos));
tpCharacter.AnimController.FindHull(cursorWorldPos, true);
if (tpCharacter.AIController?.SteeringManager is IndoorsSteeringManager pathSteering)
if (tpCharacter != null)
{
pathSteering.ResetPath();
tpCharacter.TeleportTo(cursorWorldPos);
if (tpCharacter.AIController?.SteeringManager is IndoorsSteeringManager pathSteering)
{
pathSteering.ResetPath();
}
}
}
);
@@ -1779,7 +1783,7 @@ namespace Barotrauma
List<TalentTree> talentTrees = new List<TalentTree>();
if (args.Length == 0 || args[0].Equals("all", StringComparison.OrdinalIgnoreCase))
{
talentTrees.AddRange(TalentTree.JobTalentTrees.Values);
talentTrees.AddRange(TalentTree.JobTalentTrees);
}
else
{
@@ -2370,6 +2374,16 @@ namespace Barotrauma
GameMain.Server.CreateEntityEvent(wall);
}
}));
commands.Add(new Command("stallfiletransfers", "stallfiletransfers [seconds]: A debug command that stalls each file transfer packet by the specified duration.", (string[] args) =>
{
float seconds = 0.0f;
if (args.Length > 0)
{
float.TryParse(args[0], out seconds);
}
GameMain.Server.FileSender.StallPacketsTime = seconds;
NewMessage("Set file transfer stall time to " + seconds);
}));
#endif
}

Some files were not shown because too many files have changed in this diff Show More