Unstable v0.15.17.0 (Hex is out of town edition)
This commit is contained in:
@@ -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
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
@@ -651,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
|
||||
{
|
||||
@@ -682,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);
|
||||
}
|
||||
}
|
||||
@@ -971,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;
|
||||
@@ -984,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
|
||||
{
|
||||
@@ -1159,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 => a.Value == selectedLimb && a.Key.ShouldShowIcon(Character)).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 (kvp.Value != selectedLimb || !kvp.Key.ShouldShowIcon(Character)) { 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)
|
||||
@@ -1604,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);
|
||||
|
||||
@@ -1623,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; }
|
||||
@@ -1633,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;
|
||||
@@ -1714,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)
|
||||
@@ -1758,14 +1779,28 @@ 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 =>
|
||||
bool shouldDisplayAffliction(KeyValuePair<Affliction, LimbHealth> kvp, LimbHealth limbHealth)
|
||||
{
|
||||
Limb indicatorLimb = Character.AnimController.GetLimb(a.Prefab.IndicatorLimb);
|
||||
return indicatorLimb != null && indicatorLimb.HealthIndex == i && a.ShouldShowIcon(Character);
|
||||
}));
|
||||
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 == i;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (thisAfflictions.Count() <= 0) { i++; continue; }
|
||||
afflictionsDisplayedOnLimb.Clear();
|
||||
foreach (var affliction in afflictions)
|
||||
{
|
||||
if (shouldDisplayAffliction(affliction, limbHealth)) { afflictionsDisplayedOnLimb.Add(affliction.Key); }
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1776,12 +1811,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);
|
||||
@@ -1834,8 +1869,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)
|
||||
@@ -1865,47 +1899,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++)
|
||||
{
|
||||
@@ -1931,43 +1927,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1985,14 +1988,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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -553,6 +553,12 @@ namespace Barotrauma
|
||||
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() }));
|
||||
@@ -1461,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)
|
||||
@@ -1630,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:");
|
||||
@@ -1639,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);
|
||||
@@ -1651,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);
|
||||
|
||||
@@ -2485,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")
|
||||
@@ -3162,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());
|
||||
}
|
||||
},
|
||||
() =>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -79,6 +79,8 @@ namespace Barotrauma
|
||||
|
||||
public bool AllowMouseWheelScroll { get; set; } = true;
|
||||
|
||||
public bool AllowArrowKeyScroll { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Scrolls the list smoothly
|
||||
/// </summary>
|
||||
@@ -1254,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
|
||||
|
||||
@@ -276,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>();
|
||||
|
||||
@@ -528,7 +529,7 @@ namespace Barotrauma
|
||||
{
|
||||
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);
|
||||
@@ -541,6 +542,10 @@ namespace Barotrauma
|
||||
{
|
||||
clickableArea.OnClick?.Invoke(this, clickableArea);
|
||||
}
|
||||
if (PlayerInput.SecondaryMouseButtonClicked())
|
||||
{
|
||||
clickableArea.OnSecondaryClick?.Invoke(this, clickableArea);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 };
|
||||
@@ -1643,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;
|
||||
@@ -384,51 +383,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)
|
||||
@@ -522,14 +476,9 @@ namespace Barotrauma
|
||||
DebugConsole.Log("Selected content packages: " + string.Join(", ", Config.AllEnabledPackages.Select(cp => cp.Name)));
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
GameSettings.ShowUserStatisticsPrompt = false;
|
||||
GameSettings.SendUserStatistics = false;
|
||||
#endif
|
||||
GameAnalyticsManager.InitIfConsented();
|
||||
|
||||
InitUserStats();
|
||||
|
||||
yield return CoroutineStatus.Running;
|
||||
yield return CoroutineStatus.Running;
|
||||
|
||||
Debug.WriteLine("sounds");
|
||||
|
||||
@@ -841,6 +790,8 @@ namespace Barotrauma
|
||||
}
|
||||
#endif
|
||||
|
||||
NetworkMember?.Update((float)Timing.Step);
|
||||
|
||||
if (!hasLoaded && !CoroutineManager.IsCoroutineRunning(loadingCoroutine))
|
||||
{
|
||||
throw new LoadingException(loadingCoroutine.Exception);
|
||||
@@ -915,6 +866,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();
|
||||
@@ -999,11 +955,11 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
NetworkMember?.Update((float)Timing.Step);
|
||||
|
||||
GUI.Update((float)Timing.Step);
|
||||
}
|
||||
|
||||
NetworkMember?.Update((float)Timing.Step);
|
||||
|
||||
CoroutineManager.Update((float)Timing.Step, Paused ? 0.0f : (float)Timing.Step);
|
||||
|
||||
SteamManager.Update((float)Timing.Step);
|
||||
@@ -1123,6 +1079,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();
|
||||
@@ -1131,6 +1091,7 @@ namespace Barotrauma
|
||||
GUIMessageBox.CloseAll();
|
||||
MainMenuScreen.Select();
|
||||
GameSession = null;
|
||||
|
||||
}
|
||||
|
||||
public void ShowCampaignDisclaimer(Action onContinue = null)
|
||||
@@ -1254,7 +1215,7 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Error while cleaning unnecessary save files", e);
|
||||
}
|
||||
|
||||
if (GameSettings.SendUserStatistics) { GameAnalytics.OnQuit(); }
|
||||
if (GameAnalyticsManager.SendUserStatistics) { GameAnalyticsManager.ShutDown(); }
|
||||
if (GameSettings.SaveDebugConsoleLogs || GameSettings.VerboseLogging) { DebugConsole.SaveLogs(); }
|
||||
|
||||
base.OnExiting(sender, args);
|
||||
|
||||
@@ -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;
|
||||
@@ -789,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);
|
||||
}
|
||||
}
|
||||
@@ -968,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) =>
|
||||
@@ -1153,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; }
|
||||
@@ -1902,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;
|
||||
|
||||
@@ -2605,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),
|
||||
@@ -2621,7 +2523,6 @@ namespace Barotrauma
|
||||
if (contextualOrders.None())
|
||||
{
|
||||
string orderIdentifier;
|
||||
|
||||
// Check if targeting an item or a hull
|
||||
if (itemContext != null && itemContext.IsPlayerTeamInteractable)
|
||||
{
|
||||
@@ -2630,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 => r.IsBelowRepairThreshold))
|
||||
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();
|
||||
}
|
||||
@@ -2717,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 (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; }
|
||||
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)));
|
||||
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>
|
||||
@@ -2831,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;
|
||||
@@ -2943,7 +2847,9 @@ namespace Barotrauma
|
||||
}
|
||||
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;
|
||||
@@ -3013,7 +2919,9 @@ namespace Barotrauma
|
||||
}
|
||||
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;
|
||||
@@ -3218,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;
|
||||
}
|
||||
@@ -3496,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,
|
||||
|
||||
+1
-1
@@ -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")
|
||||
|
||||
@@ -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))
|
||||
@@ -509,17 +513,53 @@ 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;
|
||||
}
|
||||
};
|
||||
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 +596,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 +1201,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -672,36 +672,33 @@ 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 || gap.HiddenInGame) { 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 && hullStatusComponents != null)
|
||||
{
|
||||
@@ -991,8 +988,40 @@ 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;
|
||||
|
||||
@@ -1013,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;
|
||||
|
||||
@@ -1111,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;
|
||||
@@ -1155,7 +1174,8 @@ namespace Barotrauma.Items.Components
|
||||
|
||||
if (hullsVisible && hullData.HullWaterAmount is { } waterAmount)
|
||||
{
|
||||
if (hullFrame.Rect.Height * waterAmount > 3.0f)
|
||||
if (!RequireWaterDetectors) { waterAmount = hull.WaterPercentage / 100.0f; }
|
||||
if (hullFrame.Rect.Height * waterAmount > 1.0f)
|
||||
{
|
||||
RectangleF waterRect = new RectangleF(hullFrame.Rect.X, hullFrame.Rect.Y + hullFrame.Rect.Height * (1.0f - waterAmount), hullFrame.Rect.Width, hullFrame.Rect.Height * waterAmount);
|
||||
|
||||
@@ -1418,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);
|
||||
}
|
||||
@@ -1598,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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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 qteTime = 0.5f;
|
||||
private float qteCooldown;
|
||||
private const float qteCooldownTime = 0.5f;
|
||||
|
||||
public float FakeBrokenTimer;
|
||||
|
||||
[Serialize("", false, description: "An optional description of the needed repairs displayed in the repair interface.")]
|
||||
@@ -55,16 +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);
|
||||
float defaultMaxCondition = item.MaxCondition / maxRepairConditionMultiplier;
|
||||
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;
|
||||
}
|
||||
@@ -145,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 = qteTime;
|
||||
|
||||
repairButtonText = TextManager.Get("RepairButton");
|
||||
repairingText = TextManager.Get("Repairing");
|
||||
RepairButton = new GUIButton(new RectTransform(new Vector2(0.4f, 1.0f), progressBarHolder.RectTransform, Anchor.TopCenter), repairButtonText)
|
||||
@@ -159,6 +166,11 @@ namespace Barotrauma.Items.Components
|
||||
requestStartFixAction = FixActions.Repair;
|
||||
item.CreateClientEvent(this);
|
||||
return true;
|
||||
},
|
||||
OnButtonDown = () =>
|
||||
{
|
||||
QTEAction();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
RepairButton.TextBlock.AutoScaleHorizontal = true;
|
||||
@@ -183,6 +195,11 @@ namespace Barotrauma.Items.Components
|
||||
requestStartFixAction = FixActions.Sabotage;
|
||||
item.CreateClientEvent(this);
|
||||
return true;
|
||||
},
|
||||
OnButtonDown = () =>
|
||||
{
|
||||
QTEAction();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -253,6 +270,21 @@ namespace Barotrauma.Items.Components
|
||||
{
|
||||
repairSoundChannel = SoundPlayer.PlaySound("repair", item.WorldPosition, hullGuess: item.CurrentHull);
|
||||
}
|
||||
|
||||
if (qteCooldown > 0.0f)
|
||||
{
|
||||
qteCooldown -= deltaTime;
|
||||
if (qteCooldown <= 0.0f)
|
||||
{
|
||||
qteTimer = qteTime;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qteTimer -= deltaTime * (qteTimer / qteTime);
|
||||
if (qteTimer < 0.0f) qteTimer = qteTime;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -270,6 +302,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 / qteCooldownTime, progressBar.Color, qteSliderColor, Color.White);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (qteTimer / qteTime <= 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 / qteTime) * sliderRect.Width), sliderRect.Y - 5, 2, sliderRect.Height + 10),
|
||||
qteSliderColor, true);
|
||||
|
||||
if (item.Condition > defaultMaxCondition)
|
||||
{
|
||||
float extraCondition = item.MaxCondition * (item.MaxRepairConditionMultiplier - 1.0f);
|
||||
@@ -282,7 +334,7 @@ namespace Barotrauma.Items.Components
|
||||
progressBarOverlayText.Visible = false;
|
||||
}
|
||||
|
||||
RepairButton.Enabled = (currentFixerAction == FixActions.None || (CurrentFixer == character && currentFixerAction != FixActions.Repair)) && !item.IsFullCondition && IsBelowRepairThreshold;
|
||||
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);
|
||||
@@ -352,6 +404,29 @@ namespace Barotrauma.Items.Components
|
||||
repairSoundChannel = null;
|
||||
}
|
||||
|
||||
private void QTEAction()
|
||||
{
|
||||
if (currentFixerAction == FixActions.Repair)
|
||||
{
|
||||
qteSuccess = qteCooldown <= 0.0f && qteTimer / qteTime <= item.Condition / item.MaxCondition;
|
||||
}
|
||||
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 = qteTime; }
|
||||
qteCooldown = qteCooldownTime;
|
||||
//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();
|
||||
@@ -363,11 +438,13 @@ namespace Barotrauma.Items.Components
|
||||
currentFixerAction = (FixActions)msg.ReadRangedInteger(0, 2);
|
||||
CurrentFixer = currentFixerID != 0 ? Entity.FindEntityByID(currentFixerID) as Character : null;
|
||||
item.MaxRepairConditionMultiplier = GetMaxRepairConditionMultiplier(CurrentFixer);
|
||||
repairBoost = msg.ReadSingle();
|
||||
}
|
||||
|
||||
public void ClientWrite(IWriteMessage msg, object[] extraData = null)
|
||||
{
|
||||
msg.WriteRangedInteger((int)requestStartFixAction, 0, 2);
|
||||
msg.Write(qteSuccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,12 +26,7 @@ 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");
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -1445,7 +1445,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 +1586,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 +1607,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;
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Barotrauma
|
||||
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 :
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -649,7 +649,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();
|
||||
@@ -779,7 +779,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;
|
||||
@@ -791,7 +791,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;
|
||||
}
|
||||
@@ -989,7 +989,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);
|
||||
}
|
||||
|
||||
@@ -1010,7 +1010,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);
|
||||
@@ -1031,7 +1031,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
|
||||
@@ -1047,7 +1047,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);
|
||||
}
|
||||
}
|
||||
@@ -1117,8 +1117,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)
|
||||
@@ -1532,7 +1532,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;
|
||||
}
|
||||
@@ -1544,7 +1544,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;
|
||||
}
|
||||
@@ -2116,9 +2116,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) &&
|
||||
@@ -2168,22 +2165,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;
|
||||
@@ -2355,7 +2345,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");
|
||||
|
||||
@@ -2591,29 +2581,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);
|
||||
@@ -2946,7 +2936,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);
|
||||
@@ -2954,23 +2943,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>
|
||||
|
||||
+2
-2
@@ -233,7 +233,7 @@ namespace Barotrauma.Networking
|
||||
|
||||
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);
|
||||
@@ -252,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();
|
||||
}
|
||||
|
||||
+3
-5
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+8
-14
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+31
-28
@@ -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;
|
||||
|
||||
@@ -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
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,8 +92,9 @@ namespace Barotrauma.Networking
|
||||
}
|
||||
}
|
||||
|
||||
public void ClientAdminRead(IReadMessage incMsg)
|
||||
public void ClientAdminRead(IReadMessage incMsg, NetFlags requiredFlags)
|
||||
{
|
||||
if (!requiredFlags.HasFlag(NetFlags.Properties)) { return; }
|
||||
int count = incMsg.ReadUInt16();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
@@ -128,8 +129,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,23 +150,23 @@ namespace Barotrauma.Networking
|
||||
TickRate = incMsg.ReadRangedInteger(1, 60);
|
||||
GameMain.NetworkMember.TickRate = TickRate;
|
||||
|
||||
ReadExtraCargo(incMsg);
|
||||
|
||||
if (requiredFlags.HasFlag(NetFlags.Properties))
|
||||
{
|
||||
ReadExtraCargo(incMsg);
|
||||
}
|
||||
|
||||
ReadHiddenSubs(incMsg);
|
||||
|
||||
GameMain.NetLobbyScreen.UpdateSubVisibility();
|
||||
|
||||
Voting.ClientRead(incMsg);
|
||||
|
||||
bool isAdmin = incMsg.ReadBoolean();
|
||||
incMsg.ReadPadBits();
|
||||
if (isAdmin)
|
||||
{
|
||||
ClientAdminRead(incMsg);
|
||||
ClientAdminRead(incMsg, requiredFlags);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
@@ -225,8 +236,6 @@ namespace Barotrauma.Networking
|
||||
|
||||
outMsg.Write(autoRestart != null);
|
||||
outMsg.Write(autoRestart ?? false);
|
||||
outMsg.Write(radiationEnabled ?? RadiationEnabled);
|
||||
outMsg.Write((byte)maxMissionCount + 1);
|
||||
|
||||
outMsg.WritePadBits();
|
||||
}
|
||||
@@ -711,7 +720,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),
|
||||
@@ -734,7 +742,7 @@ namespace Barotrauma.Networking
|
||||
GUINumberInput.NumberType.Int, textAlignment: Alignment.CenterLeft)
|
||||
{
|
||||
MinValueInt = 0,
|
||||
MaxValueInt = 100,
|
||||
MaxValueInt = MaxExtraCargoItemsOfType,
|
||||
IntValue = cargoVal
|
||||
};
|
||||
amountInput.OnValueChanged += (numberInput) =>
|
||||
@@ -742,16 +750,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
|
||||
//--------------------------------------------------------------------------------
|
||||
@@ -913,6 +931,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;
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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,7 +183,7 @@ 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; }
|
||||
@@ -191,7 +191,7 @@ namespace Barotrauma.Particles
|
||||
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);
|
||||
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);
|
||||
|
||||
@@ -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--)
|
||||
{
|
||||
@@ -257,11 +262,9 @@ namespace Barotrauma
|
||||
|
||||
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;
|
||||
|
||||
+68
-203
@@ -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,114 +189,11 @@ 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<CoroutineStatus> WaitForCampaignSetup()
|
||||
{
|
||||
GUI.SetCursorWaiting();
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
+6
-1
@@ -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
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
@@ -732,9 +732,7 @@ namespace Barotrauma
|
||||
if (!string.IsNullOrEmpty(subName))
|
||||
{
|
||||
DebugConsole.NewMessage($"Loading the predefined quick start sub \"{subName}\"", Color.White);
|
||||
selectedSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s =>
|
||||
s.Name.ToLower() == subName.ToLower());
|
||||
|
||||
selectedSub = SubmarineInfo.SavedSubmarines.FirstOrDefault(s => s.Name.ToLowerInvariant() == subName.ToLowerInvariant());
|
||||
if (selectedSub == null)
|
||||
{
|
||||
DebugConsole.NewMessage($"Cannot find a sub that matches the name \"{subName}\".", Color.Red);
|
||||
@@ -1055,17 +1053,23 @@ namespace Barotrauma
|
||||
|
||||
GUI.Draw(Cam, spriteBatch);
|
||||
|
||||
#if !UNSTABLE
|
||||
string versionString = "Barotrauma v" + GameMain.Version + " (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")";
|
||||
GUI.SmallFont.DrawString(spriteBatch, versionString, new Vector2(HUDLayoutSettings.Padding, GameMain.GraphicsHeight - GUI.SmallFont.MeasureString(versionString).Y - HUDLayoutSettings.Padding * 0.75f), Color.White * 0.7f);
|
||||
#endif
|
||||
|
||||
if (selectedTab != Tab.Credits)
|
||||
{
|
||||
#if !UNSTABLE
|
||||
string versionString = "Barotrauma v" + GameMain.Version + " (" + AssemblyInfo.BuildString + ", branch " + AssemblyInfo.GitBranch + ", revision " + AssemblyInfo.GitRevision + ")";
|
||||
GUI.SmallFont.DrawString(spriteBatch, versionString, new Vector2(HUDLayoutSettings.Padding, GameMain.GraphicsHeight - GUI.SmallFont.MeasureString(versionString).Y - HUDLayoutSettings.Padding * 0.75f), Color.White * 0.7f);
|
||||
#endif
|
||||
string gameAnalyticsStatus = TextManager.Get($"GameAnalyticsStatus.{GameAnalyticsManager.UserConsented}");
|
||||
Vector2 textSize = GUI.SmallFont.MeasureString(gameAnalyticsStatus).ToPoint().ToVector2();
|
||||
GUI.SmallFont.DrawString(spriteBatch, gameAnalyticsStatus, new Vector2(HUDLayoutSettings.Padding, GameMain.GraphicsHeight - GUI.SmallFont.LineHeight * 2 - HUDLayoutSettings.Padding * 0.75f), Color.White * 0.7f);
|
||||
|
||||
|
||||
Vector2 textPos = new Vector2(GameMain.GraphicsWidth - HUDLayoutSettings.Padding, GameMain.GraphicsHeight - HUDLayoutSettings.Padding * 0.75f);
|
||||
for (int i = legalCrap.Length - 1; i >= 0; i--)
|
||||
{
|
||||
Vector2 textSize = GUI.SmallFont.MeasureString(legalCrap[i]);
|
||||
textSize = new Vector2((int)textSize.X, (int)textSize.Y);
|
||||
textSize = GUI.SmallFont.MeasureString(legalCrap[i])
|
||||
.ToPoint().ToVector2();
|
||||
bool mouseOn = i == 0 &&
|
||||
PlayerInput.MousePosition.X > textPos.X - textSize.X && PlayerInput.MousePosition.X < textPos.X &&
|
||||
PlayerInput.MousePosition.Y > textPos.Y - textSize.Y && PlayerInput.MousePosition.Y < textPos.Y;
|
||||
@@ -1121,8 +1125,8 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Copying the file \"" + selectedSub.FilePath + "\" failed. The file may have been deleted or in use by another process. Try again or select another submarine.", e);
|
||||
GameAnalyticsManager.AddErrorEventOnce(
|
||||
"MainMenuScreen.StartGame:IOException" + selectedSub.Name,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
"Copying the file \"" + selectedSub.FilePath + "\" failed.\n" + e.Message + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Copying a submarine file failed. " + e.Message + "\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1446,7 +1450,7 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Fetching remote content to the main menu failed.", e);
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.FetchRemoteContent:Exception", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.FetchRemoteContent:Exception", GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Fetching remote content to the main menu failed. " + e.Message);
|
||||
return;
|
||||
}
|
||||
@@ -1489,7 +1493,7 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Reading received remote main menu content failed.", e);
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.WairForRemoteContentReceived:Exception", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.WairForRemoteContentReceived:Exception", GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Reading received remote main menu content failed. " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Collections.Generic;
|
||||
using Barotrauma.IO;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Steam;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -40,12 +41,6 @@ namespace Barotrauma
|
||||
|
||||
private readonly GUIScrollBar levelDifficultyScrollBar;
|
||||
|
||||
private readonly GUITickBox radiationEnabledTickBox;
|
||||
|
||||
private readonly GUIButton[] maxMissionCountButtons;
|
||||
private readonly GUITextBlock maxMissionCountText;
|
||||
private readonly GUITextBlock maxMissionCountDescription;
|
||||
|
||||
private readonly GUIButton[] traitorProbabilityButtons;
|
||||
private readonly GUITextBlock traitorProbabilityText;
|
||||
|
||||
@@ -192,6 +187,9 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyList<SubmarineInfo> GetSubList()
|
||||
=> SubList.Content.Children.Select(c => c.UserData as SubmarineInfo).ToArray();
|
||||
|
||||
public readonly GUIListBox PlayerList;
|
||||
|
||||
public GUITextBox CharacterNameBox
|
||||
@@ -1185,45 +1183,6 @@ namespace Barotrauma
|
||||
}
|
||||
};
|
||||
|
||||
if (MapGenerationParams.Instance.RadiationParams != null)
|
||||
{
|
||||
radiationEnabledTickBox = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.1f), settingsContent.RectTransform), TextManager.Get("CampaignOption.EnableRadiation"), font: GUI.Style.Font)
|
||||
{
|
||||
Selected = true,
|
||||
OnSelected = box =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, radiationEnabled: box.Selected);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var maxMissionCountSettingHolder = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.1f), settingsContent.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||
maxMissionCountDescription = new GUITextBlock(new RectTransform(new Vector2(0.7f, 0.0f), maxMissionCountSettingHolder.RectTransform), TextManager.Get("maxmissioncount", fallBackTag: "missions"), wrap: true)
|
||||
{
|
||||
ToolTip = TextManager.Get("maxmissioncounttooltip")
|
||||
};
|
||||
var maxMissionCountContainer = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1.0f), maxMissionCountSettingHolder.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft) { RelativeSpacing = 0.05f, Stretch = true };
|
||||
maxMissionCountButtons = new GUIButton[2];
|
||||
maxMissionCountButtons[0] = new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), maxMissionCountContainer.RectTransform), style: "GUIButtonToggleLeft")
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, maxMissionCount: -1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
maxMissionCountText = new GUITextBlock(new RectTransform(new Vector2(0.7f, 1.0f), maxMissionCountContainer.RectTransform), "0", textAlignment: Alignment.Center, style: "GUITextBox");
|
||||
maxMissionCountButtons[1] = new GUIButton(new RectTransform(new Vector2(0.15f, 1.0f), maxMissionCountContainer.RectTransform), style: "GUIButtonToggleRight")
|
||||
{
|
||||
OnClicked = (button, obj) =>
|
||||
{
|
||||
GameMain.Client.ServerSettings.ClientAdminWrite(ServerSettings.NetFlags.Misc, maxMissionCount: 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
maxMissionCountSettingHolder.Children.ForEach(c => c.ToolTip = maxMissionCountSettingHolder.ToolTip);
|
||||
|
||||
List<GUIComponent> settingsElements = settingsContent.Children.ToList();
|
||||
for (int i = 0; i < settingsElements.Count; i++)
|
||||
{
|
||||
@@ -1372,16 +1331,6 @@ namespace Barotrauma
|
||||
}
|
||||
SeedBox.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
|
||||
levelDifficultyScrollBar.Enabled = !CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
|
||||
if (radiationEnabledTickBox != null)
|
||||
{
|
||||
radiationEnabledTickBox.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
|
||||
}
|
||||
maxMissionCountDescription.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
|
||||
maxMissionCountText.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
|
||||
foreach (var button in maxMissionCountButtons)
|
||||
{
|
||||
button.Enabled = CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
|
||||
}
|
||||
|
||||
traitorProbabilityButtons[0].Enabled = traitorProbabilityButtons[1].Enabled = traitorProbabilityText.Enabled =
|
||||
!CampaignFrame.Visible && !CampaignSetupFrame.Visible && GameMain.Client.HasPermission(ClientPermissions.ManageSettings);
|
||||
@@ -2163,17 +2112,126 @@ namespace Barotrauma
|
||||
if (child != null) { PlayerList.RemoveChild(child); }
|
||||
}
|
||||
|
||||
private Client ExtractClientFromClickableArea(GUITextBlock.ClickableArea area)
|
||||
{
|
||||
if (!UInt64.TryParse(area.Data.Metadata, out UInt64 id)) { return null; }
|
||||
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id)
|
||||
?? GameMain.Client.ConnectedClients.Find(c => c.ID == id)
|
||||
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.SteamID == id)
|
||||
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.ID == id);
|
||||
return client;
|
||||
}
|
||||
|
||||
public void SelectPlayer(GUITextBlock component, GUITextBlock.ClickableArea area)
|
||||
{
|
||||
if (!UInt64.TryParse(area.Data.Metadata, out UInt64 id)) { return; }
|
||||
Client client = GameMain.Client.ConnectedClients.Find(c => c.SteamID == id)
|
||||
?? GameMain.Client.ConnectedClients.Find(c => c.ID == id)
|
||||
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.SteamID == id)
|
||||
?? GameMain.Client.PreviouslyConnectedClients.FirstOrDefault(c => c.ID == id);
|
||||
if (client == null) { return; }
|
||||
var client = ExtractClientFromClickableArea(area);
|
||||
if (client is null) { return; }
|
||||
GameMain.NetLobbyScreen.SelectPlayer(client);
|
||||
}
|
||||
|
||||
public void ShowPlayerContextMenu(GUITextBlock component, GUITextBlock.ClickableArea area)
|
||||
{
|
||||
var client = ExtractClientFromClickableArea(area);
|
||||
if (client is null) { return; }
|
||||
CreateModerationContextMenu(client);
|
||||
}
|
||||
|
||||
#region Context Menu
|
||||
public static void CreateModerationContextMenu(Client client)
|
||||
{
|
||||
if (GUIContextMenu.CurrentContextMenu != null) { return; }
|
||||
if (GameMain.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 bool SelectPlayer(Client selectedClient)
|
||||
{
|
||||
bool myClient = selectedClient.ID == GameMain.Client.ID;
|
||||
@@ -2763,7 +2821,8 @@ namespace Barotrauma
|
||||
msg.ClickableAreas.Add(new GUITextBlock.ClickableArea()
|
||||
{
|
||||
Data = data,
|
||||
OnClick = GameMain.NetLobbyScreen.SelectPlayer
|
||||
OnClick = GameMain.NetLobbyScreen.SelectPlayer,
|
||||
OnSecondaryClick = GameMain.NetLobbyScreen.ShowPlayerContextMenu
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -3221,6 +3280,7 @@ namespace Barotrauma
|
||||
{
|
||||
CreateSubPreview(submarine);
|
||||
}
|
||||
UpdateSubVisibility();
|
||||
}
|
||||
|
||||
private bool ViewJobInfo(GUIButton button, object obj)
|
||||
@@ -3369,14 +3429,28 @@ namespace Barotrauma
|
||||
return btn;
|
||||
}
|
||||
|
||||
public Pair<string, string> FailedSelectedSub;
|
||||
public Pair<string, string> FailedSelectedShuttle;
|
||||
public readonly struct FailedSubInfo
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly string Hash;
|
||||
public FailedSubInfo(string name, string hash) { Name = name; Hash = hash; }
|
||||
public void Deconstruct(out string name, out string hash) { name = Name; hash = Hash; }
|
||||
public static bool operator ==(FailedSubInfo a, FailedSubInfo b)
|
||||
=> a.Name.Equals(b.Name, StringComparison.OrdinalIgnoreCase)
|
||||
&& a.Hash.Equals(b.Hash, StringComparison.OrdinalIgnoreCase);
|
||||
public static bool operator !=(FailedSubInfo a, FailedSubInfo b)
|
||||
=> !(a == b);
|
||||
}
|
||||
|
||||
public List<Pair<string, string>> FailedCampaignSubs = new List<Pair<string, string>>();
|
||||
public List<Pair<string, string>> FailedOwnedSubs = new List<Pair<string, string>>();
|
||||
public FailedSubInfo? FailedSelectedSub;
|
||||
public FailedSubInfo? FailedSelectedShuttle;
|
||||
|
||||
public List<FailedSubInfo> FailedCampaignSubs = new List<FailedSubInfo>();
|
||||
public List<FailedSubInfo> FailedOwnedSubs = new List<FailedSubInfo>();
|
||||
|
||||
public bool TrySelectSub(string subName, string md5Hash, GUIListBox subList)
|
||||
{
|
||||
UpdateSubVisibility();
|
||||
if (GameMain.Client == null) { return false; }
|
||||
|
||||
//already downloading the selected sub file
|
||||
@@ -3441,9 +3515,13 @@ namespace Barotrauma
|
||||
//if we get to this point, a matching sub was not found or it has an incorrect MD5 hash
|
||||
|
||||
if (subList == SubList)
|
||||
FailedSelectedSub = new Pair<string, string>(subName, md5Hash);
|
||||
{
|
||||
FailedSelectedSub = new FailedSubInfo(subName, md5Hash);
|
||||
}
|
||||
else
|
||||
FailedSelectedShuttle = new Pair<string, string>(subName, md5Hash);
|
||||
{
|
||||
FailedSelectedShuttle = new FailedSubInfo(subName, md5Hash);
|
||||
}
|
||||
|
||||
string errorMsg = "";
|
||||
if (sub == null || !SubmarineInfo.SavedSubmarines.Contains(sub))
|
||||
@@ -3542,22 +3620,22 @@ namespace Barotrauma
|
||||
{
|
||||
UserData = "request" + serverSubmarine.Name
|
||||
};
|
||||
requestFileBox.Buttons[0].UserData = new string[] { serverSubmarine.Name, serverSubmarine.MD5Hash.Hash };
|
||||
requestFileBox.Buttons[0].UserData = new FailedSubInfo(serverSubmarine.Name, serverSubmarine.MD5Hash.Hash);
|
||||
requestFileBox.Buttons[0].OnClicked += requestFileBox.Close;
|
||||
requestFileBox.Buttons[0].OnClicked += (GUIButton button, object userdata) =>
|
||||
{
|
||||
string[] fileInfo = (string[])userdata;
|
||||
FailedSubInfo fileInfo = (FailedSubInfo)userdata;
|
||||
|
||||
if (deliveryData == "owned")
|
||||
if (deliveryData == "owned") //owned!!!!
|
||||
{
|
||||
FailedOwnedSubs.Add(new Pair<string, string>(fileInfo[0], fileInfo[1]));
|
||||
FailedOwnedSubs.Add(fileInfo);
|
||||
}
|
||||
else if (deliveryData == "campaign")
|
||||
{
|
||||
FailedCampaignSubs.Add(new Pair<string, string>(fileInfo[0], fileInfo[1]));
|
||||
FailedCampaignSubs.Add(fileInfo);
|
||||
}
|
||||
|
||||
GameMain.Client?.RequestFile(FileTransferType.Submarine, fileInfo[0], fileInfo[1]);
|
||||
GameMain.Client?.RequestFile(FileTransferType.Submarine, fileInfo.Name, fileInfo.Hash);
|
||||
return true;
|
||||
};
|
||||
requestFileBox.Buttons[1].OnClicked += requestFileBox.Close;
|
||||
@@ -3691,7 +3769,7 @@ namespace Barotrauma
|
||||
};
|
||||
|
||||
var subName = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), frameContent.RectTransform),
|
||||
text: sub.Name)
|
||||
text: sub.DisplayName)
|
||||
{
|
||||
CanBeFocused = false
|
||||
};
|
||||
@@ -3823,7 +3901,9 @@ namespace Barotrauma
|
||||
foreach (GUIComponent child in SubList.Content.Children)
|
||||
{
|
||||
if (!(child.UserData is SubmarineInfo sub)) { continue; }
|
||||
child.Visible = !GameMain.Client.ServerSettings.HiddenSubs.Contains(sub.Name)
|
||||
child.Visible =
|
||||
(!GameMain.Client.ServerSettings.HiddenSubs.Contains(sub.Name)
|
||||
|| (GameMain.GameSession?.SubmarineInfo != null && GameMain.GameSession.SubmarineInfo.Name.Equals(sub.Name, StringComparison.OrdinalIgnoreCase)))
|
||||
&& (string.IsNullOrEmpty(subSearchBox.Text) || sub.DisplayName.Contains(subSearchBox.Text, StringComparison.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2376,10 +2376,9 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMsg = "Failed to ping a server (" + ip + ") - " + (ex?.InnerException?.Message ?? ex.Message);
|
||||
GameAnalyticsManager.AddErrorEventOnce("ServerListScreen.PingServer:PingException" + ip, GameAnalyticsSDK.Net.EGAErrorSeverity.Warning, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("ServerListScreen.PingServer:PingException" + ip, GameAnalyticsManager.ErrorSeverity.Warning, "Failed to ping a server - " + (ex?.InnerException?.Message ?? ex.Message));
|
||||
#if DEBUG
|
||||
DebugConsole.NewMessage(errorMsg, Color.Red);
|
||||
DebugConsole.NewMessage("Failed to ping a server (" + ip + ") - " + (ex?.InnerException?.Message ?? ex.Message), Color.Red);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -824,9 +824,8 @@ namespace Barotrauma
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string errorMsg = "Failed to save workshop item preview image to \"" + previewImagePath + "\".";
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.OnItemPreviewDownloaded:WriteAllBytesFailed" + previewImagePath,
|
||||
GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg + "\n" + e.Message);
|
||||
GameAnalyticsManager.ErrorSeverity.Error, "Failed to save workshop item preview image.\n" + e.Message);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -1195,7 +1194,7 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Failed to edit workshop item (content package null)\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
DebugConsole.ThrowError(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.ShowCreateItemFrame:ContentPackageNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SteamWorkshopScreen.ShowCreateItemFrame:ContentPackageNull", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -358,7 +358,7 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
displayName = TextManager.Get(fallbackTag, true);
|
||||
displayName = TextManager.Get(fallbackTag, true) ?? TextManager.Get($"sp.{fallbackTag}.name", true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace Barotrauma.Sounds
|
||||
uint alSource = Sound.Owner.GetSourceFromIndex(Sound.SourcePoolIndex, ALSourceIndex);
|
||||
|
||||
float effectiveGain = gain;
|
||||
if (category != null) effectiveGain *= Sound.Owner.GetCategoryGainMultiplier(category);
|
||||
if (category != null) { effectiveGain *= Sound.Owner.GetCategoryGainMultiplier(category); }
|
||||
|
||||
Al.Sourcef(alSource, Al.Gain, effectiveGain);
|
||||
int alError = Al.GetError();
|
||||
|
||||
@@ -470,14 +470,14 @@ namespace Barotrauma
|
||||
{
|
||||
string errorMsg = "Failed to update water ambience volume - submarine's movement value invalid (" + movementSoundVolume + ", sub velocity: " + sub.Velocity + ")";
|
||||
DebugConsole.Log(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
movementSoundVolume = 0.0f;
|
||||
}
|
||||
if (!MathUtils.IsValid(insideSubFactor))
|
||||
{
|
||||
string errorMsg = "Failed to update water ambience volume - inside sub value invalid (" + insideSubFactor + ")";
|
||||
DebugConsole.Log(errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.UpdateWaterAmbience:InvalidVolume", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
insideSubFactor = 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -609,7 +609,7 @@ namespace Barotrauma
|
||||
flowSoundChannels[i] = FlowSounds[i].Play(1.0f, FlowSoundRange, soundPos);
|
||||
flowSoundChannels[i].Looping = true;
|
||||
}
|
||||
flowSoundChannels[i].Gain = Math.Max(flowVolumeRight[i], flowVolumeLeft[i]);
|
||||
flowSoundChannels[i].Gain = Math.Min(Math.Max(flowVolumeRight[i], flowVolumeLeft[i]), 1.0f);
|
||||
flowSoundChannels[i].Position = new Vector3(soundPos, 0.0f);
|
||||
}
|
||||
}
|
||||
@@ -790,7 +790,7 @@ namespace Barotrauma
|
||||
if (sound == null)
|
||||
{
|
||||
string errorMsg = "Error in SoundPlayer.PlaySound (sound was null)\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("SoundPlayer.PlaySound:SoundNull" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ namespace Barotrauma
|
||||
{
|
||||
float angle = 0.0f;
|
||||
float particleRotation = 0.0f;
|
||||
bool mirrorAngle = false;
|
||||
if (emitter.Prefab.Properties.CopyEntityAngle)
|
||||
{
|
||||
Limb targetLimb = null;
|
||||
@@ -71,7 +72,11 @@ namespace Barotrauma
|
||||
{
|
||||
angle = item.body.Rotation + ((item.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
particleRotation = -item.body.Rotation;
|
||||
if (item.body.Dir < 0.0f) { particleRotation += MathHelper.Pi; }
|
||||
if (item.body.Dir < 0.0f)
|
||||
{
|
||||
particleRotation += MathHelper.Pi;
|
||||
mirrorAngle = true;
|
||||
}
|
||||
}
|
||||
else if (entity is Character c && !c.Removed && targetLimbs?.FirstOrDefault(l => l != LimbType.None) is LimbType l)
|
||||
{
|
||||
@@ -85,11 +90,15 @@ namespace Barotrauma
|
||||
{
|
||||
angle = targetLimb.body.Rotation + ((targetLimb.body.Dir > 0.0f) ? 0.0f : MathHelper.Pi);
|
||||
particleRotation = -targetLimb.body.Rotation;
|
||||
if (targetLimb.body.Dir < 0.0f) { particleRotation += MathHelper.Pi; }
|
||||
if (targetLimb.body.Dir < 0.0f)
|
||||
{
|
||||
particleRotation += MathHelper.Pi;
|
||||
mirrorAngle = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
emitter.Emit(deltaTime, worldPosition, hull, angle: angle, particleRotation: particleRotation);
|
||||
emitter.Emit(deltaTime, worldPosition, hull, angle: angle, particleRotation: particleRotation, mirrorAngle: mirrorAngle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +117,7 @@ namespace Barotrauma
|
||||
if (sound?.Sound == null)
|
||||
{
|
||||
string errorMsg = $"Error in StatusEffect.ApplyProjSpecific1 (sound \"{sound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull1" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull1" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
soundChannel = SoundPlayer.PlaySound(sound.Sound, worldPosition, sound.Volume, sound.Range, hullGuess: hull, ignoreMuffling: sound.IgnoreMuffling);
|
||||
@@ -135,7 +144,7 @@ namespace Barotrauma
|
||||
if (selectedSound?.Sound == null)
|
||||
{
|
||||
string errorMsg = $"Error in StatusEffect.ApplyProjSpecific2 (sound \"{selectedSound?.Filename ?? "unknown"}\" was null)\n" + Environment.StackTrace.CleanupStackTrace();
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
|
||||
GameAnalyticsManager.AddErrorEventOnce("StatusEffect.ApplyProjSpecific:SoundNull2" + Environment.StackTrace.CleanupStackTrace(), GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||
return;
|
||||
}
|
||||
if (selectedSound.Sound.Disposed)
|
||||
|
||||
@@ -421,7 +421,7 @@ namespace Barotrauma
|
||||
#if DEBUG
|
||||
DebugConsole.ThrowError("Empty color array passed to the GradientLerp method.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
#endif
|
||||
GameAnalyticsManager.AddErrorEventOnce("ToolBox.GradientLerp:EmptyColorArray", GameAnalyticsSDK.Net.EGAErrorSeverity.Error,
|
||||
GameAnalyticsManager.AddErrorEventOnce("ToolBox.GradientLerp:EmptyColorArray", GameAnalyticsManager.ErrorSeverity.Error,
|
||||
"Empty color array passed to the GradientLerp method.\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return Color.Black;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user