Merge branch 'master' of https://github.com/Regalis11/Barotrauma.git into Regalis11-master
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
@@ -63,7 +63,10 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (var ic in character.MemState[0].SelectedItem.Components)
|
||||
{
|
||||
if (ic.CanBeSelected) ic.Select(character);
|
||||
if (ic.CanBeSelected)
|
||||
{
|
||||
ic.Select(character);
|
||||
}
|
||||
}
|
||||
}
|
||||
character.SelectedConstruction = character.MemState[0].SelectedItem;
|
||||
@@ -98,6 +101,16 @@ namespace Barotrauma
|
||||
if (distSqrd > 10.0f || !character.CanMove)
|
||||
{
|
||||
Collider.TargetRotation = newRotation;
|
||||
if (distSqrd > 10.0f)
|
||||
{
|
||||
//teleported very far - see if we need to move to another sub
|
||||
Hull serverHull = Hull.FindHull(ConvertUnits.ToDisplayUnits(newPosition), CurrentHull, newPosition.Y < lowestSubPos);
|
||||
if (currentHull != null && serverHull != null && serverHull.Submarine != currentHull.Submarine)
|
||||
{
|
||||
character.Submarine = serverHull.Submarine;
|
||||
character.CurrentHull = CurrentHull = serverHull;
|
||||
}
|
||||
}
|
||||
SetPosition(newPosition, lerp: distSqrd < 5.0f, ignorePlatforms: false);
|
||||
}
|
||||
else
|
||||
@@ -159,7 +172,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;
|
||||
@@ -194,7 +207,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (character.SelectedConstruction != serverPos.SelectedItem)
|
||||
{
|
||||
serverPos.SelectedItem.TryInteract(character, true, true);
|
||||
serverPos.SelectedItem.TryInteract(character, ignoreRequiredItems: true, forceSelectKey: true);
|
||||
}
|
||||
character.SelectedConstruction = serverPos.SelectedItem;
|
||||
}
|
||||
@@ -448,8 +461,8 @@ namespace Barotrauma
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.AddErrorEventOnce("Ragdoll.Draw:LimbsRemoved",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.Name + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Failed to draw a ragdoll, limbs have been removed. Character: \"" + character.SpeciesName + "\", removed: " + character.Removed + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -460,12 +473,17 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
float depthOffset = GetDepthOffset();
|
||||
if (!MathUtils.NearlyEqual(depthOffset, 0.0f))
|
||||
{
|
||||
foreach (Limb limb in limbs) { limb.ActiveSprite.Depth += depthOffset; }
|
||||
}
|
||||
for (int i = 0; i < limbs.Length; i++)
|
||||
{
|
||||
var limb = inversedLimbDrawOrder[i];
|
||||
if (depthOffset != 0.0f) { limb.ActiveSprite.Depth += depthOffset; }
|
||||
limb.Draw(spriteBatch, cam, color);
|
||||
if (depthOffset != 0.0f) { limb.ActiveSprite.Depth -= depthOffset; }
|
||||
inversedLimbDrawOrder[i].Draw(spriteBatch, cam, color);
|
||||
}
|
||||
if (!MathUtils.NearlyEqual(depthOffset, 0.0f))
|
||||
{
|
||||
foreach (Limb limb in limbs) { limb.ActiveSprite.Depth -= depthOffset; }
|
||||
}
|
||||
LimbJoints.ForEach(j => j.Draw(spriteBatch));
|
||||
}
|
||||
@@ -486,7 +504,14 @@ namespace Barotrauma
|
||||
if (character.WorldPosition.X < character.SelectedConstruction.WorldPosition.X)
|
||||
{
|
||||
//at the left side of the ladder, needs to be drawn in front of the rungs
|
||||
depthOffset = Math.Max(ladder.BackgroundSpriteDepth - 0.01f - maxDepth, 0.0f);
|
||||
if (maxDepth > ladder.BackgroundSpriteDepth)
|
||||
{
|
||||
depthOffset = Math.Max(ladder.BackgroundSpriteDepth - 0.01f - maxDepth, 0.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
depthOffset = Math.Max(ladder.Item.GetDrawDepth() + 0.0001f - minDepth, -minDepth);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -581,10 +606,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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -305,9 +305,9 @@ namespace Barotrauma
|
||||
case 0: //NetEntityEvent.Type.InventoryState
|
||||
if (Inventory == null)
|
||||
{
|
||||
string errorMsg = "Received an inventory update message for an entity with no inventory (" + Name + ", removed: " + Removed + ")";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
string errorMsg = "Received an inventory update message for an entity with no inventory ([name], removed: " + Removed + ")";
|
||||
DebugConsole.ThrowError(errorMsg.Replace("[name]", Name));
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ClientRead:NoInventory" + ID, GameAnalyticsManager.ErrorSeverity.Error, errorMsg.Replace("[name]", SpeciesName));
|
||||
|
||||
//read anyway to prevent messing up reading the rest of the message
|
||||
_ = msg.ReadUInt16();
|
||||
@@ -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];
|
||||
@@ -650,7 +651,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = $"Error in CharacterNetworking.ReadStatus: affliction not found ({afflictionName})";
|
||||
causeOfDeathType = CauseOfDeathType.Unknown;
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:AfflictionIndexOutOfBounts", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -681,7 +682,7 @@ namespace Barotrauma
|
||||
if (severedJointIndex < 0 || severedJointIndex >= AnimController.LimbJoints.Length)
|
||||
{
|
||||
string errorMsg = $"Error in CharacterNetworking.ReadStatus: severed joint index out of bounds (index: {severedJointIndex}, joint count: {AnimController.LimbJoints.Length})";
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:JointIndexOutOfBounts", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterNetworking.ReadStatus:JointIndexOutOfBounts", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -453,13 +453,14 @@ namespace Barotrauma
|
||||
{
|
||||
case Alignment.Left:
|
||||
healthWindow.RectTransform.SetPosition(Anchor.BottomLeft);
|
||||
healthWindow.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.InventoryAreaLower.X, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
|
||||
break;
|
||||
case Alignment.Right:
|
||||
healthWindow.RectTransform.SetPosition(Anchor.BottomRight);
|
||||
healthWindow.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.Padding, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
|
||||
break;
|
||||
}
|
||||
|
||||
healthWindow.RectTransform.AbsoluteOffset = new Point(HUDLayoutSettings.Padding, screenResolution.Y - HUDLayoutSettings.ChatBoxArea.Y + HUDLayoutSettings.Padding);
|
||||
healthWindow.RectTransform.RecalculateChildren(false);
|
||||
}
|
||||
|
||||
@@ -648,8 +649,9 @@ namespace Barotrauma
|
||||
grainColor = oxygenLowGrainColor;
|
||||
}
|
||||
|
||||
foreach (Affliction affliction in afflictions)
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
var affliction = kvp.Key;
|
||||
distortStrength = Math.Max(distortStrength, affliction.GetScreenDistortStrength());
|
||||
blurStrength = Math.Max(blurStrength, affliction.GetScreenBlurStrength());
|
||||
radialDistortStrength = Math.Max(radialDistortStrength, affliction.GetRadialDistortStrength());
|
||||
@@ -662,16 +664,6 @@ namespace Barotrauma
|
||||
grainColor = Color.Lerp(grainColor, afflictionGrainColor, (float)Math.Pow(1.0f - oxygenLowStrength, 2));
|
||||
}
|
||||
}
|
||||
foreach (LimbHealth limbHealth in limbHealths)
|
||||
{
|
||||
foreach (Affliction affliction in limbHealth.Afflictions)
|
||||
{
|
||||
distortStrength = Math.Max(distortStrength, affliction.GetScreenDistortStrength());
|
||||
blurStrength = Math.Max(blurStrength, affliction.GetScreenBlurStrength());
|
||||
radialDistortStrength = Math.Max(radialDistortStrength, affliction.GetRadialDistortStrength());
|
||||
chromaticAberrationStrength = Math.Max(chromaticAberrationStrength, affliction.GetChromaticAberrationStrength());
|
||||
}
|
||||
}
|
||||
|
||||
Character.RadialDistortStrength = radialDistortStrength;
|
||||
Character.ChromaticAberrationStrength = chromaticAberrationStrength;
|
||||
@@ -777,7 +769,7 @@ namespace Barotrauma
|
||||
{
|
||||
// If no limb is selected or highlighted, select the one with the most critical afflictions.
|
||||
var affliction = SortAfflictionsBySeverity(GetAllAfflictions(a => a.Prefab.IndicatorLimb != LimbType.None)).FirstOrDefault();
|
||||
if (affliction.DamagePerSecond > 0 || affliction.Strength > 0)
|
||||
if (affliction != null && (affliction.DamagePerSecond > 0 || affliction.Strength > 0))
|
||||
{
|
||||
var limbHealth = GetMatchingLimbHealth(affliction);
|
||||
if (limbHealth != null)
|
||||
@@ -788,7 +780,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
// If no affliction is critical, select the limb which has most damage.
|
||||
var limbHealth = limbHealths.OrderByDescending(l => l.TotalDamage).FirstOrDefault();
|
||||
var limbHealth = limbHealths.OrderByDescending(l => GetTotalDamage(l)).FirstOrDefault();
|
||||
selectedLimbIndex = limbHealths.IndexOf(limbHealth);
|
||||
}
|
||||
}
|
||||
@@ -805,7 +797,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;
|
||||
@@ -951,8 +963,9 @@ namespace Barotrauma
|
||||
UpdateAlignment();
|
||||
}
|
||||
|
||||
foreach (Affliction affliction in afflictions)
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
var affliction = kvp.Key;
|
||||
if (affliction.Prefab.AfflictionOverlay != null)
|
||||
{
|
||||
Sprite ScreenAfflictionOverlay = affliction.Prefab.AfflictionOverlay;
|
||||
@@ -964,7 +977,7 @@ namespace Barotrauma
|
||||
float damageOverlayAlpha = DamageOverlayTimer;
|
||||
if (Vitality < MaxVitality * 0.1f)
|
||||
{
|
||||
damageOverlayAlpha = Math.Max(1.0f - (Vitality / maxVitality * 10.0f), damageOverlayAlpha);
|
||||
damageOverlayAlpha = Math.Max(1.0f - (Vitality / UnmodifiedMaxVitality * 10.0f), damageOverlayAlpha);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1139,18 +1152,34 @@ namespace Barotrauma
|
||||
afflictionIconContainer.Content.ClearChildren();
|
||||
return;
|
||||
}
|
||||
var currentAfflictions = GetMatchingAfflictions(selectedLimb, a => a.ShouldShowIcon(Character));
|
||||
if (currentAfflictions.Any(a => !displayedAfflictions.Any(d => d.affliction == a)) ||
|
||||
displayedAfflictions.Any(a => !currentAfflictions.Contains(a.affliction)))
|
||||
|
||||
if (afflictionsDirty())
|
||||
{
|
||||
var currentAfflictions = afflictions.Where(a => ShouldDisplayAfflictionOnLimb(a, selectedLimb)).Select(a => a.Key);
|
||||
CreateAfflictionInfos(currentAfflictions);
|
||||
CreateRecommendedTreatments();
|
||||
}
|
||||
//update recommended treatments if the strength of some displayed affliction has changed by > 1
|
||||
else if (displayedAfflictions.Any(d => Math.Abs(d.strength - currentAfflictions.First(a => a == d.affliction).Strength) > 1.0f))
|
||||
else if (displayedAfflictions.Any(d => Math.Abs(d.strength - d.affliction.Strength) > 1.0f))
|
||||
{
|
||||
CreateRecommendedTreatments();
|
||||
}
|
||||
|
||||
bool afflictionsDirty()
|
||||
{
|
||||
//not displaying one of the current afflictions -> dirty
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
if (!ShouldDisplayAfflictionOnLimb(kvp, selectedLimb)) { continue; }
|
||||
if (!displayedAfflictions.Any(d => d.affliction == kvp.Key)) { return true; }
|
||||
}
|
||||
//displaying an affliction we no longer have -> dirty
|
||||
foreach ((Affliction affliction, float strength) in displayedAfflictions)
|
||||
{
|
||||
if (!afflictions.Any(a => a.Key == affliction)) { return true; }
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateAfflictionInfos(IEnumerable<Affliction> afflictions)
|
||||
@@ -1158,7 +1187,7 @@ namespace Barotrauma
|
||||
afflictionIconContainer.ClearChildren();
|
||||
displayedAfflictions.Clear();
|
||||
|
||||
Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictions).FirstOrDefault();
|
||||
Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictions, excludeBuffs: false).FirstOrDefault();
|
||||
GUIButton buttonToSelect = null;
|
||||
|
||||
foreach (Affliction affliction in afflictions)
|
||||
@@ -1249,7 +1278,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 +1317,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 +1473,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;
|
||||
|
||||
@@ -1585,7 +1613,7 @@ namespace Barotrauma
|
||||
int i = 0;
|
||||
foreach (LimbHealth limbHealth in limbHealths)
|
||||
{
|
||||
if (limbHealth.IndicatorSprite == null) continue;
|
||||
if (limbHealth.IndicatorSprite == null) { continue; }
|
||||
|
||||
float scale = Math.Min(drawArea.Width / (float)limbHealth.IndicatorSprite.SourceRect.Width, drawArea.Height / (float)limbHealth.IndicatorSprite.SourceRect.Height);
|
||||
|
||||
@@ -1604,6 +1632,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly List<Affliction> afflictionsDisplayedOnLimb = new List<Affliction>();
|
||||
private void DrawHealthWindow(SpriteBatch spriteBatch, Rectangle drawArea, bool allowHighlight)
|
||||
{
|
||||
if (Character.Removed) { return; }
|
||||
@@ -1614,21 +1643,32 @@ namespace Barotrauma
|
||||
int i = 0;
|
||||
foreach (LimbHealth limbHealth in limbHealths)
|
||||
{
|
||||
if (limbHealth.IndicatorSprite == null) continue;
|
||||
if (limbHealth.IndicatorSprite == null) { continue; }
|
||||
|
||||
Rectangle limbEffectiveArea = new Rectangle(limbHealth.IndicatorSprite.SourceRect.X + limbHealth.HighlightArea.X,
|
||||
limbHealth.IndicatorSprite.SourceRect.Y + limbHealth.HighlightArea.Y,
|
||||
limbHealth.HighlightArea.Width,
|
||||
limbHealth.HighlightArea.Height);
|
||||
|
||||
float damageLerp = limbHealth.TotalDamage > 0.0f ? MathHelper.Lerp(0.2f, 1.0f, limbHealth.TotalDamage / 100.0f) : 0.0f;
|
||||
float totalDamage = GetTotalDamage(limbHealth);
|
||||
|
||||
var tempAfflictions = GetMatchingAfflictions(limbHealth, a => true);
|
||||
float damageLerp = totalDamage > 0.0f ? MathHelper.Lerp(0.2f, 1.0f, totalDamage / 100.0f) : 0.0f;
|
||||
|
||||
float negativeEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff && a.ShouldShowIcon(Character)).Sum(a => a.Strength);
|
||||
//float negativeMaxEffect = tempAfflictions.Where(a => !a.Prefab.IsBuff).Sum(a => a.Prefab.MaxStrength);
|
||||
float positiveEffect = tempAfflictions.Where(a => a.Prefab.IsBuff && a.ShouldShowIcon(Character)).Sum(a => a.Strength * 0.2f);
|
||||
//float positiveMaxEffect = tempAfflictions.Where(a => a.Prefab.IsBuff).Sum(a => a.Prefab.MaxStrength);
|
||||
float negativeEffect = 0.0f, positiveEffect = 0.0f;
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
if (kvp.Value != limbHealth) { continue; }
|
||||
var affliction = kvp.Key;
|
||||
if (!affliction.ShouldShowIcon(Character)) { continue; }
|
||||
if (!affliction.Prefab.IsBuff)
|
||||
{
|
||||
negativeEffect += affliction.Strength;
|
||||
}
|
||||
else
|
||||
{
|
||||
positiveEffect += affliction.Strength * 0.2f;
|
||||
}
|
||||
}
|
||||
|
||||
float midPoint = (float)limbEffectiveArea.Center.Y / (float)limbHealth.IndicatorSprite.Texture.Height;
|
||||
float fadeDist = 0.6f * (float)limbEffectiveArea.Height / (float)limbHealth.IndicatorSprite.Texture.Height;
|
||||
@@ -1695,7 +1735,7 @@ namespace Barotrauma
|
||||
drawArea.Width / (float)limbIndicatorOverlay.FrameSize.X,
|
||||
drawArea.Height / (float)limbIndicatorOverlay.FrameSize.Y);
|
||||
|
||||
int frame = 0;
|
||||
int frame;
|
||||
int frameCount = 17;
|
||||
if (limbIndicatorOverlayAnimState >= frameCount * 2) limbIndicatorOverlayAnimState = 0.0f;
|
||||
if (limbIndicatorOverlayAnimState < frameCount)
|
||||
@@ -1739,14 +1779,13 @@ namespace Barotrauma
|
||||
i = 0;
|
||||
foreach (LimbHealth limbHealth in limbHealths)
|
||||
{
|
||||
IEnumerable<Affliction> thisAfflictions = limbHealth.Afflictions.Where(a => a.ShouldShowIcon(Character));
|
||||
thisAfflictions = thisAfflictions.Concat(afflictions.Where(a =>
|
||||
afflictionsDisplayedOnLimb.Clear();
|
||||
foreach (var affliction in afflictions)
|
||||
{
|
||||
Limb indicatorLimb = Character.AnimController.GetLimb(a.Prefab.IndicatorLimb);
|
||||
return indicatorLimb != null && indicatorLimb.HealthIndex == i && a.ShouldShowIcon(Character);
|
||||
}));
|
||||
if (ShouldDisplayAfflictionOnLimb(affliction, limbHealth)) { afflictionsDisplayedOnLimb.Add(affliction.Key); }
|
||||
}
|
||||
|
||||
if (thisAfflictions.Count() <= 0) { i++; continue; }
|
||||
if (!afflictionsDisplayedOnLimb.Any()) { i++; continue; }
|
||||
if (limbHealth.IndicatorSprite == null) { continue; }
|
||||
|
||||
float scale = Math.Min(drawArea.Width / (float)limbHealth.IndicatorSprite.SourceRect.Width, drawArea.Height / (float)limbHealth.IndicatorSprite.SourceRect.Height);
|
||||
@@ -1757,12 +1796,12 @@ namespace Barotrauma
|
||||
Vector2 iconPos = highlightArea.Center.ToVector2();
|
||||
|
||||
//Affliction mostSevereAffliction = thisAfflictions.FirstOrDefault(a => !a.Prefab.IsBuff && !thisAfflictions.Any(a2 => !a2.Prefab.IsBuff && a2.Strength > a.Strength)) ?? thisAfflictions.FirstOrDefault();
|
||||
Affliction mostSevereAffliction = SortAfflictionsBySeverity(thisAfflictions, excludeBuffs: false).FirstOrDefault();
|
||||
Affliction mostSevereAffliction = SortAfflictionsBySeverity(afflictionsDisplayedOnLimb, excludeBuffs: false).FirstOrDefault();
|
||||
if (mostSevereAffliction != null) { DrawLimbAfflictionIcon(spriteBatch, mostSevereAffliction, iconScale, ref iconPos); }
|
||||
|
||||
if (thisAfflictions.Count() > 1)
|
||||
if (afflictionsDisplayedOnLimb.Count() > 1)
|
||||
{
|
||||
string additionalAfflictionCount = $"+{thisAfflictions.Count() - 1}";
|
||||
string additionalAfflictionCount = $"+{afflictionsDisplayedOnLimb.Count() - 1}";
|
||||
Vector2 displace = GUI.SubHeadingFont.MeasureString(additionalAfflictionCount);
|
||||
GUI.SubHeadingFont.DrawString(spriteBatch, additionalAfflictionCount, iconPos + new Vector2(displace.X * 1.1f, -displace.Y * 0.45f), Color.Black * 0.75f);
|
||||
GUI.SubHeadingFont.DrawString(spriteBatch, additionalAfflictionCount, iconPos + new Vector2(displace.X, -displace.Y * 0.5f), Color.White);
|
||||
@@ -1785,6 +1824,22 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private bool ShouldDisplayAfflictionOnLimb(KeyValuePair<Affliction, LimbHealth> kvp, LimbHealth limbHealth)
|
||||
{
|
||||
if (!kvp.Key.ShouldShowIcon(Character)) { return false; }
|
||||
if (kvp.Value == limbHealth)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (kvp.Value == null)
|
||||
{
|
||||
Limb indicatorLimb = Character.AnimController.GetLimb(kvp.Key.Prefab.IndicatorLimb);
|
||||
return indicatorLimb != null && indicatorLimb.HealthIndex == limbHealths.IndexOf(limbHealth);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void DrawLimbAfflictionIcon(SpriteBatch spriteBatch, Affliction affliction, float iconScale, ref Vector2 iconPos)
|
||||
{
|
||||
if (!affliction.ShouldShowIcon(Character) || affliction.Prefab.Icon == null) { return; }
|
||||
@@ -1815,8 +1870,7 @@ namespace Barotrauma
|
||||
healthBarHolder.Visible = value;
|
||||
}
|
||||
|
||||
private readonly List<(AfflictionPrefab afflictionPrefab, float strength)> newAfflictions = new List<(AfflictionPrefab afflictionPrefab, float strength)>();
|
||||
private readonly List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)> newLimbAfflictions = new List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)>();
|
||||
private readonly List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)> newAfflictions = new List<(LimbHealth limb, AfflictionPrefab afflictionPrefab, float strength)>();
|
||||
private readonly List<(AfflictionPrefab.PeriodicEffect effect, float timer)> newPeriodicEffects = new List<(AfflictionPrefab.PeriodicEffect effect, float timer)>();
|
||||
|
||||
public void ClientRead(IReadMessage inc)
|
||||
@@ -1846,47 +1900,9 @@ namespace Barotrauma
|
||||
float periodicAfflictionTimer = inc.ReadRangedSingle(afflictionPrefab.PeriodicEffects[j].MinInterval, afflictionPrefab.PeriodicEffects[j].MaxInterval, 8);
|
||||
newPeriodicEffects.Add((afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
|
||||
}
|
||||
newAfflictions.Add((afflictionPrefab, afflictionStrength));
|
||||
newAfflictions.Add((null, afflictionPrefab, afflictionStrength));
|
||||
}
|
||||
|
||||
foreach (Affliction affliction in afflictions)
|
||||
{
|
||||
//deactivate afflictions that weren't included in the network message
|
||||
if (!newAfflictions.Any(a => a.afflictionPrefab == affliction.Prefab))
|
||||
{
|
||||
affliction.Strength = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (afflictionPrefab, strength) in newAfflictions)
|
||||
{
|
||||
Affliction existingAffliction = afflictions.Find(a => a.Prefab == afflictionPrefab);
|
||||
if (existingAffliction == null)
|
||||
{
|
||||
existingAffliction = afflictionPrefab.Instantiate(strength);
|
||||
afflictions.Add(existingAffliction);
|
||||
}
|
||||
existingAffliction.SetStrength(strength);
|
||||
if (existingAffliction == stunAffliction)
|
||||
{
|
||||
Character.SetStun(existingAffliction.Strength, true, true);
|
||||
}
|
||||
foreach (var periodicEffect in newPeriodicEffects)
|
||||
{
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
|
||||
//timer has wrapped around, apply the effect
|
||||
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
|
||||
{
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
|
||||
foreach (StatusEffect effect in periodicEffect.effect.StatusEffects)
|
||||
{
|
||||
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newLimbAfflictions.Clear();
|
||||
byte limbAfflictionCount = inc.ReadByte();
|
||||
for (int i = 0; i < limbAfflictionCount; i++)
|
||||
{
|
||||
@@ -1912,43 +1928,50 @@ namespace Barotrauma
|
||||
float periodicAfflictionTimer = inc.ReadRangedSingle(afflictionPrefab.PeriodicEffects[j].MinInterval, afflictionPrefab.PeriodicEffects[j].MaxInterval, 8);
|
||||
newPeriodicEffects.Add((afflictionPrefab.PeriodicEffects[j], periodicAfflictionTimer));
|
||||
}
|
||||
newLimbAfflictions.Add((limbHealths[limbIndex], afflictionPrefab, afflictionStrength));
|
||||
newAfflictions.Add((limbHealths[limbIndex], afflictionPrefab, afflictionStrength));
|
||||
}
|
||||
|
||||
foreach (LimbHealth limbHealth in limbHealths)
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
foreach (Affliction affliction in limbHealth.Afflictions)
|
||||
//deactivate afflictions that weren't included in the network message
|
||||
if (!newAfflictions.Any(a => kvp.Key.Prefab == a.afflictionPrefab && kvp.Value == a.limb))
|
||||
{
|
||||
//deactivate afflictions that weren't included in the network message
|
||||
if (!newLimbAfflictions.Any(a => a.limb == limbHealth && a.afflictionPrefab == affliction.Prefab))
|
||||
kvp.Key.Strength = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (limb, afflictionPrefab, strength) in newAfflictions)
|
||||
{
|
||||
Affliction existingAffliction = null;
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
if (kvp.Key.Prefab == afflictionPrefab && kvp.Value == limb)
|
||||
{
|
||||
affliction.Strength = 0.0f;
|
||||
existingAffliction = kvp.Key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (limb, afflictionPrefab, strength) in newLimbAfflictions)
|
||||
if (existingAffliction == null)
|
||||
{
|
||||
if (limb != limbHealth) { continue; }
|
||||
Affliction existingAffliction = limbHealth.Afflictions.Find(a => a.Prefab == afflictionPrefab);
|
||||
if (existingAffliction == null)
|
||||
existingAffliction = afflictionPrefab.Instantiate(strength);
|
||||
afflictions.Add(existingAffliction, limb);
|
||||
}
|
||||
existingAffliction.SetStrength(strength);
|
||||
if (existingAffliction == stunAffliction)
|
||||
{
|
||||
Character.SetStun(existingAffliction.Strength, true, true);
|
||||
}
|
||||
foreach (var periodicEffect in newPeriodicEffects)
|
||||
{
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
|
||||
//timer has wrapped around, apply the effect
|
||||
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
|
||||
{
|
||||
existingAffliction = afflictionPrefab.Instantiate(strength);
|
||||
limbHealth.Afflictions.Add(existingAffliction);
|
||||
}
|
||||
existingAffliction.SetStrength(strength);
|
||||
|
||||
foreach (var periodicEffect in newPeriodicEffects)
|
||||
{
|
||||
if (!existingAffliction.Prefab.PeriodicEffects.Contains(periodicEffect.effect)) { continue; }
|
||||
//timer has wrapped around, apply the effect
|
||||
if (periodicEffect.timer - existingAffliction.PeriodicEffectTimers[periodicEffect.effect] > periodicEffect.effect.MinInterval / 2)
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
|
||||
foreach (StatusEffect effect in periodicEffect.effect.StatusEffects)
|
||||
{
|
||||
existingAffliction.PeriodicEffectTimers[periodicEffect.effect] = periodicEffect.timer;
|
||||
foreach (StatusEffect effect in periodicEffect.effect.StatusEffects)
|
||||
{
|
||||
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == limbHealths.IndexOf(limb));
|
||||
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: targetLimb);
|
||||
}
|
||||
Limb targetLimb = Character.AnimController.Limbs.FirstOrDefault(l => l.HealthIndex == limbHealths.IndexOf(limb));
|
||||
existingAffliction.ApplyStatusEffect(ActionType.OnActive, effect, deltaTime: 1.0f, this, targetLimb: targetLimb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1966,14 +1989,13 @@ namespace Barotrauma
|
||||
|
||||
limb.BurnOverlayStrength = 0.0f;
|
||||
limb.DamageOverlayStrength = 0.0f;
|
||||
if (limbHealths[limb.HealthIndex].Afflictions.Count == 0) continue;
|
||||
foreach (Affliction a in limbHealths[limb.HealthIndex].Afflictions)
|
||||
foreach (KeyValuePair<Affliction, LimbHealth> kvp in afflictions)
|
||||
{
|
||||
limb.BurnOverlayStrength += a.Strength / Math.Min(a.Prefab.MaxStrength, 100) * a.Prefab.BurnOverlayAlpha;
|
||||
limb.DamageOverlayStrength += a.Strength / Math.Min(a.Prefab.MaxStrength, 100) * a.Prefab.DamageOverlayAlpha;
|
||||
if (kvp.Value != limbHealths[limb.HealthIndex]) { continue; }
|
||||
var affliction = kvp.Key;
|
||||
limb.BurnOverlayStrength += affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.BurnOverlayAlpha;
|
||||
limb.DamageOverlayStrength += affliction.Strength / Math.Min(affliction.Prefab.MaxStrength, 100) * affliction.Prefab.DamageOverlayAlpha;
|
||||
}
|
||||
limb.BurnOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count;
|
||||
limb.DamageOverlayStrength /= limbHealths[limb.HealthIndex].Afflictions.Count;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -730,8 +730,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
body.Dir = Dir;
|
||||
|
||||
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
|
||||
|
||||
bool hideLimb = Hide ||
|
||||
|
||||
@@ -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,27 @@ 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);
|
||||
}
|
||||
|
||||
if (SubmarineInfo.SavedSubmarines.None(s => s.Name.ToLowerInvariant() == subName.ToLowerInvariant()))
|
||||
{
|
||||
ThrowError($"Cannot find a sub that matches the name \"{subName}\".");
|
||||
return;
|
||||
}
|
||||
|
||||
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 +757,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 +1433,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)
|
||||
@@ -1447,10 +1467,11 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (ItemPrefab ingredientItemPrefab in ingredient.ItemPrefabs)
|
||||
{
|
||||
NewMessage(" Its ingredient " + ingredientItemPrefab.Name + " has base cost " + ingredientItemPrefab.DefaultPrice.Price);
|
||||
totalPrice += ingredientItemPrefab.DefaultPrice.Price;
|
||||
int defaultPrice = ingredientItemPrefab.DefaultPrice?.Price ?? 0;
|
||||
NewMessage(" Its ingredient " + ingredientItemPrefab.Name + " has base cost " + defaultPrice);
|
||||
totalPrice += defaultPrice;
|
||||
totalBestPrice += ingredientItemPrefab.GetMinPrice();
|
||||
int basePrice = ingredientItemPrefab.DefaultPrice.Price;
|
||||
int basePrice = defaultPrice;
|
||||
foreach (KeyValuePair<string, PriceInfo> ingredientItemLocationPrice in ingredientItemPrefab.GetBuyPricesUnder())
|
||||
{
|
||||
if (basePrice > ingredientItemLocationPrice.Value.Price)
|
||||
@@ -1616,7 +1637,7 @@ namespace Barotrauma
|
||||
|
||||
var fabricationRecipe = fabricableItems.Find(f => f.TargetItem == parentItem);
|
||||
int totalValue = 0;
|
||||
NewMessage(parentItem.Name + " has the price " + parentItem.DefaultPrice.Price);
|
||||
NewMessage(parentItem.Name + " has the price " + (parentItem.DefaultPrice?.Price ?? 0));
|
||||
if (fabricationRecipe != null)
|
||||
{
|
||||
NewMessage(" It constructs from:");
|
||||
@@ -1625,8 +1646,9 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (ItemPrefab itemPrefab in requiredItem.ItemPrefabs)
|
||||
{
|
||||
NewMessage(" " + itemPrefab.Name + " has the price " + itemPrefab.DefaultPrice.Price);
|
||||
totalValue += itemPrefab.DefaultPrice.Price;
|
||||
int defaultPrice = itemPrefab.DefaultPrice?.Price ?? 0;
|
||||
NewMessage(" " + itemPrefab.Name + " has the price " + defaultPrice);
|
||||
totalValue += defaultPrice;
|
||||
}
|
||||
}
|
||||
NewMessage("Its total value was: " + totalValue);
|
||||
@@ -1637,10 +1659,16 @@ namespace Barotrauma
|
||||
{
|
||||
ItemPrefab itemPrefab =
|
||||
(MapEntityPrefab.Find(deconstructItem.ItemIdentifier, identifier: null, showErrorMessages: false) ??
|
||||
MapEntityPrefab.Find(null, identifier: itemNameOrId, showErrorMessages: false)) as ItemPrefab;
|
||||
MapEntityPrefab.Find(null, identifier: deconstructItem.ItemIdentifier, showErrorMessages: false)) as ItemPrefab;
|
||||
if (itemPrefab == null)
|
||||
{
|
||||
ThrowError($" Couldn't find deconstruct product \"{deconstructItem.ItemIdentifier}\"!");
|
||||
continue;
|
||||
}
|
||||
|
||||
NewMessage(" " + itemPrefab.Name + " has the price " + itemPrefab.DefaultPrice.Price);
|
||||
totalValue += itemPrefab.DefaultPrice.Price;
|
||||
int defaultPrice = itemPrefab.DefaultPrice?.Price ?? 0;
|
||||
NewMessage(" " + itemPrefab.Name + " has the price " + defaultPrice);
|
||||
totalValue += defaultPrice;
|
||||
}
|
||||
NewMessage("Its deconstruct value was: " + totalValue);
|
||||
|
||||
@@ -1792,7 +1820,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 +1885,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);
|
||||
@@ -2457,8 +2499,6 @@ namespace Barotrauma
|
||||
NewMessage("Resolution set to 0 x 0 (screen resolution will be used)", Color.Green);
|
||||
NewMessage("Fullscreen enabled", Color.Green);
|
||||
|
||||
GameSettings.ShowUserStatisticsPrompt = true;
|
||||
|
||||
GameSettings.VerboseLogging = false;
|
||||
|
||||
if (GameMain.Config.MasterServerUrl != "http://www.undertowgames.com/baromaster")
|
||||
@@ -3134,7 +3174,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Failed to spawn a submarine. Arguments: \"" + string.Join(" ", args) + "\".";
|
||||
ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.AddErrorEventOnce("DebugConsole.SpawnSubmarine:Error", GameAnalyticsManager.ErrorSeverity.Error, errorMsg + '\n' + e.Message + '\n' + e.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
},
|
||||
() =>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -363,7 +363,7 @@ namespace Barotrauma
|
||||
OnSecondaryClicked = (_, o) =>
|
||||
{
|
||||
if (!(o is Client client)) { return false; }
|
||||
GameMain.GameSession?.CrewManager?.CreateModerationContextMenu(PlayerInput.MousePosition.ToPoint(), client);
|
||||
NetLobbyScreen.CreateModerationContextMenu(client);
|
||||
return true;
|
||||
},
|
||||
Text = senderName
|
||||
@@ -397,6 +397,7 @@ namespace Barotrauma
|
||||
if (GameMain.NetLobbyScreen != null && GameMain.NetworkMember != null)
|
||||
{
|
||||
clickableArea.OnClick = GameMain.NetLobbyScreen.SelectPlayer;
|
||||
clickableArea.OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu;
|
||||
}
|
||||
msgText.ClickableAreas.Add(clickableArea);
|
||||
}
|
||||
@@ -494,7 +495,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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
@@ -438,7 +438,7 @@ namespace Barotrauma
|
||||
Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
|
||||
DrawString(spriteBatch, new Vector2(10, 40),
|
||||
$"Bodies: {GameMain.World.BodyList.Count} ({GameMain.World.BodyList.FindAll(b => b.Awake && b.Enabled).Count} awake, {GameMain.World.BodyList.FindAll(b => b.Awake && b.BodyType == BodyType.Dynamic && b.Enabled).Count} dynamic)",
|
||||
$"Bodies: {GameMain.World.BodyList.Count} ({GameMain.World.BodyList.Count(b => b != null && b.Awake && b.Enabled)} awake, {GameMain.World.BodyList.Count(b => b != null && b.Awake && b.BodyType == BodyType.Dynamic && b.Enabled)} dynamic)",
|
||||
Color.White, Color.Black * 0.5f, 0, SmallFont);
|
||||
|
||||
if (Screen.Selected.Cam != null)
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -63,6 +79,8 @@ namespace Barotrauma
|
||||
|
||||
public bool AllowMouseWheelScroll { get; set; } = true;
|
||||
|
||||
public bool AllowArrowKeyScroll { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the list smoothly
|
||||
/// </summary>
|
||||
@@ -103,7 +121,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 +150,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 +229,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 +270,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 +394,7 @@ namespace Barotrauma
|
||||
(child.UserData == null && userData == null))
|
||||
{
|
||||
Select(i, force, autoScroll);
|
||||
if (!SelectMultiple) return;
|
||||
if (!SelectMultiple) { return; }
|
||||
}
|
||||
i++;
|
||||
}
|
||||
@@ -363,9 +403,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 +419,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 +487,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 +525,7 @@ namespace Barotrauma
|
||||
{
|
||||
CoroutineManager.StartCoroutine(ScrollCoroutine());
|
||||
|
||||
IEnumerable<object> ScrollCoroutine()
|
||||
IEnumerable<CoroutineStatus> ScrollCoroutine()
|
||||
{
|
||||
if (BarSize >= 1.0f)
|
||||
{
|
||||
@@ -490,68 +549,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 +694,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 +708,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 +795,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 +825,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public void ForceUpdate() => Update((float)Timing.Step);
|
||||
|
||||
protected override void Update(float deltaTime)
|
||||
{
|
||||
if (!Visible) { return; }
|
||||
@@ -805,7 +919,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * BarSize;
|
||||
ScrollBar.BarScroll -= (PlayerInput.ScrollWheelSpeed / 500.0f) * ScrollBar.UnclampedBarSize;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -870,6 +984,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 +995,8 @@ namespace Barotrauma
|
||||
|
||||
if (!wasSelected) { return; }
|
||||
|
||||
if (SelectMultiple)
|
||||
if (CurrentSelectMode == SelectMode.SelectMultiple ||
|
||||
(CurrentSelectMode == SelectMode.RequireShiftToSelectMultiple && PlayerInput.IsCtrlDown()))
|
||||
{
|
||||
if (selected.Contains(child))
|
||||
{
|
||||
@@ -891,6 +1007,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 +1070,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 +1148,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 +1196,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 +1215,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);
|
||||
@@ -1106,10 +1256,16 @@ namespace Barotrauma
|
||||
switch (key)
|
||||
{
|
||||
case Keys.Down:
|
||||
SelectNext();
|
||||
if (!isHorizontal && AllowArrowKeyScroll) { SelectNext(); }
|
||||
break;
|
||||
case Keys.Up:
|
||||
SelectPrevious();
|
||||
if (!isHorizontal && AllowArrowKeyScroll) { SelectPrevious(); }
|
||||
break;
|
||||
case Keys.Left:
|
||||
if (isHorizontal && AllowArrowKeyScroll) { SelectPrevious(); }
|
||||
break;
|
||||
case Keys.Right:
|
||||
if (isHorizontal && AllowArrowKeyScroll) { SelectNext(); }
|
||||
break;
|
||||
case Keys.Enter:
|
||||
case Keys.Space:
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Barotrauma
|
||||
{
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GUIProgressBar.BarSize_setter",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Attempted to set the BarSize of a GUIProgressBar to an invalid value (" + value + ")\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
@@ -105,7 +105,7 @@ namespace Barotrauma
|
||||
{
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GUIProgressBar.Draw:GetProgress",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"ProgressGetter of a GUIProgressBar (" + ProgressGetter.Target.ToString() + " - " + ProgressGetter.Method.ToString() + ") returned an invalid value (" + newSize + ")\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
else
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
|
||||
namespace Barotrauma
|
||||
@@ -275,6 +276,7 @@ namespace Barotrauma
|
||||
|
||||
public delegate void OnClickDelegate(GUITextBlock textBlock, ClickableArea area);
|
||||
public OnClickDelegate OnClick;
|
||||
public OnClickDelegate OnSecondaryClick;
|
||||
}
|
||||
public List<ClickableArea> ClickableAreas { get; private set; } = new List<ClickableArea>();
|
||||
|
||||
@@ -376,6 +378,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 +392,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,115 +480,56 @@ 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)
|
||||
{
|
||||
base.Update(deltaTime);
|
||||
|
||||
if (ClickableAreas.Any() && (GUI.MouseOn?.IsParentOf(this) ?? true))
|
||||
if (ClickableAreas.Any() && ((GUI.MouseOn?.IsParentOf(this) ?? true) || GUI.MouseOn == this))
|
||||
{
|
||||
if (!Rect.Contains(PlayerInput.MousePosition)) { return; }
|
||||
int index = GetCaretIndexFromScreenPos(PlayerInput.MousePosition);
|
||||
@@ -598,6 +542,10 @@ namespace Barotrauma
|
||||
{
|
||||
clickableArea.OnClick?.Invoke(this, clickableArea);
|
||||
}
|
||||
if (PlayerInput.SecondaryMouseButtonClicked())
|
||||
{
|
||||
clickableArea.OnSecondaryClick?.Invoke(this, clickableArea);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace Barotrauma
|
||||
private int? maxTextLength;
|
||||
|
||||
private int _caretIndex;
|
||||
private int CaretIndex
|
||||
public int CaretIndex
|
||||
{
|
||||
get { return _caretIndex; }
|
||||
set
|
||||
@@ -353,34 +353,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;
|
||||
}
|
||||
@@ -393,6 +382,7 @@ namespace Barotrauma
|
||||
memento.Store(Text);
|
||||
}
|
||||
CaretIndex = forcedCaretIndex == - 1 ? textBlock.GetCaretIndexFromScreenPos(PlayerInput.MousePosition) : forcedCaretIndex;
|
||||
CalculateCaretPos();
|
||||
ClearSelection();
|
||||
selected = true;
|
||||
GUI.KeyboardDispatcher.Subscriber = this;
|
||||
@@ -548,59 +538,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
|
||||
{
|
||||
@@ -738,8 +706,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();
|
||||
@@ -749,8 +724,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();
|
||||
@@ -813,6 +795,7 @@ namespace Barotrauma
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (caretPosDirty) { CalculateCaretPos(); }
|
||||
OnKeyHit?.Invoke(this, key);
|
||||
void HandleSelection()
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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 ?
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -562,7 +562,7 @@ namespace Barotrauma
|
||||
|
||||
frame.OnSecondaryClicked += (component, data) =>
|
||||
{
|
||||
GameMain.GameSession?.CrewManager?.CreateModerationContextMenu(PlayerInput.MousePosition.ToPoint(), client);
|
||||
NetLobbyScreen.CreateModerationContextMenu(client);
|
||||
return true;
|
||||
};
|
||||
|
||||
@@ -917,7 +917,8 @@ namespace Barotrauma
|
||||
textBlock.ClickableAreas.Add(new GUITextBlock.ClickableArea()
|
||||
{
|
||||
Data = data,
|
||||
OnClick = GameMain.NetLobbyScreen.SelectPlayer
|
||||
OnClick = GameMain.NetLobbyScreen.SelectPlayer,
|
||||
OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1486,12 +1487,13 @@ namespace Barotrauma
|
||||
experienceBar = new GUIProgressBar(new RectTransform(new Vector2(1f, 1f), experienceBarFrame.RectTransform, Anchor.CenterLeft),
|
||||
barSize: controlledCharacter.Info.GetProgressTowardsNextLevel(), color: GUI.Style.Green)
|
||||
{
|
||||
IsHorizontal = true
|
||||
IsHorizontal = true,
|
||||
};
|
||||
|
||||
experienceText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), experienceBarFrame.RectTransform, anchor: Anchor.Center), "", font: GUI.Font, textAlignment: Alignment.CenterRight)
|
||||
{
|
||||
Shadow = true
|
||||
Shadow = true,
|
||||
ToolTip = TextManager.Get("experiencetooltip")
|
||||
};
|
||||
|
||||
talentPointText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.5f), experienceLayout.RectTransform, anchor: Anchor.Center), "", font: GUI.SubHeadingFont, parseRichText: true, textAlignment: Alignment.CenterRight) { AutoScaleVertical = true };
|
||||
@@ -1541,13 +1543,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 +1585,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});
|
||||
@@ -1611,6 +1645,7 @@ namespace Barotrauma
|
||||
GameMain.Client.CreateEntityEvent(controlledCharacter, new object[] { NetEntityEvent.Type.UpdateTalents });
|
||||
}
|
||||
}
|
||||
selectedTalents = controlledCharacter.Info.GetUnlockedTalentsInTree().ToList();
|
||||
UpdateTalentButtons();
|
||||
}
|
||||
|
||||
|
||||
@@ -846,23 +846,27 @@ namespace Barotrauma
|
||||
|
||||
var currentOrPending = item.PendingItemSwap ?? item.Prefab;
|
||||
string name = currentOrPending.Name;
|
||||
string quantityText = "";
|
||||
string nameWithQuantity = "";
|
||||
if (linkedItems.Count > 1)
|
||||
{
|
||||
foreach (ItemPrefab distinctItem in linkedItems.Select(it => it.Prefab).Distinct())
|
||||
{
|
||||
if (quantityText != string.Empty)
|
||||
if (nameWithQuantity != string.Empty)
|
||||
{
|
||||
quantityText += ", ";
|
||||
nameWithQuantity += ", ";
|
||||
}
|
||||
int count = linkedItems.Count(it => it.Prefab == distinctItem);
|
||||
quantityText += distinctItem.Name;
|
||||
nameWithQuantity += distinctItem.Name;
|
||||
if (count > 1)
|
||||
{
|
||||
quantityText += " " + TextManager.GetWithVariable("campaignstore.quantity", "[amount]", count.ToString());
|
||||
nameWithQuantity += " " + TextManager.GetWithVariable("campaignstore.quantity", "[amount]", count.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
nameWithQuantity = name;
|
||||
}
|
||||
|
||||
bool isOpen = false;
|
||||
GUIButton toggleButton = new GUIButton(rectT(1f, 0.1f, parent.Content), text: string.Empty, style: "SlideDown")
|
||||
@@ -884,7 +888,7 @@ namespace Barotrauma
|
||||
new GUITextBlock(rectT(0.3f, 1f, buttonLayout), text: slotText, font: GUI.SubHeadingFont);
|
||||
GUILayoutGroup group = new GUILayoutGroup(rectT(0.7f, 1f, buttonLayout), isHorizontal: true) { Stretch = true };
|
||||
|
||||
string title = item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : quantityText;
|
||||
string title = item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : nameWithQuantity;
|
||||
GUITextBlock text = new GUITextBlock(rectT(0.7f, 1f, group), text: title, font: GUI.SubHeadingFont, textAlignment: Alignment.Right, parseRichText: true)
|
||||
{
|
||||
TextColor = GUI.Style.Orange
|
||||
@@ -907,7 +911,7 @@ namespace Barotrauma
|
||||
if (isUninstallPending) { canUninstall = false; }
|
||||
|
||||
frames.Add(CreateUpgradeEntry(rectT(1f, 0.25f, parent.Content), currentOrPending.UpgradePreviewSprite,
|
||||
item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : TextManager.GetWithVariable("upgrades.installeditem", "[itemname]", quantityText),
|
||||
item.PendingItemSwap != null ? TextManager.GetWithVariable("upgrades.pendingitem", "[itemname]", name) : TextManager.GetWithVariable("upgrades.installeditem", "[itemname]", nameWithQuantity),
|
||||
currentOrPending.Description,
|
||||
0, null, addBuyButton: canUninstall, addProgressBar: false, buttonStyle: "WeaponUninstallButton"));
|
||||
|
||||
|
||||
@@ -0,0 +1,114 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using Barotrauma.IO;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
public static partial class GameAnalyticsManager
|
||||
{
|
||||
static partial void CreateConsentPrompt()
|
||||
{
|
||||
if (consentTextAvailable)
|
||||
{
|
||||
var background = new GUIFrame(new RectTransform(Vector2.One, GUI.Canvas), style: "GUIBackgroundBlocker");
|
||||
var frame = new GUIFrame(new RectTransform(new Vector2(0.5f, 0.7f), background.RectTransform, Anchor.Center) { MaxSize = new Point(800, int.MaxValue) });
|
||||
|
||||
var content = new GUILayoutGroup(new RectTransform(new Vector2(0.95f), frame.RectTransform, Anchor.Center))
|
||||
{
|
||||
Stretch = true,
|
||||
AbsoluteSpacing = GUI.IntScale(15)
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.Get("statisticsconsentheader"), font: GUI.SubHeadingFont, textColor: Color.White);
|
||||
var mainText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.Get("statisticsconsenttext"), wrap: true, parseRichText: true);
|
||||
|
||||
foreach (var data in mainText.RichTextData)
|
||||
{
|
||||
mainText.ClickableAreas.Add(new GUITextBlock.ClickableArea()
|
||||
{
|
||||
Data = data,
|
||||
OnClick = (GUITextBlock component, GUITextBlock.ClickableArea area) =>
|
||||
{
|
||||
GameMain.Instance.ShowOpenUrlInWebBrowserPrompt("https://gameanalytics.com/privacy/");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
string privacyPolicyText = File.ReadAllText("daedalic_privacypolicy.txt");
|
||||
var privacyPolicyBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.5f), content.RectTransform) { MaxSize = new Point(int.MaxValue, GUI.IntScale(200)) });
|
||||
var privacyPolicy = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), privacyPolicyBox.Content.RectTransform), privacyPolicyText, wrap: true)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
privacyPolicy.RectTransform.MinSize = new Point(0, (int)privacyPolicy.TextSize.Y);
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), TextManager.Get("statisticsconsentstatement"), wrap: true);
|
||||
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.0f), content.RectTransform), isHorizontal: true);
|
||||
|
||||
void buttonContainerSpacing(float width)
|
||||
=> new GUIFrame(new RectTransform(new Vector2(width, 1.0f), buttonContainer.RectTransform), style: null);
|
||||
|
||||
buttonContainerSpacing(0.1f);
|
||||
var yesBtn = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform), TextManager.Get("Yes"));
|
||||
yesBtn.OnClicked += (btn, userdata) =>
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.Remove(background);
|
||||
SetConsentInternal(Consent.Yes);
|
||||
return true;
|
||||
};
|
||||
yesBtn.Enabled = false;
|
||||
|
||||
IEnumerable<CoroutineStatus> enableAfterTime(WaitForSeconds time, params GUIComponent[] components)
|
||||
{
|
||||
yield return time;
|
||||
foreach (var c in components)
|
||||
{
|
||||
c.Enabled = true;
|
||||
}
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
buttonContainerSpacing(0.2f);
|
||||
|
||||
var noBtn = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), buttonContainer.RectTransform), TextManager.Get("No"));
|
||||
noBtn.OnClicked += (btn, userdata) =>
|
||||
{
|
||||
GUIMessageBox.MessageBoxes.Remove(background);
|
||||
SetConsent(Consent.No);
|
||||
return true;
|
||||
};
|
||||
noBtn.Enabled = false;
|
||||
|
||||
CoroutineManager.StartCoroutine(enableAfterTime(new WaitForSeconds(0.3f), yesBtn, noBtn));
|
||||
|
||||
buttonContainerSpacing(0.1f);
|
||||
|
||||
buttonContainer.RectTransform.MinSize = new Point(0, yesBtn.RectTransform.MinSize.Y);
|
||||
buttonContainer.RectTransform.MaxSize = new Point(int.MaxValue, yesBtn.RectTransform.MinSize.Y);
|
||||
|
||||
foreach (var child in content.Children)
|
||||
{
|
||||
if (child is GUITextBlock textBlock)
|
||||
{
|
||||
textBlock.RectTransform.MinSize = new Point(0, (int)textBlock.TextSize.Y);
|
||||
textBlock.RectTransform.MaxSize = new Point(int.MaxValue, (int)textBlock.TextSize.Y + GUI.IntScale(15));
|
||||
}
|
||||
}
|
||||
|
||||
frame.RectTransform.MaxSize = new Point(
|
||||
frame.RectTransform.MaxSize.X,
|
||||
(int)(content.Children.Sum(c => c.RectTransform.MaxSize.Y + content.AbsoluteSpacing) / content.RectTransform.RelativeSize.Y));
|
||||
|
||||
GUIMessageBox.MessageBoxes.Add(background);
|
||||
}
|
||||
else
|
||||
{
|
||||
//user statistics disabled by default if the prompt cannot be shown in the user's language
|
||||
SetConsent(Consent.Unknown);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,6 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using GameAnalyticsSDK.Net;
|
||||
using Barotrauma.IO;
|
||||
using System.Threading;
|
||||
using Barotrauma.Tutorials;
|
||||
@@ -388,51 +387,6 @@ namespace Barotrauma
|
||||
loadingCoroutine = CoroutineManager.StartCoroutine(Load(canLoadInSeparateThread), "Load", canLoadInSeparateThread);
|
||||
}
|
||||
|
||||
private void InitUserStats()
|
||||
{
|
||||
return;
|
||||
|
||||
if (GameSettings.ShowUserStatisticsPrompt)
|
||||
{
|
||||
if (TextManager.ContainsTag("statisticspromptheader") && TextManager.ContainsTag("statisticsprompttext"))
|
||||
{
|
||||
var userStatsPrompt = new GUIMessageBox(
|
||||
TextManager.Get("statisticspromptheader"),
|
||||
TextManager.Get("statisticsprompttext"),
|
||||
new string[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||
userStatsPrompt.Buttons[0].OnClicked += (btn, userdata) =>
|
||||
{
|
||||
GameSettings.ShowUserStatisticsPrompt = false;
|
||||
GameSettings.SendUserStatistics = true;
|
||||
GameAnalyticsManager.Init();
|
||||
Config.SaveNewPlayerConfig();
|
||||
return true;
|
||||
};
|
||||
userStatsPrompt.Buttons[0].OnClicked += userStatsPrompt.Close;
|
||||
userStatsPrompt.Buttons[1].OnClicked += (btn, userdata) =>
|
||||
{
|
||||
GameSettings.ShowUserStatisticsPrompt = false;
|
||||
GameSettings.SendUserStatistics = false;
|
||||
Config.SaveNewPlayerConfig();
|
||||
return true;
|
||||
};
|
||||
userStatsPrompt.Buttons[1].OnClicked += userStatsPrompt.Close;
|
||||
}
|
||||
else
|
||||
{
|
||||
//user statistics enabled by default if the prompt cannot be shown in the user's language
|
||||
GameSettings.ShowUserStatisticsPrompt = false;
|
||||
GameSettings.SendUserStatistics = true;
|
||||
GameAnalyticsManager.Init();
|
||||
Config.SaveNewPlayerConfig();
|
||||
}
|
||||
}
|
||||
else if (GameSettings.SendUserStatistics)
|
||||
{
|
||||
GameAnalyticsManager.Init();
|
||||
}
|
||||
}
|
||||
|
||||
public class LoadingException : Exception
|
||||
{
|
||||
public LoadingException(Exception e) : base("Loading was interrupted due to an error.", innerException: e)
|
||||
@@ -440,7 +394,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<object> Load(bool isSeparateThread)
|
||||
private IEnumerable<CoroutineStatus> Load(bool isSeparateThread)
|
||||
{
|
||||
if (GameSettings.VerboseLogging)
|
||||
{
|
||||
@@ -526,21 +480,17 @@ namespace Barotrauma
|
||||
DebugConsole.Log("Selected content packages: " + string.Join(", ", Config.AllEnabledPackages.Select(cp => cp.Name)));
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
GameSettings.ShowUserStatisticsPrompt = false;
|
||||
GameSettings.SendUserStatistics = false;
|
||||
#if !DEBUG
|
||||
GameAnalyticsManager.InitIfConsented();
|
||||
#endif
|
||||
|
||||
InitUserStats();
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
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++;
|
||||
@@ -846,6 +796,8 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
|
||||
NetworkMember?.Update((float)Timing.Step);
|
||||
|
||||
if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine))
|
||||
{
|
||||
throw new LoadingException(loadingCoroutine.Exception);
|
||||
@@ -920,6 +872,11 @@ namespace Barotrauma
|
||||
{
|
||||
gameSession.ToggleTabMenu();
|
||||
}
|
||||
else if (GUIMessageBox.VisibleBox as GUIMessageBox != null &&
|
||||
GUIMessageBox.VisibleBox.UserData as string == "bugreporter")
|
||||
{
|
||||
((GUIMessageBox)GUIMessageBox.VisibleBox).Close();
|
||||
}
|
||||
else if (GUI.PauseMenuOpen)
|
||||
{
|
||||
GUI.TogglePauseMenu();
|
||||
@@ -1131,6 +1088,10 @@ namespace Barotrauma
|
||||
|
||||
if (GameSession != null)
|
||||
{
|
||||
double roundDuration = Timing.TotalTime - GameSession.RoundStartTime;
|
||||
GameAnalyticsManager.AddProgressionEvent(GameAnalyticsManager.ProgressionStatus.Fail,
|
||||
GameSession.GameMode?.Name ?? "none",
|
||||
roundDuration);
|
||||
if (Tutorial.Initialized)
|
||||
{
|
||||
((TutorialMode)GameSession.GameMode).Tutorial?.Stop();
|
||||
@@ -1139,6 +1100,7 @@ namespace Barotrauma
|
||||
GUIMessageBox.CloseAll();
|
||||
MainMenuScreen.Select();
|
||||
GameSession = null;
|
||||
|
||||
}
|
||||
|
||||
public void ShowCampaignDisclaimer(Action onContinue = null)
|
||||
@@ -1238,7 +1200,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;
|
||||
@@ -1262,8 +1224,8 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Error while cleaning unnecessary save files", e);
|
||||
}
|
||||
|
||||
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
|
||||
if (GameSettings.SaveDebugConsoleLogs) { DebugConsole.SaveLogs(); }
|
||||
if (GameAnalyticsManager.SendUserStatistics) { GameAnalyticsManager.ShutDown(); }
|
||||
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
|
||||
|
||||
base.OnExiting(sender, args);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -100,7 +100,7 @@ namespace Barotrauma
|
||||
{
|
||||
AutoHideScrollBar = false,
|
||||
CanBeFocused = false,
|
||||
CanDragElements = true,
|
||||
CurrentDragMode = GUIListBox.DragMode.DragWithinBox,
|
||||
CanInteractWhenUnfocusable = true,
|
||||
OnSelected = (component, userData) => false,
|
||||
SelectMultiple = false,
|
||||
@@ -330,7 +330,7 @@ namespace Barotrauma
|
||||
if (data == null) { return false; }
|
||||
if (GameMain.NetworkMember?.ConnectedClients?.Find(c => c.Character == data) is Client client)
|
||||
{
|
||||
CreateModerationContextMenu(PlayerInput.MousePosition.ToPoint(), client);
|
||||
NetLobbyScreen.CreateModerationContextMenu(client);
|
||||
return true;
|
||||
}
|
||||
return 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);
|
||||
@@ -777,7 +789,7 @@ namespace Barotrauma
|
||||
}
|
||||
else if (orderGiver != null)
|
||||
{
|
||||
OrderChatMessage msg = new OrderChatMessage(order, option, priority, order?.TargetSpatialEntity ?? order?.TargetItemComponent?.Item as ISpatialEntity, character, orderGiver);
|
||||
OrderChatMessage msg = new OrderChatMessage(order, option, priority, order?.TargetSpatialEntity ?? order?.TargetItemComponent?.Item, character, orderGiver);
|
||||
GameMain.Client?.SendChatMessage(msg);
|
||||
}
|
||||
}
|
||||
@@ -956,7 +968,8 @@ namespace Barotrauma
|
||||
{
|
||||
if (!CanIssueOrders) { return false; }
|
||||
var orderInfo = (OrderInfo)userData;
|
||||
SetCharacterOrder(character, orderInfo.Order, orderInfo.OrderOption, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
|
||||
int priority = GetManualOrderPriority(character, orderInfo.Order);
|
||||
SetCharacterOrder(character, orderInfo.Order, orderInfo.OrderOption, priority, Character.Controlled);
|
||||
return true;
|
||||
},
|
||||
OnSecondaryClicked = (button, userData) =>
|
||||
@@ -1141,105 +1154,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
#region Context Menu
|
||||
|
||||
public void CreateModerationContextMenu(Point mousePos, Client client)
|
||||
{
|
||||
if (GUIContextMenu.CurrentContextMenu != null) { return; }
|
||||
if (IsSinglePlayer || client == null || ((!GameMain.Client?.PreviouslyConnectedClients?.Contains(client)) ?? true)) { return; }
|
||||
|
||||
|
||||
bool hasSteam = client.SteamID > 0 && SteamManager.IsInitialized,
|
||||
canKick = GameMain.Client.HasPermission(ClientPermissions.Kick),
|
||||
canBan = GameMain.Client.HasPermission(ClientPermissions.Ban) && client.AllowKicking,
|
||||
canPromo = GameMain.Client.HasPermission(ClientPermissions.ManagePermissions);
|
||||
|
||||
// Disable options if we are targeting ourselves
|
||||
if (client.ID == GameMain.Client?.ID)
|
||||
{
|
||||
canKick = canBan = canPromo = false;
|
||||
}
|
||||
|
||||
List<ContextMenuOption> options = new List<ContextMenuOption>();
|
||||
|
||||
options.Add(new ContextMenuOption("ViewSteamProfile", isEnabled: hasSteam, onSelected: delegate
|
||||
{
|
||||
Steamworks.SteamFriends.OpenWebOverlay($"https://steamcommunity.com/profiles/{client.SteamID}");
|
||||
}));
|
||||
|
||||
options.Add(new ContextMenuOption("ModerationMenu.UserDetails", isEnabled: true, onSelected: delegate
|
||||
{
|
||||
GameMain.NetLobbyScreen?.SelectPlayer(client);
|
||||
}));
|
||||
|
||||
|
||||
// Creates sub context menu options for all the ranks
|
||||
List<ContextMenuOption> permissionOptions = new List<ContextMenuOption>();
|
||||
foreach (PermissionPreset rank in PermissionPreset.List)
|
||||
{
|
||||
permissionOptions.Add(new ContextMenuOption(rank.Name, isEnabled: true, onSelected: () =>
|
||||
{
|
||||
string label = TextManager.GetWithVariables(rank.Permissions == ClientPermissions.None ? "clearrankprompt" : "giverankprompt", new []{ "[user]", "[rank]" }, new []{ client.Name, rank.Name });
|
||||
GUIMessageBox msgBox = new GUIMessageBox(string.Empty, label, new[] { TextManager.Get("Yes"), TextManager.Get("Cancel") });
|
||||
|
||||
msgBox.Buttons[0].OnClicked = delegate
|
||||
{
|
||||
client.SetPermissions(rank.Permissions, rank.PermittedCommands);
|
||||
GameMain.Client.UpdateClientPermissions(client);
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
msgBox.Buttons[1].OnClicked = delegate
|
||||
{
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
}) { Tooltip = rank.Description });
|
||||
}
|
||||
|
||||
options.Add(new ContextMenuOption("Permissions", isEnabled: canPromo, options: permissionOptions.ToArray()));
|
||||
|
||||
Color clientColor = client.Character?.Info?.Job.Prefab.UIColor ?? Color.White;
|
||||
|
||||
if (GameMain.Client.ConnectedClients.Contains(client))
|
||||
{
|
||||
options.Add(new ContextMenuOption(client.MutedLocally ? "Unmute" : "Mute", isEnabled: client.ID != GameMain.Client?.ID, onSelected: delegate
|
||||
{
|
||||
client.MutedLocally = !client.MutedLocally;
|
||||
}));
|
||||
|
||||
bool kickEnabled = client.ID != GameMain.Client?.ID && client.AllowKicking;
|
||||
|
||||
// if the user can kick create a kick option else create the votekick option
|
||||
ContextMenuOption kickOption;
|
||||
if (canKick)
|
||||
{
|
||||
kickOption = new ContextMenuOption("Kick", isEnabled: kickEnabled, onSelected: delegate
|
||||
{
|
||||
GameMain.Client?.CreateKickReasonPrompt(client.Name, false);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
kickOption = new ContextMenuOption("VoteToKick", isEnabled: kickEnabled, onSelected: delegate
|
||||
{
|
||||
GameMain.Client?.VoteForKick(client);
|
||||
});
|
||||
}
|
||||
|
||||
options.Add(kickOption);
|
||||
}
|
||||
|
||||
options.Add(new ContextMenuOption("Ban", isEnabled: canBan, onSelected: delegate
|
||||
{
|
||||
GameMain.Client?.CreateKickReasonPrompt(client.Name, true);
|
||||
}));
|
||||
|
||||
GUIContextMenu.CreateContextMenu(null, client.Name, headerColor: clientColor, options.ToArray());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void AddToGUIUpdateList()
|
||||
{
|
||||
if (GUI.DisableHUD) { return; }
|
||||
@@ -1648,7 +1562,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);
|
||||
}
|
||||
@@ -1890,7 +1804,7 @@ namespace Barotrauma
|
||||
private Hull hullContext;
|
||||
private WallSection wallContext;
|
||||
private bool isContextual;
|
||||
private readonly List<Order> contextualOrders = new List<Order>();
|
||||
private readonly List<OrderInfo> contextualOrders = new List<OrderInfo>();
|
||||
private Point shorcutCenterNodeOffset;
|
||||
private const int maxShortcutNodeCount = 4;
|
||||
|
||||
@@ -2593,7 +2507,7 @@ namespace Barotrauma
|
||||
{
|
||||
order = orders[i];
|
||||
disableNode = !CanCharacterBeHeard() ||
|
||||
(order.MustSetTarget && (order.ItemComponentType != null || order.TargetItems.Length > 0) &&
|
||||
(order.MustSetTarget && (order.ItemComponentType != null || order.GetTargetItems().Any() || order.RequireItems.Any()) &&
|
||||
order.GetMatchingItems(true, interactableFor: characterContext ?? Character.Controlled).None());
|
||||
optionNodes.Add(new Tuple<GUIComponent, Keys>(
|
||||
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), order, (i + 1) % 10, disableNode: disableNode, checkIfOrderCanBeHeard: false),
|
||||
@@ -2609,7 +2523,6 @@ namespace Barotrauma
|
||||
if (contextualOrders.None())
|
||||
{
|
||||
string orderIdentifier;
|
||||
|
||||
// Check if targeting an item or a hull
|
||||
if (itemContext != null && itemContext.IsPlayerTeamInteractable)
|
||||
{
|
||||
@@ -2618,84 +2531,89 @@ namespace Barotrauma
|
||||
{
|
||||
targetComponent = null;
|
||||
if (p.UseController && itemContext.Components.None(c => c is Controller)) { continue; }
|
||||
if ((p.TargetItems.Length > 0 && (p.TargetItems.Contains(itemContext.Prefab.Identifier) || itemContext.HasTag(p.TargetItems))) ||
|
||||
p.TryGetTargetItemComponent(itemContext, out targetComponent))
|
||||
if (p.HasOptionSpecificTargetItems)
|
||||
{
|
||||
contextualOrders.Add(p.HasOptions ? p : new Order(p, itemContext, targetComponent, Character.Controlled));
|
||||
foreach (string option in p.Options)
|
||||
{
|
||||
if (p.TargetItemsMatchItem(itemContext, option))
|
||||
{
|
||||
contextualOrders.Add(new OrderInfo(new Order(p, itemContext, targetComponent, Character.Controlled), option));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (p.TargetItemsMatchItem(itemContext) || p.TryGetTargetItemComponent(itemContext, out targetComponent))
|
||||
{
|
||||
contextualOrders.Add(new OrderInfo(p.HasOptions ? p : new Order(p, itemContext, targetComponent, Character.Controlled), null));
|
||||
}
|
||||
}
|
||||
|
||||
// If targeting a periscope connected to a turret, show the 'operateweapons' order
|
||||
orderIdentifier = "operateweapons";
|
||||
var operateWeaponsPrefab = Order.GetPrefab(orderIdentifier);
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && itemContext.Components.Any(c => c is Controller))
|
||||
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)) && itemContext.Components.Any(c => c is Controller))
|
||||
{
|
||||
var turret = itemContext.GetConnectedComponents<Turret>().FirstOrDefault(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems)) ??
|
||||
itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault(c => c.Item.HasTag(operateWeaponsPrefab.TargetItems));
|
||||
if (turret != null) { contextualOrders.Add(new Order(operateWeaponsPrefab, turret.Item, turret, Character.Controlled)); }
|
||||
var turret = itemContext.GetConnectedComponents<Turret>().FirstOrDefault(c => operateWeaponsPrefab.TargetItemsMatchItem(c.Item)) ??
|
||||
itemContext.GetConnectedComponents<Turret>(recursive: true).FirstOrDefault(c => operateWeaponsPrefab.TargetItemsMatchItem(c.Item));
|
||||
if (turret != null)
|
||||
{
|
||||
contextualOrders.Add(new OrderInfo(new Order(operateWeaponsPrefab, turret.Item, turret, Character.Controlled), null));
|
||||
}
|
||||
}
|
||||
|
||||
// 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(info => info.Order.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"))))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("repairelectrical"), itemContext, targetItem: null, Character.Controlled));
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab("repairelectrical"), itemContext, targetItem: null, Character.Controlled), null));
|
||||
}
|
||||
else if (itemContext.Repairables.Any(r => r != null && r.requiredSkills.Any(s => s != null && s.Identifier.Equals("mechanical"))))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("repairmechanical"), itemContext, targetItem: null, Character.Controlled));
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab("repairmechanical"), itemContext, targetItem: null, Character.Controlled), null));
|
||||
}
|
||||
else
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled));
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled), null));
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the 'pumpwater' order if the target pump is auto-controlled (as it will immediately overwrite the work done by the bot)
|
||||
orderIdentifier = "pumpwater";
|
||||
if (contextualOrders.FirstOrDefault(o => o.Identifier.Equals(orderIdentifier)) is Order o &&
|
||||
itemContext.Components.FirstOrDefault(c => c.GetType() == o.ItemComponentType) is Pump pump)
|
||||
if (contextualOrders.FirstOrDefault(info => info.Order.Identifier.Equals(orderIdentifier)) is OrderInfo pumpOrderInfo && pumpOrderInfo.Order is Order pumpOrder &&
|
||||
itemContext.Components.FirstOrDefault(c => c.GetType() == pumpOrder.ItemComponentType) is Pump pump && pump.IsAutoControlled)
|
||||
{
|
||||
if (pump.IsAutoControlled) { contextualOrders.Remove(o); }
|
||||
contextualOrders.Remove(pumpOrderInfo);
|
||||
}
|
||||
|
||||
if (contextualOrders.None())
|
||||
{
|
||||
orderIdentifier = "cleanupitems";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
|
||||
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)))
|
||||
{
|
||||
if (AIObjectiveCleanupItems.IsValidTarget(itemContext, Character.Controlled, checkInventory: false) || AIObjectiveCleanupItems.IsValidContainer(itemContext, Character.Controlled))
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled));
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), itemContext, targetItem: null, Character.Controlled), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AddIgnoreOrder(itemContext);
|
||||
}
|
||||
else if (hullContext != null)
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab("fixleaks"), hullContext, targetItem: null, Character.Controlled));
|
||||
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab("fixleaks"), hullContext, targetItem: null, Character.Controlled), null));
|
||||
if (wallContext != null)
|
||||
{
|
||||
AddIgnoreOrder(wallContext);
|
||||
}
|
||||
}
|
||||
|
||||
void AddIgnoreOrder(IIgnorable target)
|
||||
{
|
||||
var orderIdentifier = "ignorethis";
|
||||
if (!target.OrderedToBeIgnored && contextualOrders.None(o => o.Identifier == orderIdentifier))
|
||||
if (!target.OrderedToBeIgnored && contextualOrders.None(info => info.Order.Identifier == orderIdentifier))
|
||||
{
|
||||
AddOrder();
|
||||
}
|
||||
else
|
||||
{
|
||||
orderIdentifier = "unignorethis";
|
||||
if (target.OrderedToBeIgnored && contextualOrders.None(o => o.Identifier == orderIdentifier))
|
||||
if (target.OrderedToBeIgnored && contextualOrders.None(info => info.Order.Identifier == orderIdentifier))
|
||||
{
|
||||
AddOrder();
|
||||
}
|
||||
@@ -2705,64 +2623,61 @@ namespace Barotrauma
|
||||
{
|
||||
if (target is WallSection ws)
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), ws.Wall, ws.Wall.Sections.IndexOf(ws), orderGiver: Character.Controlled));
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), ws.Wall, ws.Wall.Sections.IndexOf(ws), orderGiver: Character.Controlled), null));
|
||||
}
|
||||
else
|
||||
{
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), target as Entity, null, Character.Controlled));
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), target as Entity, null, Character.Controlled), null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
orderIdentifier = "wait";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
|
||||
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)))
|
||||
{
|
||||
Vector2 position = GameMain.GameScreen.Cam.ScreenToWorld(PlayerInput.MousePosition);
|
||||
Hull hull = Hull.FindHull(position, guess: Character.Controlled?.CurrentHull);
|
||||
contextualOrders.Add(new Order(Order.GetPrefab(orderIdentifier), new OrderTarget(position, hull), Character.Controlled));
|
||||
contextualOrders.Add(new OrderInfo(new Order(Order.GetPrefab(orderIdentifier), new OrderTarget(position, hull), Character.Controlled), null));
|
||||
}
|
||||
|
||||
if (contextualOrders.None(o => o.Category != OrderCategory.Movement) && characters.Any(c => c != Character.Controlled))
|
||||
if (contextualOrders.None(info => info.Order.Category != OrderCategory.Movement) && characters.Any(c => c != Character.Controlled))
|
||||
{
|
||||
orderIdentifier = "follow";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)))
|
||||
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)))
|
||||
{
|
||||
contextualOrders.Add(Order.GetPrefab(orderIdentifier));
|
||||
contextualOrders.Add(new OrderInfo(Order.GetPrefab(orderIdentifier), null));
|
||||
}
|
||||
}
|
||||
|
||||
// Show 'dismiss' order only when there are crew members with active orders
|
||||
orderIdentifier = "dismissed";
|
||||
if (contextualOrders.None(o => o.Identifier.Equals(orderIdentifier)) && characters.Any(c => !c.IsDismissed))
|
||||
if (contextualOrders.None(info => info.Order.Identifier.Equals(orderIdentifier)) && characters.Any(c => !c.IsDismissed))
|
||||
{
|
||||
contextualOrders.Add(Order.GetPrefab(orderIdentifier));
|
||||
contextualOrders.Add(new OrderInfo(Order.GetPrefab(orderIdentifier), null));
|
||||
}
|
||||
}
|
||||
|
||||
var offsets = MathUtils.GetPointsOnCircumference(Vector2.Zero, nodeDistance, contextualOrders.Count, MathHelper.ToRadians(90f + 180f / contextualOrders.Count));
|
||||
bool disableNode = !CanCharacterBeHeard();
|
||||
for (int i = 0; i < contextualOrders.Count; i++)
|
||||
{
|
||||
optionNodes.Add(new Tuple<GUIComponent, Keys>(
|
||||
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), contextualOrders[i], (i + 1) % 10, disableNode: disableNode, checkIfOrderCanBeHeard: false),
|
||||
!disableNode ? Keys.D0 + (i + 1) % 10 : Keys.None));
|
||||
var info = contextualOrders[i];
|
||||
int hotkey = (i + 1) % 10;
|
||||
var component = string.IsNullOrEmpty(info.OrderOption) ?
|
||||
CreateOrderNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), info.Order, hotkey, disableNode: disableNode, checkIfOrderCanBeHeard: false) :
|
||||
CreateOrderOptionNode(nodeSize, commandFrame.RectTransform, offsets[i].ToPoint(), info.Order, info.OrderOption, info.Order.Prefab.GetOptionName(info.OrderOption), hotkey);
|
||||
optionNodes.Add(new Tuple<GUIComponent, Keys>(component, !disableNode ? Keys.D0 + (i + 1) % 10 : Keys.None));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: there's duplicate logic here and above -> would be better to refactor so that the conditions are only defined in one place
|
||||
public static bool DoesItemHaveContextualOrders(Item item)
|
||||
{
|
||||
if (Order.PrefabList.Any(o => o.TargetItems.Length > 0 && o.TargetItems.Contains(item.Prefab.Identifier))) { return true; }
|
||||
if (Order.PrefabList.Any(o => item.HasTag(o.TargetItems))) { return true; }
|
||||
if (Order.PrefabList.Any(o => o.TargetItemsMatchItem(item))) { return true; }
|
||||
if (Order.PrefabList.Any(o => o.TryGetTargetItemComponent(item, out _))) { return true; }
|
||||
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; }
|
||||
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)));
|
||||
if (Order.GetPrefab("loaditems") is Order loadItemsPrefab && AIObjectiveLoadItems.IsValidTarget(item, Character.Controlled, targetContainerTags: loadItemsPrefab.GetTargetItems())) { return true; }
|
||||
if (item.Repairables.Any(r => r.IsBelowRepairThreshold)) { return true; }
|
||||
return Order.GetPrefab("operateweapons") is Order operateWeaponsPrefab && item.Components.Any(c => c is Controller) &&
|
||||
(item.GetConnectedComponents<Turret>().Any(c => operateWeaponsPrefab.TargetItemsMatchItem(c.Item)) ||
|
||||
item.GetConnectedComponents<Turret>(recursive: true).Any(c => operateWeaponsPrefab.TargetItemsMatchItem(c.Item)));
|
||||
}
|
||||
|
||||
/// <param name="hotkey">Use a negative value (e.g. -1) if there should be no hotkey associated with the node</param>
|
||||
@@ -2781,7 +2696,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 +2719,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)
|
||||
@@ -2819,7 +2734,8 @@ namespace Barotrauma
|
||||
o = new Order(o.Prefab, orderTargetEntity, orderTargetEntity.Components.FirstOrDefault(ic => ic.GetType() == order.ItemComponentType), orderGiver: order.OrderGiver);
|
||||
}
|
||||
var character = !o.TargetAllCharacters ? characterContext ?? GetCharacterForQuickAssignment(o) : null;
|
||||
SetCharacterOrder(character, o, null, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
|
||||
int priority = GetManualOrderPriority(character, o);
|
||||
SetCharacterOrder(character, o, null, priority, Character.Controlled);
|
||||
DisableCommandUI();
|
||||
}
|
||||
return true;
|
||||
@@ -2925,9 +2841,15 @@ 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);
|
||||
var character = characterContext ?? GetCharacterForQuickAssignment(o.Item1);
|
||||
int priority = GetManualOrderPriority(character, o.Item1);
|
||||
SetCharacterOrder(character, o.Item1, o.Item2, priority, Character.Controlled);
|
||||
DisableCommandUI();
|
||||
}
|
||||
return true;
|
||||
@@ -2987,12 +2909,21 @@ 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
|
||||
{
|
||||
var character = characterContext ?? GetCharacterForQuickAssignment(o.Item1);
|
||||
int priority = GetManualOrderPriority(character, o.Item1);
|
||||
SetCharacterOrder(character, o.Item1, o.Item2, priority, Character.Controlled);
|
||||
DisableCommandUI();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -3195,7 +3126,9 @@ namespace Barotrauma
|
||||
OnClicked = (_, userData) =>
|
||||
{
|
||||
if (!CanIssueOrders) { return false; }
|
||||
SetCharacterOrder(userData as Character, order.Item1, order.Item2, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
|
||||
var character = userData as Character;
|
||||
int priority = GetManualOrderPriority(character, order.Item1);
|
||||
SetCharacterOrder(character, order.Item1, order.Item2, priority, Character.Controlled);
|
||||
DisableCommandUI();
|
||||
return true;
|
||||
}
|
||||
@@ -3473,6 +3406,11 @@ namespace Barotrauma
|
||||
return order.Name;
|
||||
}
|
||||
|
||||
private int GetManualOrderPriority(Character character, Order order)
|
||||
{
|
||||
return character?.Info?.GetManualOrderPriority(order) ?? CharacterInfo.HighestManualOrderPriority;
|
||||
}
|
||||
|
||||
#region Crew Member Assignment Logic
|
||||
private bool CanOpenManualAssignment(GUIComponent node)
|
||||
{
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace Barotrauma
|
||||
|
||||
public override void ShowStartMessage()
|
||||
{
|
||||
foreach (Mission mission in Missions)
|
||||
foreach (Mission mission in Missions.ToList())
|
||||
{
|
||||
new GUIMessageBox(
|
||||
mission.Prefab.IsSideObjective ? TextManager.AddPunctuation(':', TextManager.Get("sideobjective"), mission.Name) : mission.Name,
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace Barotrauma
|
||||
var newCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
|
||||
var loadCampaignContainer = new GUIFrame(new RectTransform(new Vector2(0.95f, 0.95f), campaignContainer.RectTransform, Anchor.Center), style: null);
|
||||
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI = new MultiPlayerCampaignSetupUI(newCampaignContainer, loadCampaignContainer, null, saveFiles);
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI = new MultiPlayerCampaignSetupUI(newCampaignContainer, loadCampaignContainer, saveFiles);
|
||||
|
||||
var newCampaignButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1.0f), buttonContainer.RectTransform),
|
||||
TextManager.Get("NewCampaign"), style: "GUITabButton")
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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"))
|
||||
{
|
||||
|
||||
@@ -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) ||
|
||||
@@ -475,12 +475,12 @@ namespace Barotrauma
|
||||
ItemComponent targetItem = null;
|
||||
if (orderPrefab.MustSetTarget)
|
||||
{
|
||||
targetEntity = orderPrefab.GetMatchingItems(true, interactableFor: Character.Controlled).FirstOrDefault();
|
||||
targetEntity = orderPrefab.GetMatchingItems(true, interactableFor: Character.Controlled, orderOption: orderInfo.option).FirstOrDefault();
|
||||
if (targetEntity == null) { return; }
|
||||
targetItem = orderPrefab.GetTargetItemComponent(targetEntity);
|
||||
}
|
||||
var order = new Order(orderPrefab, targetEntity as Entity, targetItem, orderGiver: Character.Controlled);
|
||||
GameMain.GameSession.CrewManager.SetCharacterOrder(Character.Controlled, order, orderInfo.option, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
|
||||
GameMain.GameSession?.CrewManager?.SetCharacterOrder(Character.Controlled, order, orderInfo.option, CharacterInfo.HighestManualOrderPriority, Character.Controlled);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -635,9 +635,9 @@ namespace Barotrauma
|
||||
}
|
||||
else if (characterInfo.CauseOfDeath.Type == CauseOfDeathType.Affliction && characterInfo.CauseOfDeath.Affliction == null)
|
||||
{
|
||||
string errorMsg = "Character \"" + characterInfo.Name + "\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
string errorMsg = "Character \"[name]\" had an invalid cause of death (the type of the cause of death was Affliction, but affliction was not specified).";
|
||||
DebugConsole.ThrowError(errorMsg.Replace("[name]", characterInfo.Name));
|
||||
GameAnalyticsManager.AddErrorEventOnce("RoundSummary:InvalidCauseOfDeath", GameAnalyticsManager.ErrorSeverity.Error, errorMsg.Replace("[name]", characterInfo.SpeciesName));
|
||||
statusText = TextManager.Get("CauseOfDeathDescription.Unknown");
|
||||
statusColor = GUI.Style.Red;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Networking;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using OpenAL;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
|
||||
@@ -365,6 +363,12 @@ namespace Barotrauma
|
||||
TextManager.Get("Settings"), textAlignment: Alignment.TopLeft, font: GUI.LargeFont)
|
||||
{ ForceUpperCase = true };
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), settingsTitle.RectTransform, Anchor.CenterRight, scaleBasis: ScaleBasis.Smallest), style: "GUIBugButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("bugreportbutton") + $" (v{GameMain.Version})",
|
||||
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform), TextManager.Get("ContentPackages"), font: GUI.SubHeadingFont);
|
||||
|
||||
var corePackageDropdown = new GUIDropDown(new RectTransform(new Vector2(1.0f, 0.05f), leftPanel.RectTransform))
|
||||
@@ -480,7 +484,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;
|
||||
|
||||
@@ -509,17 +513,56 @@ namespace Barotrauma
|
||||
ApplySettings();
|
||||
GameMain.Instance.Exit();
|
||||
return true;
|
||||
}; msgBox.Buttons[1].OnClicked += (btn, userdata) =>
|
||||
};
|
||||
msgBox.Buttons[1].OnClicked += (btn, userdata) =>
|
||||
{
|
||||
Language = prevLanguage;
|
||||
languageDD.SelectItem(Language);
|
||||
msgBox.Close();
|
||||
return true;
|
||||
};
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
var statisticsTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.045f), leftPanel.RectTransform), TextManager.Get("statisticsconsenttickbox"))
|
||||
{
|
||||
OnSelected = (GUITickBox tickBox) =>
|
||||
{
|
||||
GameAnalyticsManager.SetConsent(
|
||||
tickBox.Selected
|
||||
? GameAnalyticsManager.Consent.Ask
|
||||
: GameAnalyticsManager.Consent.No);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#if DEBUG
|
||||
statisticsTickBox.Enabled = false;
|
||||
#endif
|
||||
void updateGATickBoxToolTip()
|
||||
=> statisticsTickBox.ToolTip = TextManager.Get($"GameAnalyticsStatus.{GameAnalyticsManager.UserConsented}");
|
||||
updateGATickBoxToolTip();
|
||||
|
||||
var cachedConsent = GameAnalyticsManager.Consent.Unknown;
|
||||
var statisticsTickBoxUpdater = new GUICustomComponent(
|
||||
new RectTransform(Vector2.Zero, statisticsTickBox.RectTransform),
|
||||
onUpdate: (deltaTime, component) =>
|
||||
{
|
||||
bool shouldTickBoxBeSelected = GameAnalyticsManager.UserConsented == GameAnalyticsManager.Consent.Yes;
|
||||
|
||||
bool shouldUpdateTickBoxState = cachedConsent != GameAnalyticsManager.UserConsented
|
||||
|| statisticsTickBox.Selected != shouldTickBoxBeSelected;
|
||||
|
||||
if (!shouldUpdateTickBoxState) { return; }
|
||||
|
||||
updateGATickBoxToolTip();
|
||||
cachedConsent = GameAnalyticsManager.UserConsented;
|
||||
GUITickBox.OnSelectedHandler prevHandler = statisticsTickBox.OnSelected;
|
||||
statisticsTickBox.OnSelected = null;
|
||||
statisticsTickBox.Selected = shouldTickBoxBeSelected;
|
||||
statisticsTickBox.OnSelected = prevHandler;
|
||||
statisticsTickBox.Enabled = GameAnalyticsManager.UserConsented != GameAnalyticsManager.Consent.Error;
|
||||
});
|
||||
|
||||
// right panel --------------------------------------
|
||||
|
||||
var rightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.99f - leftPanel.RectTransform.RelativeSize.X, leftPanel.RectTransform.RelativeSize.Y),
|
||||
@@ -556,13 +599,6 @@ namespace Barotrauma
|
||||
tabButtons[(int)tab].Text = ToolBox.LimitString(buttonText, tabButtons[(int)tab].Font, (int)(0.75f * tabWidth * tabButtonHolder.Rect.Width));
|
||||
}
|
||||
|
||||
new GUIButton(new RectTransform(new Vector2(0.05f, 0.75f), tabButtonHolder.RectTransform, Anchor.BottomRight) { RelativeOffset = new Vector2(0.0f, 0.2f) }, style: "GUIBugButton")
|
||||
{
|
||||
ToolTip = TextManager.Get("bugreportbutton"),
|
||||
OnClicked = (btn, userdata) => { GameMain.Instance.ShowBugReporter(); return true; }
|
||||
};
|
||||
|
||||
|
||||
/// Graphics tab --------------------------------------------------------------
|
||||
|
||||
var leftColumn = new GUILayoutGroup(new RectTransform(new Vector2(0.46f, 0.95f), tabs[(int)Tab.Graphics].RectTransform, Anchor.TopLeft)
|
||||
@@ -1168,7 +1204,7 @@ namespace Barotrauma
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to set voice capture mode.", e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SetVoiceCaptureMode", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, "Failed to set voice capture mode. " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.AddErrorEventOnce("SetVoiceCaptureMode", GameAnalyticsManager.ErrorSeverity.Error, "Failed to set voice capture mode. " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
|
||||
VoiceSetting = VoiceMode.Disabled;
|
||||
}
|
||||
|
||||
@@ -1767,7 +1803,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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -406,7 +406,7 @@ namespace Barotrauma.Items.Components
|
||||
DebugConsole.Log("Invalid sound volume (item " + item.Name + ", " + GetType().ToString() + "): " + newVolume);
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"ItemComponent.PlaySound:" + item.Name + GetType().ToString(),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Invalid sound volume (item " + item.Name + ", " + GetType().ToString() + "): " + newVolume);
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -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)))
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using System.Xml.Linq;
|
||||
|
||||
namespace Barotrauma.Items.Components
|
||||
{
|
||||
@@ -11,7 +8,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
public float BackgroundSpriteDepth
|
||||
{
|
||||
get { return item.GetDrawDepth() + 0.1f; }
|
||||
get { return item.GetDrawDepth() + 0.05f; }
|
||||
}
|
||||
|
||||
public Vector2 DrawSize
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -637,44 +672,61 @@ namespace Barotrauma.Items.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentMode == MiniMapMode.HullStatus)
|
||||
if (currentMode == MiniMapMode.HullStatus && item.Submarine != null)
|
||||
{
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
spriteBatch.End();
|
||||
spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, rasterizerState: GameMain.ScissorTestEnable);
|
||||
spriteBatch.GraphicsDevice.ScissorRectangle = submarineContainer.Rect;
|
||||
|
||||
if (item.Submarine != null)
|
||||
var sprite = GUI.Style.UIGlowSolidCircular?.Sprite;
|
||||
float alpha = (MathF.Sin(blipState / maxBlipState * MathHelper.TwoPi) + 1.5f) * 0.5f;
|
||||
if (sprite != null)
|
||||
{
|
||||
var sprite = GUI.Style.UIGlowSolidCircular?.Sprite;
|
||||
float alpha = (MathF.Sin(blipState / maxBlipState * MathHelper.TwoPi) + 1.5f) * 0.5f;
|
||||
if (sprite != null)
|
||||
Vector2 spriteSize = sprite.size;
|
||||
Rectangle worldBorders = item.Submarine.GetDockedBorders();
|
||||
worldBorders.Location += item.Submarine.WorldPosition.ToPoint();
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
{
|
||||
Vector2 spriteSize = sprite.size;
|
||||
Rectangle worldBorders = item.Submarine.GetDockedBorders();
|
||||
worldBorders.Location += item.Submarine.WorldPosition.ToPoint();
|
||||
foreach (Gap gap in Gap.GapList)
|
||||
{
|
||||
if (gap.IsRoomToRoom || gap.Submarine != item.Submarine || gap.ConnectedDoor != null) { continue; }
|
||||
RectangleF entityRect = ScaleRectToUI(gap, miniMapFrame.Rect, worldBorders);
|
||||
if (gap.IsRoomToRoom || gap.linkedTo.Count == 0 || 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;
|
||||
Vector2 scale = new Vector2(entityRect.Size.X / spriteSize.X, entityRect.Size.Y / spriteSize.Y) * 2.0f;
|
||||
|
||||
Color color = ToolBox.GradientLerp(gap.Open, GUI.Style.HealthBarColorMedium, GUI.Style.HealthBarColorLow) * alpha;
|
||||
sprite.Draw(spriteBatch,
|
||||
miniMapFrame.Rect.Location.ToVector2() + entityRect.Center,
|
||||
color, origin: sprite.Origin, rotate: 0.0f, scale: scale);
|
||||
}
|
||||
Color color = ToolBox.GradientLerp(gap.Open, GUI.Style.HealthBarColorMedium, GUI.Style.HealthBarColorLow) * alpha;
|
||||
sprite.Draw(spriteBatch,
|
||||
miniMapFrame.Rect.Location.ToVector2() + entityRect.Center,
|
||||
color, origin: sprite.Origin, rotate: 0.0f, scale: scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -936,15 +988,47 @@ namespace Barotrauma.Items.Components
|
||||
continue;
|
||||
}
|
||||
|
||||
hullData.HullOxygenAmount = RequireOxygenDetectors ? hullData.ReceivedOxygenAmount : hull.OxygenPercentage;
|
||||
hullData.HullWaterAmount = RequireWaterDetectors ? hullData.ReceivedWaterAmount : Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
|
||||
if (RequireOxygenDetectors)
|
||||
{
|
||||
hullData.HullOxygenAmount = hullData.ReceivedOxygenAmount;
|
||||
}
|
||||
else if (hullData.LinkedHulls.Any())
|
||||
{
|
||||
hullData.HullOxygenAmount = 0.0f;
|
||||
foreach (Hull linkedHull in hullData.LinkedHulls)
|
||||
{
|
||||
hullData.HullOxygenAmount += linkedHull.OxygenPercentage;
|
||||
}
|
||||
hullData.HullOxygenAmount /= hullData.LinkedHulls.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
hullData.HullOxygenAmount = hull.OxygenPercentage;
|
||||
}
|
||||
if (RequireWaterDetectors)
|
||||
{
|
||||
hullData.HullWaterAmount = hullData.ReceivedWaterAmount;
|
||||
}
|
||||
else if (hullData.LinkedHulls.Any())
|
||||
{
|
||||
hullData.HullWaterAmount = 0.0f;
|
||||
foreach (Hull linkedHull in hullData.LinkedHulls)
|
||||
{
|
||||
hullData.HullWaterAmount += Math.Min(linkedHull.WaterVolume / linkedHull.Volume, 1.0f);
|
||||
}
|
||||
hullData.HullWaterAmount /= hullData.LinkedHulls.Count;
|
||||
}
|
||||
else
|
||||
{
|
||||
hullData.HullWaterAmount = Math.Min(hull.WaterVolume / hull.Volume, 1.0f);
|
||||
}
|
||||
|
||||
float gapOpenSum = 0.0f;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
@@ -958,15 +1042,6 @@ namespace Barotrauma.Items.Components
|
||||
float? oxygenAmount = hullData.HullOxygenAmount,
|
||||
waterAmount = hullData.HullWaterAmount;
|
||||
|
||||
foreach (Hull linkedHull in hullData.LinkedHulls)
|
||||
{
|
||||
oxygenAmount += linkedHull.OxygenPercentage;
|
||||
waterAmount += Math.Min(linkedHull.WaterVolume / linkedHull.Volume, 1.0f);
|
||||
}
|
||||
|
||||
oxygenAmount /= (hullData.LinkedHulls.Count + 1);
|
||||
waterAmount /= (hullData.LinkedHulls.Count + 1);
|
||||
|
||||
string line1 = gapOpenSum > 0.1f ? TextManager.Get("MiniMapHullBreach") : string.Empty;
|
||||
Color line1Color = GUI.Style.Red;
|
||||
|
||||
@@ -1039,10 +1114,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());
|
||||
}
|
||||
|
||||
@@ -1057,10 +1131,9 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private void DrawHUDBack(SpriteBatch spriteBatch, GUICustomComponent container)
|
||||
{
|
||||
if (item.Submarine != null)
|
||||
{
|
||||
DrawSubmarine(spriteBatch);
|
||||
}
|
||||
if (item.Submarine == null) { return; }
|
||||
|
||||
DrawSubmarine(spriteBatch);
|
||||
|
||||
if (Voltage < MinVoltage) { return; }
|
||||
Rectangle prevScissorRect = spriteBatch.GraphicsDevice.ScissorRectangle;
|
||||
@@ -1086,38 +1159,42 @@ 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 (!RequireWaterDetectors) { waterAmount = hull.WaterPercentage / 100.0f; }
|
||||
if (hullFrame.Rect.Height * 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);
|
||||
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 +1298,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;
|
||||
@@ -1361,7 +1438,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
if (linkedEntity is Hull linkedHull)
|
||||
{
|
||||
if (linkedHulls.Contains(linkedHull)) { continue; }
|
||||
if (linkedHulls.Contains(linkedHull) || linkedHull.HiddenInGame) { continue; }
|
||||
linkedHulls.Add(linkedHull);
|
||||
GetLinkedHulls(linkedHull, linkedHulls);
|
||||
}
|
||||
@@ -1541,7 +1618,7 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
bool IsPartofSub(MapEntity entity)
|
||||
{
|
||||
if (entity.Submarine != sub && !connectedSubs.Contains(entity.Submarine)) { return false; }
|
||||
if (entity.Submarine != sub && !connectedSubs.Contains(entity.Submarine) || entity.HiddenInGame) { return false; }
|
||||
return !settings.IgnoreOutposts || sub.IsEntityFoundOnThisSub(entity, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -1623,6 +1623,11 @@ namespace Barotrauma.Items.Components
|
||||
markerDistances.Add(targetIdentifier, cachedDistance);
|
||||
dist = path.TotalLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
var cachedDistance = new CachedDistance(transducerPosition, worldPosition, linearDist, Timing.TotalTime + Rand.Range(4.0f, 7.0f));
|
||||
markerDistances.Add(targetIdentifier, cachedDistance);
|
||||
}
|
||||
}
|
||||
|
||||
Vector2 position = worldPosition - transducerPosition;
|
||||
|
||||
@@ -35,6 +35,13 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
private FixActions requestStartFixAction;
|
||||
|
||||
private bool qteSuccess;
|
||||
|
||||
private float qteTimer;
|
||||
private const float QteDuration = 0.5f;
|
||||
private float qteCooldown;
|
||||
private const float QteCooldownDuration = 0.5f;
|
||||
|
||||
public float FakeBrokenTimer;
|
||||
|
||||
[Serialize("", false, description: "An optional description of the needed repairs displayed in the repair interface.")]
|
||||
@@ -55,14 +62,13 @@ namespace Barotrauma.Items.Components
|
||||
if (!HasRequiredItems(character, false) || character.SelectedConstruction != item) { return false; }
|
||||
if (character.IsTraitor && item.ConditionPercentage > MinSabotageCondition) { return true; }
|
||||
|
||||
float maxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(character);
|
||||
if (item.Condition / maxRepairConditionMultiplier < RepairThreshold) { return true; }
|
||||
float defaultMaxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier;
|
||||
|
||||
if (MathUtils.Percentage(item.Condition, defaultMaxCondition) < RepairThreshold) { return true; }
|
||||
|
||||
if (CurrentFixer == character)
|
||||
{
|
||||
float condition = item.Condition / item.MaxRepairConditionMultiplier;
|
||||
float maxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier;
|
||||
if (condition < maxCondition * maxRepairConditionMultiplier)
|
||||
if (item.Condition < item.MaxCondition)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -143,11 +149,14 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
progressBar = new GUIProgressBar(new RectTransform(new Vector2(0.6f, 1.0f), progressBarHolder.RectTransform),
|
||||
color: GUI.Style.Green, barSize: 0.0f, style: "DeviceProgressBar");
|
||||
|
||||
progressBarOverlayText = new GUITextBlock(new RectTransform(Vector2.One, progressBar.RectTransform), string.Empty, font: GUI.SubHeadingFont, textAlignment: Alignment.Center)
|
||||
{
|
||||
IgnoreLayoutGroups = true
|
||||
};
|
||||
|
||||
qteTimer = QteDuration;
|
||||
|
||||
repairButtonText = TextManager.Get("RepairButton");
|
||||
repairingText = TextManager.Get("Repairing");
|
||||
RepairButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), progressBarHolder.RectTransform, Anchor.TopCenter), repairButtonText)
|
||||
@@ -157,6 +166,11 @@ namespace Barotrauma.Items.Components
|
||||
requestStartFixAction = FixActions.Repair;
|
||||
item.CreateClientEvent(this);
|
||||
return true;
|
||||
},
|
||||
OnButtonDown = () =>
|
||||
{
|
||||
QTEAction();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
RepairButton.TextBlock.AutoScaleHorizontal = true;
|
||||
@@ -181,6 +195,11 @@ namespace Barotrauma.Items.Components
|
||||
requestStartFixAction = FixActions.Sabotage;
|
||||
item.CreateClientEvent(this);
|
||||
return true;
|
||||
},
|
||||
OnButtonDown = () =>
|
||||
{
|
||||
QTEAction();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -251,6 +270,20 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
repairSoundChannel = SoundPlayer.PlaySound("repair", item.WorldPosition, hullGuess: item.CurrentHull);
|
||||
}
|
||||
|
||||
if (qteCooldown > 0.0f)
|
||||
{
|
||||
qteCooldown -= deltaTime;
|
||||
if (qteCooldown <= 0.0f)
|
||||
{
|
||||
qteTimer = QteDuration;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qteTimer -= deltaTime * (qteTimer / QteDuration);
|
||||
if (qteTimer < 0.0f) { qteTimer = QteDuration; }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -268,6 +301,26 @@ namespace Barotrauma.Items.Components
|
||||
progressBar.BarSize = item.Condition / defaultMaxCondition;
|
||||
progressBar.Color = ToolBox.GradientLerp(progressBar.BarSize, GUI.Style.Red, GUI.Style.Orange, GUI.Style.Green);
|
||||
|
||||
Rectangle sliderRect = progressBar.GetSliderRect(1.0f);
|
||||
Color qteSliderColor = Color.White;
|
||||
if (qteCooldown > 0.0f)
|
||||
{
|
||||
qteSliderColor = qteSuccess ? GUI.Style.Green : GUI.Style.Red * 0.5f;
|
||||
progressBar.Color = ToolBox.GradientLerp(qteCooldown / QteCooldownDuration, progressBar.Color, qteSliderColor, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qteTimer / QteDuration <= item.Condition / item.MaxCondition)
|
||||
{
|
||||
qteSliderColor = Color.Lerp(qteSliderColor, GUI.Style.Green, 0.5f);
|
||||
}
|
||||
}
|
||||
|
||||
progressBar.Parent.Parent.Parent.DrawManually(spriteBatch, true);
|
||||
GUI.DrawRectangle(spriteBatch,
|
||||
new Rectangle(sliderRect.X + (int)((qteTimer / QteDuration) * sliderRect.Width), sliderRect.Y - 5, 2, sliderRect.Height + 10),
|
||||
qteSliderColor, true);
|
||||
|
||||
if (item.Condition > defaultMaxCondition)
|
||||
{
|
||||
float extraCondition = item.MaxCondition * (item.MaxRepairConditionMultiplier - 1.0f);
|
||||
@@ -280,9 +333,9 @@ 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) && !item.IsFullCondition;
|
||||
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;
|
||||
@@ -350,6 +403,30 @@ namespace Barotrauma.Items.Components
|
||||
repairSoundChannel = null;
|
||||
}
|
||||
|
||||
private void QTEAction()
|
||||
{
|
||||
if (currentFixerAction == FixActions.Repair)
|
||||
{
|
||||
float defaultMaxCondition = item.MaxCondition / item.MaxRepairConditionMultiplier;
|
||||
qteSuccess = qteCooldown <= 0.0f && qteTimer / QteDuration <= item.Condition / defaultMaxCondition;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GameMain.IsMultiplayer) { RepairBoost(qteSuccess); }
|
||||
|
||||
SoundPlayer.PlayUISound(qteSuccess ? GUISoundType.IncreaseQuantity : GUISoundType.DecreaseQuantity);
|
||||
|
||||
//on failure during cooldown reset cursor to beginning
|
||||
if (!qteSuccess && qteCooldown > 0.0f) { qteTimer = QteDuration; }
|
||||
qteCooldown = QteCooldownDuration;
|
||||
//this will be set on button down so we can reset it here
|
||||
requestStartFixAction = FixActions.None;
|
||||
item.CreateClientEvent(this);
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
{
|
||||
deteriorationTimer = msg.ReadSingle();
|
||||
@@ -361,11 +438,17 @@ namespace Barotrauma.Items.Components
|
||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
|
||||
item.MaxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(CurrentFixer);
|
||||
if (CurrentFixer == null)
|
||||
{
|
||||
qteTimer = QteDuration;
|
||||
qteCooldown = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger((int)requestStartFixAction, 0, 2);
|
||||
msg.Write(qteSuccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,16 +26,11 @@ namespace Barotrauma.Items.Components
|
||||
AutoHideScrollBar = false
|
||||
};
|
||||
|
||||
// Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox
|
||||
// This could be removed if GUIListBox supported aligning its children
|
||||
fillerBlock = new GUITextBlock(new RectTransform(new Vector2(1, 1), historyBox.Content.RectTransform, anchor: Anchor.TopCenter), string.Empty)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
CreateFillerBlock();
|
||||
|
||||
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,
|
||||
@@ -55,6 +50,16 @@ namespace Barotrauma.Items.Components
|
||||
};
|
||||
}
|
||||
|
||||
// Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox
|
||||
// This could be removed if GUIListBox supported aligning its children
|
||||
public void CreateFillerBlock()
|
||||
{
|
||||
fillerBlock = new GUITextBlock(new RectTransform(new Vector2(1, 1), historyBox.Content.RectTransform, anchor: Anchor.TopCenter), string.Empty)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
}
|
||||
|
||||
private void SendOutput(string input)
|
||||
{
|
||||
if (input.Length > MaxMessageLength)
|
||||
@@ -63,15 +68,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 +90,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
|
||||
};
|
||||
@@ -130,7 +135,12 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.Write((string)extraData[2]);
|
||||
if (extraData is null) { return; }
|
||||
|
||||
if (extraData[2] is string str)
|
||||
{
|
||||
msg.Write(str);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
errorMsg += "\nTrying to dock the submarine to itself.";
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("DockingPort.ClientRead:JointNotCreated", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("DockingPort.ClientRead:JointNotCreated", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
|
||||
if (isLocked)
|
||||
|
||||
@@ -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)
|
||||
@@ -314,7 +314,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
string colorStr = XMLExtensions.ColorToString(!item.AllowStealing ? GUI.Style.Red : Color.White);
|
||||
string colorStr = XMLExtensions.ColorToString(item.SpawnedInCurrentOutpost && !item.AllowStealing ? GUI.Style.Red : Color.White);
|
||||
|
||||
toolTip = $"‖color:{colorStr}‖{name}‖color:end‖";
|
||||
if (item.GetComponent<Quality>() != null)
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -648,12 +648,18 @@ namespace Barotrauma
|
||||
if (linkedTo.Contains(otherEntity))
|
||||
{
|
||||
linkedTo.Remove(otherEntity);
|
||||
if (otherEntity.linkedTo != null && otherEntity.linkedTo.Contains(this)) otherEntity.linkedTo.Remove(this);
|
||||
if (otherEntity.linkedTo != null && otherEntity.linkedTo.Contains(this))
|
||||
{
|
||||
otherEntity.linkedTo.Remove(this);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
linkedTo.Add(otherEntity);
|
||||
if (otherEntity.Linkable && otherEntity.linkedTo != null) otherEntity.linkedTo.Add(this);
|
||||
if (otherEntity.Linkable && otherEntity.linkedTo != null)
|
||||
{
|
||||
otherEntity.linkedTo.Add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1445,7 +1451,7 @@ namespace Barotrauma
|
||||
#else
|
||||
if (GameSettings.VerboseLogging) { DebugConsole.ThrowError(errorMsg); }
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ClientReadPosition:nophysicsbody", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ClientReadPosition:nophysicsbody", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1586,7 +1592,7 @@ namespace Barotrauma
|
||||
string errorMsg = "Failed to spawn item, prefab not found (name: " + (itemName ?? "null") + ", identifier: " + (itemIdentifier ?? "null") + ")";
|
||||
errorMsg += "\n" + string.Join(", ", GameMain.Config.AllEnabledPackages.Select(cp => cp.Name));
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:PrefabNotFound" + (itemName ?? "null") + (itemIdentifier ?? "null"),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Critical,
|
||||
GameAnalyticsManager.ErrorSeverity.Critical,
|
||||
errorMsg);
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
return null;
|
||||
@@ -1607,7 +1613,7 @@ namespace Barotrauma
|
||||
string errorMsg =
|
||||
$"Failed to spawn item \"{(itemIdentifier ?? "null")}\" in the inventory of \"{parentItem.prefab.Identifier} ({parentItem.ID})\" (component index out of range). Index: {itemContainerIndex}, components: {parentItem.components.Count}.";
|
||||
GameAnalyticsManager.AddErrorEventOnce("Item.ReadSpawnData:ContainerIndexOutOfRange" + (itemName ?? "null") + (itemIdentifier ?? "null"),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
errorMsg);
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
inventory = parentItem.GetComponent<ItemContainer>()?.Inventory;
|
||||
@@ -1632,7 +1638,7 @@ namespace Barotrauma
|
||||
{
|
||||
item = new Item(itemPrefab, pos, sub, id: itemId)
|
||||
{
|
||||
SpawnedInOutpost = spawnedInOutpost,
|
||||
SpawnedInCurrentOutpost = spawnedInOutpost,
|
||||
AllowStealing = allowStealing,
|
||||
Quality = quality
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -95,10 +95,10 @@ 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)
|
||||
while (light.Color.A > 0.0f && flashDuration > 0.0f && currBrightness > 0.0f)
|
||||
{
|
||||
light.Color = new Color(light.Color.R, light.Color.G, light.Color.B, (byte)(currBrightness * 255));
|
||||
currBrightness -= 1.0f / flashDuration * CoroutineManager.DeltaTime;
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Invalid left normal");
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidLeftNormal:" + level.Seed,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
GameAnalyticsManager.ErrorSeverity.Warning,
|
||||
"Invalid left normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + leftNormal + ", seed: " + level.Seed + ")");
|
||||
|
||||
if (cell.Body != null)
|
||||
@@ -127,7 +127,7 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Invalid right normal");
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("CaveGenerator.GenerateWallShapes:InvalidRightNormal:" + level.Seed,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
GameAnalyticsManager.ErrorSeverity.Warning,
|
||||
"Invalid right normal (leftedge: " + leftEdge + ", rightedge: " + rightEdge + ", normal: " + rightNormal + ", seed: " + level.Seed + ")");
|
||||
|
||||
if (cell.Body != null)
|
||||
|
||||
@@ -497,11 +497,13 @@ namespace Barotrauma.Lights
|
||||
return true;
|
||||
}
|
||||
|
||||
private readonly Dictionary<Hull, Rectangle> visibleHulls = new Dictionary<Hull, Rectangle>();
|
||||
private Dictionary<Hull, Rectangle> GetVisibleHulls(Camera cam)
|
||||
{
|
||||
Dictionary<Hull, Rectangle> visibleHulls = new Dictionary<Hull, Rectangle>();
|
||||
visibleHulls.Clear();
|
||||
foreach (Hull hull in Hull.hullList)
|
||||
{
|
||||
if (hull.HiddenInGame) { continue; }
|
||||
var drawRect =
|
||||
hull.Submarine == null ?
|
||||
hull.Rect :
|
||||
|
||||
@@ -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,
|
||||
@@ -536,7 +536,7 @@ namespace Barotrauma
|
||||
invalidMessage = true;
|
||||
string errorMsg = $"Error while reading a network event for the structure \"{Name} ({ID})\". Section count does not match (server: {sectionCount} client: {Sections.Length})";
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Structure.ClientRead:SectionCountMismatch", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
}
|
||||
|
||||
for (int i = 0; i < sectionCount; i++)
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Error when loading round sound (" + element + ") - file path not set";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FilePathEmpty" + element.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FilePathEmpty" + element.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Failed to load sound file \"" + filename + "\".";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Failed to load sound file \"" + roundSound.Filename + "\".";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + roundSound.Filename, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine.LoadRoundSound:FileNotFound" + roundSound.Filename, GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -183,13 +183,14 @@ namespace Barotrauma
|
||||
visibleSubs.Clear();
|
||||
foreach (Submarine sub in Loaded)
|
||||
{
|
||||
if (sub.WorldPosition.Y < Level.MaxEntityDepth) continue;
|
||||
if (sub.WorldPosition.Y < Level.MaxEntityDepth) { continue; }
|
||||
|
||||
int margin = 500;
|
||||
Rectangle worldBorders = new Rectangle(
|
||||
sub.Borders.X + (int)sub.WorldPosition.X - 500,
|
||||
sub.Borders.Y + (int)sub.WorldPosition.Y + 500,
|
||||
sub.Borders.Width + 1000,
|
||||
sub.Borders.Height + 1000);
|
||||
sub.VisibleBorders.X + (int)sub.WorldPosition.X - margin,
|
||||
sub.VisibleBorders.Y + (int)sub.WorldPosition.Y + margin,
|
||||
sub.VisibleBorders.Width + margin * 2,
|
||||
sub.VisibleBorders.Height + margin * 2);
|
||||
|
||||
if (RectsOverlap(worldBorders, cam.WorldView))
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace Barotrauma
|
||||
catch (Exception e)
|
||||
{
|
||||
DebugConsole.ThrowError("Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.", e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine..ctor:PreviewImageLoadingFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.AddErrorEventOnce("Submarine..ctor:PreviewImageLoadingFailed", GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Loading the preview image of the submarine \"" + Name + "\" failed. The file may be corrupted.");
|
||||
PreviewImage = null;
|
||||
}
|
||||
@@ -202,6 +202,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
GUITextBlock.AutoScaleAndNormalize(parent.Content.GetAllChildren<GUITextBlock>().Where(c => c != submarineNameText && c != descBlock));
|
||||
parent.ForceLayoutRecalculation();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -462,7 +462,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;
|
||||
@@ -651,7 +651,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
errorMsg += "\nInner exception: " + e.InnerException.Message + "\n" + e.InnerException.StackTrace.CleanupStackTrace();
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.Update:CheckServerMessagesException" + e.TargetSite.ToString(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
DebugConsole.ThrowError("Error while reading a message from server.", e);
|
||||
new GUIMessageBox(TextManager.Get("Error"), TextManager.GetWithVariables("MessageReadError", new string[2] { "[message]", "[targetsite]" }, new string[2] { e.Message, e.TargetSite.ToString() }));
|
||||
Disconnect();
|
||||
@@ -781,7 +781,7 @@ namespace Barotrauma.Networking
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Error while reading an ingame update message from server.", e);
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadDataMessage:ReadIngameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadDataMessage:ReadIngameUpdate", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw;
|
||||
}
|
||||
break;
|
||||
@@ -793,7 +793,7 @@ namespace Barotrauma.Networking
|
||||
errorMsg += "\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GameClient.ReadDataMessage:VoipClientNull",
|
||||
GameMain.Client == null ? GameAnalyticsSDK.Net.EGAErrorSeverity.Error : GameAnalyticsSDK.Net.EGAErrorSeverity.Warning,
|
||||
GameMain.Client == null ? GameAnalyticsManager.ErrorSeverity.Error : GameAnalyticsManager.ErrorSeverity.Warning,
|
||||
errorMsg);
|
||||
return;
|
||||
}
|
||||
@@ -863,8 +863,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;
|
||||
@@ -874,6 +874,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();
|
||||
@@ -907,6 +908,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();
|
||||
@@ -992,7 +994,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
string errorMsg = "Submarine equality check failed. The submarine loaded at your end doesn't match the one loaded by the server." +
|
||||
" There may have been an error in receiving the up-to-date submarine file from the server.";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:SubsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:SubsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
|
||||
@@ -1013,7 +1015,7 @@ namespace Barotrauma.Networking
|
||||
if (!GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier).OrderBy(id => id).SequenceEqual(serverMissionIdentifiers.OrderBy(id => id)))
|
||||
{
|
||||
string errorMsg = $"Mission equality check failed. The mission selected at your end doesn't match the one loaded by the server (server: {string.Join(", ", serverMissionIdentifiers)}, client: {string.Join(", ", GameMain.GameSession.Missions.Select(m => m.Prefab.Identifier))})";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:MissionsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:MissionsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
GameMain.GameSession.EnforceMissionOrder(serverMissionIdentifiers);
|
||||
@@ -1034,7 +1036,7 @@ namespace Barotrauma.Networking
|
||||
", seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortHash + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
else
|
||||
@@ -1050,7 +1052,7 @@ namespace Barotrauma.Networking
|
||||
", seed: " + Level.Loaded.Seed +
|
||||
", sub: " + Submarine.MainSub.Info.Name + " (" + Submarine.MainSub.Info.MD5Hash.ShortHash + ")" +
|
||||
", mirrored: " + Level.Loaded.Mirrored + ").";
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:LevelsDontMatch" + Level.Loaded.Seed, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
throw new Exception(errorMsg);
|
||||
}
|
||||
}
|
||||
@@ -1120,8 +1122,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"GameClient.HandleDisconnectMessage",
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Debug,
|
||||
"Client received a disconnect message. Reason: " + disconnectReason.ToString() + ", message: " + disconnectMsg);
|
||||
GameAnalyticsManager.ErrorSeverity.Debug,
|
||||
"Client received a disconnect message. Reason: " + disconnectReason.ToString());
|
||||
}
|
||||
|
||||
if (disconnectReason == DisconnectReason.ServerFull)
|
||||
@@ -1241,7 +1243,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<object> WaitInServerQueue()
|
||||
private IEnumerable<CoroutineStatus> WaitInServerQueue()
|
||||
{
|
||||
waitInServerQueueBox = new GUIMessageBox(
|
||||
TextManager.Get("ServerQueuePleaseWait"),
|
||||
@@ -1429,7 +1431,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.RefreshEnabledElements();
|
||||
}
|
||||
|
||||
private IEnumerable<object> StartGame(IReadMessage inc)
|
||||
private IEnumerable<CoroutineStatus> StartGame(IReadMessage inc)
|
||||
{
|
||||
Character?.Remove();
|
||||
Character = null;
|
||||
@@ -1473,6 +1475,7 @@ namespace Barotrauma.Networking
|
||||
serverSettings.AllowFriendlyFire = inc.ReadBoolean();
|
||||
serverSettings.LockAllDefaultWires = inc.ReadBoolean();
|
||||
serverSettings.AllowRagdollButton = inc.ReadBoolean();
|
||||
serverSettings.AllowLinkingWifiToChat = inc.ReadBoolean();
|
||||
GameMain.NetLobbyScreen.UsingShuttle = inc.ReadBoolean();
|
||||
GameMain.LightManager.LosMode = (LosMode)inc.ReadByte();
|
||||
bool includesFinalize = inc.ReadBoolean(); inc.ReadPadBits();
|
||||
@@ -1535,7 +1538,7 @@ namespace Barotrauma.Networking
|
||||
gameStarted = true;
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectSub" + subName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectSub" + subName, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
@@ -1547,7 +1550,7 @@ namespace Barotrauma.Networking
|
||||
GameMain.NetLobbyScreen.Select();
|
||||
string errorMsg = "Failed to select shuttle \"" + shuttleName + "\" (hash: " + shuttleHash + ").";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectShuttle" + shuttleName, GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.StartGame:FailedToSelectShuttle" + shuttleName, GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
roundInitStatus = RoundInitStatus.Interrupted;
|
||||
yield return CoroutineStatus.Failure;
|
||||
}
|
||||
@@ -1567,31 +1570,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 ?
|
||||
@@ -1670,10 +1689,6 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
|
||||
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize) { break; }
|
||||
|
||||
clientPeer.Update((float)Timing.Step);
|
||||
|
||||
if (roundInitStatus != RoundInitStatus.WaitingForStartGameFinalize) { break; }
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -1749,7 +1764,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);
|
||||
@@ -1859,8 +1874,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"))
|
||||
@@ -2108,9 +2122,6 @@ namespace Barotrauma.Networking
|
||||
bool autoRestartEnabled = inc.ReadBoolean();
|
||||
float autoRestartTimer = autoRestartEnabled ? inc.ReadSingle() : 0.0f;
|
||||
|
||||
bool radiationEnabled = inc.ReadBoolean();
|
||||
byte maxMissionCount = inc.ReadByte();
|
||||
|
||||
//ignore the message if we already a more up-to-date one
|
||||
//or if we're still waiting for the initial update
|
||||
if (NetIdUtils.IdMoreRecent(updateID, GameMain.NetLobbyScreen.LastUpdateID) &&
|
||||
@@ -2160,22 +2171,15 @@ namespace Barotrauma.Networking
|
||||
if (GameMain.NetLobbyScreen.CheckIfCampaignSubMatches(sub, "campaign"))
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines.Add(sub);
|
||||
}
|
||||
}
|
||||
|
||||
if (HasPermission(ClientPermissions.ManageCampaign) && !gameStarted && GameMain.NetLobbyScreen?.CampaignSetupUI != null)
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSetupUI.RefreshMultiplayerCampaignSubUI(GameMain.NetLobbyScreen.CampaignSubmarines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GameMain.NetLobbyScreen.SetAllowSpectating(allowSpectating);
|
||||
GameMain.NetLobbyScreen.LevelSeed = levelSeed;
|
||||
GameMain.NetLobbyScreen.SetLevelDifficulty(levelDifficulty);
|
||||
GameMain.NetLobbyScreen.SetRadiationEnabled(radiationEnabled);
|
||||
GameMain.NetLobbyScreen.SetBotSpawnMode(botSpawnMode);
|
||||
GameMain.NetLobbyScreen.SetBotCount(botCount);
|
||||
GameMain.NetLobbyScreen.SetMaxMissionCount(maxMissionCount);
|
||||
GameMain.NetLobbyScreen.SetAutoRestart(autoRestartEnabled, autoRestartTimer);
|
||||
|
||||
serverSettings.VoiceChatEnabled = voiceChatEnabled;
|
||||
@@ -2347,7 +2351,7 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
errorLines.Add("[" + DebugConsole.Messages[i].Time + "] " + DebugConsole.Messages[i].Text);
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadInGameUpdate", GameAnalyticsSDK.Net.EGAErrorSeverity.Critical, string.Join("\n", errorLines));
|
||||
GameAnalyticsManager.AddErrorEventOnce("GameClient.ReadInGameUpdate", GameAnalyticsManager.ErrorSeverity.Critical, string.Join("\n", errorLines));
|
||||
|
||||
DebugConsole.ThrowError("Writing object data to \"networkerror_data.log\", please send this file to us at http://github.com/Regalis11/Barotrauma/issues");
|
||||
|
||||
@@ -2583,29 +2587,29 @@ namespace Barotrauma.Networking
|
||||
subElement.ToolTip = newSub.Description;
|
||||
}
|
||||
|
||||
if (GameMain.NetLobbyScreen.FailedSelectedSub != null &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedSub.First == newSub.Name &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedSub.Second == newSub.MD5Hash.Hash)
|
||||
if (GameMain.NetLobbyScreen.FailedSelectedSub.HasValue &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedSub.Value.Name == newSub.Name &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedSub.Value.Hash == newSub.MD5Hash.Hash)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.Hash, GameMain.NetLobbyScreen.SubList);
|
||||
}
|
||||
|
||||
if (GameMain.NetLobbyScreen.FailedSelectedShuttle != null &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedShuttle.First == newSub.Name &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedShuttle.Second == newSub.MD5Hash.Hash)
|
||||
if (GameMain.NetLobbyScreen.FailedSelectedShuttle.HasValue &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedShuttle.Value.Name == newSub.Name &&
|
||||
GameMain.NetLobbyScreen.FailedSelectedShuttle.Value.Hash == newSub.MD5Hash.Hash)
|
||||
{
|
||||
GameMain.NetLobbyScreen.TrySelectSub(newSub.Name, newSub.MD5Hash.Hash, GameMain.NetLobbyScreen.ShuttleList.ListBox);
|
||||
}
|
||||
|
||||
Pair<string, string> failedCampaignSub = GameMain.NetLobbyScreen.FailedCampaignSubs.Find(s => s.First == newSub.Name && s.Second == newSub.MD5Hash.Hash);
|
||||
if (failedCampaignSub != null)
|
||||
NetLobbyScreen.FailedSubInfo failedCampaignSub = GameMain.NetLobbyScreen.FailedCampaignSubs.Find(s => s.Name == newSub.Name && s.Hash == newSub.MD5Hash.Hash);
|
||||
if (failedCampaignSub != default)
|
||||
{
|
||||
GameMain.NetLobbyScreen.CampaignSubmarines.Add(newSub);
|
||||
GameMain.NetLobbyScreen.FailedCampaignSubs.Remove(failedCampaignSub);
|
||||
}
|
||||
|
||||
Pair<string, string> failedOwnedSub = GameMain.NetLobbyScreen.FailedOwnedSubs.Find(s => s.First == newSub.Name && s.Second == newSub.MD5Hash.Hash);
|
||||
if (failedOwnedSub != null)
|
||||
NetLobbyScreen.FailedSubInfo failedOwnedSub = GameMain.NetLobbyScreen.FailedOwnedSubs.Find(s => s.Name == newSub.Name && s.Hash == newSub.MD5Hash.Hash);
|
||||
if (failedOwnedSub != default)
|
||||
{
|
||||
GameMain.NetLobbyScreen.ServerOwnedSubmarines.Add(newSub);
|
||||
GameMain.NetLobbyScreen.FailedOwnedSubs.Remove(failedOwnedSub);
|
||||
@@ -2675,8 +2679,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)
|
||||
@@ -2941,7 +2948,6 @@ namespace Barotrauma.Networking
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
|
||||
msg.Write((UInt16)ClientPermissions.SelectSub);
|
||||
msg.Write(false);
|
||||
msg.Write(isShuttle); msg.WritePadBits();
|
||||
msg.Write((UInt16)subIndex);
|
||||
msg.Write((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
@@ -2949,23 +2955,6 @@ namespace Barotrauma.Networking
|
||||
clientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell the server to add / remove a purchasable submarine (permission required)
|
||||
/// </summary>
|
||||
public void RequestCampaignSub(SubmarineInfo sub, bool add)
|
||||
{
|
||||
if (!HasPermission(ClientPermissions.SelectSub) || sub == null) return;
|
||||
IWriteMessage msg = new WriteOnlyMessage();
|
||||
msg.Write((byte)ClientPacketHeader.SERVER_COMMAND);
|
||||
msg.Write((UInt16)ClientPermissions.SelectSub);
|
||||
msg.Write(true);
|
||||
msg.Write(sub.EqualityCheckVal);
|
||||
msg.Write(add);
|
||||
msg.Write((byte)ServerNetObject.END_OF_MESSAGE);
|
||||
|
||||
clientPeer.Send(msg, DeliveryMethod.Reliable);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell the server to select a mode (permission required)
|
||||
/// </summary>
|
||||
@@ -3024,12 +3013,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);
|
||||
}
|
||||
@@ -3332,7 +3322,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)
|
||||
{
|
||||
@@ -3448,7 +3440,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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,12 +225,15 @@ 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);
|
||||
|
||||
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:BitPosMismatch", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:BitPosMismatch", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
|
||||
//TODO: force the BitPosition to correct place? Having some entity in a potentially incorrect state is not as bad as a desync kick
|
||||
//msg.BitPosition = (int)(msgPosition + msgLength * 8);
|
||||
@@ -264,7 +252,7 @@ namespace Barotrauma.Networking
|
||||
DebugConsole.ThrowError("Failed to read event for entity \"" + entity.ToString() + "\"!", e);
|
||||
|
||||
GameAnalyticsManager.AddErrorEventOnce("ClientEntityEventManager.Read:ReadFailed" + entity.ToString(),
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
msg.BitPosition = (int)(msgPosition + msgLength * 8);
|
||||
msg.ReadPadBits();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -115,13 +115,11 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
if (!isActive) { return; }
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
|
||||
|
||||
//Console.WriteLine(isCompressed + " " + isConnectionInitializationStep + " " + (int)incByte);
|
||||
|
||||
if (isConnectionInitializationStep && initializationStep != ConnectionInitialization.Success)
|
||||
if (packetHeader.IsConnectionInitializationStep() && initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
ReadConnectionInitializationStep(new ReadWriteMessage(inc.Data, (int)inc.Position, inc.LengthBits, false));
|
||||
}
|
||||
@@ -133,7 +131,7 @@ namespace Barotrauma.Networking
|
||||
initializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, isCompressed, inc.PositionInBytes, length, ServerConnection);
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Data, packetHeader.IsCompressed(), inc.PositionInBytes, length, ServerConnection);
|
||||
OnMessageReceived?.Invoke(msg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,33 +112,28 @@ namespace Barotrauma.Networking
|
||||
NetworkConnection.TimeoutThresholdInGame :
|
||||
NetworkConnection.TimeoutThreshold;
|
||||
|
||||
byte incByte = data[0];
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
PacketHeader packetHeader = (PacketHeader)data[0];
|
||||
|
||||
if (!isServerMessage) { return; }
|
||||
if (!packetHeader.IsServerMessage()) { return; }
|
||||
|
||||
if (isConnectionInitializationStep)
|
||||
if (packetHeader.IsConnectionInitializationStep())
|
||||
{
|
||||
ulong low = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8);
|
||||
ulong high = Lidgren.Network.NetBitWriter.ReadUInt32(data, 32, 8 + 32);
|
||||
ulong lobbyId = low + (high << 32);
|
||||
|
||||
Steam.SteamManager.JoinLobby(lobbyId, false);
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 1 + 8, dataLength - 9, ServerConnection);
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 1 + 8, dataLength - (1 + 8), ServerConnection);
|
||||
if (initializationStep != ConnectionInitialization.Success)
|
||||
{
|
||||
incomingInitializationMessages.Add(inc);
|
||||
}
|
||||
}
|
||||
else if (isHeartbeatMessage)
|
||||
else if (packetHeader.IsHeartbeatMessage())
|
||||
{
|
||||
return; //TODO: implement heartbeats
|
||||
}
|
||||
else if (isDisconnectMessage)
|
||||
else if (packetHeader.IsDisconnectMessage())
|
||||
{
|
||||
IReadMessage inc = new ReadOnlyMessage(data, false, 1, dataLength - 1, ServerConnection);
|
||||
string msg = inc.ReadString();
|
||||
@@ -147,10 +142,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
UInt16 length = data[1];
|
||||
length |= (UInt16)(((UInt32)data[2]) << 8);
|
||||
UInt16 length = Lidgren.Network.NetBitWriter.ReadUInt16(data, 16, 8);
|
||||
|
||||
IReadMessage inc = new ReadOnlyMessage(data, isCompressed, 3, length, ServerConnection);
|
||||
IReadMessage inc = new ReadOnlyMessage(data, packetHeader.IsCompressed(), 3, length, ServerConnection);
|
||||
incomingDataMessages.Add(inc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,18 +147,13 @@ namespace Barotrauma.Networking
|
||||
|
||||
DeliveryMethod deliveryMethod = (DeliveryMethod)data[0];
|
||||
|
||||
byte incByte = data[1];
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
PacketHeader packetHeader = (PacketHeader)data[1];
|
||||
|
||||
if (!remotePeer.Authenticated & !remotePeer.Authenticating && isConnectionInitializationStep)
|
||||
if (!remotePeer.Authenticated & !remotePeer.Authenticating && packetHeader.IsConnectionInitializationStep())
|
||||
{
|
||||
remotePeer.DisconnectTime = null;
|
||||
|
||||
IReadMessage authMsg = new ReadOnlyMessage(data, isCompressed, 2, dataLength - 2, null);
|
||||
IReadMessage authMsg = new ReadOnlyMessage(data, packetHeader.IsCompressed(), 2, dataLength - 2, null);
|
||||
ConnectionInitialization initializationStep = (ConnectionInitialization)authMsg.ReadByte();
|
||||
if (initializationStep == ConnectionInitialization.SteamTicketAndVersion)
|
||||
{
|
||||
@@ -242,17 +237,11 @@ namespace Barotrauma.Networking
|
||||
|
||||
int p2pDataStart = inc.BytePosition;
|
||||
|
||||
byte incByte = inc.ReadByte();
|
||||
|
||||
bool isCompressed = (incByte & (byte)PacketHeader.IsCompressed) != 0;
|
||||
bool isConnectionInitializationStep = (incByte & (byte)PacketHeader.IsConnectionInitializationStep) != 0;
|
||||
bool isDisconnectMessage = (incByte & (byte)PacketHeader.IsDisconnectMessage) != 0;
|
||||
bool isServerMessage = (incByte & (byte)PacketHeader.IsServerMessage) != 0;
|
||||
bool isHeartbeatMessage = (incByte & (byte)PacketHeader.IsHeartbeatMessage) != 0;
|
||||
PacketHeader packetHeader = (PacketHeader)inc.ReadByte();
|
||||
|
||||
if (recipientSteamId != selfSteamID)
|
||||
{
|
||||
if (!isServerMessage)
|
||||
if (!packetHeader.IsServerMessage())
|
||||
{
|
||||
DebugConsole.ThrowError("Received non-server message meant for remote peer");
|
||||
return;
|
||||
@@ -262,7 +251,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
if (peer == null) { return; }
|
||||
|
||||
if (isDisconnectMessage)
|
||||
if (packetHeader.IsDisconnectMessage())
|
||||
{
|
||||
DisconnectPeer(peer, inc.ReadString());
|
||||
return;
|
||||
@@ -273,8 +262,8 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
case DeliveryMethod.Reliable:
|
||||
case DeliveryMethod.ReliableOrdered:
|
||||
//the documentation seems to suggest that the Reliable send type
|
||||
//enforces packet order (TODO: verify)
|
||||
//the documentation seems to suggest that the
|
||||
//Reliable send type enforces packet order
|
||||
sendType = Steamworks.P2PSend.Reliable;
|
||||
break;
|
||||
default:
|
||||
@@ -284,17 +273,31 @@ namespace Barotrauma.Networking
|
||||
|
||||
byte[] p2pData;
|
||||
|
||||
if (isConnectionInitializationStep)
|
||||
if (packetHeader.IsConnectionInitializationStep())
|
||||
{
|
||||
p2pData = new byte[inc.LengthBytes - p2pDataStart + 8];
|
||||
p2pData[0] = inc.Buffer[p2pDataStart];
|
||||
Lidgren.Network.NetBitWriter.WriteUInt64(SteamManager.CurrentLobbyID, 64, p2pData, 8);
|
||||
Array.Copy(inc.Buffer, p2pDataStart+1, p2pData, 9, inc.LengthBytes - p2pDataStart - 1);
|
||||
Lidgren.Network.NetBitWriter.WriteUInt64(SteamManager.CurrentLobbyID, 8 * 8, p2pData, 1 * 8);
|
||||
Array.Copy(inc.Buffer, p2pDataStart+1, p2pData, 1 + 8, inc.LengthBytes - p2pDataStart - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
p2pData = new byte[inc.LengthBytes - p2pDataStart];
|
||||
Array.Copy(inc.Buffer, p2pDataStart, p2pData, 0, p2pData.Length);
|
||||
|
||||
if (!packetHeader.IsHeartbeatMessage() && !packetHeader.IsDisconnectMessage())
|
||||
{
|
||||
UInt16 length = Lidgren.Network.NetBitWriter.ReadUInt16(p2pData, 16, 8);
|
||||
if (length > p2pData.Length - 2)
|
||||
{
|
||||
string errorMsg = $"Length written in message to send to client is larger than buffer size ({length} > {p2pData.Length - 2})";
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"SteamP2POwnerPeerLengthValidationFail",
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
errorMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (p2pData.Length + 4 >= MsgConstants.MTU)
|
||||
@@ -323,21 +326,21 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
else
|
||||
{
|
||||
if (isDisconnectMessage)
|
||||
if (packetHeader.IsDisconnectMessage())
|
||||
{
|
||||
DebugConsole.ThrowError("Received disconnect message from owned server");
|
||||
return;
|
||||
}
|
||||
if (!isServerMessage)
|
||||
if (!packetHeader.IsServerMessage())
|
||||
{
|
||||
DebugConsole.ThrowError("Received non-server message from owned server");
|
||||
return;
|
||||
}
|
||||
if (isHeartbeatMessage)
|
||||
if (packetHeader.IsHeartbeatMessage())
|
||||
{
|
||||
return; //timeout is handled by Lidgren, ignore this message
|
||||
return; //no timeout since we're using pipes, ignore this message
|
||||
}
|
||||
if (isConnectionInitializationStep)
|
||||
if (packetHeader.IsConnectionInitializationStep())
|
||||
{
|
||||
IWriteMessage outMsg = new WriteOnlyMessage();
|
||||
outMsg.Write(selfSteamID);
|
||||
@@ -358,7 +361,7 @@ namespace Barotrauma.Networking
|
||||
initializationStep = ConnectionInitialization.Success;
|
||||
}
|
||||
UInt16 length = inc.ReadUInt16();
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, isCompressed, inc.BytePosition, length, ServerConnection);
|
||||
IReadMessage msg = new ReadOnlyMessage(inc.Buffer, packetHeader.IsCompressed(), inc.BytePosition, length, ServerConnection);
|
||||
OnMessageReceived?.Invoke(msg);
|
||||
|
||||
return;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -242,7 +242,8 @@ namespace Barotrauma.Networking
|
||||
textBlock.ClickableAreas.Add(new GUITextBlock.ClickableArea()
|
||||
{
|
||||
Data = data,
|
||||
OnClick = GameMain.NetLobbyScreen.SelectPlayer
|
||||
OnClick = GameMain.NetLobbyScreen.SelectPlayer,
|
||||
OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,8 +128,18 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
cachedServerListInfo = null;
|
||||
|
||||
ServerName = incMsg.ReadString();
|
||||
ServerMessageText = incMsg.ReadString();
|
||||
NetFlags requiredFlags = (NetFlags)incMsg.ReadByte();
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.Name))
|
||||
{
|
||||
ServerName = incMsg.ReadString();
|
||||
}
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.Message))
|
||||
{
|
||||
ServerMessageText = incMsg.ReadString();
|
||||
}
|
||||
PlayStyle = (PlayStyle)incMsg.ReadByte();
|
||||
MaxPlayers = incMsg.ReadByte();
|
||||
HasPassword = incMsg.ReadBoolean();
|
||||
IsPublic = incMsg.ReadBoolean();
|
||||
@@ -139,9 +149,13 @@ namespace Barotrauma.Networking
|
||||
TickRate = incMsg.ReadRangedInteger(1, 60);
|
||||
GameMain.NetworkMember.TickRate = TickRate;
|
||||
|
||||
ReadExtraCargo(incMsg);
|
||||
|
||||
Voting.ClientRead(incMsg);
|
||||
if (requiredFlags.HasFlag(NetFlags.Properties))
|
||||
{
|
||||
ReadExtraCargo(incMsg);
|
||||
}
|
||||
|
||||
ReadHiddenSubs(incMsg);
|
||||
GameMain.NetLobbyScreen.UpdateSubVisibility();
|
||||
|
||||
bool isAdmin = incMsg.ReadBoolean();
|
||||
incMsg.ReadPadBits();
|
||||
@@ -151,7 +165,7 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientAdminWrite(NetFlags dataToSend, int? missionTypeOr = null, int? missionTypeAnd = null, float? levelDifficulty = null, bool? autoRestart = null, int traitorSetting = 0, int botCount = 0, int botSpawnMode = 0, bool? radiationEnabled = null, bool? useRespawnShuttle = null, int maxMissionCount = 0)
|
||||
public void ClientAdminWrite(NetFlags dataToSend, int? missionTypeOr = null, int? missionTypeAnd = null, float? levelDifficulty = null, bool? autoRestart = null, int traitorSetting = 0, int botCount = 0, int botSpawnMode = 0, bool? useRespawnShuttle = null)
|
||||
{
|
||||
if (!GameMain.Client.HasPermission(Networking.ClientPermissions.ManageSettings)) return;
|
||||
|
||||
@@ -202,6 +216,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);
|
||||
@@ -216,8 +235,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
outMsg.Write(autoRestart != null);
|
||||
outMsg.Write(autoRestart ?? false);
|
||||
outMsg.Write(radiationEnabled ?? RadiationEnabled);
|
||||
outMsg.Write((byte)maxMissionCount + 1);
|
||||
|
||||
outMsg.WritePadBits();
|
||||
}
|
||||
@@ -288,7 +305,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 +380,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 +398,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 +406,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 +424,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 +442,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 +465,7 @@ namespace Barotrauma.Networking
|
||||
return true;
|
||||
}
|
||||
};
|
||||
GetPropertyData("SaveServerLogs").AssignGUIComponent(saveLogsBox);
|
||||
GetPropertyData(nameof(SaveServerLogs)).AssignGUIComponent(saveLogsBox);
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// game settings
|
||||
@@ -480,20 +497,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 +520,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 +535,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 +562,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 +586,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 +602,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)
|
||||
{
|
||||
@@ -669,7 +719,6 @@ namespace Barotrauma.Networking
|
||||
RelativeSpacing = 0.05f
|
||||
};
|
||||
|
||||
|
||||
if (ip.InventoryIcon != null || ip.sprite != null)
|
||||
{
|
||||
GUIImage img = new GUIImage(new RectTransform(new Point(itemFrame.Rect.Height), itemFrame.RectTransform),
|
||||
@@ -692,7 +741,7 @@ namespace Barotrauma.Networking
|
||||
GUINumberInput.NumberType.Int, textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueInt = 100,
|
||||
MaxValueInt = MaxExtraCargoItemsOfType,
|
||||
IntValue = cargoVal
|
||||
};
|
||||
amountInput.OnValueChanged += (numberInput) =>
|
||||
@@ -700,16 +749,26 @@ namespace Barotrauma.Networking
|
||||
if (ExtraCargo.ContainsKey(ip))
|
||||
{
|
||||
ExtraCargo[ip] = numberInput.IntValue;
|
||||
if (numberInput.IntValue <= 0) ExtraCargo.Remove(ip);
|
||||
if (numberInput.IntValue <= 0) { ExtraCargo.Remove(ip); }
|
||||
}
|
||||
else
|
||||
else if (ExtraCargo.Keys.Count() < MaxExtraCargoItemTypes)
|
||||
{
|
||||
ExtraCargo.Add(ip, numberInput.IntValue);
|
||||
}
|
||||
numberInput.IntValue = ExtraCargo.ContainsKey(ip) ? ExtraCargo[ip] : 0;
|
||||
CoroutineManager.Invoke(() =>
|
||||
{
|
||||
foreach (var child in cargoFrame.Content.GetAllChildren())
|
||||
{
|
||||
if (child.GetChild<GUINumberInput>() is GUINumberInput otherNumberInput)
|
||||
{
|
||||
otherNumberInput.PlusButton.Enabled = ExtraCargo.Keys.Count() < MaxExtraCargoItemTypes && otherNumberInput.IntValue < otherNumberInput.MaxValueInt;
|
||||
}
|
||||
}
|
||||
}, 0.0f);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
// antigriefing
|
||||
//--------------------------------------------------------------------------------
|
||||
@@ -729,35 +788,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 +831,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 +843,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 +859,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)
|
||||
@@ -871,6 +930,7 @@ namespace Barotrauma.Networking
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
Whitelist.CreateWhiteListFrame(settingsTabs[(int)SettingsTab.Whitelist]);
|
||||
Whitelist.localEnabled = Whitelist.Enabled;
|
||||
}
|
||||
|
||||
private void CreateLabeledSlider(GUIComponent parent, string labelTag, out GUIScrollBar slider, out GUITextBlock label)
|
||||
|
||||
@@ -147,7 +147,14 @@ namespace Barotrauma.Steam
|
||||
|
||||
if (currentLobby == null)
|
||||
{
|
||||
DebugConsole.ThrowError("Failed to create Steam lobby");
|
||||
DebugConsole.ThrowError("Failed to create Steam lobby: returned lobby was null");
|
||||
lobbyState = LobbyState.NotConnected;
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentLobby.Value.Result != Steamworks.Result.OK)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to create Steam lobby: result was {currentLobby.Value.Result}");
|
||||
lobbyState = LobbyState.NotConnected;
|
||||
return;
|
||||
}
|
||||
@@ -525,18 +532,6 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
|
||||
#region Connecting to servers
|
||||
private static Steamworks.AuthTicket currentTicket = null;
|
||||
public static Steamworks.AuthTicket GetAuthSessionTicket()
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
currentTicket?.Cancel();
|
||||
currentTicket = Steamworks.SteamUser.GetAuthSessionTicket();
|
||||
return currentTicket;
|
||||
}
|
||||
|
||||
public static Steamworks.BeginAuthResult StartAuthSession(byte[] authTicketData, ulong clientSteamID)
|
||||
{
|
||||
@@ -884,9 +879,9 @@ namespace Barotrauma.Steam
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Failed to save workshop item preview image to \"" + previewImagePath + "\" when creating workshop item staging folder.";
|
||||
string errorMsg = "Failed to save workshop item preview image when creating workshop item staging folder.";
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CreateWorkshopItemStaging:WriteAllBytesFailed" + previewImagePath,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + e.Message);
|
||||
GameAnalyticsManager.ErrorSeverity.Error, errorMsg + "\n" + e.Message);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -935,7 +930,7 @@ namespace Barotrauma.Steam
|
||||
return workshopPublishStatus;
|
||||
}
|
||||
|
||||
private static IEnumerable<object> PublishItem(WorkshopPublishStatus workshopPublishStatus)
|
||||
private static IEnumerable<CoroutineStatus> PublishItem(WorkshopPublishStatus workshopPublishStatus)
|
||||
{
|
||||
if (!isInitialized)
|
||||
{
|
||||
@@ -1434,8 +1429,8 @@ namespace Barotrauma.Steam
|
||||
"\" not found. Could not combine path (" + (item.Directory ?? "directory name empty") + ").";
|
||||
DebugConsole.ThrowError(errorMessage);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamManager.CheckWorkshopItemInstalled:PathCombineException" + item.Title,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
errorMessage);
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Metadata file for a Workshop item not found. Could not combine path.");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1567,8 +1562,8 @@ namespace Barotrauma.Steam
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"SteamManager.AutoUpdateWorkshopItems:" + e.Message,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Failed to autoupdate workshop item \"" + item.Title + "\". " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Failed to autoupdate workshop item. " + e.Message + "\n" + e.StackTrace.CleanupStackTrace());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,7 +113,7 @@ namespace Barotrauma.Networking
|
||||
UserData = "capturedevicenotfound"
|
||||
};
|
||||
}
|
||||
GameAnalyticsManager.AddErrorEventOnce("Alc.CaptureDeviceOpenFailed", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.AddErrorEventOnce("Alc.CaptureDeviceOpenFailed", GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Alc.CaptureDeviceOpen(" + deviceName + ") failed. Error code: " + errorCode);
|
||||
GameMain.Config.VoiceSetting = GameSettings.VoiceMode.Disabled;
|
||||
Instance?.Dispose();
|
||||
|
||||
@@ -17,7 +17,11 @@ namespace Barotrauma
|
||||
allowSubVoting = value;
|
||||
GameMain.NetLobbyScreen.SubList.Enabled = value ||
|
||||
(GameMain.Client != null && GameMain.Client.HasPermission(ClientPermissions.SelectSub));
|
||||
GameMain.NetLobbyScreen.Frame.FindChild("subvotes", true).Visible = value;
|
||||
var subVotesLabel = GameMain.NetLobbyScreen.Frame.FindChild("subvotes", true) as GUITextBlock;
|
||||
subVotesLabel.Visible = value;
|
||||
var subVisButton = GameMain.NetLobbyScreen.SubVisibilityButton;
|
||||
subVisButton.RectTransform.AbsoluteOffset
|
||||
= new Point(value ? (int)(subVotesLabel.TextSize.X + subVisButton.Rect.Width) : 0, 0);
|
||||
|
||||
UpdateVoteTexts(null, VoteType.Sub);
|
||||
GameMain.NetLobbyScreen.SubList.Deselect();
|
||||
@@ -66,10 +70,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:
|
||||
|
||||
@@ -56,17 +56,12 @@ namespace Barotrauma.Networking
|
||||
{
|
||||
nameBox.Enabled = box.Selected;
|
||||
ipBox.Enabled = box.Selected;
|
||||
addNewButton.Enabled = box.Selected;
|
||||
|
||||
addNewButton.Enabled = box.Selected && !string.IsNullOrEmpty(ipBox.Text) && !string.IsNullOrEmpty(nameBox.Text);
|
||||
localEnabled = box.Selected;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
localEnabled = Enabled;
|
||||
|
||||
var listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.7f), whitelistFrame.RectTransform));
|
||||
foreach (WhiteListedPlayer wlp in whitelistedPlayers)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace Barotrauma.Particles
|
||||
Prefab = prefab;
|
||||
}
|
||||
|
||||
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||
public void Emit(float deltaTime, Vector2 position, Hull hullGuess = null, float angle = 0.0f, float particleRotation = 0.0f, float velocityMultiplier = 1.0f, float sizeMultiplier = 1.0f, float amountMultiplier = 1.0f, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, bool mirrorAngle = false, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||
{
|
||||
if (GameMain.Client?.MidRoundSyncing ?? false) { return; }
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace Barotrauma.Particles
|
||||
for (float z = 0.0f; z < dist; z += Prefab.Properties.EmitAcrossRayInterval)
|
||||
{
|
||||
Vector2 pos = tracerPoints.Item1 + dir * z;
|
||||
Emit(pos, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, tracerPoints: null);
|
||||
Emit(pos, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, mirrorAngle, tracerPoints: null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -169,7 +169,7 @@ namespace Barotrauma.Particles
|
||||
float emitInterval = 1.0f / Prefab.Properties.ParticlesPerSecond;
|
||||
while (emitTimer > emitInterval)
|
||||
{
|
||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, tracerPoints: tracerPoints);
|
||||
Emit(position, hullGuess, angle, particleRotation, velocityMultiplier, sizeMultiplier, colorMultiplier, overrideParticle, mirrorAngle, tracerPoints: tracerPoints);
|
||||
emitTimer -= emitInterval;
|
||||
}
|
||||
}
|
||||
@@ -183,16 +183,19 @@ namespace Barotrauma.Particles
|
||||
}
|
||||
}
|
||||
|
||||
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||
private void Emit(Vector2 position, Hull hullGuess, float angle, float particleRotation, float velocityMultiplier, float sizeMultiplier, Color? colorMultiplier = null, ParticlePrefab overrideParticle = null, bool mirrorAngle = false, Tuple<Vector2, Vector2> tracerPoints = null)
|
||||
{
|
||||
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) * (mirrorAngle ? -1 : 1);
|
||||
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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -201,7 +201,7 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("PhysicsBody.ClientRead:InvalidData" + parentDebugName,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
errorMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
#region Using Statements
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using GameAnalyticsSDK.Net;
|
||||
using Barotrauma.Steam;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -245,6 +243,13 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (GameAnalyticsManager.SendUserStatistics)
|
||||
{
|
||||
//send crash report before appending debug console messages (which may contain non-anonymous information)
|
||||
GameAnalyticsManager.AddErrorEvent(GameAnalyticsManager.ErrorSeverity.Critical, sb.ToString());
|
||||
GameAnalyticsManager.ShutDown();
|
||||
}
|
||||
|
||||
sb.AppendLine("Last debug messages:");
|
||||
for (int i = DebugConsole.Messages.Count - 1; i >= 0; i--)
|
||||
{
|
||||
@@ -255,13 +260,11 @@ namespace Barotrauma
|
||||
|
||||
File.WriteAllText(filePath, crashReport);
|
||||
|
||||
if (GameSettings.SaveDebugConsoleLogs) DebugConsole.SaveLogs();
|
||||
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
|
||||
|
||||
if (GameSettings.SendUserStatistics)
|
||||
if (GameAnalyticsManager.SendUserStatistics)
|
||||
{
|
||||
CrashMessageBox("A crash report (\"" + filePath + "\") was saved in the root folder of the game and sent to the developers.", filePath);
|
||||
GameAnalytics.AddErrorEvent(EGAErrorSeverity.Critical, crashReport);
|
||||
GameAnalytics.OnQuit();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -7,14 +7,10 @@ namespace Barotrauma
|
||||
{
|
||||
protected readonly GUIComponent newGameContainer, loadGameContainer;
|
||||
|
||||
protected GUIListBox subList;
|
||||
protected GUIListBox saveList;
|
||||
protected List<GUITickBox> subTickBoxes;
|
||||
|
||||
protected GUITextBox saveNameBox, seedBox;
|
||||
|
||||
protected GUILayoutGroup subPreviewContainer;
|
||||
|
||||
protected GUIButton loadGameButton;
|
||||
|
||||
public Action<SubmarineInfo, string, string, CampaignSettings> StartNewGame;
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using System.Globalization;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -14,55 +15,79 @@ namespace Barotrauma
|
||||
{
|
||||
private GUIButton deleteMpSaveButton;
|
||||
|
||||
public MultiPlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<SubmarineInfo> submarines, IEnumerable<string> saveFiles = null)
|
||||
public MultiPlayerCampaignSetupUI(GUIComponent newGameContainer, GUIComponent loadGameContainer, IEnumerable<string> saveFiles = null)
|
||||
: base(newGameContainer, loadGameContainer)
|
||||
{
|
||||
var columnContainer = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: true)
|
||||
var verticalLayout = new GUILayoutGroup(new RectTransform(Vector2.One, newGameContainer.RectTransform), isHorizontal: false)
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.0f
|
||||
};
|
||||
|
||||
var leftColumn = new GUILayoutGroup(new RectTransform(Vector2.One, columnContainer.RectTransform))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.015f
|
||||
};
|
||||
|
||||
var rightColumn = new GUILayoutGroup(new RectTransform(Vector2.Zero, columnContainer.RectTransform))
|
||||
{
|
||||
Stretch = true,
|
||||
RelativeSpacing = 0.015f
|
||||
};
|
||||
|
||||
columnContainer.Recalculate();
|
||||
|
||||
// New game left side
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SaveName"), font: GUI.SubHeadingFont);
|
||||
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, string.Empty)
|
||||
// New game
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), verticalLayout.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("SaveName"), font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft);
|
||||
saveNameBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.03f), verticalLayout.RectTransform) { MinSize = new Point(0, 20) }, string.Empty)
|
||||
{
|
||||
textFilterFunction = (string str) => { return ToolBox.RemoveInvalidFileNameChars(str); }
|
||||
};
|
||||
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.02f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUI.SubHeadingFont);
|
||||
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.05f), leftColumn.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
|
||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.03f), verticalLayout.RectTransform) { MinSize = new Point(0, 20) }, TextManager.Get("MapSeed"), font: GUI.SubHeadingFont, textAlignment: Alignment.BottomLeft);
|
||||
seedBox = new GUITextBox(new RectTransform(new Vector2(1.0f, 0.03f), verticalLayout.RectTransform) { MinSize = new Point(0, 20) }, ToolBox.RandomSeed(8));
|
||||
|
||||
// Spacing to fix the multiplayer campaign setup layout
|
||||
CreateMultiplayerCampaignSubList(leftColumn.RectTransform);
|
||||
|
||||
//spacing
|
||||
//new GUIFrame(new RectTransform(new Vector2(1.0f, 0.25f), leftColumn.RectTransform), style: null);
|
||||
|
||||
// New game right side
|
||||
subPreviewContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 1.0f), rightColumn.RectTransform))
|
||||
GUIFrame radiationBoxContainer
|
||||
= new GUIFrame(new RectTransform(new Vector2(1.0f, 0.05f), verticalLayout.RectTransform), style: null);
|
||||
GUITickBox radiationEnabledTickBox = null;
|
||||
if (MapGenerationParams.Instance.RadiationParams != null)
|
||||
{
|
||||
Stretch = true
|
||||
radiationEnabledTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.5f), radiationBoxContainer.RectTransform, Anchor.Center), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font)
|
||||
{
|
||||
Selected = true,
|
||||
OnSelected = box => true
|
||||
};
|
||||
}
|
||||
|
||||
var maxMissionCountSettingHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.05f), verticalLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
var maxMissionCountDescription = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.0f), maxMissionCountSettingHolder.RectTransform), TextManager.Get("maxmissioncount", fallBackTag: "missions"), wrap: true)
|
||||
{
|
||||
ToolTip = TextManager.Get("maxmissioncounttooltip")
|
||||
};
|
||||
int maxMissionCount = GameMain.NetworkMember.ServerSettings.MaxMissionCount;
|
||||
var maxMissionCountContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), maxMissionCountSettingHolder.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { RelativeSpacing = 0.05f, Stretch = true };
|
||||
var maxMissionCountButtons = new GUIButton[2];
|
||||
maxMissionCountButtons[0]
|
||||
= new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), maxMissionCountContainer.RectTransform),
|
||||
style: "GUIButtonToggleLeft");
|
||||
var maxMissionCountText = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), maxMissionCountContainer.RectTransform), "0", textAlignment: Alignment.Center, style: "GUITextBox");
|
||||
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.12f),
|
||||
leftColumn.RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
|
||||
void updateMissionCountText()
|
||||
{
|
||||
maxMissionCount = MathHelper.Clamp(maxMissionCount,
|
||||
CampaignSettings.MinMissionCountLimit,
|
||||
CampaignSettings.MaxMissionCountLimit);
|
||||
maxMissionCountText.Text = maxMissionCount.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
maxMissionCountButtons[1]
|
||||
= new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), maxMissionCountContainer.RectTransform),
|
||||
style: "GUIButtonToggleRight");
|
||||
maxMissionCountButtons[0].OnClicked = (button, o) =>
|
||||
{
|
||||
maxMissionCount--;
|
||||
updateMissionCountText();
|
||||
return false;
|
||||
};
|
||||
maxMissionCountButtons[1].OnClicked = (button, o) =>
|
||||
{
|
||||
maxMissionCount++;
|
||||
updateMissionCountText();
|
||||
return false;
|
||||
};
|
||||
updateMissionCountText();
|
||||
maxMissionCountSettingHolder.Children.ForEach(c => c.ToolTip = maxMissionCountSettingHolder.ToolTip);
|
||||
|
||||
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), buttonContainer.RectTransform, Anchor.BottomRight) { MaxSize = new Point(350, 60) }, TextManager.Get("StartCampaignButton"))
|
||||
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.04f),
|
||||
verticalLayout.RectTransform) { MaxSize = new Point(int.MaxValue, 60) }, childAnchor: Anchor.BottomRight, isHorizontal: true);
|
||||
|
||||
StartButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1f), buttonContainer.RectTransform, Anchor.BottomRight), TextManager.Get("StartCampaignButton"))
|
||||
{
|
||||
OnClicked = (GUIButton btn, object userData) =>
|
||||
{
|
||||
@@ -85,20 +110,19 @@ namespace Barotrauma
|
||||
|
||||
if (string.IsNullOrEmpty(selectedSub.MD5Hash.Hash))
|
||||
{
|
||||
((GUITextBlock)subList.SelectedComponent).TextColor = Color.DarkRed * 0.8f;
|
||||
subList.SelectedComponent.CanBeFocused = false;
|
||||
subList.Deselect();
|
||||
new GUIMessageBox(TextManager.Get("error"), TextManager.Get("nohashsubmarineselected"));
|
||||
return false;
|
||||
}
|
||||
|
||||
string savePath = SaveUtil.CreateSavePath(SaveUtil.SaveType.Multiplayer, saveNameBox.Text);
|
||||
bool hasRequiredContentPackages = selectedSub.RequiredContentPackagesInstalled;
|
||||
|
||||
CampaignSettings settings = new CampaignSettings();
|
||||
CampaignSettings settings = new CampaignSettings
|
||||
{
|
||||
RadiationEnabled = radiationEnabledTickBox?.Selected ?? GameMain.NetworkMember.ServerSettings.RadiationEnabled,
|
||||
MaxMissionCount = maxMissionCount
|
||||
};
|
||||
|
||||
settings.RadiationEnabled = GameMain.NetLobbyScreen.IsRadiationEnabled();
|
||||
settings.MaxMissionCount = GameMain.NetLobbyScreen.GetMaxMissionCount();
|
||||
|
||||
if (selectedSub.HasTag(SubmarineTag.Shuttle) || !hasRequiredContentPackages)
|
||||
{
|
||||
if (!hasRequiredContentPackages)
|
||||
@@ -148,7 +172,9 @@ namespace Barotrauma
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
StartButton.RectTransform.MaxSize = RectTransform.MaxPoint;
|
||||
StartButton.Children.ForEach(c => c.RectTransform.MaxSize = RectTransform.MaxPoint);
|
||||
|
||||
InitialMoneyText = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1f), buttonContainer.RectTransform), "", font: GUI.Style.SmallFont, textColor: GUI.Style.Green)
|
||||
{
|
||||
TextGetter = () =>
|
||||
@@ -163,115 +189,12 @@ namespace Barotrauma
|
||||
}
|
||||
};
|
||||
|
||||
columnContainer.Recalculate();
|
||||
leftColumn.Recalculate();
|
||||
rightColumn.Recalculate();
|
||||
verticalLayout.Recalculate();
|
||||
|
||||
if (submarines != null) { UpdateSubList(submarines); }
|
||||
UpdateLoadMenu(saveFiles);
|
||||
}
|
||||
|
||||
private void CreateMultiplayerCampaignSubList(RectTransform parent)
|
||||
{
|
||||
GUILayoutGroup subHolder = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.725f), parent))
|
||||
{
|
||||
RelativeSpacing = 0.005f,
|
||||
Stretch = true
|
||||
};
|
||||
|
||||
var subLabel = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.055f), subHolder.RectTransform) { MinSize = new Point(0, 25) }, TextManager.Get("purchasablesubmarines", fallBackTag: "workshoplabelsubmarines"), font: GUI.SubHeadingFont);
|
||||
|
||||
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) =>
|
||||
{
|
||||
foreach (GUIComponent child in subList.Content.Children)
|
||||
{
|
||||
if (!(child.UserData is SubmarineInfo sub)) { continue; }
|
||||
child.Visible = string.IsNullOrEmpty(text) ? true : sub.DisplayName.ToLower().Contains(text.ToLower());
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
subList = new GUIListBox(new RectTransform(Vector2.One, subHolder.RectTransform));
|
||||
subTickBoxes = new List<GUITickBox>();
|
||||
|
||||
for (int i = 0; i < GameMain.Client.ServerSubmarines.Count; i++)
|
||||
{
|
||||
SubmarineInfo sub = GameMain.Client.ServerSubmarines[i];
|
||||
|
||||
if (!sub.IsCampaignCompatible) continue;
|
||||
|
||||
var frame = new GUIFrame(new RectTransform(new Vector2(1.0f, 0.2f), subList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||
style: "ListBoxElement")
|
||||
{
|
||||
ToolTip = sub.Description,
|
||||
UserData = sub
|
||||
};
|
||||
|
||||
int buttonSize = (int)(frame.Rect.Height * 0.8f);
|
||||
|
||||
GUITickBox tickBox = new GUITickBox(new RectTransform(new Vector2(0.8f, 1.0f), frame.RectTransform, Anchor.CenterLeft), ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Content.Rect.Width - 65))
|
||||
{
|
||||
UserData = sub,
|
||||
OnSelected = (GUITickBox box) =>
|
||||
{
|
||||
GameMain.Client.RequestCampaignSub(box.UserData as SubmarineInfo, box.Selected);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
subTickBoxes.Add(tickBox);
|
||||
tickBox.Selected = GameMain.NetLobbyScreen.CampaignSubmarines.Contains(sub);
|
||||
|
||||
frame.RectTransform.MinSize = new Point(0, tickBox.RectTransform.MinSize.Y);
|
||||
|
||||
var subTextBlock = tickBox.TextBlock;
|
||||
|
||||
var matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name && s.MD5Hash?.Hash == sub.MD5Hash?.Hash);
|
||||
if (matchingSub == null) matchingSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name == sub.Name);
|
||||
|
||||
if (matchingSub == null)
|
||||
{
|
||||
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
|
||||
frame.ToolTip = TextManager.Get("SubNotFound");
|
||||
}
|
||||
else if (matchingSub?.MD5Hash == null || matchingSub.MD5Hash?.Hash != sub.MD5Hash?.Hash)
|
||||
{
|
||||
subTextBlock.TextColor = new Color(subTextBlock.TextColor, 0.5f);
|
||||
frame.ToolTip = TextManager.Get("SubDoesntMatch");
|
||||
}
|
||||
|
||||
if (!sub.RequiredContentPackagesInstalled)
|
||||
{
|
||||
subTextBlock.TextColor = Color.Lerp(subTextBlock.TextColor, Color.DarkRed, 0.5f);
|
||||
frame.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + frame.RawToolTip;
|
||||
}
|
||||
|
||||
var classText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), frame.RectTransform, Anchor.CenterRight),
|
||||
TextManager.Get($"submarineclass.{sub.SubmarineClass}"), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
||||
{
|
||||
TextColor = subTextBlock.TextColor * 0.8f,
|
||||
ToolTip = subTextBlock.RawToolTip
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
public void RefreshMultiplayerCampaignSubUI(List<SubmarineInfo> campaignSubs)
|
||||
{
|
||||
for (int i = 0; i < subTickBoxes.Count; i++)
|
||||
{
|
||||
subTickBoxes[i].Selected = campaignSubs.Contains(subTickBoxes[i].UserData as SubmarineInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<object> WaitForCampaignSetup()
|
||||
private IEnumerable<CoroutineStatus> WaitForCampaignSetup()
|
||||
{
|
||||
GUI.SetCursorWaiting();
|
||||
string headerText = TextManager.Get("CampaignStartingPleaseWait");
|
||||
@@ -298,64 +221,6 @@ namespace Barotrauma
|
||||
yield return CoroutineStatus.Success;
|
||||
}
|
||||
|
||||
public void UpdateSubList(IEnumerable<SubmarineInfo> submarines)
|
||||
{
|
||||
List<SubmarineInfo> subsToShow;
|
||||
string downloadFolder = Path.GetFullPath(SaveUtil.SubmarineDownloadFolder);
|
||||
subsToShow = submarines.Where(s => s.IsCampaignCompatibleIgnoreClass && Path.GetDirectoryName(Path.GetFullPath(s.FilePath)) != downloadFolder).ToList();
|
||||
|
||||
subsToShow.Sort((s1, s2) =>
|
||||
{
|
||||
int p1 = s1.Price > CampaignMode.InitialMoney ? 10 : 0;
|
||||
int p2 = s2.Price > CampaignMode.InitialMoney ? 10 : 0;
|
||||
return p1.CompareTo(p2) * 100 + s1.Name.CompareTo(s2.Name);
|
||||
});
|
||||
|
||||
subList.ClearChildren();
|
||||
|
||||
foreach (SubmarineInfo sub in subsToShow)
|
||||
{
|
||||
var textBlock = new GUITextBlock(
|
||||
new RectTransform(new Vector2(1, 0.1f), subList.Content.RectTransform) { MinSize = new Point(0, 30) },
|
||||
ToolBox.LimitString(sub.DisplayName, GUI.Font, subList.Rect.Width - 65), style: "ListBoxElement")
|
||||
{
|
||||
ToolTip = sub.Description,
|
||||
UserData = sub
|
||||
};
|
||||
|
||||
if (!sub.RequiredContentPackagesInstalled)
|
||||
{
|
||||
textBlock.TextColor = Color.Lerp(textBlock.TextColor, Color.DarkRed, .5f);
|
||||
textBlock.ToolTip = TextManager.Get("ContentPackageMismatch") + "\n\n" + textBlock.RawToolTip;
|
||||
}
|
||||
|
||||
var priceText = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1.0f), textBlock.RectTransform, Anchor.CenterRight),
|
||||
TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", sub.Price)), textAlignment: Alignment.CenterRight, font: GUI.SmallFont)
|
||||
{
|
||||
TextColor = sub.Price > CampaignMode.InitialMoney ? GUI.Style.Red : textBlock.TextColor * 0.8f,
|
||||
ToolTip = textBlock.ToolTip
|
||||
};
|
||||
#if !DEBUG
|
||||
if (!GameMain.DebugDraw)
|
||||
{
|
||||
if (sub.Price > CampaignMode.InitialMoney || !sub.IsCampaignCompatible)
|
||||
{
|
||||
textBlock.CanBeFocused = false;
|
||||
textBlock.TextColor *= 0.5f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (SubmarineInfo.SavedSubmarines.Any())
|
||||
{
|
||||
var validSubs = subsToShow.Where(s => s.IsCampaignCompatible && s.Price <= CampaignMode.InitialMoney).ToList();
|
||||
if (validSubs.Count > 0)
|
||||
{
|
||||
subList.Select(validSubs[Rand.Int(validSubs.Count)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> prevSaveFiles;
|
||||
public void UpdateLoadMenu(IEnumerable<string> saveFiles = null)
|
||||
{
|
||||
|
||||
@@ -12,6 +12,10 @@ namespace Barotrauma
|
||||
{
|
||||
class SinglePlayerCampaignSetupUI : CampaignSetupUI
|
||||
{
|
||||
private GUIListBox subList;
|
||||
|
||||
protected GUILayoutGroup subPreviewContainer;
|
||||
|
||||
public CharacterInfo.AppearanceCustomizationMenu[] CharacterMenus { get; private set; }
|
||||
|
||||
private GUIButton nextButton;
|
||||
@@ -38,7 +42,7 @@ namespace Barotrauma
|
||||
pageContainer.BarScroll = targetScroll;
|
||||
}
|
||||
|
||||
for (int i=0; i<CharacterMenus.Length; i++)
|
||||
for (int i = 0; i < CharacterMenus.Length; i++)
|
||||
{
|
||||
CharacterMenus[i]?.Update();
|
||||
}
|
||||
@@ -77,6 +81,7 @@ namespace Barotrauma
|
||||
{
|
||||
ScrollBarEnabled = false,
|
||||
ScrollBarVisible = false,
|
||||
AllowArrowKeyScroll = false,
|
||||
HoverCursor = CursorState.Default
|
||||
};
|
||||
|
||||
|
||||
@@ -705,7 +705,7 @@ namespace Barotrauma.CharacterEditor
|
||||
{
|
||||
string errorMsg = "Attempted to modify the state of the physics simulation while a time step was running.";
|
||||
DebugConsole.ThrowError(errorMsg, e);
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterEditorScreen.Update:WorldLockedException" + e.Message, GameAnalyticsSDK.Net.EGAErrorSeverity.Critical, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("CharacterEditorScreen.Update:WorldLockedException" + e.Message, GameAnalyticsManager.ErrorSeverity.Critical, errorMsg);
|
||||
}
|
||||
}
|
||||
// Camera
|
||||
@@ -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()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user