Unstable 0.17.4.0
This commit is contained in:
@@ -39,7 +39,7 @@ namespace Barotrauma
|
|||||||
targetPos.Y = -targetPos.Y;
|
targetPos.Y = -targetPos.Y;
|
||||||
|
|
||||||
GUI.DrawLine(spriteBatch, pos, targetPos, GUIStyle.Red * 0.5f, 0, 4);
|
GUI.DrawLine(spriteBatch, pos, targetPos, GUIStyle.Red * 0.5f, 0, 4);
|
||||||
if (wallTarget != null)
|
if (wallTarget != null && !IsCoolDownRunning)
|
||||||
{
|
{
|
||||||
Vector2 wallTargetPos = wallTarget.Position;
|
Vector2 wallTargetPos = wallTarget.Position;
|
||||||
if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.Position; }
|
if (wallTarget.Structure.Submarine != null) { wallTargetPos += wallTarget.Structure.Submarine.Position; }
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
partial void InitProjSpecific(ContentXElement element)
|
partial void InitProjSpecific(ContentXElement element)
|
||||||
{
|
{
|
||||||
if (element.Attribute("sound") != null)
|
if (element.GetAttribute("sound") != null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error in attack ("+element+") - sounds should be defined as child elements, not as attributes.");
|
DebugConsole.ThrowError("Error in attack ("+element+") - sounds should be defined as child elements, not as attributes.");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ namespace Barotrauma
|
|||||||
case TreatmentEventData _:
|
case TreatmentEventData _:
|
||||||
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
msg.Write(AnimController.Anim == AnimController.Animation.CPR);
|
||||||
break;
|
break;
|
||||||
case StatusEventData _:
|
case CharacterStatusEventData _:
|
||||||
//do nothing
|
//do nothing
|
||||||
break;
|
break;
|
||||||
case UpdateTalentsEventData _:
|
case UpdateTalentsEventData _:
|
||||||
@@ -343,8 +343,12 @@ namespace Barotrauma
|
|||||||
if (controlled == this)
|
if (controlled == this)
|
||||||
{
|
{
|
||||||
Controlled = null;
|
Controlled = null;
|
||||||
IsRemotePlayer = ownerID > 0;
|
|
||||||
}
|
}
|
||||||
|
if (GameMain.Client?.Character == this)
|
||||||
|
{
|
||||||
|
GameMain.Client.Character = null;
|
||||||
|
}
|
||||||
|
IsRemotePlayer = ownerID > 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case EventType.Status:
|
case EventType.Status:
|
||||||
@@ -371,7 +375,9 @@ namespace Barotrauma
|
|||||||
if (attackLimbIndex == 255 || Removed) { break; }
|
if (attackLimbIndex == 255 || Removed) { break; }
|
||||||
if (attackLimbIndex >= AnimController.Limbs.Length)
|
if (attackLimbIndex >= AnimController.Limbs.Length)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})");
|
string errorMsg = $"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Limb index out of bounds (character: {Name}, limb index: {attackLimbIndex}, limb count: {AnimController.Limbs.Length})";
|
||||||
|
DebugConsole.ThrowError(errorMsg);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("Character.ClientEventRead:AttackLimbOutOfBounds", GameAnalyticsManager.ErrorSeverity.Error, errorMsg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
|
Limb attackLimb = AnimController.Limbs[attackLimbIndex];
|
||||||
@@ -380,13 +386,16 @@ namespace Barotrauma
|
|||||||
if (targetEntity == null && eventType == EventType.SetAttackTarget)
|
if (targetEntity == null && eventType == EventType.SetAttackTarget)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Received invalid SetAttackTarget message. Target entity not found (ID {targetEntityID})");
|
DebugConsole.ThrowError($"Received invalid SetAttackTarget message. Target entity not found (ID {targetEntityID})");
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("Character.ClientEventRead:TargetNotFound", GameAnalyticsManager.ErrorSeverity.Error, "Received invalid SetAttackTarget message. Target entity not found.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (targetEntity is Character targetCharacter)
|
if (targetEntity is Character targetCharacter && targetLimbIndex != 255)
|
||||||
{
|
{
|
||||||
if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
|
if (targetLimbIndex >= targetCharacter.AnimController.Limbs.Length)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
|
DebugConsole.ThrowError($"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Target limb index out of bounds (target character: {targetCharacter.Name}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})");
|
||||||
|
string errorMsgWithoutName = $"Received invalid {(eventType == EventType.SetAttackTarget ? "SetAttackTarget" : "ExecuteAttack")} message. Target limb index out of bounds (target character: {targetCharacter.SpeciesName}, limb index: {targetLimbIndex}, limb count: {targetCharacter.AnimController.Limbs.Length})";
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("Character.ClientEventRead:TargetLimbOutOfBounds", GameAnalyticsManager.ErrorSeverity.Error, errorMsgWithoutName);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
|
targetLimb = targetCharacter.AnimController.Limbs[targetLimbIndex];
|
||||||
@@ -560,6 +569,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
character.TeamID = (CharacterTeamType)teamID;
|
character.TeamID = (CharacterTeamType)teamID;
|
||||||
character.CampaignInteractionType = (CampaignMode.InteractionType)inc.ReadByte();
|
character.CampaignInteractionType = (CampaignMode.InteractionType)inc.ReadByte();
|
||||||
|
if (character.CampaignInteractionType == CampaignMode.InteractionType.Store)
|
||||||
|
{
|
||||||
|
character.MerchantIdentifier = inc.ReadIdentifier();
|
||||||
|
}
|
||||||
character.Wallet.Balance = balance;
|
character.Wallet.Balance = balance;
|
||||||
character.Wallet.RewardDistribution = rewardDistribution;
|
character.Wallet.RewardDistribution = rewardDistribution;
|
||||||
if (character.CampaignInteractionType != CampaignMode.InteractionType.None)
|
if (character.CampaignInteractionType != CampaignMode.InteractionType.None)
|
||||||
|
|||||||
@@ -400,7 +400,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (GameMain.Client != null)
|
if (GameMain.Client != null)
|
||||||
{
|
{
|
||||||
GameMain.Client.CreateEntityEvent(Character.Controlled, new Character.StatusEventData());
|
GameMain.Client.CreateEntityEvent(Character.Controlled, new Character.CharacterStatusEventData());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+15
-7
@@ -12,22 +12,30 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
public sealed partial class PackageSource : ICollection<ContentPackage>
|
public sealed partial class PackageSource : ICollection<ContentPackage>
|
||||||
{
|
{
|
||||||
public ContentPackage SaveAndEnableRegularMod(ModProject modProject)
|
public string SaveRegularMod(ModProject modProject)
|
||||||
{
|
{
|
||||||
if (modProject.IsCore) { throw new ArgumentException("ModProject must not be a core package"); }
|
if (modProject.IsCore) { throw new ArgumentException("ModProject must not be a core package"); }
|
||||||
|
|
||||||
//save the content package
|
|
||||||
string fileListPath = Path.Combine(directory, ToolBox.RemoveInvalidFileNameChars(modProject.Name), ContentPackage.FileListFileName)
|
string fileListPath = Path.Combine(directory, ToolBox.RemoveInvalidFileNameChars(modProject.Name), ContentPackage.FileListFileName)
|
||||||
.CleanUpPathCrossPlatform(correctFilenameCase: false);
|
.CleanUpPathCrossPlatform(correctFilenameCase: false);
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(fileListPath)!);
|
|
||||||
modProject.Save(fileListPath);
|
modProject.Save(fileListPath);
|
||||||
Refresh(); EnabledPackages.DisableRemovedMods();
|
Refresh(); EnabledPackages.DisableRemovedMods();
|
||||||
var newPackage = Regular.First(p => p.Path == fileListPath);
|
|
||||||
|
|
||||||
//enable it
|
return fileListPath;
|
||||||
EnabledPackages.EnableRegular(newPackage);
|
}
|
||||||
|
|
||||||
return newPackage;
|
public RegularPackage GetRegularModByPath(string fileListPath)
|
||||||
|
{
|
||||||
|
return Regular.First(p => p.Path == fileListPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegularPackage SaveAndEnableRegularMod(ModProject modProject)
|
||||||
|
{
|
||||||
|
string fileListPath = SaveRegularMod(modProject);
|
||||||
|
var package = GetRegularModByPath(fileListPath);
|
||||||
|
EnabledPackages.EnableRegular(package);
|
||||||
|
|
||||||
|
return package;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1454,9 +1454,9 @@ namespace Barotrauma
|
|||||||
// omega nesting incoming
|
// omega nesting incoming
|
||||||
if (fabricationRecipe != null)
|
if (fabricationRecipe != null)
|
||||||
{
|
{
|
||||||
foreach (KeyValuePair<Identifier, PriceInfo> itemLocationPrice in itemPrefab.GetSellPricesOver(0))
|
foreach (var priceInfo in itemPrefab.GetSellPricesOver(0))
|
||||||
{
|
{
|
||||||
NewMessage(" If bought at " + itemLocationPrice.Key + " it costs " + itemLocationPrice.Value.Price);
|
NewMessage($" If bought at {GetSeller(priceInfo.Value)} it costs {priceInfo.Value.Price}");
|
||||||
int totalPrice = 0;
|
int totalPrice = 0;
|
||||||
int? totalBestPrice = 0;
|
int? totalBestPrice = 0;
|
||||||
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
foreach (var ingredient in fabricationRecipe.RequiredItems)
|
||||||
@@ -1464,31 +1464,33 @@ namespace Barotrauma
|
|||||||
foreach (ItemPrefab ingredientItemPrefab in ingredient.ItemPrefabs)
|
foreach (ItemPrefab ingredientItemPrefab in ingredient.ItemPrefabs)
|
||||||
{
|
{
|
||||||
int defaultPrice = ingredientItemPrefab.DefaultPrice?.Price ?? 0;
|
int defaultPrice = ingredientItemPrefab.DefaultPrice?.Price ?? 0;
|
||||||
NewMessage(" Its ingredient " + ingredientItemPrefab.Name + " has base cost " + defaultPrice);
|
NewMessage($" Its ingredient {ingredientItemPrefab.Name} has base cost {defaultPrice}");
|
||||||
totalPrice += defaultPrice;
|
totalPrice += defaultPrice;
|
||||||
totalBestPrice += ingredientItemPrefab.GetMinPrice();
|
totalBestPrice += ingredientItemPrefab.GetMinPrice();
|
||||||
int basePrice = defaultPrice;
|
int basePrice = defaultPrice;
|
||||||
foreach (KeyValuePair<Identifier, PriceInfo> ingredientItemLocationPrice in ingredientItemPrefab.GetBuyPricesUnder())
|
foreach (var ingredientItemPriceInfo in ingredientItemPrefab.GetBuyPricesUnder())
|
||||||
{
|
{
|
||||||
if (basePrice > ingredientItemLocationPrice.Value.Price)
|
if (basePrice > ingredientItemPriceInfo.Value.Price)
|
||||||
{
|
{
|
||||||
NewMessage(" Location " + ingredientItemLocationPrice.Key + " sells ingredient " + ingredientItemPrefab.Name + " for cheaper, " + ingredientItemLocationPrice.Value.Price, Color.Yellow);
|
NewMessage($" {GetSeller(ingredientItemPriceInfo.Value).CapitaliseFirstInvariant()} sells ingredient {ingredientItemPrefab.Name} for cheaper, {ingredientItemPriceInfo.Value.Price}", Color.Yellow);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
NewMessage(" Location " + ingredientItemLocationPrice.Key + " sells ingredient " + ingredientItemPrefab.Name + " for more, " + ingredientItemLocationPrice.Value.Price, Color.Teal);
|
NewMessage($" {GetSeller(ingredientItemPriceInfo.Value).CapitaliseFirstInvariant()} sells ingredient {ingredientItemPrefab.Name} for more, {ingredientItemPriceInfo.Value.Price}", Color.Teal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int costDifference = itemPrefab.DefaultPrice.Price - totalPrice;
|
int costDifference = itemPrefab.DefaultPrice.Price - totalPrice;
|
||||||
NewMessage(" Constructing the item from store-bought items provides " + costDifference + " profit with default values.");
|
NewMessage($" Constructing the item from store-bought items provides {costDifference} profit with default values.");
|
||||||
|
|
||||||
if (totalBestPrice.HasValue)
|
if (totalBestPrice.HasValue)
|
||||||
{
|
{
|
||||||
int? bestDifference = itemLocationPrice.Value.Price - totalBestPrice;
|
int? bestDifference = priceInfo.Value.Price - totalBestPrice;
|
||||||
NewMessage(" Constructing the item from store-bought items provides " + bestDifference + " profit with best-case scenario values.");
|
NewMessage($" Constructing the item from store-bought items provides {bestDifference} profit with best-case scenario values.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static string GetSeller(PriceInfo priceInfo) => $"store with identifier \"{priceInfo.StoreIdentifier}\"";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1763,7 +1765,7 @@ namespace Barotrauma
|
|||||||
//check missing mission texts
|
//check missing mission texts
|
||||||
foreach (var missionPrefab in MissionPrefab.Prefabs)
|
foreach (var missionPrefab in MissionPrefab.Prefabs)
|
||||||
{
|
{
|
||||||
Identifier missionId = (missionPrefab.ConfigElement.Attribute("textidentifier") == null ? missionPrefab.Identifier : missionPrefab.ConfigElement.GetAttributeIdentifier("textidentifier", Identifier.Empty));
|
Identifier missionId = (missionPrefab.ConfigElement.GetAttribute("textidentifier") == null ? missionPrefab.Identifier : missionPrefab.ConfigElement.GetAttributeIdentifier("textidentifier", Identifier.Empty));
|
||||||
addIfMissing($"missionname.{missionId}".ToIdentifier(), language);
|
addIfMissing($"missionname.{missionId}".ToIdentifier(), language);
|
||||||
addIfMissing($"missiondescription.{missionId}".ToIdentifier(), language);
|
addIfMissing($"missiondescription.{missionId}".ToIdentifier(), language);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ namespace Barotrauma
|
|||||||
UISprite newSprite = new UISprite(subElement);
|
UISprite newSprite = new UISprite(subElement);
|
||||||
|
|
||||||
GUIComponent.ComponentState spriteState = GUIComponent.ComponentState.None;
|
GUIComponent.ComponentState spriteState = GUIComponent.ComponentState.None;
|
||||||
if (subElement.Attribute("state") != null)
|
if (subElement.GetAttribute("state") != null)
|
||||||
{
|
{
|
||||||
string stateStr = subElement.GetAttributeString("state", "None");
|
string stateStr = subElement.GetAttributeString("state", "None");
|
||||||
Enum.TryParse(stateStr, out spriteState);
|
Enum.TryParse(stateStr, out spriteState);
|
||||||
|
|||||||
@@ -172,7 +172,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
AutoScaleVertical = true,
|
AutoScaleVertical = true,
|
||||||
TextScale = 1.1f,
|
TextScale = 1.1f,
|
||||||
TextGetter = () => FormatCurrency(campaign.Wallet.Balance)
|
TextGetter = () => TextManager.FormatCurrency(campaign.Wallet.Balance)
|
||||||
};
|
};
|
||||||
|
|
||||||
var pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
|
var pendingAndCrewGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), anchor: Anchor.Center,
|
||||||
@@ -400,7 +400,7 @@ namespace Barotrauma
|
|||||||
if (listBox != crewList)
|
if (listBox != crewList)
|
||||||
{
|
{
|
||||||
new GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform),
|
new GUITextBlock(new RectTransform(new Vector2(width, 1.0f), mainGroup.RectTransform),
|
||||||
FormatCurrency(characterInfo.Salary),
|
TextManager.FormatCurrency(characterInfo.Salary),
|
||||||
textAlignment: Alignment.Center)
|
textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
@@ -629,7 +629,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
total += ((InfoSkill)c.UserData).CharacterInfo.Salary;
|
total += ((InfoSkill)c.UserData).CharacterInfo.Salary;
|
||||||
});
|
});
|
||||||
totalBlock.Text = FormatCurrency(total);
|
totalBlock.Text = TextManager.FormatCurrency(total);
|
||||||
bool enoughMoney = campaign == null || campaign.Wallet.CanAfford(total);
|
bool enoughMoney = campaign == null || campaign.Wallet.CanAfford(total);
|
||||||
totalBlock.TextColor = enoughMoney ? Color.White : Color.Red;
|
totalBlock.TextColor = enoughMoney ? Color.White : Color.Red;
|
||||||
validateHiresButton.Enabled = enoughMoney && pendingList.Content.RectTransform.Children.Any();
|
validateHiresButton.Enabled = enoughMoney && pendingList.Content.RectTransform.Children.Any();
|
||||||
@@ -925,7 +925,5 @@ namespace Barotrauma
|
|||||||
GameMain.Client.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
GameMain.Client.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalizedString FormatCurrency(int currency) => TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", currency));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public IEnumerable<T> GetAllChildren<T>() where T : GUIComponent
|
public IEnumerable<T> GetAllChildren<T>() where T : GUIComponent
|
||||||
{
|
{
|
||||||
return GetAllChildren().Where(c => c is T).Select(c => c as T);
|
return GetAllChildren().OfType<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -67,7 +67,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
foreach (GUIComponent child in Children)
|
foreach (GUIComponent child in Children)
|
||||||
{
|
{
|
||||||
if (child.UserData == obj || (child.UserData != null && child.UserData.Equals(obj))) { return child; }
|
if (Equals(child.UserData, obj)) { return child; }
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -108,7 +108,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
public GUIComponent FindChild(object userData, bool recursive = false)
|
public GUIComponent FindChild(object userData, bool recursive = false)
|
||||||
{
|
{
|
||||||
var matchingChild = Children.FirstOrDefault(c => c.UserData == userData);
|
var matchingChild = Children.FirstOrDefault(c => Equals(c.UserData, userData));
|
||||||
if (recursive && matchingChild == null)
|
if (recursive && matchingChild == null)
|
||||||
{
|
{
|
||||||
foreach (GUIComponent child in Children)
|
foreach (GUIComponent child in Children)
|
||||||
@@ -123,7 +123,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public IEnumerable<GUIComponent> FindChildren(object userData)
|
public IEnumerable<GUIComponent> FindChildren(object userData)
|
||||||
{
|
{
|
||||||
return Children.Where(c => c.UserData == userData);
|
return Children.Where(c => Equals(c.UserData, userData));
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<GUIComponent> FindChildren(Func<GUIComponent, bool> predicate)
|
public IEnumerable<GUIComponent> FindChildren(Func<GUIComponent, bool> predicate)
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ namespace Barotrauma
|
|||||||
public LocalizedString Tooltip;
|
public LocalizedString Tooltip;
|
||||||
|
|
||||||
|
|
||||||
public ContextMenuOption(string labelTag, bool isEnabled, Action onSelected)
|
public ContextMenuOption(string label, bool isEnabled, Action onSelected)
|
||||||
: this(TextManager.Get(labelTag), isEnabled, onSelected) { }
|
: this(TextManager.Get(label).Fallback(label), isEnabled, onSelected) { }
|
||||||
|
|
||||||
public ContextMenuOption(Identifier labelTag, bool isEnabled, Action onSelected)
|
public ContextMenuOption(Identifier labelTag, bool isEnabled, Action onSelected)
|
||||||
: this(TextManager.Get(labelTag), isEnabled, onSelected) { }
|
: this(TextManager.Get(labelTag), isEnabled, onSelected) { }
|
||||||
|
|||||||
@@ -314,13 +314,12 @@ namespace Barotrauma
|
|||||||
foreach (GUIComponent child in ListBox.Content.Children)
|
foreach (GUIComponent child in ListBox.Content.Children)
|
||||||
{
|
{
|
||||||
var tickBox = child.GetChild<GUITickBox>();
|
var tickBox = child.GetChild<GUITickBox>();
|
||||||
if (obj == child.UserData) { tickBox.Selected = true; }
|
if (Equals(obj, child.UserData)) { tickBox.Selected = true; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GUITextBlock textBlock = component as GUITextBlock;
|
if (!(component is GUITextBlock textBlock))
|
||||||
if (textBlock == null)
|
|
||||||
{
|
{
|
||||||
textBlock = component.GetChild<GUITextBlock>();
|
textBlock = component.GetChild<GUITextBlock>();
|
||||||
if (textBlock is null && !AllowNonText) { return false; }
|
if (textBlock is null && !AllowNonText) { return false; }
|
||||||
|
|||||||
@@ -96,15 +96,11 @@ namespace Barotrauma
|
|||||||
switch (child.ScaleBasis)
|
switch (child.ScaleBasis)
|
||||||
{
|
{
|
||||||
case ScaleBasis.BothHeight:
|
case ScaleBasis.BothHeight:
|
||||||
child.MinSize = new Point(child.Rect.Height, child.MinSize.Y);
|
|
||||||
break;
|
|
||||||
case ScaleBasis.Smallest when Rect.Height <= Rect.Width:
|
case ScaleBasis.Smallest when Rect.Height <= Rect.Width:
|
||||||
case ScaleBasis.Largest when Rect.Height > Rect.Width:
|
case ScaleBasis.Largest when Rect.Height > Rect.Width:
|
||||||
child.MinSize = new Point((int)((child.Rect.Height * child.RelativeSize.X) / child.RelativeSize.Y), child.MinSize.Y);
|
child.MinSize = new Point((int)((child.Rect.Height * child.RelativeSize.X) / child.RelativeSize.Y), child.MinSize.Y);
|
||||||
break;
|
break;
|
||||||
case ScaleBasis.BothWidth:
|
case ScaleBasis.BothWidth:
|
||||||
child.MinSize = new Point(child.MinSize.X, child.Rect.Width);
|
|
||||||
break;
|
|
||||||
case ScaleBasis.Smallest when Rect.Width <= Rect.Height:
|
case ScaleBasis.Smallest when Rect.Width <= Rect.Height:
|
||||||
case ScaleBasis.Largest when Rect.Width > Rect.Height:
|
case ScaleBasis.Largest when Rect.Width > Rect.Height:
|
||||||
child.MinSize = new Point(child.MinSize.X, (int)((child.Rect.Width * child.RelativeSize.Y) / child.RelativeSize.X));
|
child.MinSize = new Point(child.MinSize.X, (int)((child.Rect.Width * child.RelativeSize.Y) / child.RelativeSize.X));
|
||||||
|
|||||||
@@ -402,8 +402,7 @@ namespace Barotrauma
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (GUIComponent child in children)
|
foreach (GUIComponent child in children)
|
||||||
{
|
{
|
||||||
if ((child.UserData != null && child.UserData.Equals(userData)) ||
|
if (Equals(child.UserData, userData))
|
||||||
(child.UserData == null && userData == null))
|
|
||||||
{
|
{
|
||||||
Select(i, force, autoScroll);
|
Select(i, force, autoScroll);
|
||||||
if (!SelectMultiple) { return; }
|
if (!SelectMultiple) { return; }
|
||||||
@@ -1219,6 +1218,20 @@ namespace Barotrauma
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isDraggingElement && CurrentDragMode == DragMode.DragOutsideBox && HideDraggedElement)
|
||||||
|
{
|
||||||
|
Rectangle drawRect = DraggedElement.Rect;
|
||||||
|
int draggedElementIndex = Content.GetChildIndex(DraggedElement);
|
||||||
|
CalculateChildrenOffsets((index, point) =>
|
||||||
|
{
|
||||||
|
if (draggedElementIndex == index)
|
||||||
|
{
|
||||||
|
drawRect.Location = Content.Rect.Location + point;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
GUI.DrawRectangle(spriteBatch, drawRect, Color.White * 0.5f, thickness: 2f);
|
||||||
|
}
|
||||||
|
|
||||||
if (HideChildrenOutsideFrame)
|
if (HideChildrenOutsideFrame)
|
||||||
{
|
{
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ namespace Barotrauma
|
|||||||
LoadFont();
|
LoadFont();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadFont()
|
public void LoadFont()
|
||||||
{
|
{
|
||||||
string fontPath = GetFontFilePath(element);
|
string fontPath = GetFontFilePath(element);
|
||||||
uint size = GetFontSize(element);
|
uint size = GetFontSize(element);
|
||||||
|
|||||||
@@ -268,7 +268,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
int totalCost = medicalClinic.GetTotalCost();
|
int totalCost = medicalClinic.GetTotalCost();
|
||||||
healList.PriceBlock.Text = UpgradeStore.FormatCurrency(totalCost);
|
healList.PriceBlock.Text = TextManager.FormatCurrency(totalCost);
|
||||||
healList.PriceBlock.TextColor = GUIStyle.Red;
|
healList.PriceBlock.TextColor = GUIStyle.Red;
|
||||||
healList.HealButton.Enabled = false;
|
healList.HealButton.Enabled = false;
|
||||||
if (medicalClinic.GetWallet().CanAfford(totalCost))
|
if (medicalClinic.GetWallet().CanAfford(totalCost))
|
||||||
@@ -288,7 +288,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (element.FindAfflictionElement(affliction) is { } existingAffliction)
|
if (element.FindAfflictionElement(affliction) is { } existingAffliction)
|
||||||
{
|
{
|
||||||
existingAffliction.Price.Text = UpgradeStore.FormatCurrency(affliction.Strength);
|
existingAffliction.Price.Text = TextManager.FormatCurrency(affliction.Strength);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,7 +467,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GUITextBlock moneyLabel = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), balanceLayout.RectTransform), string.Empty, textAlignment: Alignment.TopRight, font: GUIStyle.SubHeadingFont)
|
GUITextBlock moneyLabel = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), balanceLayout.RectTransform), string.Empty, textAlignment: Alignment.TopRight, font: GUIStyle.SubHeadingFont)
|
||||||
{
|
{
|
||||||
TextGetter = () => UpgradeStore.FormatCurrency(medicalClinic.GetWallet().Balance),
|
TextGetter = () => TextManager.FormatCurrency(medicalClinic.GetWallet().Balance),
|
||||||
AutoScaleVertical = true,
|
AutoScaleVertical = true,
|
||||||
TextScale = 1.1f
|
TextScale = 1.1f
|
||||||
};
|
};
|
||||||
@@ -571,7 +571,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
GUILayoutGroup priceLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), footerLayout.RectTransform), isHorizontal: true);
|
GUILayoutGroup priceLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), footerLayout.RectTransform), isHorizontal: true);
|
||||||
GUITextBlock priceLabelBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), priceLayout.RectTransform), TextManager.Get("campaignstore.total"));
|
GUITextBlock priceLabelBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), priceLayout.RectTransform), TextManager.Get("campaignstore.total"));
|
||||||
GUITextBlock priceBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), priceLayout.RectTransform), UpgradeStore.FormatCurrency(medicalClinic.GetTotalCost()), font: GUIStyle.SubHeadingFont,
|
GUITextBlock priceBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), priceLayout.RectTransform), TextManager.FormatCurrency(medicalClinic.GetTotalCost()), font: GUIStyle.SubHeadingFont,
|
||||||
textAlignment: Alignment.Right);
|
textAlignment: Alignment.Right);
|
||||||
|
|
||||||
GUILayoutGroup buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), footerLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterRight);
|
GUILayoutGroup buttonLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), footerLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterRight);
|
||||||
@@ -684,7 +684,7 @@ namespace Barotrauma
|
|||||||
GUIFrame textContainer = new GUIFrame(new RectTransform(new Vector2(0.6f, 1f), textLayout.RectTransform), style: null);
|
GUIFrame textContainer = new GUIFrame(new RectTransform(new Vector2(0.6f, 1f), textLayout.RectTransform), style: null);
|
||||||
GUITextBlock afflictionName = new GUITextBlock(new RectTransform(Vector2.One, textContainer.RectTransform), name, font: GUIStyle.SubHeadingFont);
|
GUITextBlock afflictionName = new GUITextBlock(new RectTransform(Vector2.One, textContainer.RectTransform), name, font: GUIStyle.SubHeadingFont);
|
||||||
|
|
||||||
GUITextBlock healCost = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), textLayout.RectTransform), UpgradeStore.FormatCurrency(affliction.Price), textAlignment: Alignment.Center, font: GUIStyle.LargeFont)
|
GUITextBlock healCost = new GUITextBlock(new RectTransform(new Vector2(0.2f, 1f), textLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), textAlignment: Alignment.Center, font: GUIStyle.LargeFont)
|
||||||
{
|
{
|
||||||
Padding = Vector4.Zero
|
Padding = Vector4.Zero
|
||||||
};
|
};
|
||||||
@@ -876,7 +876,7 @@ namespace Barotrauma
|
|||||||
ToolTip = prefab.Description
|
ToolTip = prefab.Description
|
||||||
};
|
};
|
||||||
|
|
||||||
GUITextBlock priceBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), bottomTextLayout.RectTransform), UpgradeStore.FormatCurrency(affliction.Price), font: GUIStyle.LargeFont);
|
GUITextBlock priceBlock = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), bottomTextLayout.RectTransform), TextManager.FormatCurrency(affliction.Price), font: GUIStyle.LargeFont);
|
||||||
|
|
||||||
GUIButton buyButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.75f), bottomLayout.RectTransform), style: "CrewManagementAddButton");
|
GUIButton buyButton = new GUIButton(new RectTransform(new Vector2(0.2f, 0.75f), bottomLayout.RectTransform), style: "CrewManagementAddButton");
|
||||||
|
|
||||||
@@ -931,7 +931,7 @@ namespace Barotrauma
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void EnsureTextDoesntOverflow(string? text, GUITextBlock textBlock, Rectangle bounds, ImmutableArray<GUILayoutGroup>? layoutGroups = null)
|
public static void EnsureTextDoesntOverflow(string? text, GUITextBlock textBlock, Rectangle bounds, ImmutableArray<GUILayoutGroup>? layoutGroups = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(text)) { return; }
|
if (string.IsNullOrWhiteSpace(text)) { return; }
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace Barotrauma
|
|||||||
private bool suppressBuySell;
|
private bool suppressBuySell;
|
||||||
private int buyTotal, sellTotal, sellFromSubTotal;
|
private int buyTotal, sellTotal, sellFromSubTotal;
|
||||||
|
|
||||||
|
private GUITextBlock storeNameBlock;
|
||||||
private GUITextBlock merchantBalanceBlock;
|
private GUITextBlock merchantBalanceBlock;
|
||||||
private GUITextBlock currentSellValueBlock, newSellValueBlock;
|
private GUITextBlock currentSellValueBlock, newSellValueBlock;
|
||||||
private GUIImage sellValueChangeArrow;
|
private GUIImage sellValueChangeArrow;
|
||||||
@@ -65,6 +66,7 @@ namespace Barotrauma
|
|||||||
private Point resolutionWhenCreated;
|
private Point resolutionWhenCreated;
|
||||||
|
|
||||||
private Dictionary<ItemPrefab, ItemQuantity> OwnedItems { get; } = new Dictionary<ItemPrefab, ItemQuantity>();
|
private Dictionary<ItemPrefab, ItemQuantity> OwnedItems { get; } = new Dictionary<ItemPrefab, ItemQuantity>();
|
||||||
|
private Location.StoreInfo ActiveStore { get; set; }
|
||||||
|
|
||||||
private CargoManager CargoManager => campaignUI.Campaign.CargoManager;
|
private CargoManager CargoManager => campaignUI.Campaign.CargoManager;
|
||||||
private Location CurrentLocation => campaignUI.Campaign.Map?.CurrentLocation;
|
private Location CurrentLocation => campaignUI.Campaign.Map?.CurrentLocation;
|
||||||
@@ -238,6 +240,39 @@ namespace Barotrauma
|
|||||||
campaignUI.Campaign.CargoManager.OnItemsInSellFromSubCrateChanged += () => { needsSellingFromSubRefresh = true; };
|
campaignUI.Campaign.CargoManager.OnItemsInSellFromSubCrateChanged += () => { needsSellingFromSubRefresh = true; };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void SelectStore(Identifier identifier)
|
||||||
|
{
|
||||||
|
if (CurrentLocation?.Stores != null)
|
||||||
|
{
|
||||||
|
if (CurrentLocation.GetStore(identifier) is { } store)
|
||||||
|
{
|
||||||
|
ActiveStore = store;
|
||||||
|
if (storeNameBlock != null)
|
||||||
|
{
|
||||||
|
var storeName = TextManager.Get($"storename.{store.Identifier}");
|
||||||
|
if (storeName.IsNullOrEmpty())
|
||||||
|
{
|
||||||
|
storeName = TextManager.Get("store");
|
||||||
|
}
|
||||||
|
storeNameBlock.SetRichText(storeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ActiveStore = null;
|
||||||
|
string msg = $"Error selecting store with identifier \"{identifier}\" at {CurrentLocation}: store with the identifier doesn't exist at the location.";
|
||||||
|
DebugConsole.ShowError(msg);
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("Store.SelectStore:StoreDoesntExist", GameAnalyticsManager.ErrorSeverity.Error, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ActiveStore = null;
|
||||||
|
}
|
||||||
|
RefreshItemsToSell();
|
||||||
|
Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
public void Refresh(bool updateOwned = true)
|
public void Refresh(bool updateOwned = true)
|
||||||
{
|
{
|
||||||
UpdatePermissions();
|
UpdatePermissions();
|
||||||
@@ -321,7 +356,7 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
var imageWidth = (float)headerGroup.Rect.Height / headerGroup.Rect.Width;
|
var imageWidth = (float)headerGroup.Rect.Height / headerGroup.Rect.Width;
|
||||||
new GUIImage(new RectTransform(new Vector2(imageWidth, 1.0f), headerGroup.RectTransform), "StoreTradingIcon");
|
new GUIImage(new RectTransform(new Vector2(imageWidth, 1.0f), headerGroup.RectTransform), "StoreTradingIcon");
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f - imageWidth, 1.0f), headerGroup.RectTransform), TextManager.Get("store"), font: GUIStyle.LargeFont)
|
storeNameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f - imageWidth, 1.0f), headerGroup.RectTransform), TextManager.Get("store"), font: GUIStyle.LargeFont)
|
||||||
{
|
{
|
||||||
CanBeFocused = false,
|
CanBeFocused = false,
|
||||||
ForceUpperCase = ForceUpperCase.Yes
|
ForceUpperCase = ForceUpperCase.Yes
|
||||||
@@ -350,7 +385,7 @@ namespace Barotrauma
|
|||||||
TextScale = 1.1f,
|
TextScale = 1.1f,
|
||||||
TextGetter = () =>
|
TextGetter = () =>
|
||||||
{
|
{
|
||||||
merchantBalanceBlock.TextColor = CurrentLocation?.BalanceColor ?? Color.Red;
|
merchantBalanceBlock.TextColor = ActiveStore?.BalanceColor ?? Color.Red;
|
||||||
return GetMerchantBalanceText();
|
return GetMerchantBalanceText();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -388,17 +423,17 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
int balanceAfterTransaction = activeTab switch
|
int balanceAfterTransaction = activeTab switch
|
||||||
{
|
{
|
||||||
StoreTab.Buy => CurrentLocation.StoreCurrentBalance + buyTotal,
|
StoreTab.Buy => ActiveStore.Balance + buyTotal,
|
||||||
StoreTab.Sell => CurrentLocation.StoreCurrentBalance - sellTotal,
|
StoreTab.Sell => ActiveStore.Balance - sellTotal,
|
||||||
StoreTab.SellSub => CurrentLocation.StoreCurrentBalance - sellFromSubTotal,
|
StoreTab.SellSub => ActiveStore.Balance - sellFromSubTotal,
|
||||||
_ => throw new NotImplementedException(),
|
_ => throw new NotImplementedException(),
|
||||||
};
|
};
|
||||||
if (balanceAfterTransaction != CurrentLocation.StoreCurrentBalance)
|
if (balanceAfterTransaction != ActiveStore.Balance)
|
||||||
{
|
{
|
||||||
var newStatus = CurrentLocation.GetStoreBalanceStatus(balanceAfterTransaction);
|
var newStatus = CurrentLocation.GetStoreBalanceStatus(balanceAfterTransaction);
|
||||||
if (CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier != newStatus.SellPriceModifier)
|
if (ActiveStore.ActiveBalanceStatus.SellPriceModifier != newStatus.SellPriceModifier)
|
||||||
{
|
{
|
||||||
string tooltipTag = newStatus.SellPriceModifier > CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier ?
|
string tooltipTag = newStatus.SellPriceModifier > ActiveStore.ActiveBalanceStatus.SellPriceModifier ?
|
||||||
"campaingstore.valueincreasetooltip" : "campaingstore.valuedecreasetooltip";
|
"campaingstore.valueincreasetooltip" : "campaingstore.valuedecreasetooltip";
|
||||||
sellValueContainer.ToolTip = TextManager.Get(tooltipTag);
|
sellValueContainer.ToolTip = TextManager.Get(tooltipTag);
|
||||||
currentSellValueBlock.TextColor = newStatus.Color;
|
currentSellValueBlock.TextColor = newStatus.Color;
|
||||||
@@ -406,14 +441,14 @@ namespace Barotrauma
|
|||||||
sellValueChangeArrow.Visible = true;
|
sellValueChangeArrow.Visible = true;
|
||||||
newSellValueBlock.TextColor = newStatus.Color;
|
newSellValueBlock.TextColor = newStatus.Color;
|
||||||
newSellValueBlock.Text = $"{(newStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
newSellValueBlock.Text = $"{(newStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||||
return $"{(CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
return $"{(ActiveStore.ActiveBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sellValueContainer.ToolTip = TextManager.Get("campaignstore.sellvaluetooltip");
|
sellValueContainer.ToolTip = TextManager.Get("campaignstore.sellvaluetooltip");
|
||||||
currentSellValueBlock.TextColor = CurrentLocation.BalanceColor;
|
currentSellValueBlock.TextColor = ActiveStore.BalanceColor;
|
||||||
sellValueChangeArrow.Visible = false;
|
sellValueChangeArrow.Visible = false;
|
||||||
newSellValueBlock.Text = null;
|
newSellValueBlock.Text = null;
|
||||||
return $"{(CurrentLocation.ActiveStoreBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
return $"{(ActiveStore.ActiveBalanceStatus.SellPriceModifier * 100).FormatZeroDecimal()} %";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -698,9 +733,9 @@ namespace Barotrauma
|
|||||||
if (!HasActiveTabPermissions()) { return false; }
|
if (!HasActiveTabPermissions()) { return false; }
|
||||||
var itemsToRemove = activeTab switch
|
var itemsToRemove = activeTab switch
|
||||||
{
|
{
|
||||||
StoreTab.Buy => new List<PurchasedItem>(CargoManager.ItemsInBuyCrate),
|
StoreTab.Buy => new List<PurchasedItem>(CargoManager.GetBuyCrateItems(ActiveStore)),
|
||||||
StoreTab.Sell => new List<PurchasedItem>(CargoManager.ItemsInSellCrate),
|
StoreTab.Sell => new List<PurchasedItem>(CargoManager.GetSellCrateItems(ActiveStore)),
|
||||||
StoreTab.SellSub => new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate),
|
StoreTab.SellSub => new List<PurchasedItem>(CargoManager.GetSubCrateItems(ActiveStore)),
|
||||||
_ => throw new NotImplementedException(),
|
_ => throw new NotImplementedException(),
|
||||||
};
|
};
|
||||||
itemsToRemove.ForEach(i => ClearFromShoppingCrate(i));
|
itemsToRemove.ForEach(i => ClearFromShoppingCrate(i));
|
||||||
@@ -708,14 +743,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Refresh();
|
|
||||||
ChangeStoreTab(activeTab);
|
ChangeStoreTab(activeTab);
|
||||||
resolutionWhenCreated = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
resolutionWhenCreated = new Point(GameMain.GraphicsWidth, GameMain.GraphicsHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalizedString GetMerchantBalanceText() => GetCurrencyFormatted(CurrentLocation?.StoreCurrentBalance ?? 0);
|
private LocalizedString GetMerchantBalanceText() => TextManager.FormatCurrency(ActiveStore?.Balance ?? 0);
|
||||||
|
|
||||||
private LocalizedString GetPlayerBalanceText() => GetCurrencyFormatted(PlayerWallet.Balance);
|
private LocalizedString GetPlayerBalanceText() => TextManager.FormatCurrency(PlayerWallet.Balance);
|
||||||
|
|
||||||
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList, int elementCount = 4)
|
private GUILayoutGroup CreateDealsGroup(GUIListBox parentList, int elementCount = 4)
|
||||||
{
|
{
|
||||||
@@ -746,21 +780,25 @@ namespace Barotrauma
|
|||||||
private void UpdateLocation(Location prevLocation, Location newLocation)
|
private void UpdateLocation(Location prevLocation, Location newLocation)
|
||||||
{
|
{
|
||||||
if (prevLocation == newLocation) { return; }
|
if (prevLocation == newLocation) { return; }
|
||||||
|
|
||||||
if (prevLocation?.Reputation != null)
|
if (prevLocation?.Reputation != null)
|
||||||
{
|
{
|
||||||
prevLocation.Reputation.OnReputationValueChanged = null;
|
prevLocation.Reputation.OnReputationValueChanged -= SetNeedsRefresh;
|
||||||
}
|
}
|
||||||
if (ItemPrefab.Prefabs.Any(p => p.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo _)))
|
if (ItemPrefab.Prefabs.Any(p => p.CanBeBoughtFrom(newLocation)))
|
||||||
{
|
{
|
||||||
selectedItemCategory = null;
|
selectedItemCategory = null;
|
||||||
searchBox.Text = "";
|
searchBox.Text = "";
|
||||||
ChangeStoreTab(StoreTab.Buy);
|
ChangeStoreTab(StoreTab.Buy);
|
||||||
if (newLocation?.Reputation != null)
|
if (newLocation?.Reputation != null)
|
||||||
{
|
{
|
||||||
newLocation.Reputation.OnReputationValueChanged += () => { needsRefresh = true; };
|
newLocation.Reputation.OnReputationValueChanged += SetNeedsRefresh;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetNeedsRefresh()
|
||||||
|
{
|
||||||
|
needsRefresh = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangeStoreTab(StoreTab tab)
|
private void ChangeStoreTab(StoreTab tab)
|
||||||
@@ -862,9 +900,9 @@ namespace Barotrauma
|
|||||||
bool hasPermissions = HasBuyPermissions;
|
bool hasPermissions = HasBuyPermissions;
|
||||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||||
|
|
||||||
int dailySpecialCount = CurrentLocation?.DailySpecials.Count() ?? 3;
|
int dailySpecialCount = ActiveStore.DailySpecials.Count;
|
||||||
|
|
||||||
if ((storeDailySpecialsGroup != null) != CurrentLocation.DailySpecials.Any() || dailySpecialCount != prevDailySpecialCount)
|
if ((storeDailySpecialsGroup != null) != ActiveStore.DailySpecials.Any() || dailySpecialCount != prevDailySpecialCount)
|
||||||
{
|
{
|
||||||
if (storeDailySpecialsGroup == null || dailySpecialCount != prevDailySpecialCount)
|
if (storeDailySpecialsGroup == null || dailySpecialCount != prevDailySpecialCount)
|
||||||
{
|
{
|
||||||
@@ -881,32 +919,32 @@ namespace Barotrauma
|
|||||||
prevDailySpecialCount = dailySpecialCount;
|
prevDailySpecialCount = dailySpecialCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (PurchasedItem item in CurrentLocation.StoreStock)
|
foreach (PurchasedItem item in ActiveStore.Stock)
|
||||||
{
|
{
|
||||||
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (ItemPrefab itemPrefab in CurrentLocation.DailySpecials)
|
foreach (ItemPrefab itemPrefab in ActiveStore.DailySpecials)
|
||||||
{
|
{
|
||||||
if (CurrentLocation.StoreStock.Any(pi => pi.ItemPrefab == itemPrefab)) { continue; }
|
if (ActiveStore.Stock.Any(pi => pi.ItemPrefab == itemPrefab)) { continue; }
|
||||||
CreateOrUpdateItemFrame(itemPrefab, 0);
|
CreateOrUpdateItemFrame(itemPrefab, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int quantity)
|
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int quantity)
|
||||||
{
|
{
|
||||||
if (itemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo priceInfo))
|
if (itemPrefab.CanBeBoughtFrom(ActiveStore, out PriceInfo priceInfo))
|
||||||
{
|
{
|
||||||
var isDailySpecial = CurrentLocation.DailySpecials.Contains(itemPrefab);
|
bool isDailySpecial = ActiveStore.DailySpecials.Contains(itemPrefab);
|
||||||
var itemFrame = isDailySpecial ?
|
var itemFrame = isDailySpecial ?
|
||||||
storeDailySpecialsGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
storeDailySpecialsGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
||||||
storeBuyList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
storeBuyList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
||||||
if (CargoManager.PurchasedItems.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem purchasedItem)
|
if (CargoManager.GetPurchasedItem(ActiveStore, itemPrefab) is { } purchasedItem)
|
||||||
{
|
{
|
||||||
quantity = Math.Max(quantity - purchasedItem.Quantity, 0);
|
quantity = Math.Max(quantity - purchasedItem.Quantity, 0);
|
||||||
}
|
}
|
||||||
if (CargoManager.ItemsInBuyCrate.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem itemInBuyCrate)
|
if (CargoManager.GetBuyCrateItem(ActiveStore, itemPrefab) is { } buyCrateItem)
|
||||||
{
|
{
|
||||||
quantity = Math.Max(quantity - itemInBuyCrate.Quantity, 0);
|
quantity = Math.Max(quantity - buyCrateItem.Quantity, 0);
|
||||||
}
|
}
|
||||||
if (itemFrame == null)
|
if (itemFrame == null)
|
||||||
{
|
{
|
||||||
@@ -945,7 +983,7 @@ namespace Barotrauma
|
|||||||
bool hasPermissions = HasTabPermissions(StoreTab.Sell);
|
bool hasPermissions = HasTabPermissions(StoreTab.Sell);
|
||||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||||
|
|
||||||
if ((storeRequestedGoodGroup != null) != CurrentLocation.RequestedGoods.Any())
|
if ((storeRequestedGoodGroup != null) != ActiveStore.RequestedGoods.Any())
|
||||||
{
|
{
|
||||||
if (storeRequestedGoodGroup == null)
|
if (storeRequestedGoodGroup == null)
|
||||||
{
|
{
|
||||||
@@ -965,7 +1003,7 @@ namespace Barotrauma
|
|||||||
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var requestedGood in CurrentLocation.RequestedGoods)
|
foreach (var requestedGood in ActiveStore.RequestedGoods)
|
||||||
{
|
{
|
||||||
if (itemsToSell.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
|
if (itemsToSell.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
|
||||||
CreateOrUpdateItemFrame(requestedGood, 0);
|
CreateOrUpdateItemFrame(requestedGood, 0);
|
||||||
@@ -973,15 +1011,15 @@ namespace Barotrauma
|
|||||||
|
|
||||||
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int itemQuantity)
|
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int itemQuantity)
|
||||||
{
|
{
|
||||||
PriceInfo priceInfo = itemPrefab.GetPriceInfo(CurrentLocation);
|
PriceInfo priceInfo = itemPrefab.GetPriceInfo(ActiveStore);
|
||||||
if (priceInfo == null) { return; }
|
if (priceInfo == null) { return; }
|
||||||
var isRequestedGood = CurrentLocation.RequestedGoods.Contains(itemPrefab);
|
var isRequestedGood = ActiveStore.RequestedGoods.Contains(itemPrefab);
|
||||||
var itemFrame = isRequestedGood ?
|
var itemFrame = isRequestedGood ?
|
||||||
storeRequestedGoodGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
storeRequestedGoodGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
||||||
storeSellList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
storeSellList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
||||||
if (CargoManager.ItemsInSellCrate.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem itemInSellCrate)
|
if (CargoManager.GetSellCrateItem(ActiveStore, itemPrefab) is { } sellCrateItem)
|
||||||
{
|
{
|
||||||
itemQuantity = Math.Max(itemQuantity - itemInSellCrate.Quantity, 0);
|
itemQuantity = Math.Max(itemQuantity - sellCrateItem.Quantity, 0);
|
||||||
}
|
}
|
||||||
if (itemFrame == null)
|
if (itemFrame == null)
|
||||||
{
|
{
|
||||||
@@ -1023,7 +1061,7 @@ namespace Barotrauma
|
|||||||
bool hasPermissions = HasSellSubPermissions;
|
bool hasPermissions = HasSellSubPermissions;
|
||||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||||
|
|
||||||
if ((storeRequestedSubGoodGroup != null) != CurrentLocation.RequestedGoods.Any())
|
if ((storeRequestedSubGoodGroup != null) != ActiveStore.RequestedGoods.Any())
|
||||||
{
|
{
|
||||||
if (storeRequestedSubGoodGroup == null)
|
if (storeRequestedSubGoodGroup == null)
|
||||||
{
|
{
|
||||||
@@ -1043,7 +1081,7 @@ namespace Barotrauma
|
|||||||
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
CreateOrUpdateItemFrame(item.ItemPrefab, item.Quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var requestedGood in CurrentLocation.RequestedGoods)
|
foreach (var requestedGood in ActiveStore.RequestedGoods)
|
||||||
{
|
{
|
||||||
if (itemsToSellFromSub.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
|
if (itemsToSellFromSub.Any(pi => pi.ItemPrefab == requestedGood)) { continue; }
|
||||||
CreateOrUpdateItemFrame(requestedGood, 0);
|
CreateOrUpdateItemFrame(requestedGood, 0);
|
||||||
@@ -1051,15 +1089,15 @@ namespace Barotrauma
|
|||||||
|
|
||||||
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int itemQuantity)
|
void CreateOrUpdateItemFrame(ItemPrefab itemPrefab, int itemQuantity)
|
||||||
{
|
{
|
||||||
PriceInfo priceInfo = itemPrefab.GetPriceInfo(CurrentLocation);
|
PriceInfo priceInfo = itemPrefab.GetPriceInfo(ActiveStore);
|
||||||
if (priceInfo == null) { return; }
|
if (priceInfo == null) { return; }
|
||||||
var isRequestedGood = CurrentLocation.RequestedGoods.Contains(itemPrefab);
|
bool isRequestedGood = ActiveStore.RequestedGoods.Contains(itemPrefab);
|
||||||
var itemFrame = isRequestedGood ?
|
var itemFrame = isRequestedGood ?
|
||||||
storeRequestedSubGoodGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
storeRequestedSubGoodGroup.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab) :
|
||||||
storeSellFromSubList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
storeSellFromSubList.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab == itemPrefab);
|
||||||
if (CargoManager.ItemsInSellFromSubCrate.Find(i => i.ItemPrefab == itemPrefab) is PurchasedItem itemInSellFromSubCrate)
|
if (CargoManager.GetSubCrateItem(ActiveStore, itemPrefab) is { } subCrateItem)
|
||||||
{
|
{
|
||||||
itemQuantity = Math.Max(itemQuantity - itemInSellFromSubCrate.Quantity, 0);
|
itemQuantity = Math.Max(itemQuantity - subCrateItem.Quantity, 0);
|
||||||
}
|
}
|
||||||
if (itemFrame == null)
|
if (itemFrame == null)
|
||||||
{
|
{
|
||||||
@@ -1102,13 +1140,13 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (buying)
|
if (buying)
|
||||||
{
|
{
|
||||||
undiscountedPriceBlock.TextGetter = () => GetCurrencyFormatted(
|
undiscountedPriceBlock.TextGetter = () => TextManager.FormatCurrency(
|
||||||
CurrentLocation?.GetAdjustedItemBuyPrice(pi.ItemPrefab, considerDailySpecials: false) ?? 0);
|
ActiveStore?.GetAdjustedItemBuyPrice(pi.ItemPrefab, considerDailySpecials: false) ?? 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
undiscountedPriceBlock.TextGetter = () => GetCurrencyFormatted(
|
undiscountedPriceBlock.TextGetter = () => TextManager.FormatCurrency(
|
||||||
CurrentLocation?.GetAdjustedItemSellPrice(pi.ItemPrefab, considerRequestedGoods: false) ?? 0);
|
ActiveStore?.GetAdjustedItemSellPrice(pi.ItemPrefab, considerRequestedGoods: false) ?? 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1116,11 +1154,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (buying)
|
if (buying)
|
||||||
{
|
{
|
||||||
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemBuyPrice(pi.ItemPrefab) ?? 0);
|
priceBlock.TextGetter = () => TextManager.FormatCurrency(ActiveStore?.GetAdjustedItemBuyPrice(pi.ItemPrefab) ?? 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
priceBlock.TextGetter = () => GetCurrencyFormatted(CurrentLocation?.GetAdjustedItemSellPrice(pi.ItemPrefab) ?? 0);
|
priceBlock.TextGetter = () => TextManager.FormatCurrency(ActiveStore?.GetAdjustedItemSellPrice(pi.ItemPrefab) ?? 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1135,21 +1173,21 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
item.Quantity += 1;
|
item.Quantity += 1;
|
||||||
}
|
}
|
||||||
else if (playerItem.Prefab.GetPriceInfo(CurrentLocation) != null)
|
else if (playerItem.Prefab.GetPriceInfo(ActiveStore) != null)
|
||||||
{
|
{
|
||||||
itemsToSell.Add(new PurchasedItem(playerItem.Prefab, 1));
|
itemsToSell.Add(new PurchasedItem(playerItem.Prefab, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove items from sell crate if they aren't in player inventory anymore
|
// Remove items from sell crate if they aren't in player inventory anymore
|
||||||
var itemsInCrate = new List<PurchasedItem>(CargoManager.ItemsInSellCrate);
|
var itemsInCrate = new List<PurchasedItem>(CargoManager.GetSellCrateItems(ActiveStore));
|
||||||
foreach (PurchasedItem crateItem in itemsInCrate)
|
foreach (PurchasedItem crateItem in itemsInCrate)
|
||||||
{
|
{
|
||||||
var playerItem = itemsToSell.Find(i => i.ItemPrefab == crateItem.ItemPrefab);
|
var playerItem = itemsToSell.Find(i => i.ItemPrefab == crateItem.ItemPrefab);
|
||||||
var playerItemQuantity = playerItem != null ? playerItem.Quantity : 0;
|
var playerItemQuantity = playerItem != null ? playerItem.Quantity : 0;
|
||||||
if (crateItem.Quantity > playerItemQuantity)
|
if (crateItem.Quantity > playerItemQuantity)
|
||||||
{
|
{
|
||||||
CargoManager.ModifyItemQuantityInSellCrate(crateItem.ItemPrefab, playerItemQuantity - crateItem.Quantity);
|
CargoManager.ModifyItemQuantityInSellCrate(ActiveStore.Identifier, crateItem.ItemPrefab, playerItemQuantity - crateItem.Quantity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
needsItemsToSellRefresh = false;
|
needsItemsToSellRefresh = false;
|
||||||
@@ -1165,35 +1203,35 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
item.Quantity += 1;
|
item.Quantity += 1;
|
||||||
}
|
}
|
||||||
else if (subItem.Prefab.GetPriceInfo(CurrentLocation) != null)
|
else if (subItem.Prefab.GetPriceInfo(ActiveStore) != null)
|
||||||
{
|
{
|
||||||
itemsToSellFromSub.Add(new PurchasedItem(subItem.Prefab, 1));
|
itemsToSellFromSub.Add(new PurchasedItem(subItem.Prefab, 1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove items from sell crate if they aren't on the sub anymore
|
// Remove items from sell crate if they aren't on the sub anymore
|
||||||
var itemsInCrate = new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate);
|
var itemsInCrate = new List<PurchasedItem>(CargoManager.GetSubCrateItems(ActiveStore));
|
||||||
foreach (PurchasedItem crateItem in itemsInCrate)
|
foreach (PurchasedItem crateItem in itemsInCrate)
|
||||||
{
|
{
|
||||||
var subItem = itemsToSellFromSub.Find(i => i.ItemPrefab == crateItem.ItemPrefab);
|
var subItem = itemsToSellFromSub.Find(i => i.ItemPrefab == crateItem.ItemPrefab);
|
||||||
var subItemQuantity = subItem != null ? subItem.Quantity : 0;
|
var subItemQuantity = subItem != null ? subItem.Quantity : 0;
|
||||||
if (crateItem.Quantity > subItemQuantity)
|
if (crateItem.Quantity > subItemQuantity)
|
||||||
{
|
{
|
||||||
CargoManager.ModifyItemQuantityInSellFromSubCrate(crateItem.ItemPrefab, subItemQuantity - crateItem.Quantity);
|
CargoManager.ModifyItemQuantityInSubSellCrate(ActiveStore.Identifier, crateItem.ItemPrefab, subItemQuantity - crateItem.Quantity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sellableItemsFromSubUpdateTimer = 0.0f;
|
sellableItemsFromSubUpdateTimer = 0.0f;
|
||||||
needsItemsToSellFromSubRefresh = false;
|
needsItemsToSellFromSubRefresh = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshShoppingCrateList(List<PurchasedItem> items, GUIListBox listBox, StoreTab tab)
|
private void RefreshShoppingCrateList(IEnumerable<PurchasedItem> items, GUIListBox listBox, StoreTab tab)
|
||||||
{
|
{
|
||||||
bool hasPermissions = HasTabPermissions(tab);
|
bool hasPermissions = HasTabPermissions(tab);
|
||||||
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
HashSet<GUIComponent> existingItemFrames = new HashSet<GUIComponent>();
|
||||||
int totalPrice = 0;
|
int totalPrice = 0;
|
||||||
foreach (PurchasedItem item in items)
|
foreach (PurchasedItem item in items)
|
||||||
{
|
{
|
||||||
if (!(item.ItemPrefab.GetPriceInfo(CurrentLocation) is { } priceInfo)) { continue; }
|
if (!(item.ItemPrefab.GetPriceInfo(ActiveStore) is { } priceInfo)) { continue; }
|
||||||
GUINumberInput numInput = null;
|
GUINumberInput numInput = null;
|
||||||
if (!(listBox.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab.Identifier == item.ItemPrefab.Identifier) is { } itemFrame))
|
if (!(listBox.Content.FindChild(c => c.UserData is PurchasedItem pi && pi.ItemPrefab.Identifier == item.ItemPrefab.Identifier) is { } itemFrame))
|
||||||
{
|
{
|
||||||
@@ -1227,9 +1265,9 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
int price = tab switch
|
int price = tab switch
|
||||||
{
|
{
|
||||||
StoreTab.Buy => CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo),
|
StoreTab.Buy => ActiveStore.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo),
|
||||||
StoreTab.Sell => CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo),
|
StoreTab.Sell => ActiveStore.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo),
|
||||||
StoreTab.SellSub => CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo),
|
StoreTab.SellSub => ActiveStore.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo),
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
};
|
};
|
||||||
totalPrice += item.Quantity * price;
|
totalPrice += item.Quantity * price;
|
||||||
@@ -1265,11 +1303,11 @@ namespace Barotrauma
|
|||||||
SetConfirmButtonStatus();
|
SetConfirmButtonStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshShoppingCrateBuyList() => RefreshShoppingCrateList(CargoManager.ItemsInBuyCrate, shoppingCrateBuyList, StoreTab.Buy);
|
private void RefreshShoppingCrateBuyList() => RefreshShoppingCrateList(CargoManager.GetBuyCrateItems(ActiveStore), shoppingCrateBuyList, StoreTab.Buy);
|
||||||
|
|
||||||
private void RefreshShoppingCrateSellList() => RefreshShoppingCrateList(CargoManager.ItemsInSellCrate, shoppingCrateSellList, StoreTab.Sell);
|
private void RefreshShoppingCrateSellList() => RefreshShoppingCrateList(CargoManager.GetSellCrateItems(ActiveStore), shoppingCrateSellList, StoreTab.Sell);
|
||||||
|
|
||||||
private void RefreshShoppingCrateSellFromSubList() => RefreshShoppingCrateList(CargoManager.ItemsInSellFromSubCrate, shoppingCrateSellFromSubList, StoreTab.SellSub);
|
private void RefreshShoppingCrateSellFromSubList() => RefreshShoppingCrateList(CargoManager.GetSubCrateItems(ActiveStore), shoppingCrateSellFromSubList, StoreTab.SellSub);
|
||||||
|
|
||||||
private void SortItems(GUIListBox list, SortingMethod sortingMethod)
|
private void SortItems(GUIListBox list, SortingMethod sortingMethod)
|
||||||
{
|
{
|
||||||
@@ -1316,8 +1354,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||||
{
|
{
|
||||||
var sortResult = CurrentLocation.GetAdjustedItemSellPrice(itemX.ItemPrefab).CompareTo(
|
int sortResult = ActiveStore.GetAdjustedItemSellPrice(itemX.ItemPrefab).CompareTo(
|
||||||
CurrentLocation.GetAdjustedItemSellPrice(itemY.ItemPrefab));
|
ActiveStore.GetAdjustedItemSellPrice(itemY.ItemPrefab));
|
||||||
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
|
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
|
||||||
return sortResult;
|
return sortResult;
|
||||||
}
|
}
|
||||||
@@ -1340,8 +1378,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
if (x.GUIComponent.UserData is PurchasedItem itemX && y.GUIComponent.UserData is PurchasedItem itemY)
|
||||||
{
|
{
|
||||||
var sortResult = CurrentLocation.GetAdjustedItemBuyPrice(itemX.ItemPrefab).CompareTo(
|
int sortResult = ActiveStore.GetAdjustedItemBuyPrice(itemX.ItemPrefab).CompareTo(
|
||||||
CurrentLocation.GetAdjustedItemBuyPrice(itemY.ItemPrefab));
|
ActiveStore.GetAdjustedItemBuyPrice(itemY.ItemPrefab));
|
||||||
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
|
if (sortingMethod == SortingMethod.PriceDesc) { sortResult *= -1; }
|
||||||
return sortResult;
|
return sortResult;
|
||||||
}
|
}
|
||||||
@@ -1485,7 +1523,7 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
bool isSellingRelatedList = containingTab != StoreTab.Buy;
|
bool isSellingRelatedList = containingTab != StoreTab.Buy;
|
||||||
bool locationHasDealOnItem = isSellingRelatedList ?
|
bool locationHasDealOnItem = isSellingRelatedList ?
|
||||||
CurrentLocation.RequestedGoods.Contains(pi.ItemPrefab) : CurrentLocation.DailySpecials.Contains(pi.ItemPrefab);
|
ActiveStore.RequestedGoods.Contains(pi.ItemPrefab) : ActiveStore.DailySpecials.Contains(pi.ItemPrefab);
|
||||||
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), nameAndQuantityGroup.RectTransform),
|
GUITextBlock nameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.4f), nameAndQuantityGroup.RectTransform),
|
||||||
pi.ItemPrefab.Name, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft)
|
pi.ItemPrefab.Name, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft)
|
||||||
{
|
{
|
||||||
@@ -1673,7 +1711,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add items already purchased
|
// Add items already purchased
|
||||||
CargoManager?.PurchasedItems?.ForEach(pi => AddNonEmptyOwnedItems(pi));
|
CargoManager?.GetPurchasedItems(ActiveStore).ForEach(pi => AddNonEmptyOwnedItems(pi));
|
||||||
|
|
||||||
ownedItemsUpdateTimer = 0.0f;
|
ownedItemsUpdateTimer = 0.0f;
|
||||||
|
|
||||||
@@ -1689,7 +1727,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
void AddOwnedItem(Item item)
|
void AddOwnedItem(Item item)
|
||||||
{
|
{
|
||||||
if (!(item?.Prefab.GetPriceInfo(CurrentLocation) is PriceInfo priceInfo)) { return; }
|
if (!(item?.Prefab.GetPriceInfo(ActiveStore) is PriceInfo priceInfo)) { return; }
|
||||||
bool isNonEmpty = !priceInfo.DisplayNonEmpty || item.ConditionPercentage > 5.0f;
|
bool isNonEmpty = !priceInfo.DisplayNonEmpty || item.ConditionPercentage > 5.0f;
|
||||||
if (OwnedItems.TryGetValue(item.Prefab, out ItemQuantity itemQuantity))
|
if (OwnedItems.TryGetValue(item.Prefab, out ItemQuantity itemQuantity))
|
||||||
{
|
{
|
||||||
@@ -1862,7 +1900,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
list = mode switch
|
list = mode switch
|
||||||
{
|
{
|
||||||
StoreTab.Buy => CurrentLocation?.StoreStock,
|
StoreTab.Buy => ActiveStore?.Stock,
|
||||||
StoreTab.Sell => itemsToSell,
|
StoreTab.Sell => itemsToSell,
|
||||||
StoreTab.SellSub => itemsToSellFromSub,
|
StoreTab.SellSub => itemsToSellFromSub,
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
@@ -1876,7 +1914,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (mode == StoreTab.Buy)
|
if (mode == StoreTab.Buy)
|
||||||
{
|
{
|
||||||
var purchasedItem = CargoManager.PurchasedItems.Find(i => i.ItemPrefab == item.ItemPrefab);
|
var purchasedItem = CargoManager.GetPurchasedItem(ActiveStore, item.ItemPrefab);
|
||||||
if (purchasedItem != null) { return Math.Max(item.Quantity - purchasedItem.Quantity, 0); }
|
if (purchasedItem != null) { return Math.Max(item.Quantity - purchasedItem.Quantity, 0); }
|
||||||
}
|
}
|
||||||
return item.Quantity;
|
return item.Quantity;
|
||||||
@@ -1887,22 +1925,19 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalizedString GetCurrencyFormatted(int amount) =>
|
|
||||||
TextManager.GetWithVariable("currencyformat", "[credits]", string.Format(CultureInfo.InvariantCulture, "{0:N0}", amount));
|
|
||||||
|
|
||||||
private bool ModifyBuyQuantity(PurchasedItem item, int quantity)
|
private bool ModifyBuyQuantity(PurchasedItem item, int quantity)
|
||||||
{
|
{
|
||||||
if (item?.ItemPrefab == null) { return false; }
|
if (item?.ItemPrefab == null) { return false; }
|
||||||
if (!HasBuyPermissions) { return false; }
|
if (!HasBuyPermissions) { return false; }
|
||||||
if (quantity > 0)
|
if (quantity > 0)
|
||||||
{
|
{
|
||||||
var itemInCrate = CargoManager.ItemsInBuyCrate.Find(i => i.ItemPrefab == item.ItemPrefab);
|
var crateItem = CargoManager.GetBuyCrateItem(ActiveStore, item.ItemPrefab);
|
||||||
if (itemInCrate != null && itemInCrate.Quantity >= CargoManager.MaxQuantity) { return false; }
|
if (crateItem != null && crateItem.Quantity >= CargoManager.MaxQuantity) { return false; }
|
||||||
// Make sure there's enough available in the store
|
// Make sure there's enough available in the store
|
||||||
var totalQuantityToBuy = itemInCrate != null ? itemInCrate.Quantity + quantity : quantity;
|
var totalQuantityToBuy = crateItem != null ? crateItem.Quantity + quantity : quantity;
|
||||||
if (totalQuantityToBuy > GetMaxAvailable(item.ItemPrefab, StoreTab.Buy)) { return false; }
|
if (totalQuantityToBuy > GetMaxAvailable(item.ItemPrefab, StoreTab.Buy)) { return false; }
|
||||||
}
|
}
|
||||||
CargoManager.ModifyItemQuantityInBuyCrate(item.ItemPrefab, quantity);
|
CargoManager.ModifyItemQuantityInBuyCrate(ActiveStore.Identifier, item.ItemPrefab, quantity);
|
||||||
GameMain.Client?.SendCampaignState();
|
GameMain.Client?.SendCampaignState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1914,11 +1949,11 @@ namespace Barotrauma
|
|||||||
if (quantity > 0)
|
if (quantity > 0)
|
||||||
{
|
{
|
||||||
// Make sure there's enough available to sell
|
// Make sure there's enough available to sell
|
||||||
var itemToSell = CargoManager.ItemsInSellCrate.Find(i => i.ItemPrefab == item.ItemPrefab);
|
var itemToSell = CargoManager.GetSellCrateItem(ActiveStore, item.ItemPrefab);
|
||||||
var totalQuantityToSell = itemToSell != null ? itemToSell.Quantity + quantity : quantity;
|
var totalQuantityToSell = itemToSell != null ? itemToSell.Quantity + quantity : quantity;
|
||||||
if (totalQuantityToSell > GetMaxAvailable(item.ItemPrefab, StoreTab.Sell)) { return false; }
|
if (totalQuantityToSell > GetMaxAvailable(item.ItemPrefab, StoreTab.Sell)) { return false; }
|
||||||
}
|
}
|
||||||
CargoManager.ModifyItemQuantityInSellCrate(item.ItemPrefab, quantity);
|
CargoManager.ModifyItemQuantityInSellCrate(ActiveStore.Identifier, item.ItemPrefab, quantity);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1929,11 +1964,11 @@ namespace Barotrauma
|
|||||||
if (quantity > 0)
|
if (quantity > 0)
|
||||||
{
|
{
|
||||||
// Make sure there's enough available to sell
|
// Make sure there's enough available to sell
|
||||||
var itemToSell = CargoManager.ItemsInSellFromSubCrate.Find(i => i.ItemPrefab == item.ItemPrefab);
|
var itemToSell = CargoManager.GetSubCrateItem(ActiveStore, item.ItemPrefab);
|
||||||
var totalQuantityToSell = itemToSell != null ? itemToSell.Quantity + quantity : quantity;
|
var totalQuantityToSell = itemToSell != null ? itemToSell.Quantity + quantity : quantity;
|
||||||
if (totalQuantityToSell > GetMaxAvailable(item.ItemPrefab, StoreTab.SellSub)) { return false; }
|
if (totalQuantityToSell > GetMaxAvailable(item.ItemPrefab, StoreTab.SellSub)) { return false; }
|
||||||
}
|
}
|
||||||
CargoManager.ModifyItemQuantityInSellFromSubCrate(item.ItemPrefab, quantity);
|
CargoManager.ModifyItemQuantityInSubSellCrate(ActiveStore.Identifier, item.ItemPrefab, quantity);
|
||||||
GameMain.Client?.SendCampaignState();
|
GameMain.Client?.SendCampaignState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1981,32 +2016,27 @@ namespace Barotrauma
|
|||||||
private bool BuyItems()
|
private bool BuyItems()
|
||||||
{
|
{
|
||||||
if (!HasBuyPermissions) { return false; }
|
if (!HasBuyPermissions) { return false; }
|
||||||
|
var itemsToPurchase = new List<PurchasedItem>(CargoManager.GetBuyCrateItems(ActiveStore));
|
||||||
var itemsToPurchase = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
|
|
||||||
var itemsToRemove = new List<PurchasedItem>();
|
var itemsToRemove = new List<PurchasedItem>();
|
||||||
var totalPrice = 0;
|
int totalPrice = 0;
|
||||||
foreach (PurchasedItem item in itemsToPurchase)
|
foreach (var item in itemsToPurchase)
|
||||||
{
|
{
|
||||||
if (item?.ItemPrefab == null || !item.ItemPrefab.CanBeBoughtAtLocation(CurrentLocation, out PriceInfo priceInfo))
|
if (item?.ItemPrefab == null || !item.ItemPrefab.CanBeBoughtFrom(ActiveStore, out var priceInfo))
|
||||||
{
|
{
|
||||||
itemsToRemove.Add(item);
|
itemsToRemove.Add(item);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
totalPrice += item.Quantity * CurrentLocation.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo);
|
totalPrice += item.Quantity * ActiveStore.GetAdjustedItemBuyPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||||
}
|
}
|
||||||
itemsToRemove.ForEach(i => itemsToPurchase.Remove(i));
|
itemsToRemove.ForEach(i => itemsToPurchase.Remove(i));
|
||||||
|
|
||||||
if (itemsToPurchase.None() || !PlayerWallet.CanAfford(totalPrice)) { return false; }
|
if (itemsToPurchase.None() || !PlayerWallet.CanAfford(totalPrice)) { return false; }
|
||||||
|
CargoManager.PurchaseItems(ActiveStore.Identifier, itemsToPurchase, true);
|
||||||
CargoManager.PurchaseItems(itemsToPurchase, true);
|
|
||||||
GameMain.Client?.SendCampaignState();
|
GameMain.Client?.SendCampaignState();
|
||||||
|
|
||||||
var dialog = new GUIMessageBox(
|
var dialog = new GUIMessageBox(
|
||||||
TextManager.Get("newsupplies"),
|
TextManager.Get("newsupplies"),
|
||||||
TextManager.GetWithVariable("suppliespurchasedmessage", "[location]", campaignUI?.Campaign?.Map?.CurrentLocation?.Name),
|
TextManager.GetWithVariable("suppliespurchasedmessage", "[location]", campaignUI?.Campaign?.Map?.CurrentLocation?.Name),
|
||||||
new LocalizedString[] { TextManager.Get("Ok") });
|
new LocalizedString[] { TextManager.Get("Ok") });
|
||||||
dialog.Buttons[0].OnClicked += dialog.Close;
|
dialog.Buttons[0].OnClicked += dialog.Close;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2018,8 +2048,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
itemsToSell = activeTab switch
|
itemsToSell = activeTab switch
|
||||||
{
|
{
|
||||||
StoreTab.Sell => new List<PurchasedItem>(CargoManager.ItemsInSellCrate),
|
StoreTab.Sell => new List<PurchasedItem>(CargoManager.GetSellCrateItems(ActiveStore)),
|
||||||
StoreTab.SellSub => new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate),
|
StoreTab.SellSub => new List<PurchasedItem>(CargoManager.GetSubCrateItems(ActiveStore)),
|
||||||
_ => throw new NotImplementedException()
|
_ => throw new NotImplementedException()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2032,9 +2062,9 @@ namespace Barotrauma
|
|||||||
int totalValue = 0;
|
int totalValue = 0;
|
||||||
foreach (PurchasedItem item in itemsToSell)
|
foreach (PurchasedItem item in itemsToSell)
|
||||||
{
|
{
|
||||||
if (item?.ItemPrefab?.GetPriceInfo(CurrentLocation) is PriceInfo priceInfo)
|
if (item?.ItemPrefab?.GetPriceInfo(ActiveStore) is PriceInfo priceInfo)
|
||||||
{
|
{
|
||||||
totalValue += item.Quantity * CurrentLocation.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
totalValue += item.Quantity * ActiveStore.GetAdjustedItemSellPrice(item.ItemPrefab, priceInfo: priceInfo);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2042,8 +2072,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
itemsToRemove.ForEach(i => itemsToSell.Remove(i));
|
itemsToRemove.ForEach(i => itemsToSell.Remove(i));
|
||||||
if (itemsToSell.None() || totalValue > CurrentLocation.StoreCurrentBalance) { return false; }
|
if (itemsToSell.None() || totalValue > ActiveStore.Balance) { return false; }
|
||||||
CargoManager.SellItems(itemsToSell, activeTab);
|
CargoManager.SellItems(ActiveStore.Identifier, itemsToSell, activeTab);
|
||||||
GameMain.Client?.SendCampaignState();
|
GameMain.Client?.SendCampaignState();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2052,7 +2082,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (IsBuying)
|
if (IsBuying)
|
||||||
{
|
{
|
||||||
shoppingCrateTotal.Text = GetCurrencyFormatted(buyTotal);
|
shoppingCrateTotal.Text = TextManager.FormatCurrency(buyTotal);
|
||||||
shoppingCrateTotal.TextColor = !PlayerWallet.CanAfford(buyTotal) ? Color.Red : Color.White;
|
shoppingCrateTotal.TextColor = !PlayerWallet.CanAfford(buyTotal) ? Color.Red : Color.White;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -2063,8 +2093,8 @@ namespace Barotrauma
|
|||||||
StoreTab.SellSub => sellFromSubTotal,
|
StoreTab.SellSub => sellFromSubTotal,
|
||||||
_ => throw new NotImplementedException(),
|
_ => throw new NotImplementedException(),
|
||||||
};
|
};
|
||||||
shoppingCrateTotal.Text = GetCurrencyFormatted(total);
|
shoppingCrateTotal.Text = TextManager.FormatCurrency(total);
|
||||||
shoppingCrateTotal.TextColor = CurrentLocation != null && total > CurrentLocation.StoreCurrentBalance ? Color.Red : Color.White;
|
shoppingCrateTotal.TextColor = CurrentLocation != null && total > ActiveStore.Balance ? Color.Red : Color.White;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2100,8 +2130,8 @@ namespace Barotrauma
|
|||||||
activeTab switch
|
activeTab switch
|
||||||
{
|
{
|
||||||
StoreTab.Buy => PlayerWallet.CanAfford(buyTotal),
|
StoreTab.Buy => PlayerWallet.CanAfford(buyTotal),
|
||||||
StoreTab.Sell => CurrentLocation != null && sellTotal <= CurrentLocation.StoreCurrentBalance,
|
StoreTab.Sell => CurrentLocation != null && sellTotal <= ActiveStore.Balance,
|
||||||
StoreTab.SellSub => CurrentLocation != null && sellFromSubTotal <= CurrentLocation.StoreCurrentBalance,
|
StoreTab.SellSub => CurrentLocation != null && sellFromSubTotal <= ActiveStore.Balance,
|
||||||
_ => false
|
_ => false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -2124,6 +2154,7 @@ namespace Barotrauma
|
|||||||
if (GameMain.GraphicsWidth != resolutionWhenCreated.X || GameMain.GraphicsHeight != resolutionWhenCreated.Y)
|
if (GameMain.GraphicsWidth != resolutionWhenCreated.X || GameMain.GraphicsHeight != resolutionWhenCreated.Y)
|
||||||
{
|
{
|
||||||
CreateUI();
|
CreateUI();
|
||||||
|
needsRefresh = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -2131,38 +2162,62 @@ namespace Barotrauma
|
|||||||
ownedItemsUpdateTimer += deltaTime;
|
ownedItemsUpdateTimer += deltaTime;
|
||||||
if (ownedItemsUpdateTimer >= timerUpdateInterval)
|
if (ownedItemsUpdateTimer >= timerUpdateInterval)
|
||||||
{
|
{
|
||||||
var prevOwnedItems = new Dictionary<ItemPrefab, ItemQuantity>(OwnedItems);
|
bool checkForRefresh = !needsItemsToSellRefresh || !needsRefresh;
|
||||||
|
var prevOwnedItems = checkForRefresh ? new Dictionary<ItemPrefab, ItemQuantity>(OwnedItems) : null;
|
||||||
UpdateOwnedItems();
|
UpdateOwnedItems();
|
||||||
bool refresh = OwnedItems.Count != prevOwnedItems.Count ||
|
if (checkForRefresh)
|
||||||
OwnedItems.Values.Sum(v => v.Total) != prevOwnedItems.Values.Sum(v => v.Total) ||
|
|
||||||
OwnedItems.Any(kvp => !prevOwnedItems.TryGetValue(kvp.Key, out ItemQuantity v) || kvp.Value.Total != v.Total) ||
|
|
||||||
prevOwnedItems.Any(kvp => !OwnedItems.ContainsKey(kvp.Key));
|
|
||||||
if (refresh)
|
|
||||||
{
|
{
|
||||||
needsItemsToSellRefresh = true;
|
bool refresh = OwnedItems.Count != prevOwnedItems.Count ||
|
||||||
needsRefresh = true;
|
OwnedItems.Values.Sum(v => v.Total) != prevOwnedItems.Values.Sum(v => v.Total) ||
|
||||||
|
OwnedItems.Any(kvp => !prevOwnedItems.TryGetValue(kvp.Key, out ItemQuantity v) || kvp.Value.Total != v.Total) ||
|
||||||
|
prevOwnedItems.Any(kvp => !OwnedItems.ContainsKey(kvp.Key));
|
||||||
|
if (refresh)
|
||||||
|
{
|
||||||
|
needsItemsToSellRefresh = true;
|
||||||
|
needsRefresh = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Update the sellable sub items at short intervals and check if the interface should be refreshed
|
// Update the sellable sub items at short intervals and check if the interface should be refreshed
|
||||||
sellableItemsFromSubUpdateTimer += deltaTime;
|
sellableItemsFromSubUpdateTimer += deltaTime;
|
||||||
if (sellableItemsFromSubUpdateTimer >= timerUpdateInterval)
|
if (sellableItemsFromSubUpdateTimer >= timerUpdateInterval)
|
||||||
{
|
{
|
||||||
var prevSubItems = new List<PurchasedItem>(itemsToSellFromSub);
|
bool checkForRefresh = !needsRefresh;
|
||||||
|
var prevSubItems = checkForRefresh ? new List<PurchasedItem>(itemsToSellFromSub) : null;
|
||||||
RefreshItemsToSellFromSub();
|
RefreshItemsToSellFromSub();
|
||||||
needsRefresh = needsRefresh ||
|
if (checkForRefresh)
|
||||||
itemsToSellFromSub.Count != prevSubItems.Count ||
|
{
|
||||||
itemsToSellFromSub.Sum(i => i.Quantity) != prevSubItems.Sum(i => i.Quantity) ||
|
needsRefresh = itemsToSellFromSub.Count != prevSubItems.Count ||
|
||||||
itemsToSellFromSub.Any(i => !(prevSubItems.FirstOrDefault(prev => prev.ItemPrefab == i.ItemPrefab) is PurchasedItem prev) || i.Quantity != prev.Quantity) ||
|
itemsToSellFromSub.Sum(i => i.Quantity) != prevSubItems.Sum(i => i.Quantity) ||
|
||||||
prevSubItems.Any(prev => itemsToSellFromSub.None(i => i.ItemPrefab == prev.ItemPrefab));
|
itemsToSellFromSub.Any(i => !(prevSubItems.FirstOrDefault(prev => prev.ItemPrefab == i.ItemPrefab) is PurchasedItem prev) || i.Quantity != prev.Quantity) ||
|
||||||
|
prevSubItems.Any(prev => itemsToSellFromSub.None(i => i.ItemPrefab == prev.ItemPrefab));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (needsItemsToSellRefresh)
|
||||||
if (needsItemsToSellRefresh) { RefreshItemsToSell(); }
|
{
|
||||||
if (needsItemsToSellFromSubRefresh) { RefreshItemsToSellFromSub(); }
|
RefreshItemsToSell();
|
||||||
if (needsRefresh || HavePermissionsChanged()) { Refresh(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
}
|
||||||
if (needsBuyingRefresh || HavePermissionsChanged(StoreTab.Buy)) { RefreshBuying(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
if (needsItemsToSellFromSubRefresh)
|
||||||
if (needsSellingRefresh || HavePermissionsChanged(StoreTab.Sell)) { RefreshSelling(updateOwned: ownedItemsUpdateTimer > 0.0f); }
|
{
|
||||||
if (needsSellingFromSubRefresh || HavePermissionsChanged(StoreTab.SellSub)) { RefreshSellingFromSub(updateOwned: ownedItemsUpdateTimer > 0.0f, updateItemsToSellFromSub: sellableItemsFromSubUpdateTimer > 0.0f); }
|
RefreshItemsToSellFromSub();
|
||||||
|
}
|
||||||
|
if (needsRefresh || HavePermissionsChanged())
|
||||||
|
{
|
||||||
|
Refresh(updateOwned: ownedItemsUpdateTimer > 0.0f);
|
||||||
|
}
|
||||||
|
if (needsBuyingRefresh || HavePermissionsChanged(StoreTab.Buy))
|
||||||
|
{
|
||||||
|
RefreshBuying(updateOwned: ownedItemsUpdateTimer > 0.0f);
|
||||||
|
}
|
||||||
|
if (needsSellingRefresh || HavePermissionsChanged(StoreTab.Sell))
|
||||||
|
{
|
||||||
|
RefreshSelling(updateOwned: ownedItemsUpdateTimer > 0.0f);
|
||||||
|
}
|
||||||
|
if (needsSellingFromSubRefresh || HavePermissionsChanged(StoreTab.SellSub))
|
||||||
|
{
|
||||||
|
RefreshSellingFromSub(updateOwned: ownedItemsUpdateTimer > 0.0f, updateItemsToSellFromSub: sellableItemsFromSubUpdateTimer > 0.0f);
|
||||||
|
}
|
||||||
|
|
||||||
updateStopwatch.Stop();
|
updateStopwatch.Stop();
|
||||||
GameMain.PerformanceCounter.AddPartialElapsedTicks("GameSessionUpdate", "StoreUpdate", updateStopwatch.ElapsedTicks);
|
GameMain.PerformanceCounter.AddPartialElapsedTicks("GameSessionUpdate", "StoreUpdate", updateStopwatch.ElapsedTicks);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Barotrauma
|
|||||||
private readonly List<SubmarineInfo> subsToShow;
|
private readonly List<SubmarineInfo> subsToShow;
|
||||||
private readonly SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
|
private readonly SubmarineDisplayContent[] submarineDisplays = new SubmarineDisplayContent[submarinesPerPage];
|
||||||
private SubmarineInfo selectedSubmarine = null;
|
private SubmarineInfo selectedSubmarine = null;
|
||||||
private LocalizedString purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, deliveryFeeText, priceText, switchText, missingPreviewText, currencyShorthandText, currencyLongText;
|
private LocalizedString purchaseAndSwitchText, purchaseOnlyText, deliveryText, currentSubText, deliveryFeeText, priceText, switchText, missingPreviewText, currencyName;
|
||||||
private readonly RectTransform parent;
|
private readonly RectTransform parent;
|
||||||
private readonly Action closeAction;
|
private readonly Action closeAction;
|
||||||
private Sprite pageIndicator;
|
private Sprite pageIndicator;
|
||||||
@@ -99,8 +99,7 @@ namespace Barotrauma
|
|||||||
priceText = TextManager.Get("price");
|
priceText = TextManager.Get("price");
|
||||||
}
|
}
|
||||||
|
|
||||||
currencyShorthandText = TextManager.Get("currencyformat");
|
currencyName = TextManager.Get("credit").Value.ToLowerInvariant();
|
||||||
currencyLongText = TextManager.Get("credit").Value.ToLowerInvariant();
|
|
||||||
|
|
||||||
UpdateSubmarines();
|
UpdateSubmarines();
|
||||||
missingPreviewText = TextManager.Get("SubPreviewImageNotFound");
|
missingPreviewText = TextManager.Get("SubPreviewImageNotFound");
|
||||||
@@ -335,7 +334,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (!GameMain.GameSession.IsSubmarineOwned(subToDisplay))
|
if (!GameMain.GameSession.IsSubmarineOwned(subToDisplay))
|
||||||
{
|
{
|
||||||
LocalizedString amountString = currencyShorthandText.Replace("[credits]", subToDisplay.Price.ToString());
|
LocalizedString amountString = TextManager.FormatCurrency(subToDisplay.Price);
|
||||||
submarineDisplays[i].submarineFee.Text = priceText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
|
submarineDisplays[i].submarineFee.Text = priceText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -344,7 +343,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (deliveryFee > 0)
|
if (deliveryFee > 0)
|
||||||
{
|
{
|
||||||
LocalizedString amountString = currencyShorthandText.Replace("[credits]", deliveryFee.ToString());
|
LocalizedString amountString = TextManager.FormatCurrency(deliveryFee);
|
||||||
submarineDisplays[i].submarineFee.Text = deliveryFeeText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
|
submarineDisplays[i].submarineFee.Text = deliveryFeeText.Replace("[amount]", amountString).Replace("[currencyname]", string.Empty).TrimEnd();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -584,7 +583,7 @@ namespace Barotrauma
|
|||||||
if (!GameMain.GameSession.Campaign.Wallet.CanAfford(deliveryFee) && deliveryFee > 0)
|
if (!GameMain.GameSession.Campaign.Wallet.CanAfford(deliveryFee) && deliveryFee > 0)
|
||||||
{
|
{
|
||||||
new GUIMessageBox(TextManager.Get("deliveryrequestheader"), TextManager.GetWithVariables("notenoughmoneyfordeliverytext",
|
new GUIMessageBox(TextManager.Get("deliveryrequestheader"), TextManager.GetWithVariables("notenoughmoneyfordeliverytext",
|
||||||
("[currencyname]", currencyLongText),
|
("[currencyname]", currencyName),
|
||||||
("[submarinename]", selectedSubmarine.DisplayName),
|
("[submarinename]", selectedSubmarine.DisplayName),
|
||||||
("[location1]", deliveryLocationName),
|
("[location1]", deliveryLocationName),
|
||||||
("[location2]", GameMain.GameSession.Map.CurrentLocation.Name)));
|
("[location2]", GameMain.GameSession.Map.CurrentLocation.Name)));
|
||||||
@@ -601,7 +600,7 @@ namespace Barotrauma
|
|||||||
("[location2]", GameMain.GameSession.Map.CurrentLocation.Name),
|
("[location2]", GameMain.GameSession.Map.CurrentLocation.Name),
|
||||||
("[submarinename2]", CurrentOrPendingSubmarine().DisplayName),
|
("[submarinename2]", CurrentOrPendingSubmarine().DisplayName),
|
||||||
("[amount]", deliveryFee.ToString()),
|
("[amount]", deliveryFee.ToString()),
|
||||||
("[currencyname]", currencyLongText)), messageBoxOptions);
|
("[currencyname]", currencyName)), messageBoxOptions);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -632,7 +631,7 @@ namespace Barotrauma
|
|||||||
if (!GameMain.GameSession.Campaign.Wallet.CanAfford(selectedSubmarine.Price))
|
if (!GameMain.GameSession.Campaign.Wallet.CanAfford(selectedSubmarine.Price))
|
||||||
{
|
{
|
||||||
new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("notenoughmoneyforpurchasetext",
|
new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("notenoughmoneyforpurchasetext",
|
||||||
("[currencyname]", currencyLongText),
|
("[currencyname]", currencyName),
|
||||||
("[submarinename]", selectedSubmarine.DisplayName)));
|
("[submarinename]", selectedSubmarine.DisplayName)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -644,7 +643,7 @@ namespace Barotrauma
|
|||||||
msgBox = new GUIMessageBox(TextManager.Get("purchaseandswitchsubmarineheader"), TextManager.GetWithVariables("purchaseandswitchsubmarinetext",
|
msgBox = new GUIMessageBox(TextManager.Get("purchaseandswitchsubmarineheader"), TextManager.GetWithVariables("purchaseandswitchsubmarinetext",
|
||||||
("[submarinename1]", selectedSubmarine.DisplayName),
|
("[submarinename1]", selectedSubmarine.DisplayName),
|
||||||
("[amount]", selectedSubmarine.Price.ToString()),
|
("[amount]", selectedSubmarine.Price.ToString()),
|
||||||
("[currencyname]", currencyLongText),
|
("[currencyname]", currencyName),
|
||||||
("[submarinename2]", CurrentOrPendingSubmarine().DisplayName)), messageBoxOptions);
|
("[submarinename2]", CurrentOrPendingSubmarine().DisplayName)), messageBoxOptions);
|
||||||
|
|
||||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||||
@@ -667,7 +666,7 @@ namespace Barotrauma
|
|||||||
msgBox = new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("purchasesubmarinetext",
|
msgBox = new GUIMessageBox(TextManager.Get("purchasesubmarineheader"), TextManager.GetWithVariables("purchasesubmarinetext",
|
||||||
("[submarinename]", selectedSubmarine.DisplayName),
|
("[submarinename]", selectedSubmarine.DisplayName),
|
||||||
("[amount]", selectedSubmarine.Price.ToString()),
|
("[amount]", selectedSubmarine.Price.ToString()),
|
||||||
("[currencyname]", currencyLongText)), messageBoxOptions);
|
("[currencyname]", currencyName)), messageBoxOptions);
|
||||||
|
|
||||||
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
msgBox.Buttons[0].OnClicked = (applyButton, obj) =>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -218,7 +218,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void AddToGUIUpdateList()
|
public void AddToGUIUpdateList()
|
||||||
{
|
{
|
||||||
infoFrame?.AddToGUIUpdateList();
|
infoFrame?.AddToGUIUpdateList(order: 1);
|
||||||
NetLobbyScreen.JobInfoFrame?.AddToGUIUpdateList();
|
NetLobbyScreen.JobInfoFrame?.AddToGUIUpdateList();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,8 +379,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void CreateCrewListFrame(GUIFrame crewFrame)
|
private void CreateCrewListFrame(GUIFrame crewFrame)
|
||||||
{
|
{
|
||||||
// FIXME remove TestScreen stuff
|
crew = GameMain.GameSession?.CrewManager?.GetCharacters() ?? Array.Empty<Character>();
|
||||||
crew = GameMain.GameSession?.CrewManager?.GetCharacters() ?? new []{ TestScreen.dummyCharacter };
|
|
||||||
teamIDs = crew.Select(c => c.TeamID).Distinct().ToList();
|
teamIDs = crew.Select(c => c.TeamID).Distinct().ToList();
|
||||||
|
|
||||||
// Show own team first when there's more than one team
|
// Show own team first when there's more than one team
|
||||||
@@ -817,8 +816,11 @@ namespace Barotrauma
|
|||||||
else if (client != null)
|
else if (client != null)
|
||||||
{
|
{
|
||||||
GUIComponent preview = CreateClientInfoFrame(background, client, GetPermissionIcon(client));
|
GUIComponent preview = CreateClientInfoFrame(background, client, GetPermissionIcon(client));
|
||||||
if (GameMain.NetworkMember != null) { GameMain.Client.SelectCrewClient(client, preview); }
|
GameMain.Client?.SelectCrewClient(client, preview);
|
||||||
CreateWalletFrame(background, client.Character);
|
if (client.Character != null)
|
||||||
|
{
|
||||||
|
CreateWalletFrame(background, client.Character);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -845,22 +847,23 @@ namespace Barotrauma
|
|||||||
float relativeX = icon.RectTransform.NonScaledSize.X / (float)icon.Parent.RectTransform.NonScaledSize.X;
|
float relativeX = icon.RectTransform.NonScaledSize.X / (float)icon.Parent.RectTransform.NonScaledSize.X;
|
||||||
GUILayoutGroup headerTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativeX, 1f), headerLayout.RectTransform), isHorizontal: true) { Stretch = true };
|
GUILayoutGroup headerTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1.0f - relativeX, 1f), headerLayout.RectTransform), isHorizontal: true) { Stretch = true };
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.Get("crewwallet.wallet"), font: GUIStyle.LargeFont);
|
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.Get("crewwallet.wallet"), font: GUIStyle.LargeFont);
|
||||||
GUITextBlock moneyBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), UpgradeStore.FormatCurrency(targetWallet.Balance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
|
GUITextBlock moneyBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), headerTextLayout.RectTransform), TextManager.FormatCurrency(targetWallet.Balance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
|
||||||
|
|
||||||
GUILayoutGroup middleLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), walletLayout.RectTransform));
|
GUILayoutGroup middleLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.66f), walletLayout.RectTransform));
|
||||||
GUILayoutGroup salaryTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true);
|
GUILayoutGroup salaryTextLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true);
|
||||||
GUITextBlock salaryTitle = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.Get("crewwallet.salary"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
|
GUITextBlock salaryTitle = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.Get("crewwallet.salary"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.BottomLeft);
|
||||||
GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), TextManager.GetWithVariable("percentageformat", "[value]", GetSharePercentage()), textAlignment: Alignment.BottomRight);
|
GUITextBlock rewardBlock = new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), salaryTextLayout.RectTransform), string.Empty, textAlignment: Alignment.BottomRight);
|
||||||
GUILayoutGroup sliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.Center);
|
GUILayoutGroup sliderLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), middleLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.Center);
|
||||||
GUIScrollBar salarySlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 1f), sliderLayout.RectTransform), style: "GUISlider", barSize: 0.03f)
|
GUIScrollBar salarySlider = new GUIScrollBar(new RectTransform(new Vector2(0.9f, 1f), sliderLayout.RectTransform), style: "GUISlider", barSize: 0.03f)
|
||||||
{
|
{
|
||||||
Range = Vector2.UnitY,
|
ToolTip = TextManager.Get("crewwallet.salary.tooltip"),
|
||||||
|
Range = new Vector2(0, 1),
|
||||||
BarScrollValue = targetWallet.RewardDistribution / 100f,
|
BarScrollValue = targetWallet.RewardDistribution / 100f,
|
||||||
Step = 0.01f,
|
Step = 0.01f,
|
||||||
BarSize = 0.1f,
|
BarSize = 0.1f,
|
||||||
OnMoved = (bar, scroll) =>
|
OnMoved = (bar, scroll) =>
|
||||||
{
|
{
|
||||||
rewardBlock.Text = TextManager.GetWithVariable("percentageformat", "[value]", GetSharePercentage());
|
SetRewardText((int)(scroll * 100), rewardBlock);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
OnReleased = (bar, scroll) =>
|
OnReleased = (bar, scroll) =>
|
||||||
@@ -871,6 +874,9 @@ namespace Barotrauma
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SetRewardText(targetWallet.RewardDistribution, rewardBlock);
|
||||||
|
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
GUIScissorComponent scissorComponent = new GUIScissorComponent(new RectTransform(new Vector2(0.85f, 1.25f), walletFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter))
|
GUIScissorComponent scissorComponent = new GUIScissorComponent(new RectTransform(new Vector2(0.85f, 1.25f), walletFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter))
|
||||||
{
|
{
|
||||||
@@ -883,7 +889,7 @@ namespace Barotrauma
|
|||||||
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), paddedTransferMenuLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.5f), paddedTransferMenuLayout.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||||
GUILayoutGroup leftLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1f), mainLayout.RectTransform));
|
GUILayoutGroup leftLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1f), mainLayout.RectTransform));
|
||||||
GUITextBlock leftName = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), leftLayout.RectTransform), character.Name, textAlignment: Alignment.CenterLeft, font: GUIStyle.SubHeadingFont);
|
GUITextBlock leftName = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), leftLayout.RectTransform), character.Name, textAlignment: Alignment.CenterLeft, font: GUIStyle.SubHeadingFont);
|
||||||
GUITextBlock leftBalance = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), leftLayout.RectTransform), UpgradeStore.FormatCurrency(targetWallet.Balance), textAlignment: Alignment.Left) { TextColor = GUIStyle.Blue };
|
GUITextBlock leftBalance = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), leftLayout.RectTransform), TextManager.FormatCurrency(targetWallet.Balance), textAlignment: Alignment.Left) { TextColor = GUIStyle.Blue };
|
||||||
GUILayoutGroup rightLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1f), mainLayout.RectTransform), childAnchor: Anchor.TopRight);
|
GUILayoutGroup rightLayout = new GUILayoutGroup(new RectTransform(new Vector2(0.5f, 1f), mainLayout.RectTransform), childAnchor: Anchor.TopRight);
|
||||||
GUITextBlock rightName = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), rightLayout.RectTransform), string.Empty, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight);
|
GUITextBlock rightName = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), rightLayout.RectTransform), string.Empty, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.CenterRight);
|
||||||
GUITextBlock rightBalance = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), rightLayout.RectTransform), string.Empty, textAlignment: Alignment.Right) { TextColor = GUIStyle.Red };
|
GUITextBlock rightBalance = new GUITextBlock(new RectTransform(new Vector2(1f, 0.5f), rightLayout.RectTransform), string.Empty, textAlignment: Alignment.Right) { TextColor = GUIStyle.Red };
|
||||||
@@ -902,8 +908,11 @@ namespace Barotrauma
|
|||||||
GUIButton confirmButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), centerButtonLayout.RectTransform), TextManager.Get("confirm"), style: "GUIButtonFreeScale") { Enabled = false };
|
GUIButton confirmButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), centerButtonLayout.RectTransform), TextManager.Get("confirm"), style: "GUIButtonFreeScale") { Enabled = false };
|
||||||
GUIButton resetButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), centerButtonLayout.RectTransform), TextManager.Get("reset"), style: "GUIButtonFreeScale") { Enabled = false };
|
GUIButton resetButton = new GUIButton(new RectTransform(new Vector2(0.5f, 1f), centerButtonLayout.RectTransform), TextManager.Get("reset"), style: "GUIButtonFreeScale") { Enabled = false };
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
|
ImmutableArray<GUILayoutGroup> layoutGroups = ImmutableArray.Create(transferMenuLayout, paddedTransferMenuLayout, mainLayout, leftLayout, rightLayout);
|
||||||
|
MedicalClinicUI.EnsureTextDoesntOverflow(character.Name, leftName, leftLayout.Rect, layoutGroups);
|
||||||
transferMenuButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), walletFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter), style: "UIToggleButtonVertical")
|
transferMenuButton = new GUIButton(new RectTransform(new Vector2(0.5f, 0.2f), walletFrame.RectTransform, Anchor.BottomCenter, Pivot.TopCenter), style: "UIToggleButtonVertical")
|
||||||
{
|
{
|
||||||
|
ToolTip = TextManager.Get("crewwallet.transfer.tooltip"),
|
||||||
OnClicked = (button, o) =>
|
OnClicked = (button, o) =>
|
||||||
{
|
{
|
||||||
isTransferMenuOpen = !isTransferMenuOpen;
|
isTransferMenuOpen = !isTransferMenuOpen;
|
||||||
@@ -951,13 +960,15 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MedicalClinicUI.EnsureTextDoesntOverflow(rightName.Text.ToString(), rightName, rightLayout.Rect, layoutGroups);
|
||||||
|
|
||||||
if (!hasPermissions)
|
if (!hasPermissions)
|
||||||
{
|
{
|
||||||
centerButton.Enabled = centerButton.CanBeFocused = false;
|
centerButton.Enabled = centerButton.CanBeFocused = false;
|
||||||
salarySlider.Enabled = salarySlider.CanBeFocused = false;
|
salarySlider.Enabled = salarySlider.CanBeFocused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
leftBalance.Text = UpgradeStore.FormatCurrency(otherWallet.Balance);
|
leftBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
||||||
|
|
||||||
UpdateAllInputs();
|
UpdateAllInputs();
|
||||||
|
|
||||||
@@ -983,7 +994,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (e.Wallet == targetWallet)
|
if (e.Wallet == targetWallet)
|
||||||
{
|
{
|
||||||
moneyBlock.Text = UpgradeStore.FormatCurrency(e.Info.Balance);
|
moneyBlock.Text = TextManager.FormatCurrency(e.Info.Balance);
|
||||||
salarySlider.BarScrollValue = e.Info.RewardDistribution / 100f;
|
salarySlider.BarScrollValue = e.Info.RewardDistribution / 100f;
|
||||||
}
|
}
|
||||||
UpdateAllInputs();
|
UpdateAllInputs();
|
||||||
@@ -1022,23 +1033,23 @@ namespace Barotrauma
|
|||||||
confirmButton.Enabled = resetButton.Enabled = transferAmountInput.IntValue > 0;
|
confirmButton.Enabled = resetButton.Enabled = transferAmountInput.IntValue > 0;
|
||||||
if (transferAmountInput.IntValue == 0)
|
if (transferAmountInput.IntValue == 0)
|
||||||
{
|
{
|
||||||
rightBalance.Text = UpgradeStore.FormatCurrency(otherWallet.Balance);
|
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance);
|
||||||
rightBalance.TextColor = GUIStyle.TextColorNormal;
|
rightBalance.TextColor = GUIStyle.TextColorNormal;
|
||||||
leftBalance.Text = UpgradeStore.FormatCurrency(targetWallet.Balance);
|
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance);
|
||||||
leftBalance.TextColor = GUIStyle.TextColorNormal;
|
leftBalance.TextColor = GUIStyle.TextColorNormal;
|
||||||
}
|
}
|
||||||
else if (isSending)
|
else if (isSending)
|
||||||
{
|
{
|
||||||
rightBalance.Text = UpgradeStore.FormatCurrency(otherWallet.Balance + transferAmountInput.IntValue);
|
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance + transferAmountInput.IntValue);
|
||||||
rightBalance.TextColor = GUIStyle.Blue;
|
rightBalance.TextColor = GUIStyle.Blue;
|
||||||
leftBalance.Text = UpgradeStore.FormatCurrency(targetWallet.Balance - transferAmountInput.IntValue);
|
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance - transferAmountInput.IntValue);
|
||||||
leftBalance.TextColor = GUIStyle.Red;
|
leftBalance.TextColor = GUIStyle.Red;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rightBalance.Text = UpgradeStore.FormatCurrency(otherWallet.Balance - transferAmountInput.IntValue);
|
rightBalance.Text = TextManager.FormatCurrency(otherWallet.Balance - transferAmountInput.IntValue);
|
||||||
rightBalance.TextColor = GUIStyle.Red;
|
rightBalance.TextColor = GUIStyle.Red;
|
||||||
leftBalance.Text = UpgradeStore.FormatCurrency(targetWallet.Balance + transferAmountInput.IntValue);
|
leftBalance.Text = TextManager.FormatCurrency(targetWallet.Balance + transferAmountInput.IntValue);
|
||||||
leftBalance.TextColor = GUIStyle.Blue;
|
leftBalance.TextColor = GUIStyle.Blue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1073,14 +1084,14 @@ namespace Barotrauma
|
|||||||
Receiver = to.Select(option => option.ID),
|
Receiver = to.Select(option => option.ID),
|
||||||
Amount = amount
|
Amount = amount
|
||||||
};
|
};
|
||||||
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.MONEY);
|
IWriteMessage msg = new WriteOnlyMessage().WithHeader(ClientPacketHeader.TRANSFER_MONEY);
|
||||||
transfer.Write(msg);
|
transfer.Write(msg);
|
||||||
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void SetRewardDistribution(Character character, int newValue)
|
static void SetRewardDistribution(Character character, int newValue)
|
||||||
{
|
{
|
||||||
INetSerializableStruct transfer = new NetWalletSalaryUpdate
|
INetSerializableStruct transfer = new NetWalletSetSalaryUpdate
|
||||||
{
|
{
|
||||||
Target = character.ID,
|
Target = character.ID,
|
||||||
NewRewardDistribution = newValue
|
NewRewardDistribution = newValue
|
||||||
@@ -1090,7 +1101,23 @@ namespace Barotrauma
|
|||||||
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
GameMain.Client?.ClientPeer?.Send(msg, DeliveryMethod.Reliable);
|
||||||
}
|
}
|
||||||
|
|
||||||
string GetSharePercentage() => Mission.GetRewardShare(targetWallet.RewardDistribution, salaryCrew, Option<int>.None()).Percentage.ToString();
|
void SetRewardText(int value, GUITextBlock block)
|
||||||
|
{
|
||||||
|
var (_, percentage, sum) = Mission.GetRewardShare(value, salaryCrew, Option<int>.None());
|
||||||
|
LocalizedString tooltip = string.Empty;
|
||||||
|
block.TextColor = GUIStyle.TextColorNormal;
|
||||||
|
|
||||||
|
if (sum > 100)
|
||||||
|
{
|
||||||
|
tooltip = TextManager.GetWithVariables("crewwallet.salary.over100toolitp", ("[sum]", $"{(int)sum}"), ("[newvalue]", $"{percentage}"));
|
||||||
|
block.TextColor = GUIStyle.Orange;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalizedString text = TextManager.GetWithVariable("percentageformat", "[value]", $"{value}");
|
||||||
|
|
||||||
|
block.Text = text;
|
||||||
|
block.ToolTip = RichString.Rich(tooltip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null)
|
private GUIComponent CreateClientInfoFrame(GUIFrame frame, Client client, Sprite permissionIcon = null)
|
||||||
|
|||||||
@@ -287,7 +287,7 @@ namespace Barotrauma
|
|||||||
GUILayoutGroup rightLayout = new GUILayoutGroup(rectT(0.5f, 1, topHeaderLayout), childAnchor: Anchor.TopRight);
|
GUILayoutGroup rightLayout = new GUILayoutGroup(rectT(0.5f, 1, topHeaderLayout), childAnchor: Anchor.TopRight);
|
||||||
GUILayoutGroup priceLayout = new GUILayoutGroup(rectT(1, 0.8f, rightLayout), childAnchor: Anchor.Center) { RelativeSpacing = 0.08f };
|
GUILayoutGroup priceLayout = new GUILayoutGroup(rectT(1, 0.8f, rightLayout), childAnchor: Anchor.Center) { RelativeSpacing = 0.08f };
|
||||||
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.Get("CampaignStore.Balance"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
|
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.Get("CampaignStore.Balance"), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right);
|
||||||
new GUITextBlock(rectT(1f, 0f, priceLayout), FormatCurrency(PlayerWallet.Balance, format: true), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right) { TextGetter = () => FormatCurrency(PlayerWallet.Balance, format: true) };
|
new GUITextBlock(rectT(1f, 0f, priceLayout), TextManager.FormatCurrency(PlayerWallet.Balance), font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Right) { TextGetter = () => TextManager.FormatCurrency(PlayerWallet.Balance) };
|
||||||
new GUIFrame(rectT(0.5f, 0.1f, rightLayout, Anchor.BottomRight), style: "HorizontalLine") { IgnoreLayoutGroups = true };
|
new GUIFrame(rectT(0.5f, 0.1f, rightLayout, Anchor.BottomRight), style: "HorizontalLine") { IgnoreLayoutGroups = true };
|
||||||
|
|
||||||
repairButton.OnClicked = upgradeButton.OnClicked = (button, o) =>
|
repairButton.OnClicked = upgradeButton.OnClicked = (button, o) =>
|
||||||
@@ -571,7 +571,7 @@ namespace Barotrauma
|
|||||||
var repairIcon = new GUIFrame(rectT(new Point(contentLayout.Rect.Height, contentLayout.Rect.Height), contentLayout), style: imageStyle);
|
var repairIcon = new GUIFrame(rectT(new Point(contentLayout.Rect.Height, contentLayout.Rect.Height), contentLayout), style: imageStyle);
|
||||||
GUILayoutGroup textLayout = new GUILayoutGroup(rectT(0.8f - repairIcon.RectTransform.RelativeSize.X, 1, contentLayout)) { Stretch = true };
|
GUILayoutGroup textLayout = new GUILayoutGroup(rectT(0.8f - repairIcon.RectTransform.RelativeSize.X, 1, contentLayout)) { Stretch = true };
|
||||||
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUIStyle.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
|
new GUITextBlock(rectT(1, 0, textLayout), title, font: GUIStyle.SubHeadingFont) { CanBeFocused = false, AutoScaleHorizontal = true };
|
||||||
new GUITextBlock(rectT(1, 0, textLayout), FormatCurrency(price));
|
new GUITextBlock(rectT(1, 0, textLayout), TextManager.FormatCurrency(price));
|
||||||
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = "buybutton" };
|
GUILayoutGroup buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, contentLayout), childAnchor: Anchor.Center) { UserData = "buybutton" };
|
||||||
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { ClickSound = GUISoundType.HireRepairClick, Enabled = PlayerWallet.Balance >= price && !isDisabled, OnClicked = onPressed };
|
new GUIButton(rectT(0.7f, 0.5f, buyButtonLayout), string.Empty, style: "RepairBuyButton") { ClickSound = GUISoundType.HireRepairClick, Enabled = PlayerWallet.Balance >= price && !isDisabled, OnClicked = onPressed };
|
||||||
contentLayout.Recalculate();
|
contentLayout.Recalculate();
|
||||||
@@ -1094,7 +1094,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (addBuyButton)
|
if (addBuyButton)
|
||||||
{
|
{
|
||||||
var formattedPrice = FormatCurrency(Math.Abs(price));
|
var formattedPrice = TextManager.FormatCurrency(Math.Abs(price));
|
||||||
//negative price = refund
|
//negative price = refund
|
||||||
if (price < 0) { formattedPrice = "+" + formattedPrice; }
|
if (price < 0) { formattedPrice = "+" + formattedPrice; }
|
||||||
buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, prefabLayout), childAnchor: Anchor.TopCenter) { UserData = "buybutton" };
|
buyButtonLayout = new GUILayoutGroup(rectT(0.2f, 1, prefabLayout), childAnchor: Anchor.TopCenter) { UserData = "buybutton" };
|
||||||
@@ -1577,7 +1577,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (priceLabel != null && !WaitForServerUpdate)
|
if (priceLabel != null && !WaitForServerUpdate)
|
||||||
{
|
{
|
||||||
priceLabel.Text = FormatCurrency(price);
|
priceLabel.Text = TextManager.FormatCurrency(price);
|
||||||
if (currentLevel >= prefab.MaxLevel)
|
if (currentLevel >= prefab.MaxLevel)
|
||||||
{
|
{
|
||||||
priceLabel.Text = TextManager.Get("Upgrade.MaxedUpgrade");
|
priceLabel.Text = TextManager.Get("Upgrade.MaxedUpgrade");
|
||||||
@@ -1695,11 +1695,6 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private bool HasPermission => campaignUI.Campaign.AllowedToManageCampaign();
|
private bool HasPermission => campaignUI.Campaign.AllowedToManageCampaign();
|
||||||
|
|
||||||
public static LocalizedString FormatCurrency(int money, bool format = true)
|
|
||||||
{
|
|
||||||
return TextManager.GetWithVariable("CurrencyFormat", "[credits]", format ? string.Format(CultureInfo.InvariantCulture, "{0:N0}", money) : money.ToString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// just a shortcut to create new RectTransforms since all the new RectTransform and new Vector2 confuses my IDE (and me)
|
// just a shortcut to create new RectTransforms since all the new RectTransform and new Vector2 confuses my IDE (and me)
|
||||||
private static RectTransform rectT(float x, float y, GUIComponent parentComponent, Anchor anchor = Anchor.TopLeft, ScaleBasis scaleBasis = ScaleBasis.Normal)
|
private static RectTransform rectT(float x, float y, GUIComponent parentComponent, Anchor anchor = Anchor.TopLeft, ScaleBasis scaleBasis = ScaleBasis.Normal)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1038,9 +1038,9 @@ namespace Barotrauma
|
|||||||
// Update store stock when saving and quitting in an outpost (normally updated when CampaignMode.End() is called)
|
// Update store stock when saving and quitting in an outpost (normally updated when CampaignMode.End() is called)
|
||||||
if (GameSession?.Campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedOutpost && spCampaign.Map?.CurrentLocation != null && spCampaign.CargoManager != null)
|
if (GameSession?.Campaign is SinglePlayerCampaign spCampaign && Level.IsLoadedOutpost && spCampaign.Map?.CurrentLocation != null && spCampaign.CargoManager != null)
|
||||||
{
|
{
|
||||||
spCampaign.Map.CurrentLocation.AddToStock(spCampaign.CargoManager.SoldItems);
|
spCampaign.Map.CurrentLocation.AddStock(spCampaign.CargoManager.SoldItems);
|
||||||
spCampaign.CargoManager.ClearSoldItemsProjSpecific();
|
spCampaign.CargoManager.ClearSoldItemsProjSpecific();
|
||||||
spCampaign.Map.CurrentLocation.RemoveFromStock(spCampaign.CargoManager.PurchasedItems);
|
spCampaign.Map.CurrentLocation.RemoveStock(spCampaign.CargoManager.PurchasedItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveUtil.SaveGame(GameSession.SavePath);
|
SaveUtil.SaveGame(GameSession.SavePath);
|
||||||
|
|||||||
@@ -45,28 +45,37 @@ namespace Barotrauma
|
|||||||
return SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
|
return SoldEntities.Where(se => se.Status != SoldEntity.SellStatus.Unconfirmed);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetItemsInBuyCrate(List<PurchasedItem> items)
|
public void SetItemsInBuyCrate(Dictionary<Identifier, List<PurchasedItem>> items)
|
||||||
{
|
{
|
||||||
ItemsInBuyCrate.Clear();
|
ItemsInBuyCrate.Clear();
|
||||||
ItemsInBuyCrate.AddRange(items);
|
foreach (var entry in items)
|
||||||
|
{
|
||||||
|
ItemsInBuyCrate.Add(entry.Key, entry.Value);
|
||||||
|
}
|
||||||
OnItemsInBuyCrateChanged?.Invoke();
|
OnItemsInBuyCrateChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetItemsInSubSellCrate(List<PurchasedItem> items)
|
public void SetItemsInSubSellCrate(Dictionary<Identifier, List<PurchasedItem>> items)
|
||||||
{
|
{
|
||||||
ItemsInSellFromSubCrate.Clear();
|
ItemsInSellFromSubCrate.Clear();
|
||||||
ItemsInSellFromSubCrate.AddRange(items);
|
foreach (var entry in items)
|
||||||
|
{
|
||||||
|
ItemsInSellFromSubCrate.Add(entry.Key, entry.Value);
|
||||||
|
}
|
||||||
OnItemsInSellFromSubCrateChanged?.Invoke();
|
OnItemsInSellFromSubCrateChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetSoldItems(List<SoldItem> items)
|
public void SetSoldItems(Dictionary<Identifier, List<SoldItem>> items)
|
||||||
{
|
{
|
||||||
SoldItems.Clear();
|
SoldItems.Clear();
|
||||||
SoldItems.AddRange(items);
|
foreach (var entry in items)
|
||||||
|
{
|
||||||
|
SoldItems.Add(entry.Key, entry.Value);
|
||||||
|
}
|
||||||
foreach (var se in SoldEntities)
|
foreach (var se in SoldEntities)
|
||||||
{
|
{
|
||||||
if (se.Status == SoldEntity.SellStatus.Confirmed) { continue; }
|
if (se.Status == SoldEntity.SellStatus.Confirmed) { continue; }
|
||||||
if (SoldItems.Any(si => Match(si, se, true)))
|
if (SoldItems.Any(si => si.Value.Any(si => Match(si, se, true))))
|
||||||
{
|
{
|
||||||
se.Status = SoldEntity.SellStatus.Confirmed;
|
se.Status = SoldEntity.SellStatus.Confirmed;
|
||||||
}
|
}
|
||||||
@@ -75,13 +84,16 @@ namespace Barotrauma
|
|||||||
se.Status = SoldEntity.SellStatus.Unconfirmed;
|
se.Status = SoldEntity.SellStatus.Unconfirmed;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
foreach (var si in SoldItems)
|
foreach (var soldItems in SoldItems.Values)
|
||||||
{
|
{
|
||||||
if (si.Origin != SoldItem.SellOrigin.Submarine) { continue; }
|
foreach (var si in soldItems)
|
||||||
if (!(SoldEntities.FirstOrDefault(se => se.Item == null && Match(si, se, false)) is SoldEntity soldEntityMatch)) { continue; }
|
{
|
||||||
if (!(Entity.FindEntityByID(si.ID) is Item item)) { continue; }
|
if (si.Origin != SoldItem.SellOrigin.Submarine) { continue; }
|
||||||
soldEntityMatch.SetItem(item);
|
if (!(SoldEntities.FirstOrDefault(se => se.Item == null && Match(si, se, false)) is SoldEntity soldEntityMatch)) { continue; }
|
||||||
soldEntityMatch.Status = SoldEntity.SellStatus.Confirmed;
|
if (!(Entity.FindEntityByID(si.ID) is Item item)) { continue; }
|
||||||
|
soldEntityMatch.SetItem(item);
|
||||||
|
soldEntityMatch.Status = SoldEntity.SellStatus.Confirmed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
OnSoldItemsChanged?.Invoke();
|
OnSoldItemsChanged?.Invoke();
|
||||||
|
|
||||||
@@ -94,45 +106,24 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ModifyItemQuantityInSellCrate(ItemPrefab itemPrefab, int changeInQuantity)
|
public void ModifyItemQuantityInSellCrate(Identifier storeIdentifier, ItemPrefab itemPrefab, int changeInQuantity)
|
||||||
{
|
{
|
||||||
var itemToSell = ItemsInSellCrate.Find(i => i.ItemPrefab == itemPrefab);
|
if (GetSellCrateItem(storeIdentifier, itemPrefab) is { } item)
|
||||||
if (itemToSell != null)
|
|
||||||
{
|
{
|
||||||
itemToSell.Quantity += changeInQuantity;
|
item.Quantity += changeInQuantity;
|
||||||
if (itemToSell.Quantity < 1)
|
if (item.Quantity < 1)
|
||||||
{
|
{
|
||||||
ItemsInSellCrate.Remove(itemToSell);
|
GetSellCrateItems(storeIdentifier)?.Remove(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (changeInQuantity > 0)
|
else if (changeInQuantity > 0)
|
||||||
{
|
{
|
||||||
itemToSell = new PurchasedItem(itemPrefab, changeInQuantity);
|
GetSellCrateItems(storeIdentifier, create: true).Add(new PurchasedItem(itemPrefab, changeInQuantity));
|
||||||
ItemsInSellCrate.Add(itemToSell);
|
|
||||||
}
|
}
|
||||||
OnItemsInSellCrateChanged?.Invoke();
|
OnItemsInSellCrateChanged?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ModifyItemQuantityInSellFromSubCrate(ItemPrefab itemPrefab, int changeInQuantity)
|
public void SellItems(Identifier storeIdentifier, List<PurchasedItem> itemsToSell, Store.StoreTab sellingMode)
|
||||||
{
|
|
||||||
var itemToSell = ItemsInSellFromSubCrate.Find(i => i.ItemPrefab == itemPrefab);
|
|
||||||
if (itemToSell != null)
|
|
||||||
{
|
|
||||||
itemToSell.Quantity += changeInQuantity;
|
|
||||||
if (itemToSell.Quantity < 1)
|
|
||||||
{
|
|
||||||
ItemsInSellFromSubCrate.Remove(itemToSell);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (changeInQuantity > 0)
|
|
||||||
{
|
|
||||||
itemToSell = new PurchasedItem(itemPrefab, changeInQuantity);
|
|
||||||
ItemsInSellFromSubCrate.Add(itemToSell);
|
|
||||||
}
|
|
||||||
OnItemsInSellFromSubCrateChanged?.Invoke();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SellItems(List<PurchasedItem> itemsToSell, Store.StoreTab sellingMode)
|
|
||||||
{
|
{
|
||||||
IEnumerable<Item> sellableItems;
|
IEnumerable<Item> sellableItems;
|
||||||
try
|
try
|
||||||
@@ -146,19 +137,24 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
catch (NotImplementedException e)
|
catch (NotImplementedException e)
|
||||||
{
|
{
|
||||||
DebugConsole.ShowError($"Error selling items: Uknown store tab type. {e.StackTrace.CleanupStackTrace()}");
|
DebugConsole.ShowError($"Error selling items: uknown store tab type \"{sellingMode}\".\n{e.StackTrace.CleanupStackTrace()}");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
bool canAddToRemoveQueue = campaign.IsSinglePlayer && Entity.Spawner != null;
|
bool canAddToRemoveQueue = campaign.IsSinglePlayer && Entity.Spawner != null;
|
||||||
byte sellerId = GameMain.Client?.ID ?? 0;
|
byte sellerId = GameMain.Client?.ID ?? 0;
|
||||||
// Check all the prices before starting the transaction
|
// Check all the prices before starting the transaction to make sure the modifiers stay the same for the whole transaction
|
||||||
// to make sure the modifiers stay the same for the whole transaction
|
var sellValues = GetSellValuesAtCurrentLocation(storeIdentifier, itemsToSell.Select(i => i.ItemPrefab));
|
||||||
Dictionary<ItemPrefab, int> sellValues = GetSellValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
|
if (!(Location.GetStore(storeIdentifier) is { } store))
|
||||||
foreach (PurchasedItem item in itemsToSell)
|
{
|
||||||
|
DebugConsole.ShowError($"Error selling items at {Location}: no store with identifier \"{storeIdentifier}\" exists.\n{Environment.StackTrace.CleanupStackTrace()}");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var storeSpecificSoldItems = GetSoldItems(storeIdentifier, create: true);
|
||||||
|
foreach (var item in itemsToSell)
|
||||||
{
|
{
|
||||||
int itemValue = item.Quantity * sellValues[item.ItemPrefab];
|
int itemValue = item.Quantity * sellValues[item.ItemPrefab];
|
||||||
// check if the store can afford the item
|
// check if the store can afford the item
|
||||||
if (Location.StoreCurrentBalance < itemValue) { continue; }
|
if (store.Balance < itemValue) { continue; }
|
||||||
// TODO: Write logic for prioritizing certain items over others (e.g. lone Battery Cell should be preferred over one inside a Stun Baton)
|
// TODO: Write logic for prioritizing certain items over others (e.g. lone Battery Cell should be preferred over one inside a Stun Baton)
|
||||||
var matchingItems = sellableItems.Where(i => i.Prefab == item.ItemPrefab);
|
var matchingItems = sellableItems.Where(i => i.Prefab == item.ItemPrefab);
|
||||||
int count = Math.Min(item.Quantity, matchingItems.Count());
|
int count = Math.Min(item.Quantity, matchingItems.Count());
|
||||||
@@ -168,7 +164,7 @@ namespace Barotrauma
|
|||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
var matchingItem = matchingItems.ElementAt(i);
|
var matchingItem = matchingItems.ElementAt(i);
|
||||||
SoldItems.Add(new SoldItem(matchingItem.Prefab, matchingItem.ID, canAddToRemoveQueue, sellerId, origin));
|
storeSpecificSoldItems.Add(new SoldItem(matchingItem.Prefab, matchingItem.ID, canAddToRemoveQueue, sellerId, origin));
|
||||||
SoldEntities.Add(new SoldEntity(matchingItem, campaign.IsSinglePlayer ? SoldEntity.SellStatus.Confirmed : SoldEntity.SellStatus.Local));
|
SoldEntities.Add(new SoldEntity(matchingItem, campaign.IsSinglePlayer ? SoldEntity.SellStatus.Confirmed : SoldEntity.SellStatus.Local));
|
||||||
if (canAddToRemoveQueue) { Entity.Spawner.AddItemToRemoveQueue(matchingItem); }
|
if (canAddToRemoveQueue) { Entity.Spawner.AddItemToRemoveQueue(matchingItem); }
|
||||||
}
|
}
|
||||||
@@ -178,22 +174,23 @@ namespace Barotrauma
|
|||||||
// When selling from the sub in multiplayer, the server will determine the items that are sold
|
// When selling from the sub in multiplayer, the server will determine the items that are sold
|
||||||
for (int i = 0; i < count; i++)
|
for (int i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
SoldItems.Add(new SoldItem(item.ItemPrefab, Entity.NullEntityID, canAddToRemoveQueue, sellerId, origin));
|
storeSpecificSoldItems.Add(new SoldItem(item.ItemPrefab, Entity.NullEntityID, canAddToRemoveQueue, sellerId, origin));
|
||||||
SoldEntities.Add(new SoldEntity(item.ItemPrefab, SoldEntity.SellStatus.Local));
|
SoldEntities.Add(new SoldEntity(item.ItemPrefab, SoldEntity.SellStatus.Local));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Exchange money
|
// Exchange money
|
||||||
Location.StoreCurrentBalance -= itemValue;
|
store.Balance -= itemValue;
|
||||||
campaign.Bank.Give(itemValue);
|
campaign.Bank.Give(itemValue);
|
||||||
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value);
|
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value);
|
||||||
|
|
||||||
// Remove from the sell crate
|
// Remove from the sell crate
|
||||||
if ((sellingMode == Store.StoreTab.Sell ? ItemsInSellCrate : ItemsInSellFromSubCrate)?.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } itemToSell)
|
var sellCrate = (sellingMode == Store.StoreTab.Sell ? GetSellCrateItems(storeIdentifier) : GetSubCrateItems(storeIdentifier));
|
||||||
|
if (sellCrate?.Find(pi => pi.ItemPrefab == item.ItemPrefab) is { } itemToSell)
|
||||||
{
|
{
|
||||||
itemToSell.Quantity -= item.Quantity;
|
itemToSell.Quantity -= item.Quantity;
|
||||||
if (itemToSell.Quantity < 1)
|
if (itemToSell.Quantity < 1)
|
||||||
{
|
{
|
||||||
(sellingMode == Store.StoreTab.Sell ? ItemsInSellCrate : ItemsInSellFromSubCrate)?.Remove(itemToSell);
|
sellCrate.Remove(itemToSell);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,6 +63,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the current personal wallet
|
||||||
|
/// In singleplayer this is the campaign bank and in multiplayer this is the personal wallet
|
||||||
|
/// </summary>
|
||||||
public virtual Wallet Wallet => GetWallet();
|
public virtual Wallet Wallet => GetWallet();
|
||||||
|
|
||||||
public override void ShowStartMessage()
|
public override void ShowStartMessage()
|
||||||
@@ -301,7 +305,7 @@ namespace Barotrauma
|
|||||||
goto default;
|
goto default;
|
||||||
default:
|
default:
|
||||||
ShowCampaignUI = true;
|
ShowCampaignUI = true;
|
||||||
CampaignUI.SelectTab(npc.CampaignInteractionType);
|
CampaignUI.SelectTab(npc.CampaignInteractionType, storeIdentifier: npc.MerchantIdentifier);
|
||||||
CampaignUI.UpgradeStore?.RefreshAll();
|
CampaignUI.UpgradeStore?.RefreshAll();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-72
@@ -553,36 +553,10 @@ namespace Barotrauma
|
|||||||
msg.Write(PurchasedItemRepairs);
|
msg.Write(PurchasedItemRepairs);
|
||||||
msg.Write(PurchasedLostShuttles);
|
msg.Write(PurchasedLostShuttles);
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.ItemsInBuyCrate.Count);
|
WriteItems(msg, CargoManager.ItemsInBuyCrate);
|
||||||
foreach (PurchasedItem pi in CargoManager.ItemsInBuyCrate)
|
WriteItems(msg, CargoManager.ItemsInSellFromSubCrate);
|
||||||
{
|
WriteItems(msg, CargoManager.PurchasedItems);
|
||||||
msg.Write(pi.ItemPrefab.Identifier);
|
WriteItems(msg, CargoManager.SoldItems);
|
||||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.ItemsInSellFromSubCrate.Count);
|
|
||||||
foreach (PurchasedItem pi in CargoManager.ItemsInSellFromSubCrate)
|
|
||||||
{
|
|
||||||
msg.Write(pi.ItemPrefab.Identifier);
|
|
||||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
|
|
||||||
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
|
|
||||||
{
|
|
||||||
msg.Write(pi.ItemPrefab.Identifier);
|
|
||||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.SoldItems.Count);
|
|
||||||
foreach (SoldItem si in CargoManager.SoldItems)
|
|
||||||
{
|
|
||||||
msg.Write(si.ItemPrefab.Identifier);
|
|
||||||
msg.Write((UInt16)si.ID);
|
|
||||||
msg.Write(si.Removed);
|
|
||||||
msg.Write(si.SellerID);
|
|
||||||
msg.Write((byte)si.Origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Write((ushort)UpgradeManager.PurchasedUpgrades.Count);
|
msg.Write((ushort)UpgradeManager.PurchasedUpgrades.Count);
|
||||||
foreach (var (prefab, category, level) in UpgradeManager.PurchasedUpgrades)
|
foreach (var (prefab, category, level) in UpgradeManager.PurchasedUpgrades)
|
||||||
@@ -644,50 +618,22 @@ namespace Barotrauma
|
|||||||
availableMissions.Add((missionIdentifier, connectionIndex));
|
availableMissions.Add((missionIdentifier, connectionIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt16? storeBalance = null;
|
var storeBalances = new Dictionary<Identifier, UInt16>();
|
||||||
if (msg.ReadBoolean())
|
if (msg.ReadBoolean())
|
||||||
{
|
{
|
||||||
storeBalance = msg.ReadUInt16();
|
byte storeCount = msg.ReadByte();
|
||||||
|
for (int i = 0; i < storeCount; i++)
|
||||||
|
{
|
||||||
|
Identifier identifier = msg.ReadIdentifier();
|
||||||
|
UInt16 storeBalance = msg.ReadUInt16();
|
||||||
|
storeBalances.Add(identifier, storeBalance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UInt16 buyCrateItemCount = msg.ReadUInt16();
|
var buyCrateItems = ReadPurchasedItems(msg, sender: null);
|
||||||
List<PurchasedItem> buyCrateItems = new List<PurchasedItem>();
|
var subSellCrateItems = ReadPurchasedItems(msg, sender: null);
|
||||||
for (int i = 0; i < buyCrateItemCount; i++)
|
var purchasedItems = ReadPurchasedItems(msg, sender: null);
|
||||||
{
|
var soldItems = ReadSoldItems(msg);
|
||||||
Identifier itemPrefabIdentifier = msg.ReadIdentifier();
|
|
||||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
|
||||||
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt16 subSellCrateItemCount = msg.ReadUInt16();
|
|
||||||
List<PurchasedItem> subSellCrateItems = new List<PurchasedItem>();
|
|
||||||
for (int i = 0; i < subSellCrateItemCount; i++)
|
|
||||||
{
|
|
||||||
string itemPrefabIdentifier = msg.ReadString();
|
|
||||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
|
||||||
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt16 purchasedItemCount = msg.ReadUInt16();
|
|
||||||
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
|
|
||||||
for (int i = 0; i < purchasedItemCount; i++)
|
|
||||||
{
|
|
||||||
Identifier itemPrefabIdentifier = msg.ReadIdentifier();
|
|
||||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
|
||||||
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity));
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt16 soldItemCount = msg.ReadUInt16();
|
|
||||||
List<SoldItem> soldItems = new List<SoldItem>();
|
|
||||||
for (int i = 0; i < soldItemCount; i++)
|
|
||||||
{
|
|
||||||
Identifier itemPrefabIdentifier = msg.ReadIdentifier();
|
|
||||||
UInt16 id = msg.ReadUInt16();
|
|
||||||
bool removed = msg.ReadBoolean();
|
|
||||||
byte sellerId = msg.ReadByte();
|
|
||||||
byte origin = msg.ReadByte();
|
|
||||||
soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId, (SoldItem.SellOrigin)origin));
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort pendingUpgradeCount = msg.ReadUInt16();
|
ushort pendingUpgradeCount = msg.ReadUInt16();
|
||||||
List<PurchasedUpgrade> pendingUpgrades = new List<PurchasedUpgrade>();
|
List<PurchasedUpgrade> pendingUpgrades = new List<PurchasedUpgrade>();
|
||||||
@@ -756,7 +702,13 @@ namespace Barotrauma
|
|||||||
campaign.CargoManager.SetItemsInSubSellCrate(subSellCrateItems);
|
campaign.CargoManager.SetItemsInSubSellCrate(subSellCrateItems);
|
||||||
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
campaign.CargoManager.SetPurchasedItems(purchasedItems);
|
||||||
campaign.CargoManager.SetSoldItems(soldItems);
|
campaign.CargoManager.SetSoldItems(soldItems);
|
||||||
if (storeBalance.HasValue) { campaign.Map.CurrentLocation.StoreCurrentBalance = storeBalance.Value; }
|
foreach (var balance in storeBalances)
|
||||||
|
{
|
||||||
|
if (campaign.Map.CurrentLocation.GetStore(balance.Key) is { } store)
|
||||||
|
{
|
||||||
|
store.Balance = balance.Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
|
campaign.UpgradeManager.SetPendingUpgrades(pendingUpgrades);
|
||||||
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
campaign.UpgradeManager.PurchasedUpgrades.Clear();
|
||||||
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
foreach (var purchasedItemSwap in purchasedItemSwaps)
|
||||||
@@ -914,7 +866,7 @@ namespace Barotrauma
|
|||||||
WalletInfo info = transaction.Info;
|
WalletInfo info = transaction.Info;
|
||||||
switch (transaction.CharacterID)
|
switch (transaction.CharacterID)
|
||||||
{
|
{
|
||||||
case Some<ushort> { Value: var charID}:
|
case Some<ushort> { Value: var charID }:
|
||||||
{
|
{
|
||||||
Character targetCharacter = Character.CharacterList?.FirstOrDefault(c => c.ID == charID);
|
Character targetCharacter = Character.CharacterList?.FirstOrDefault(c => c.ID == charID);
|
||||||
if (targetCharacter is null) { break; }
|
if (targetCharacter is null) { break; }
|
||||||
|
|||||||
+1
-1
@@ -121,7 +121,7 @@ namespace Barotrauma.Tutorials
|
|||||||
return new CharacterInfo(
|
return new CharacterInfo(
|
||||||
CharacterPrefab.HumanSpeciesName,
|
CharacterPrefab.HumanSpeciesName,
|
||||||
jobOrJobPrefab: new Job(
|
jobOrJobPrefab: new Job(
|
||||||
JobPrefab.Prefabs["medicaldoctor"], Rand.RandSync.Unsynced, 0,
|
JobPrefab.Prefabs["engineer"], Rand.RandSync.Unsynced, 0,
|
||||||
new Skill("medical".ToIdentifier(), 0),
|
new Skill("medical".ToIdentifier(), 0),
|
||||||
new Skill("weapons".ToIdentifier(), 0),
|
new Skill("weapons".ToIdentifier(), 0),
|
||||||
new Skill("mechanical".ToIdentifier(), 20),
|
new Skill("mechanical".ToIdentifier(), 20),
|
||||||
|
|||||||
+1
-1
@@ -147,7 +147,7 @@ namespace Barotrauma.Tutorials
|
|||||||
return new CharacterInfo(
|
return new CharacterInfo(
|
||||||
CharacterPrefab.HumanSpeciesName,
|
CharacterPrefab.HumanSpeciesName,
|
||||||
jobOrJobPrefab: new Job(
|
jobOrJobPrefab: new Job(
|
||||||
JobPrefab.Prefabs["medicaldoctor"], Rand.RandSync.Unsynced, 0,
|
JobPrefab.Prefabs["mechanic"], Rand.RandSync.Unsynced, 0,
|
||||||
new Skill("medical".ToIdentifier(), 0),
|
new Skill("medical".ToIdentifier(), 0),
|
||||||
new Skill("weapons".ToIdentifier(), 0),
|
new Skill("weapons".ToIdentifier(), 0),
|
||||||
new Skill("mechanical".ToIdentifier(), 50),
|
new Skill("mechanical".ToIdentifier(), 50),
|
||||||
|
|||||||
+1
-1
@@ -128,7 +128,7 @@ namespace Barotrauma.Tutorials
|
|||||||
return new CharacterInfo(
|
return new CharacterInfo(
|
||||||
CharacterPrefab.HumanSpeciesName,
|
CharacterPrefab.HumanSpeciesName,
|
||||||
jobOrJobPrefab: new Job(
|
jobOrJobPrefab: new Job(
|
||||||
JobPrefab.Prefabs["medicaldoctor"], Rand.RandSync.Unsynced, 0,
|
JobPrefab.Prefabs["securityofficer"], Rand.RandSync.Unsynced, 0,
|
||||||
new Skill("medical".ToIdentifier(), 20),
|
new Skill("medical".ToIdentifier(), 20),
|
||||||
new Skill("weapons".ToIdentifier(), 70),
|
new Skill("weapons".ToIdentifier(), 70),
|
||||||
new Skill("mechanical".ToIdentifier(), 20),
|
new Skill("mechanical".ToIdentifier(), 20),
|
||||||
|
|||||||
@@ -318,7 +318,7 @@ namespace Barotrauma
|
|||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), RichString.Rich(displayedMission.GetMissionRewardText(Submarine.MainSub)));
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), missionTextContent.RectTransform), RichString.Rich(displayedMission.GetMissionRewardText(Submarine.MainSub)));
|
||||||
if (GameMain.IsMultiplayer && Character.Controlled is { } controlled)
|
if (GameMain.IsMultiplayer && Character.Controlled is { } controlled)
|
||||||
{
|
{
|
||||||
var (share, percentage) = Mission.GetRewardShare(controlled.Wallet.RewardDistribution, Mission.GetSalaryEligibleCrew(), Option<int>.Some(reward));
|
var (share, percentage, _) = Mission.GetRewardShare(controlled.Wallet.RewardDistribution, Mission.GetSalaryEligibleCrew().Where(c => c != controlled), Option<int>.Some(reward));
|
||||||
if (share > 0)
|
if (share > 0)
|
||||||
{
|
{
|
||||||
string shareFormatted = string.Format(CultureInfo.InvariantCulture, "{0:N0}", share);
|
string shareFormatted = string.Format(CultureInfo.InvariantCulture, "{0:N0}", share);
|
||||||
|
|||||||
@@ -966,7 +966,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else if (character.HeldItems.Any(i =>
|
else if (character.HeldItems.Any(i =>
|
||||||
i.OwnInventory != null &&
|
i.OwnInventory != null &&
|
||||||
(i.OwnInventory.CanBePut(item) || (i.OwnInventory.Capacity == 1 && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item)))))
|
((i.OwnInventory.CanBePut(item) && allowInventorySwap) || (i.OwnInventory.Capacity == 1 && i.OwnInventory.AllowSwappingContainedItems && i.OwnInventory.Container.CanBeContained(item)))))
|
||||||
{
|
{
|
||||||
return QuickUseAction.PutToEquippedItem;
|
return QuickUseAction.PutToEquippedItem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ namespace Barotrauma.Items.Components
|
|||||||
ContentXElement spriteElement = limbElement.GetChildElement("sprite");
|
ContentXElement spriteElement = limbElement.GetChildElement("sprite");
|
||||||
if (spriteElement == null) { continue; }
|
if (spriteElement == null) { continue; }
|
||||||
|
|
||||||
string spritePath = spriteElement.Attribute("texture").Value;
|
string spritePath = spriteElement.GetAttribute("texture").Value;
|
||||||
|
|
||||||
spritePath = characterInfo.ReplaceVars(spritePath);
|
spritePath = characterInfo.ReplaceVars(spritePath);
|
||||||
|
|
||||||
|
|||||||
@@ -462,7 +462,7 @@ namespace Barotrauma.Items.Components
|
|||||||
switch (subElement.Name.ToString().ToLowerInvariant())
|
switch (subElement.Name.ToString().ToLowerInvariant())
|
||||||
{
|
{
|
||||||
case "guiframe":
|
case "guiframe":
|
||||||
if (subElement.Attribute("rect") != null)
|
if (subElement.GetAttribute("rect") != null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Error in item config \"{item.ConfigFilePath}\" - GUIFrame defined as rect, use RectTransform instead.");
|
DebugConsole.ThrowError($"Error in item config \"{item.ConfigFilePath}\" - GUIFrame defined as rect, use RectTransform instead.");
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
using System;
|
using Microsoft.Xna.Framework;
|
||||||
using System.Linq;
|
|
||||||
using System.Xml.Linq;
|
|
||||||
using Microsoft.Xna.Framework;
|
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,12 +2,14 @@
|
|||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Barotrauma.Items.Components
|
namespace Barotrauma.Items.Components
|
||||||
{
|
{
|
||||||
partial class ItemLabel : ItemComponent, IDrawableComponent
|
partial class ItemLabel : ItemComponent, IDrawableComponent, IHasExtraTextPickerEntries
|
||||||
{
|
{
|
||||||
private GUITextBlock textBlock;
|
private GUITextBlock textBlock;
|
||||||
|
|
||||||
@@ -94,7 +96,15 @@ namespace Barotrauma.Items.Components
|
|||||||
get { return textBlock == null ? 1.0f : textBlock.TextScale; }
|
get { return textBlock == null ? 1.0f : textBlock.TextScale; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (textBlock != null) { textBlock.TextScale = MathHelper.Clamp(value, 0.1f, 10.0f); }
|
if (textBlock != null)
|
||||||
|
{
|
||||||
|
float prevScale = TextBlock.TextScale;
|
||||||
|
textBlock.TextScale = MathHelper.Clamp(value, 0.1f, 10.0f);
|
||||||
|
if (!MathUtils.NearlyEqual(prevScale, TextBlock.TextScale))
|
||||||
|
{
|
||||||
|
SetScrollingText();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +116,7 @@ namespace Barotrauma.Items.Components
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
scrollable = value;
|
scrollable = value;
|
||||||
IsActive = value;
|
IsActive = value || parseSpecialTextTagOnStart;
|
||||||
TextBlock.Wrap = !scrollable;
|
TextBlock.Wrap = !scrollable;
|
||||||
TextBlock.TextAlignment = scrollable ? Alignment.CenterLeft : Alignment.Center;
|
TextBlock.TextAlignment = scrollable ? Alignment.CenterLeft : Alignment.Center;
|
||||||
}
|
}
|
||||||
@@ -136,18 +146,23 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> GetExtraTextPickerEntries()
|
||||||
|
{
|
||||||
|
return SpecialTextTags;
|
||||||
|
}
|
||||||
|
|
||||||
private void SetScrollingText()
|
private void SetScrollingText()
|
||||||
{
|
{
|
||||||
if (!scrollable) { return; }
|
if (!scrollable) { return; }
|
||||||
|
|
||||||
float totalWidth = textBlock.Font.MeasureString(DisplayText).X;
|
float totalWidth = textBlock.Font.MeasureString(DisplayText).X * TextBlock.TextScale;
|
||||||
float textAreaWidth = Math.Max(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z, 0);
|
float textAreaWidth = Math.Max(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z, 0);
|
||||||
if (totalWidth >= textAreaWidth)
|
if (totalWidth >= textAreaWidth)
|
||||||
{
|
{
|
||||||
//add enough spaces to fill the rect
|
//add enough spaces to fill the rect
|
||||||
//(so the text can scroll entirely out of view before we reset it back to start)
|
//(so the text can scroll entirely out of view before we reset it back to start)
|
||||||
needsScrolling = true;
|
needsScrolling = true;
|
||||||
float spaceWidth = textBlock.Font.MeasureChar(' ').X;
|
float spaceWidth = textBlock.Font.MeasureChar(' ').X * TextBlock.TextScale;
|
||||||
scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + DisplayText.Value;
|
scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + DisplayText.Value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -166,7 +181,7 @@ namespace Barotrauma.Items.Components
|
|||||||
charWidths = new float[scrollingText.Length];
|
charWidths = new float[scrollingText.Length];
|
||||||
for (int i = 0; i < scrollingText.Length; i++)
|
for (int i = 0; i < scrollingText.Length; i++)
|
||||||
{
|
{
|
||||||
float charWidth = TextBlock.Font.MeasureChar(scrollingText[i]).X;
|
float charWidth = TextBlock.Font.MeasureChar(scrollingText[i]).X * TextBlock.TextScale;
|
||||||
scrollPadding = Math.Max(charWidth, scrollPadding);
|
scrollPadding = Math.Max(charWidth, scrollPadding);
|
||||||
charWidths[i] = charWidth;
|
charWidths[i] = charWidth;
|
||||||
}
|
}
|
||||||
@@ -174,9 +189,18 @@ namespace Barotrauma.Items.Components
|
|||||||
scrollIndex = MathHelper.Clamp(scrollIndex, 0, DisplayText.Length);
|
scrollIndex = MathHelper.Clamp(scrollIndex, 0, DisplayText.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static readonly string[] SpecialTextTags = new string[] { "[CurrentLocationName]", "[CurrentBiomeName]", "[CurrentSubName]" };
|
||||||
|
private bool parseSpecialTextTagOnStart;
|
||||||
private void SetDisplayText(string value)
|
private void SetDisplayText(string value)
|
||||||
{
|
{
|
||||||
|
if (SpecialTextTags.Contains(value))
|
||||||
|
{
|
||||||
|
parseSpecialTextTagOnStart = true;
|
||||||
|
IsActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
DisplayText = IgnoreLocalization ? value : TextManager.Get(value).Fallback(value);
|
DisplayText = IgnoreLocalization ? value : TextManager.Get(value).Fallback(value);
|
||||||
|
|
||||||
TextBlock.Text = DisplayText;
|
TextBlock.Text = DisplayText;
|
||||||
if (Screen.Selected == GameMain.SubEditorScreen && Scrollable)
|
if (Screen.Selected == GameMain.SubEditorScreen && Scrollable)
|
||||||
{
|
{
|
||||||
@@ -198,9 +222,37 @@ namespace Barotrauma.Items.Components
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ParseSpecialTextTag()
|
||||||
|
{
|
||||||
|
switch (text)
|
||||||
|
{
|
||||||
|
case "[CurrentLocationName]":
|
||||||
|
SetDisplayText(Level.Loaded?.StartLocation?.Name ?? string.Empty);
|
||||||
|
break;
|
||||||
|
case "[CurrentBiomeName]":
|
||||||
|
SetDisplayText(Level.Loaded?.LevelData?.Biome?.DisplayName.Value ?? string.Empty);
|
||||||
|
break;
|
||||||
|
case "[CurrentSubName]":
|
||||||
|
SetDisplayText(item.Submarine?.Info?.DisplayName.Value ?? string.Empty);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void Update(float deltaTime, Camera cam)
|
public override void Update(float deltaTime, Camera cam)
|
||||||
{
|
{
|
||||||
if (!scrollable) { return; }
|
if (parseSpecialTextTagOnStart)
|
||||||
|
{
|
||||||
|
ParseSpecialTextTag();
|
||||||
|
parseSpecialTextTagOnStart = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!scrollable)
|
||||||
|
{
|
||||||
|
IsActive = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (scrollingText == null)
|
if (scrollingText == null)
|
||||||
{
|
{
|
||||||
@@ -286,5 +338,6 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
Text = msg.ReadString();
|
Text = msg.ReadString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Microsoft.Xna.Framework;
|
|||||||
using Microsoft.Xna.Framework.Graphics;
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection.Metadata;
|
using System.Reflection.Metadata;
|
||||||
|
|
||||||
@@ -46,9 +47,12 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
private GUITextBlock requiredTimeBlock;
|
private GUITextBlock requiredTimeBlock;
|
||||||
|
|
||||||
|
[Serialize("FabricatorCreate", IsPropertySaveable.Yes)]
|
||||||
|
public string CreateButtonText { get; set; }
|
||||||
|
|
||||||
partial void InitProjSpecific()
|
partial void InitProjSpecific()
|
||||||
{
|
{
|
||||||
CreateGUI();
|
//CreateGUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnResolutionChanged()
|
protected override void OnResolutionChanged()
|
||||||
@@ -68,9 +72,11 @@ namespace Barotrauma.Items.Components
|
|||||||
AutoScaleVertical = true
|
AutoScaleVertical = true
|
||||||
};
|
};
|
||||||
|
|
||||||
var mainFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 1f), paddedFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
var mainFrame = new GUILayoutGroup(new RectTransform(new Vector2(1f, 0.95f), paddedFrame.RectTransform, Anchor.Center), childAnchor: Anchor.TopCenter)
|
||||||
{
|
{
|
||||||
RelativeSpacing = 0.02f
|
RelativeSpacing = 0.02f,
|
||||||
|
Stretch = true,
|
||||||
|
CanBeFocused = true
|
||||||
};
|
};
|
||||||
|
|
||||||
// === TOP AREA ===
|
// === TOP AREA ===
|
||||||
@@ -131,41 +137,55 @@ namespace Barotrauma.Items.Components
|
|||||||
// === BOTTOM AREA === //
|
// === BOTTOM AREA === //
|
||||||
var bottomFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.3f), mainFrame.RectTransform), style: null);
|
var bottomFrame = new GUIFrame(new RectTransform(new Vector2(1f, 0.3f), mainFrame.RectTransform), style: null);
|
||||||
|
|
||||||
|
if (inputContainer.Capacity > 0)
|
||||||
|
{
|
||||||
// === SEPARATOR === //
|
// === SEPARATOR === //
|
||||||
var separatorArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.15f), bottomFrame.RectTransform, Anchor.TopCenter), childAnchor: Anchor.CenterLeft, isHorizontal: true)
|
var separatorArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.15f), bottomFrame.RectTransform, Anchor.TopCenter), childAnchor: Anchor.CenterLeft, isHorizontal: true)
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = 0.03f
|
RelativeSpacing = 0.03f
|
||||||
};
|
};
|
||||||
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, separatorArea.RectTransform), TextManager.Get("fabricator.input", "uilabel.input"), font: GUIStyle.SubHeadingFont) { Padding = Vector4.Zero };
|
var inputLabel = new GUITextBlock(new RectTransform(Vector2.One, separatorArea.RectTransform), TextManager.Get("fabricator.input", "uilabel.input"), font: GUIStyle.SubHeadingFont) { Padding = Vector4.Zero };
|
||||||
inputLabel.RectTransform.Resize(new Point((int) inputLabel.Font.MeasureString(inputLabel.Text).X, inputLabel.RectTransform.Rect.Height));
|
inputLabel.RectTransform.Resize(new Point((int)inputLabel.Font.MeasureString(inputLabel.Text).X, inputLabel.RectTransform.Rect.Height));
|
||||||
new GUIFrame(new RectTransform(Vector2.One, separatorArea.RectTransform), style: "HorizontalLine");
|
new GUIFrame(new RectTransform(Vector2.One, separatorArea.RectTransform), style: "HorizontalLine");
|
||||||
|
|
||||||
// === INPUT AREA === //
|
// === INPUT AREA === //
|
||||||
var inputArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 1f), bottomFrame.RectTransform, Anchor.BottomCenter), isHorizontal: true, childAnchor: Anchor.BottomLeft);
|
var inputArea = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 1f), bottomFrame.RectTransform, Anchor.BottomCenter), isHorizontal: true, childAnchor: Anchor.BottomLeft);
|
||||||
|
|
||||||
// === INPUT SLOTS === //
|
// === INPUT SLOTS === //
|
||||||
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 1f), inputArea.RectTransform), style: null);
|
inputInventoryHolder = new GUIFrame(new RectTransform(new Vector2(0.7f, 1f), inputArea.RectTransform), style: null);
|
||||||
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay) { CanBeFocused = false };
|
new GUICustomComponent(new RectTransform(Vector2.One, inputInventoryHolder.RectTransform), DrawInputOverLay) { CanBeFocused = false };
|
||||||
|
|
||||||
// === ACTIVATE BUTTON === //
|
// === ACTIVATE BUTTON === //
|
||||||
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterRight);
|
var buttonFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.3f, 0.8f), inputArea.RectTransform), childAnchor: Anchor.CenterRight);
|
||||||
activateButton = new GUIButton(new RectTransform(new Vector2(1f, 0.6f), buttonFrame.RectTransform),
|
activateButton = new GUIButton(new RectTransform(new Vector2(1f, 0.6f), buttonFrame.RectTransform),
|
||||||
TextManager.Get("FabricatorCreate"), style: "DeviceButton")
|
TextManager.Get(CreateButtonText), style: "DeviceButton")
|
||||||
{
|
{
|
||||||
OnClicked = StartButtonClicked,
|
OnClicked = StartButtonClicked,
|
||||||
UserData = selectedItem,
|
UserData = selectedItem,
|
||||||
Enabled = false
|
Enabled = false
|
||||||
};
|
};
|
||||||
// === POWER WARNING === //
|
}
|
||||||
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
|
else
|
||||||
TextManager.Get("FabricatorNoPower"), textColor: GUIStyle.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
|
{
|
||||||
{
|
bottomFrame.RectTransform.RelativeSize = new Vector2(1.0f, 0.1f);
|
||||||
HoverColor = Color.Black,
|
activateButton = new GUIButton(new RectTransform(new Vector2(0.3f, 1.0f), bottomFrame.RectTransform, Anchor.CenterRight),
|
||||||
IgnoreLayoutGroups = true,
|
TextManager.Get(CreateButtonText), style: "DeviceButton")
|
||||||
Visible = false,
|
{
|
||||||
CanBeFocused = false
|
OnClicked = StartButtonClicked,
|
||||||
};
|
UserData = selectedItem,
|
||||||
|
Enabled = false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// === POWER WARNING === //
|
||||||
|
inSufficientPowerWarning = new GUITextBlock(new RectTransform(Vector2.One, activateButton.RectTransform),
|
||||||
|
TextManager.Get("FabricatorNoPower"), textColor: GUIStyle.Orange, textAlignment: Alignment.Center, color: Color.Black, style: "OuterGlow", wrap: true)
|
||||||
|
{
|
||||||
|
HoverColor = Color.Black,
|
||||||
|
IgnoreLayoutGroups = true,
|
||||||
|
Visible = false,
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
CreateRecipes();
|
CreateRecipes();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,8 +242,12 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
partial void OnItemLoadedProjSpecific()
|
partial void OnItemLoadedProjSpecific()
|
||||||
{
|
{
|
||||||
inputContainer.AllowUIOverlap = true;
|
CreateGUI();
|
||||||
inputContainer.Inventory.RectTransform = inputInventoryHolder.RectTransform;
|
if (inputInventoryHolder != null)
|
||||||
|
{
|
||||||
|
inputContainer.AllowUIOverlap = true;
|
||||||
|
inputContainer.Inventory.RectTransform = inputInventoryHolder.RectTransform;
|
||||||
|
}
|
||||||
outputContainer.AllowUIOverlap = true;
|
outputContainer.AllowUIOverlap = true;
|
||||||
outputContainer.Inventory.RectTransform = outputInventoryHolder.RectTransform;
|
outputContainer.Inventory.RectTransform = outputInventoryHolder.RectTransform;
|
||||||
}
|
}
|
||||||
@@ -262,7 +286,7 @@ namespace Barotrauma.Items.Components
|
|||||||
|
|
||||||
var insufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
var insufficientSkillsText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||||
TextManager.Get("fabricatorinsufficientskills"), textColor: Color.Orange, font: GUIStyle.SubHeadingFont)
|
TextManager.Get("fabricatorinsufficientskills"), textColor: Color.Orange, font: GUIStyle.SubHeadingFont)
|
||||||
{
|
{
|
||||||
AutoScaleHorizontal = true,
|
AutoScaleHorizontal = true,
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
@@ -271,10 +295,14 @@ namespace Barotrauma.Items.Components
|
|||||||
{
|
{
|
||||||
insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform));
|
insufficientSkillsText.RectTransform.RepositionChildInHierarchy(itemList.Content.RectTransform.GetChildIndex(firstinSufficient.RectTransform));
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sufficientSkillsText.Visible = false;
|
||||||
|
}
|
||||||
|
|
||||||
var requiresRecipeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
var requiresRecipeText = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.15f), itemList.Content.RectTransform),
|
||||||
TextManager.Get("fabricatorrequiresrecipe"), textColor: Color.Red, font: GUIStyle.SubHeadingFont)
|
TextManager.Get("fabricatorrequiresrecipe"), textColor: Color.Red, font: GUIStyle.SubHeadingFont)
|
||||||
{
|
{
|
||||||
AutoScaleHorizontal = true,
|
AutoScaleHorizontal = true,
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
@@ -593,14 +621,28 @@ namespace Barotrauma.Items.Components
|
|||||||
float requiredTime = overrideRequiredTime ??
|
float requiredTime = overrideRequiredTime ??
|
||||||
(user == null ? selectedItem.RequiredTime : GetRequiredTime(selectedItem, user));
|
(user == null ? selectedItem.RequiredTime : GetRequiredTime(selectedItem, user));
|
||||||
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform),
|
if (requiredTime > 0.0f)
|
||||||
TextManager.Get("FabricatorRequiredTime") , textColor: ToolBox.GradientLerp(degreeOfSuccess, GUIStyle.Red, Color.Yellow, GUIStyle.Green), font: GUIStyle.SubHeadingFont)
|
|
||||||
{
|
{
|
||||||
AutoScaleHorizontal = true,
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform),
|
||||||
};
|
TextManager.Get("FabricatorRequiredTime") , textColor: ToolBox.GradientLerp(degreeOfSuccess, GUIStyle.Red, Color.Yellow, GUIStyle.Green), font: GUIStyle.SubHeadingFont)
|
||||||
|
{
|
||||||
|
AutoScaleHorizontal = true,
|
||||||
|
};
|
||||||
|
requiredTimeBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform), ToolBox.SecondsToReadableTime(requiredTime),
|
||||||
|
font: GUIStyle.SmallFont);
|
||||||
|
}
|
||||||
|
|
||||||
requiredTimeBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform), ToolBox.SecondsToReadableTime(requiredTime),
|
if (SelectedItem.RequiredMoney > 0)
|
||||||
font: GUIStyle.SmallFont);
|
{
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform),
|
||||||
|
TextManager.Get("subeditor.price"), textColor: ToolBox.GradientLerp(degreeOfSuccess, GUIStyle.Red, Color.Yellow, GUIStyle.Green), font: GUIStyle.SubHeadingFont)
|
||||||
|
{
|
||||||
|
AutoScaleHorizontal = true,
|
||||||
|
};
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), paddedReqFrame.RectTransform), TextManager.FormatCurrency(SelectedItem.RequiredMoney),
|
||||||
|
font: GUIStyle.SmallFont);
|
||||||
|
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,6 +34,13 @@ namespace Barotrauma.Items.Components
|
|||||||
[Serialize("0.5,0.5)", IsPropertySaveable.No)]
|
[Serialize("0.5,0.5)", IsPropertySaveable.No)]
|
||||||
public Vector2 Origin { get; set; } = new Vector2(0.5f, 0.5f);
|
public Vector2 Origin { get; set; } = new Vector2(0.5f, 0.5f);
|
||||||
|
|
||||||
|
[Serialize(true, IsPropertySaveable.No, description: "")]
|
||||||
|
public bool BreakFromMiddle
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
set;
|
||||||
|
}
|
||||||
|
|
||||||
public Vector2 DrawSize
|
public Vector2 DrawSize
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -125,8 +132,13 @@ namespace Barotrauma.Items.Components
|
|||||||
int width = (int)(SpriteWidth * snapState);
|
int width = (int)(SpriteWidth * snapState);
|
||||||
if (width > 0.0f)
|
if (width > 0.0f)
|
||||||
{
|
{
|
||||||
DrawRope(spriteBatch, endPos - diff * snapState * 0.5f, endPos, width);
|
float positionMultiplier = snapState;
|
||||||
DrawRope(spriteBatch, startPos, startPos + diff * snapState * 0.5f, width);
|
if (BreakFromMiddle)
|
||||||
|
{
|
||||||
|
positionMultiplier /= 2;
|
||||||
|
DrawRope(spriteBatch, endPos - diff * positionMultiplier, endPos, width);
|
||||||
|
}
|
||||||
|
DrawRope(spriteBatch, startPos, startPos + diff * positionMultiplier, width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -143,7 +155,7 @@ namespace Barotrauma.Items.Components
|
|||||||
float depth = Math.Min(item.GetDrawDepth() + (startSprite.Depth - item.Sprite.Depth), 0.999f);
|
float depth = Math.Min(item.GetDrawDepth() + (startSprite.Depth - item.Sprite.Depth), 0.999f);
|
||||||
startSprite?.Draw(spriteBatch, startPos, SpriteColor, angle, depth: depth);
|
startSprite?.Draw(spriteBatch, startPos, SpriteColor, angle, depth: depth);
|
||||||
}
|
}
|
||||||
if (endSprite != null)
|
if (endSprite != null && (!Snapped || BreakFromMiddle))
|
||||||
{
|
{
|
||||||
float depth = Math.Min(item.GetDrawDepth() + (endSprite.Depth - item.Sprite.Depth), 0.999f);
|
float depth = Math.Min(item.GetDrawDepth() + (endSprite.Depth - item.Sprite.Depth), 0.999f);
|
||||||
endSprite?.Draw(spriteBatch, endPos, SpriteColor, angle, depth: depth);
|
endSprite?.Draw(spriteBatch, endPos, SpriteColor, angle, depth: depth);
|
||||||
|
|||||||
@@ -1846,7 +1846,7 @@ namespace Barotrauma
|
|||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyReceivedState()
|
public void ApplyReceivedState()
|
||||||
{
|
{
|
||||||
if (receivedItemIDs == null || (Owner != null && Owner.Removed)) { return; }
|
if (receivedItemIDs == null || (Owner != null && Owner.Removed)) { return; }
|
||||||
|
|
||||||
|
|||||||
@@ -1198,9 +1198,9 @@ namespace Barotrauma
|
|||||||
Color color = Color.Gray;
|
Color color = Color.Gray;
|
||||||
if (ic.HasRequiredItems(character, false))
|
if (ic.HasRequiredItems(character, false))
|
||||||
{
|
{
|
||||||
if (ic is Repairable)
|
if (ic is Repairable r)
|
||||||
{
|
{
|
||||||
if (!IsFullCondition) { color = Color.Cyan; }
|
if (r.IsBelowRepairThreshold) { color = Color.Cyan; }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
int groupID = 0;
|
int groupID = 0;
|
||||||
DecorativeSprite decorativeSprite = null;
|
DecorativeSprite decorativeSprite = null;
|
||||||
if (subElement.Attribute("texture") == null)
|
if (subElement.GetAttribute("texture") == null)
|
||||||
{
|
{
|
||||||
groupID = subElement.GetAttributeInt("randomgroupid", 0);
|
groupID = subElement.GetAttributeInt("randomgroupid", 0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -370,6 +370,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
|||||||
private BallastFloraBranch ReadBranch(IReadMessage msg)
|
private BallastFloraBranch ReadBranch(IReadMessage msg)
|
||||||
{
|
{
|
||||||
int id = msg.ReadInt32();
|
int id = msg.ReadInt32();
|
||||||
|
bool isRootGrowth = msg.ReadBoolean();
|
||||||
byte type = (byte)msg.ReadRangedInteger(0b0000, 0b1111);
|
byte type = (byte)msg.ReadRangedInteger(0b0000, 0b1111);
|
||||||
byte sides = (byte)msg.ReadRangedInteger(0b0000, 0b1111);
|
byte sides = (byte)msg.ReadRangedInteger(0b0000, 0b1111);
|
||||||
int flowerConfig = msg.ReadRangedInteger(0, 0xFFF);
|
int flowerConfig = msg.ReadRangedInteger(0, 0xFFF);
|
||||||
@@ -385,7 +386,8 @@ namespace Barotrauma.MapCreatures.Behavior
|
|||||||
{
|
{
|
||||||
ID = id,
|
ID = id,
|
||||||
MaxHealth = maxHealth,
|
MaxHealth = maxHealth,
|
||||||
Sides = (TileSide) sides
|
Sides = (TileSide) sides,
|
||||||
|
IsRootGrowth = isRootGrowth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -217,8 +217,8 @@ namespace Barotrauma
|
|||||||
Vector2 mapTileSize = mapTile.size * generationParams.MapTileScale;
|
Vector2 mapTileSize = mapTile.size * generationParams.MapTileScale;
|
||||||
int startX = (int)Math.Max(Math.Floor(location.MapPosition.X / mapTileSize.X - 0.25f), 0);
|
int startX = (int)Math.Max(Math.Floor(location.MapPosition.X / mapTileSize.X - 0.25f), 0);
|
||||||
int startY = (int)Math.Max(Math.Floor(location.MapPosition.Y / mapTileSize.Y - 0.25f), 0);
|
int startY = (int)Math.Max(Math.Floor(location.MapPosition.Y / mapTileSize.Y - 0.25f), 0);
|
||||||
int endX = (int)Math.Min(Math.Floor(location.MapPosition.X / mapTileSize.X + 0.25f), mapTiles.GetLength(0));
|
int endX = (int)Math.Min(Math.Floor(location.MapPosition.X / mapTileSize.X + 0.25f), mapTiles.GetLength(0) - 1);
|
||||||
int endY = (int)Math.Min(Math.Floor(location.MapPosition.Y / mapTileSize.Y + 0.25f), mapTiles.GetLength(1));
|
int endY = (int)Math.Min(Math.Floor(location.MapPosition.Y / mapTileSize.Y + 0.25f), mapTiles.GetLength(1) - 1);
|
||||||
for (int x = startX; x <= endX; x++)
|
for (int x = startX; x <= endX; x++)
|
||||||
{
|
{
|
||||||
for (int y = startY; y <= endY; y++)
|
for (int y = startY; y <= endY; y++)
|
||||||
@@ -451,7 +451,7 @@ namespace Barotrauma
|
|||||||
SelectLocation(-1);
|
SelectLocation(-1);
|
||||||
if (GameMain.Client == null)
|
if (GameMain.Client == null)
|
||||||
{
|
{
|
||||||
CurrentLocation.CreateStore();
|
CurrentLocation.CreateStores();
|
||||||
ProgressWorld();
|
ProgressWorld();
|
||||||
Radiation?.OnStep(1);
|
Radiation?.OnStep(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -272,11 +272,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private GUIComponent CreateEditingHUD()
|
private GUIComponent CreateEditingHUD()
|
||||||
{
|
{
|
||||||
int width = 500;
|
editingHUD = new GUIFrame(new RectTransform(new Vector2(0.3f, 0.15f), GUI.Canvas, Anchor.CenterRight) { MinSize = new Point(400, 0) })
|
||||||
int height = spawnType == SpawnType.Path ? 80 : 200;
|
|
||||||
int x = GameMain.GraphicsWidth / 2 - width / 2, y = 30;
|
|
||||||
|
|
||||||
editingHUD = new GUIFrame(new RectTransform(new Point(width, height), GUI.Canvas) { ScreenSpaceOffset = new Point(x, y) })
|
|
||||||
{
|
{
|
||||||
UserData = this
|
UserData = this
|
||||||
};
|
};
|
||||||
@@ -284,7 +280,7 @@ namespace Barotrauma
|
|||||||
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), editingHUD.RectTransform, Anchor.Center))
|
var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), editingHUD.RectTransform, Anchor.Center))
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = 0.05f
|
AbsoluteSpacing = (int)(GUI.Scale * 5)
|
||||||
};
|
};
|
||||||
|
|
||||||
if (spawnType == SpawnType.Path)
|
if (spawnType == SpawnType.Path)
|
||||||
@@ -418,6 +414,10 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editingHUD.RectTransform.Resize(new Point(
|
||||||
|
editingHUD.Rect.Width,
|
||||||
|
(int)(paddedFrame.Children.Sum(c => c.Rect.Height + paddedFrame.AbsoluteSpacing) / paddedFrame.RectTransform.RelativeSize.Y)));
|
||||||
|
|
||||||
PositionEditingHUD();
|
PositionEditingHUD();
|
||||||
|
|
||||||
return editingHUD;
|
return editingHUD;
|
||||||
|
|||||||
@@ -156,7 +156,12 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const int MaxFileSize = 50000000; //50 MB
|
private static int GetMaxFileSizeInBytes(FileTransferType fileTransferType) =>
|
||||||
|
fileTransferType switch
|
||||||
|
{
|
||||||
|
FileTransferType.Mod => 500 * 1024 * 1024, //500 MiB should be good enough, right?
|
||||||
|
_ => 50 * 1024 * 1024 //50 MiB for everything other than mods
|
||||||
|
};
|
||||||
|
|
||||||
public delegate void TransferInDelegate(FileTransferIn fileStreamReceiver);
|
public delegate void TransferInDelegate(FileTransferIn fileStreamReceiver);
|
||||||
public TransferInDelegate OnFinished;
|
public TransferInDelegate OnFinished;
|
||||||
@@ -410,18 +415,18 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
errorMessage = "";
|
errorMessage = "";
|
||||||
|
|
||||||
if (fileSize > MaxFileSize)
|
|
||||||
{
|
|
||||||
errorMessage = "File too large (" + MathUtils.GetBytesReadable(fileSize) + ")";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Enum.IsDefined(typeof(FileTransferType), (int)type))
|
if (!Enum.IsDefined(typeof(FileTransferType), (int)type))
|
||||||
{
|
{
|
||||||
errorMessage = "Unknown file type";
|
errorMessage = "Unknown file type";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fileSize > GetMaxFileSizeInBytes((FileTransferType)type))
|
||||||
|
{
|
||||||
|
errorMessage = $"File too large ({MathUtils.GetBytesReadable(fileSize)} > {MathUtils.GetBytesReadable(GetMaxFileSizeInBytes((FileTransferType)type))})";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(fileName) ||
|
if (string.IsNullOrEmpty(fileName) ||
|
||||||
fileName.IndexOfAny(Path.GetInvalidFileNameChars().ToArray()) > -1)
|
fileName.IndexOfAny(Path.GetInvalidFileNameChars().ToArray()) > -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -163,16 +163,11 @@ namespace Barotrauma.Networking
|
|||||||
|
|
||||||
public static void ChangeCaptureDevice(string deviceName)
|
public static void ChangeCaptureDevice(string deviceName)
|
||||||
{
|
{
|
||||||
var config = GameSettings.CurrentConfig;
|
if (Instance == null) { return; }
|
||||||
config.Audio.VoiceCaptureDevice = deviceName;
|
|
||||||
GameSettings.SetCurrentConfig(config);
|
|
||||||
|
|
||||||
if (Instance != null)
|
UInt16 storedBufferID = Instance.LatestBufferID;
|
||||||
{
|
Instance.Dispose();
|
||||||
UInt16 storedBufferID = Instance.LatestBufferID;
|
Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID);
|
||||||
Instance.Dispose();
|
|
||||||
Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
IntPtr nativeBuffer;
|
IntPtr nativeBuffer;
|
||||||
|
|||||||
@@ -54,7 +54,17 @@ namespace Barotrauma.Networking
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (VoipCapture.Instance == null) { VoipCapture.Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID); }
|
try
|
||||||
|
{
|
||||||
|
if (VoipCapture.Instance == null) { VoipCapture.Create(GameSettings.CurrentConfig.Audio.VoiceCaptureDevice, storedBufferID); }
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"VoipCature.Create failed: {e.Message} {e.StackTrace.CleanupStackTrace()}");
|
||||||
|
var config = GameSettings.CurrentConfig;
|
||||||
|
config.Audio.VoiceSetting = VoiceMode.Disabled;
|
||||||
|
GameSettings.SetCurrentConfig(config);
|
||||||
|
}
|
||||||
if (VoipCapture.Instance == null || VoipCapture.Instance.EnqueuedTotalLength <= 0) { return; }
|
if (VoipCapture.Instance == null || VoipCapture.Instance.EnqueuedTotalLength <= 0) { return; }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,7 +156,7 @@ namespace Barotrauma.Networking
|
|||||||
{
|
{
|
||||||
var soundIconStyle = GUIStyle.GetComponentStyle("GUISoundIcon");
|
var soundIconStyle = GUIStyle.GetComponentStyle("GUISoundIcon");
|
||||||
Rectangle sourceRect = soundIconStyle.Sprites.First().Value.First().Sprite.SourceRect;
|
Rectangle sourceRect = soundIconStyle.Sprites.First().Value.First().Sprite.SourceRect;
|
||||||
var indexPieces = soundIconStyle.Element.Attribute("sheetindices").Value.Split(';');
|
var indexPieces = soundIconStyle.Element.GetAttribute("sheetindices").Value.Split(';');
|
||||||
voiceIconSheetRects = new Rectangle[indexPieces.Length];
|
voiceIconSheetRects = new Rectangle[indexPieces.Length];
|
||||||
for (int i = 0; i < indexPieces.Length; i++)
|
for (int i = 0; i < indexPieces.Length; i++)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -242,30 +242,30 @@ namespace Barotrauma.Particles
|
|||||||
}
|
}
|
||||||
|
|
||||||
//if velocity change in water is not given, it defaults to the normal velocity change
|
//if velocity change in water is not given, it defaults to the normal velocity change
|
||||||
if (element.Attribute("velocitychangewater") == null)
|
if (element.GetAttribute("velocitychangewater") == null)
|
||||||
{
|
{
|
||||||
VelocityChangeWater = VelocityChange;
|
VelocityChangeWater = VelocityChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.Attribute("angularvelocity") != null)
|
if (element.GetAttribute("angularvelocity") != null)
|
||||||
{
|
{
|
||||||
AngularVelocityMin = element.GetAttributeFloat("angularvelocity", 0.0f);
|
AngularVelocityMin = element.GetAttributeFloat("angularvelocity", 0.0f);
|
||||||
AngularVelocityMax = AngularVelocityMin;
|
AngularVelocityMax = AngularVelocityMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.Attribute("startsize") != null)
|
if (element.GetAttribute("startsize") != null)
|
||||||
{
|
{
|
||||||
StartSizeMin = element.GetAttributeVector2("startsize", Vector2.One);
|
StartSizeMin = element.GetAttributeVector2("startsize", Vector2.One);
|
||||||
StartSizeMax = StartSizeMin;
|
StartSizeMax = StartSizeMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.Attribute("sizechange") != null)
|
if (element.GetAttribute("sizechange") != null)
|
||||||
{
|
{
|
||||||
SizeChangeMin = element.GetAttributeVector2("sizechange", Vector2.Zero);
|
SizeChangeMin = element.GetAttributeVector2("sizechange", Vector2.Zero);
|
||||||
SizeChangeMax = SizeChangeMin;
|
SizeChangeMax = SizeChangeMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.Attribute("startrotation") != null)
|
if (element.GetAttribute("startrotation") != null)
|
||||||
{
|
{
|
||||||
StartRotationMin = element.GetAttributeFloat("startrotation", 0.0f);
|
StartRotationMin = element.GetAttributeFloat("startrotation", 0.0f);
|
||||||
StartRotationMax = StartRotationMin;
|
StartRotationMax = StartRotationMin;
|
||||||
|
|||||||
@@ -680,7 +680,7 @@ namespace Barotrauma
|
|||||||
//locationInfoPanel?.UpdateAuto(1.0f);
|
//locationInfoPanel?.UpdateAuto(1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SelectTab(CampaignMode.InteractionType tab)
|
public void SelectTab(CampaignMode.InteractionType tab, Identifier storeIdentifier = default)
|
||||||
{
|
{
|
||||||
if (Campaign.ShowCampaignUI || (Campaign.ForceMapUI && tab == CampaignMode.InteractionType.Map))
|
if (Campaign.ShowCampaignUI || (Campaign.ForceMapUI && tab == CampaignMode.InteractionType.Map))
|
||||||
{
|
{
|
||||||
@@ -724,8 +724,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CampaignMode.InteractionType.Store:
|
case CampaignMode.InteractionType.Store:
|
||||||
Store.RefreshItemsToSell();
|
Store.SelectStore(storeIdentifier);
|
||||||
Store.Refresh();
|
|
||||||
break;
|
break;
|
||||||
case CampaignMode.InteractionType.Crew:
|
case CampaignMode.InteractionType.Crew:
|
||||||
CrewManagement.UpdateCrew();
|
CrewManagement.UpdateCrew();
|
||||||
|
|||||||
+2
-1
@@ -2805,7 +2805,8 @@ namespace Barotrauma.CharacterEditor
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (!character.IsHuman && !string.IsNullOrEmpty(RagdollParams.Texture) && !File.Exists(RagdollParams.Texture))
|
ContentPath texturePath = ContentPath.FromRaw(character.Prefab.ContentPackage, RagdollParams.Texture);
|
||||||
|
if (!character.IsHuman && (texturePath.IsNullOrWhiteSpace() || !File.Exists(texturePath.Value)))
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError($"Invalid texture path: {RagdollParams.Texture}");
|
DebugConsole.ThrowError($"Invalid texture path: {RagdollParams.Texture}");
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -248,18 +248,24 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|
||||||
//draw characters with deformable limbs last, because they can't be batched into SpriteBatch
|
|
||||||
//pretty hacky way of preventing draw order issues between normal and deformable sprites
|
|
||||||
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, DepthStencilState.None, null, null, cam.Transform);
|
||||||
//backwards order to render the most recently spawned characters in front (characters spawned later have a larger sprite depth)
|
DrawDeformed(firstPass: true);
|
||||||
for (int i = Character.CharacterList.Count - 1; i >= 0; i--)
|
DrawDeformed(firstPass: false);
|
||||||
{
|
|
||||||
Character c = Character.CharacterList[i];
|
|
||||||
if (!c.IsVisible || c.AnimController.Limbs.All(l => l.DeformSprite == null)) { continue; }
|
|
||||||
c.Draw(spriteBatch, Cam);
|
|
||||||
}
|
|
||||||
spriteBatch.End();
|
spriteBatch.End();
|
||||||
|
|
||||||
|
void DrawDeformed(bool firstPass)
|
||||||
|
{
|
||||||
|
//backwards order to render the most recently spawned characters in front (characters spawned later have a larger sprite depth)
|
||||||
|
for (int i = Character.CharacterList.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
Character c = Character.CharacterList[i];
|
||||||
|
if (!c.IsVisible) { continue; }
|
||||||
|
if (c.Params.DrawLast == firstPass) { continue; }
|
||||||
|
if (c.AnimController.Limbs.All(l => l.DeformSprite == null)) { continue; }
|
||||||
|
c.Draw(spriteBatch, Cam);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Level.Loaded?.DrawFront(spriteBatch, cam);
|
Level.Loaded?.DrawFront(spriteBatch, cam);
|
||||||
|
|
||||||
//draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
|
//draw the rendertarget and particles that are only supposed to be drawn in water into renderTargetWater
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private readonly GUITextBox seedBox;
|
private readonly GUITextBox seedBox;
|
||||||
|
|
||||||
private readonly GUITickBox lightingEnabled, cursorLightEnabled, mirrorLevel;
|
private readonly GUITickBox lightingEnabled, cursorLightEnabled, allowInvalidOutpost, mirrorLevel;
|
||||||
|
|
||||||
private Sprite editingSprite;
|
private Sprite editingSprite;
|
||||||
|
|
||||||
@@ -126,6 +126,7 @@ namespace Barotrauma
|
|||||||
OnClicked = (btn, obj) =>
|
OnClicked = (btn, obj) =>
|
||||||
{
|
{
|
||||||
SerializeAll();
|
SerializeAll();
|
||||||
|
GUI.AddMessage(TextManager.Get("leveleditor.allsaved"), GUIStyle.Green);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -169,6 +170,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
mirrorLevel = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), TextManager.Get("mirrorentityx"));
|
mirrorLevel = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.02f), paddedRightPanel.RectTransform), TextManager.Get("mirrorentityx"));
|
||||||
|
|
||||||
|
allowInvalidOutpost = new GUITickBox(new RectTransform(new Vector2(1.0f, 0.025f), paddedRightPanel.RectTransform),
|
||||||
|
TextManager.Get("leveleditor.allowinvalidoutpost"))
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("leveleditor.allowinvalidoutpost.tooltip")
|
||||||
|
};
|
||||||
|
|
||||||
new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
|
new GUIButton(new RectTransform(new Vector2(1.0f, 0.05f), paddedRightPanel.RectTransform),
|
||||||
TextManager.Get("leveleditor.generate"))
|
TextManager.Get("leveleditor.generate"))
|
||||||
{
|
{
|
||||||
@@ -179,6 +186,7 @@ namespace Barotrauma
|
|||||||
GameMain.LightManager.ClearLights();
|
GameMain.LightManager.ClearLights();
|
||||||
LevelData levelData = LevelData.CreateRandom(seedBox.Text, generationParams: selectedParams);
|
LevelData levelData = LevelData.CreateRandom(seedBox.Text, generationParams: selectedParams);
|
||||||
levelData.ForceOutpostGenerationParams = outpostParamsList.SelectedData as OutpostGenerationParams;
|
levelData.ForceOutpostGenerationParams = outpostParamsList.SelectedData as OutpostGenerationParams;
|
||||||
|
levelData.AllowInvalidOutpost = allowInvalidOutpost.Selected;
|
||||||
Level.Generate(levelData, mirror: mirrorLevel.Selected);
|
Level.Generate(levelData, mirror: mirrorLevel.Selected);
|
||||||
GameMain.LightManager.AddLight(pointerLightSource);
|
GameMain.LightManager.AddLight(pointerLightSource);
|
||||||
if (!wasLevelLoaded || Cam.Position.X < 0 || Cam.Position.Y < 0 || Cam.Position.Y > Level.Loaded.Size.X || Cam.Position.Y > Level.Loaded.Size.Y)
|
if (!wasLevelLoaded || Cam.Position.X < 0 || Cam.Position.Y < 0 || Cam.Position.Y > Level.Loaded.Size.X || Cam.Position.Y > Level.Loaded.Size.Y)
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private GUITextBox serverNameBox, passwordBox, maxPlayersBox;
|
private GUITextBox serverNameBox, passwordBox, maxPlayersBox;
|
||||||
private GUITickBox isPublicBox, wrongPasswordBanBox, karmaBox;
|
private GUITickBox isPublicBox, wrongPasswordBanBox, karmaBox;
|
||||||
|
private GUIDropDown serverExecutableDropdown;
|
||||||
private readonly GUIButton joinServerButton, hostServerButton, steamWorkshopButton;
|
private readonly GUIButton joinServerButton, hostServerButton, steamWorkshopButton;
|
||||||
private readonly GameMain game;
|
private readonly GameMain game;
|
||||||
|
|
||||||
@@ -418,7 +419,14 @@ namespace Barotrauma
|
|||||||
//PLACEHOLDER
|
//PLACEHOLDER
|
||||||
var tutorialList = new GUIListBox(
|
var tutorialList = new GUIListBox(
|
||||||
new RectTransform(new Vector2(0.95f, 0.85f), menuTabs[Tab.Tutorials].RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.1f) });
|
new RectTransform(new Vector2(0.95f, 0.85f), menuTabs[Tab.Tutorials].RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.1f) });
|
||||||
var tutorialTypes = ReflectionUtils.GetDerivedNonAbstract<Tutorial>();
|
var tutorialTypes = new List<Type>()
|
||||||
|
{
|
||||||
|
typeof(MechanicTutorial),
|
||||||
|
typeof(EngineerTutorial),
|
||||||
|
typeof(DoctorTutorial),
|
||||||
|
typeof(OfficerTutorial),
|
||||||
|
typeof(CaptainTutorial),
|
||||||
|
};
|
||||||
foreach (Type tutorialType in tutorialTypes)
|
foreach (Type tutorialType in tutorialTypes)
|
||||||
{
|
{
|
||||||
Tutorial tutorial = (Tutorial)Activator.CreateInstance(tutorialType);
|
Tutorial tutorial = (Tutorial)Activator.CreateInstance(tutorialType);
|
||||||
@@ -557,6 +565,35 @@ namespace Barotrauma
|
|||||||
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.HostServer); });
|
GameMain.Instance.ShowCampaignDisclaimer(() => { SelectTab(null, Tab.HostServer); });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serverExecutableDropdown.ListBox.Content.Children.ToArray()
|
||||||
|
.Where(c => c.UserData is ServerExecutableFile f && !ContentPackageManager.EnabledPackages.All.Contains(f.ContentPackage))
|
||||||
|
.ForEach(serverExecutableDropdown.ListBox.RemoveChild);
|
||||||
|
var newServerExes
|
||||||
|
= ContentPackageManager.EnabledPackages.All.SelectMany(p => p.GetFiles<ServerExecutableFile>())
|
||||||
|
.Where(f => serverExecutableDropdown.ListBox.Content.Children.None(c => c.UserData == f))
|
||||||
|
.ToArray();
|
||||||
|
foreach (var newServerExe in newServerExes)
|
||||||
|
{
|
||||||
|
serverExecutableDropdown.AddItem($"{newServerExe.ContentPackage.Name} - {Path.GetFileNameWithoutExtension(newServerExe.Path.Value)}", userData: newServerExe);
|
||||||
|
}
|
||||||
|
serverExecutableDropdown.ListBox.Content.Children.ForEach(c =>
|
||||||
|
{
|
||||||
|
c.RectTransform.RelativeSize = (1.0f, c.RectTransform.RelativeSize.Y);
|
||||||
|
c.ForceLayoutRecalculation();
|
||||||
|
});
|
||||||
|
bool serverExePickable = serverExecutableDropdown.ListBox.Content.CountChildren > 1;
|
||||||
|
serverExecutableDropdown.Parent.Visible
|
||||||
|
= serverExePickable;
|
||||||
|
serverExecutableDropdown.Parent.RectTransform.RelativeSize
|
||||||
|
= (1.0f, serverExePickable ? 0.1f : 0.0f);
|
||||||
|
serverExecutableDropdown.Parent.ForceLayoutRecalculation();
|
||||||
|
(serverExecutableDropdown.Parent.Parent as GUILayoutGroup)?.Recalculate();
|
||||||
|
if (serverExecutableDropdown.SelectedComponent is null)
|
||||||
|
{
|
||||||
|
serverExecutableDropdown.Select(0);
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case Tab.Tutorials:
|
case Tab.Tutorials:
|
||||||
if (!GameSettings.CurrentConfig.CampaignDisclaimerShown)
|
if (!GameSettings.CurrentConfig.CampaignDisclaimerShown)
|
||||||
@@ -784,7 +821,7 @@ namespace Barotrauma
|
|||||||
GameMain.ResetNetLobbyScreen();
|
GameMain.ResetNetLobbyScreen();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string exeName = "DedicatedServer.exe";
|
string exeName = serverExecutableDropdown.SelectedComponent?.UserData is ServerExecutableFile f ? f.Path.Value : "DedicatedServer";
|
||||||
|
|
||||||
string arguments = "-name \"" + ToolBox.EscapeCharacters(name) + "\"" +
|
string arguments = "-name \"" + ToolBox.EscapeCharacters(name) + "\"" +
|
||||||
" -public " + isPublicBox.Selected.ToString() +
|
" -public " + isPublicBox.Selected.ToString() +
|
||||||
@@ -814,15 +851,20 @@ namespace Barotrauma
|
|||||||
arguments += " -ownerkey " + ownerKey;
|
arguments += " -ownerkey " + ownerKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
string filename = exeName;
|
string filename = Path.Combine(
|
||||||
#if LINUX || OSX
|
Path.GetDirectoryName(exeName),
|
||||||
filename = "./" + Path.GetFileNameWithoutExtension(exeName);
|
Path.GetFileNameWithoutExtension(exeName));
|
||||||
//arguments = ToolBox.EscapeCharacters(arguments);
|
#if WINDOWS
|
||||||
|
filename += ".exe";
|
||||||
|
#else
|
||||||
|
filename = "./" + exeName;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
var processInfo = new ProcessStartInfo
|
var processInfo = new ProcessStartInfo
|
||||||
{
|
{
|
||||||
FileName = filename,
|
FileName = filename,
|
||||||
Arguments = arguments,
|
Arguments = arguments,
|
||||||
|
WorkingDirectory = Directory.GetCurrentDirectory(),
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
CreateNoWindow = true,
|
CreateNoWindow = true,
|
||||||
UseShellExecute = false,
|
UseShellExecute = false,
|
||||||
@@ -1184,12 +1226,12 @@ namespace Barotrauma
|
|||||||
label.RectTransform.MaxSize = serverNameBox.RectTransform.MaxSize;
|
label.RectTransform.MaxSize = serverNameBox.RectTransform.MaxSize;
|
||||||
|
|
||||||
var maxPlayersLabel = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("MaxPlayers"), textAlignment: textAlignment);
|
var maxPlayersLabel = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform), TextManager.Get("MaxPlayers"), textAlignment: textAlignment);
|
||||||
var buttonContainer = new GUILayoutGroup(new RectTransform(textFieldSize, maxPlayersLabel.RectTransform, Anchor.CenterRight), isHorizontal: true)
|
var buttonContainer = new GUILayoutGroup(new RectTransform(textFieldSize, maxPlayersLabel.RectTransform, Anchor.CenterRight), isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
||||||
{
|
{
|
||||||
Stretch = true,
|
Stretch = true,
|
||||||
RelativeSpacing = 0.1f
|
RelativeSpacing = 0.1f
|
||||||
};
|
};
|
||||||
new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIMinusButton", textAlignment: Alignment.Center)
|
new GUIButton(new RectTransform(Vector2.One, buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIMinusButton", textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
UserData = -1,
|
UserData = -1,
|
||||||
OnClicked = ChangeMaxPlayers
|
OnClicked = ChangeMaxPlayers
|
||||||
@@ -1209,7 +1251,7 @@ namespace Barotrauma
|
|||||||
currMaxPlayers = (int)MathHelper.Clamp(currMaxPlayers, 1, NetConfig.MaxPlayers);
|
currMaxPlayers = (int)MathHelper.Clamp(currMaxPlayers, 1, NetConfig.MaxPlayers);
|
||||||
maxPlayersBox.Text = currMaxPlayers.ToString();
|
maxPlayersBox.Text = currMaxPlayers.ToString();
|
||||||
};
|
};
|
||||||
new GUIButton(new RectTransform(new Vector2(0.2f, 1.0f), buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton", textAlignment: Alignment.Center)
|
new GUIButton(new RectTransform(Vector2.One, buttonContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUIPlusButton", textAlignment: Alignment.Center)
|
||||||
{
|
{
|
||||||
UserData = 1,
|
UserData = 1,
|
||||||
OnClicked = ChangeMaxPlayers
|
OnClicked = ChangeMaxPlayers
|
||||||
@@ -1223,6 +1265,41 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
label.RectTransform.MaxSize = passwordBox.RectTransform.MaxSize;
|
label.RectTransform.MaxSize = passwordBox.RectTransform.MaxSize;
|
||||||
|
|
||||||
|
var serverExecutableLabel = new GUITextBlock(new RectTransform(textLabelSize, parent.RectTransform),
|
||||||
|
TextManager.Get("ServerExecutable"), textAlignment: textAlignment);
|
||||||
|
const string vanillaServerOption = "Vanilla";
|
||||||
|
serverExecutableDropdown
|
||||||
|
= new GUIDropDown(new RectTransform(textFieldSize, serverExecutableLabel.RectTransform, Anchor.CenterRight),
|
||||||
|
vanillaServerOption);
|
||||||
|
var listBoxSize = serverExecutableDropdown.ListBox.RectTransform.RelativeSize;
|
||||||
|
serverExecutableDropdown.ListBox.RectTransform.RelativeSize = new Vector2(listBoxSize.X * 1.5f, listBoxSize.Y);
|
||||||
|
serverExecutableDropdown.AddItem(vanillaServerOption, userData: null);
|
||||||
|
serverExecutableDropdown.OnSelected = (selected, userData) =>
|
||||||
|
{
|
||||||
|
if (userData != null)
|
||||||
|
{
|
||||||
|
var warningBox = new GUIMessageBox(headerText: TextManager.Get("Warning"),
|
||||||
|
text: TextManager.GetWithVariable("ModServerExesAtYourOwnRisk", "[exename]", serverExecutableDropdown.Text),
|
||||||
|
new LocalizedString[] { TextManager.Get("Yes"), TextManager.Get("No") });
|
||||||
|
warningBox.Buttons[0].OnClicked = (_, __) =>
|
||||||
|
{
|
||||||
|
warningBox.Close();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
warningBox.Buttons[1].OnClicked = (_, __) =>
|
||||||
|
{
|
||||||
|
serverExecutableDropdown.Select(0);
|
||||||
|
warningBox.Close();
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
serverExecutableDropdown.Text = ToolBox.LimitString(serverExecutableDropdown.Text,
|
||||||
|
serverExecutableDropdown.Font, serverExecutableDropdown.Rect.Width * 8 / 10);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
// tickbox upper ---------------
|
// tickbox upper ---------------
|
||||||
|
|
||||||
var tickboxAreaUpper = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, tickBoxSize.Y), parent.RectTransform), isHorizontal: true);
|
var tickboxAreaUpper = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, tickBoxSize.Y), parent.RectTransform), isHorizontal: true);
|
||||||
@@ -1312,8 +1389,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
var client = new RestClient(RemoteContentUrl);
|
var client = new RestClient(RemoteContentUrl);
|
||||||
var request = new RestRequest("MenuContent.xml", Method.GET);
|
var request = new RestRequest("MenuContent.xml", Method.GET);
|
||||||
client.ExecuteAsync(request, RemoteContentReceived);
|
TaskPool.Add("RequestMainMenuRemoteContent", client.ExecuteAsync(request),
|
||||||
CoroutineManager.StartCoroutine(WairForRemoteContentReceived());
|
RemoteContentReceived);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@@ -1327,58 +1404,31 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<CoroutineStatus> WairForRemoteContentReceived()
|
private void RemoteContentReceived(Task t)
|
||||||
{
|
{
|
||||||
while (true)
|
try
|
||||||
{
|
{
|
||||||
lock (remoteContentLock)
|
if (!t.TryGetResult(out IRestResponse remoteContentResponse)) { throw new Exception("Task did not return a valid result"); }
|
||||||
|
string xml = remoteContentResponse.Content;
|
||||||
|
int index = xml.IndexOf('<');
|
||||||
|
if (index > 0) { xml = xml.Substring(index, xml.Length - index); }
|
||||||
|
if (!string.IsNullOrWhiteSpace(xml))
|
||||||
{
|
{
|
||||||
if (remoteContentResponse != null) { break; }
|
remoteContentDoc = XDocument.Parse(xml);
|
||||||
}
|
foreach (var subElement in remoteContentDoc?.Root.Elements())
|
||||||
yield return new WaitForSeconds(0.1f);
|
|
||||||
}
|
|
||||||
lock (remoteContentLock)
|
|
||||||
{
|
|
||||||
if (remoteContentResponse.ResponseStatus != ResponseStatus.Completed || remoteContentResponse.StatusCode != HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
yield return CoroutineStatus.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string xml = remoteContentResponse.Content;
|
|
||||||
int index = xml.IndexOf('<');
|
|
||||||
if (index > 0) { xml = xml.Substring(index, xml.Length - index); }
|
|
||||||
if (!string.IsNullOrWhiteSpace(xml))
|
|
||||||
{
|
{
|
||||||
remoteContentDoc = XDocument.Parse(xml);
|
GUIComponent.FromXML(subElement.FromPackage(null), remoteContentContainer.RectTransform);
|
||||||
foreach (var subElement in remoteContentDoc?.Root.Elements())
|
|
||||||
{
|
|
||||||
GUIComponent.FromXML(subElement.FromPackage(null), remoteContentContainer.RectTransform);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
DebugConsole.ThrowError("Reading received remote main menu content failed.", e);
|
|
||||||
#endif
|
|
||||||
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.WairForRemoteContentReceived:Exception", GameAnalyticsManager.ErrorSeverity.Error,
|
|
||||||
"Reading received remote main menu content failed. " + e.Message);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
yield return CoroutineStatus.Success;
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object remoteContentLock = new object();
|
catch (Exception e)
|
||||||
private IRestResponse remoteContentResponse;
|
|
||||||
|
|
||||||
private void RemoteContentReceived(IRestResponse response, RestRequestAsyncHandle handle)
|
|
||||||
{
|
|
||||||
lock (remoteContentLock)
|
|
||||||
{
|
{
|
||||||
remoteContentResponse = response;
|
#if DEBUG
|
||||||
|
DebugConsole.ThrowError("Reading received remote main menu content failed.", e);
|
||||||
|
#endif
|
||||||
|
GameAnalyticsManager.AddErrorEventOnce("MainMenuScreen.RemoteContentReceived:Exception", GameAnalyticsManager.ErrorSeverity.Error,
|
||||||
|
"Reading received remote main menu content failed. " + e.Message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
using Barotrauma.IO;
|
using Barotrauma.IO;
|
||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
@@ -30,9 +31,18 @@ namespace Barotrauma
|
|||||||
confirmDownload = false;
|
confirmDownload = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DeletePrevDownloads()
|
||||||
|
{
|
||||||
|
if (Directory.Exists(ModReceiver.DownloadFolder))
|
||||||
|
{
|
||||||
|
Directory.Delete(ModReceiver.DownloadFolder, recursive: true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void Select()
|
public override void Select()
|
||||||
{
|
{
|
||||||
base.Select();
|
base.Select();
|
||||||
|
DeletePrevDownloads();
|
||||||
Reset();
|
Reset();
|
||||||
|
|
||||||
Frame.ClearChildren();
|
Frame.ClearChildren();
|
||||||
@@ -67,6 +77,18 @@ namespace Barotrauma
|
|||||||
.Where(sp => sp.ContentPackage is null).ToArray();
|
.Where(sp => sp.ContentPackage is null).ToArray();
|
||||||
if (!missingPackages.Any())
|
if (!missingPackages.Any())
|
||||||
{
|
{
|
||||||
|
if (!GameMain.Client.IsServerOwner)
|
||||||
|
{
|
||||||
|
ContentPackageManager.EnabledPackages.BackUp();
|
||||||
|
ContentPackageManager.EnabledPackages.SetCore(
|
||||||
|
GameMain.Client.ClientPeer.ServerContentPackages
|
||||||
|
.Select(p => p.CorePackage)
|
||||||
|
.First(p => p != null));
|
||||||
|
ContentPackageManager.EnabledPackages.SetRegular(
|
||||||
|
GameMain.Client.ClientPeer.ServerContentPackages
|
||||||
|
.Select(p => p.RegularPackage)
|
||||||
|
.Where(p => p != null).ToArray());
|
||||||
|
}
|
||||||
GameMain.NetLobbyScreen.Select();
|
GameMain.NetLobbyScreen.Select();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -201,7 +223,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (!pendingDownloads.Contains(p))
|
if (!pendingDownloads.Contains(p))
|
||||||
{
|
{
|
||||||
downloadProgress.ClearChildren();
|
downloadProgress.GetAllChildren<GUITextBlock>().ToArray().ForEach(c => downloadProgress.RemoveChild(c));
|
||||||
return 1.0f;
|
return 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3786,7 +3786,7 @@ namespace Barotrauma
|
|||||||
RelativeSpacing = 0.02f
|
RelativeSpacing = 0.02f
|
||||||
};
|
};
|
||||||
|
|
||||||
var dragIndicator = new GUIButton(new RectTransform(new Vector2(0.1f, 0.5f), frameContent.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
var dragIndicator = new GUIButton(new RectTransform(new Vector2(0.5f, 0.5f), frameContent.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
||||||
style: "GUIDragIndicator")
|
style: "GUIDragIndicator")
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
|
|||||||
@@ -380,7 +380,7 @@ namespace Barotrauma
|
|||||||
string spriteFolder = "";
|
string spriteFolder = "";
|
||||||
ContentPath texturePath = null;
|
ContentPath texturePath = null;
|
||||||
|
|
||||||
if (element.Attribute("texture") != null)
|
if (element.GetAttribute("texture") != null)
|
||||||
{
|
{
|
||||||
texturePath = element.GetAttributeContentPath("texture");
|
texturePath = element.GetAttributeContentPath("texture");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,11 +9,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using Microsoft.Xna.Framework.Input;
|
using Microsoft.Xna.Framework.Input;
|
||||||
#if DEBUG
|
|
||||||
using System.IO;
|
|
||||||
#else
|
|
||||||
using Barotrauma.IO;
|
using Barotrauma.IO;
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Barotrauma
|
namespace Barotrauma
|
||||||
{
|
{
|
||||||
@@ -1262,7 +1258,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
textBlock.Text = ToolBox.LimitString(textBlock.Text, textBlock.Font, textBlock.Rect.Width);
|
textBlock.Text = ToolBox.LimitString(textBlock.Text, textBlock.Font, textBlock.Rect.Width);
|
||||||
|
|
||||||
if (ep.Category == MapEntityCategory.ItemAssembly)
|
if (ep.Category == MapEntityCategory.ItemAssembly
|
||||||
|
&& ep.ContentPackage?.Files.Length == 1
|
||||||
|
&& ContentPackageManager.LocalPackages.Contains(ep.ContentPackage))
|
||||||
{
|
{
|
||||||
var deleteButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform, Anchor.BottomCenter) { MinSize = new Point(0, 20) },
|
var deleteButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.2f), paddedFrame.RectTransform, Anchor.BottomCenter) { MinSize = new Point(0, 20) },
|
||||||
TextManager.Get("Delete"), style: "GUIButtonSmall")
|
TextManager.Get("Delete"), style: "GUIButtonSmall")
|
||||||
@@ -1978,6 +1976,7 @@ namespace Barotrauma
|
|||||||
if (newPackage is RegularPackage regular)
|
if (newPackage is RegularPackage regular)
|
||||||
{
|
{
|
||||||
ContentPackageManager.EnabledPackages.EnableRegular(regular);
|
ContentPackageManager.EnabledPackages.EnableRegular(regular);
|
||||||
|
GameSettings.SaveCurrentConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SubmarineInfo.RefreshSavedSub(savePath);
|
SubmarineInfo.RefreshSavedSub(savePath);
|
||||||
@@ -2164,12 +2163,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var allowAttachDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), allowAttachGroup.RectTransform),
|
var allowAttachDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), allowAttachGroup.RectTransform),
|
||||||
text: LocalizedString.Join(", ", MainSub?.Info?.OutpostModuleInfo?.AllowAttachToModules.Select(s => TextManager.Capitalize(s.Value)) ?? ((LocalizedString)"Any").ToEnumerable()), selectMultiple: true);
|
text: LocalizedString.Join(", ", MainSub?.Info?.OutpostModuleInfo?.AllowAttachToModules.Select(s => TextManager.Capitalize(s.Value)) ?? ((LocalizedString)"Any").ToEnumerable()), selectMultiple: true);
|
||||||
allowAttachDropDown.AddItem(TextManager.Capitalize("any"), "any");
|
allowAttachDropDown.AddItem(TextManager.Capitalize("any"), "any".ToIdentifier());
|
||||||
if (MainSub.Info.OutpostModuleInfo == null ||
|
if (MainSub.Info.OutpostModuleInfo == null ||
|
||||||
!MainSub.Info.OutpostModuleInfo.AllowAttachToModules.Any() ||
|
!MainSub.Info.OutpostModuleInfo.AllowAttachToModules.Any() ||
|
||||||
MainSub.Info.OutpostModuleInfo.AllowAttachToModules.All(s => s == "any"))
|
MainSub.Info.OutpostModuleInfo.AllowAttachToModules.All(s => s == "any"))
|
||||||
{
|
{
|
||||||
allowAttachDropDown.SelectItem("any");
|
allowAttachDropDown.SelectItem("any".ToIdentifier());
|
||||||
}
|
}
|
||||||
foreach (Identifier flag in availableFlags)
|
foreach (Identifier flag in availableFlags)
|
||||||
{
|
{
|
||||||
@@ -2211,7 +2210,7 @@ namespace Barotrauma
|
|||||||
locationTypeDropDown.SelectItem(locationType);
|
locationTypeDropDown.SelectItem(locationType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!MainSub.Info?.OutpostModuleInfo?.AllowedLocationTypes?.Any() ?? true) { locationTypeDropDown.SelectItem("any"); }
|
if (!MainSub.Info?.OutpostModuleInfo?.AllowedLocationTypes?.Any() ?? true) { locationTypeDropDown.SelectItem("any".ToIdentifier()); }
|
||||||
|
|
||||||
locationTypeDropDown.OnSelected += (_, __) =>
|
locationTypeDropDown.OnSelected += (_, __) =>
|
||||||
{
|
{
|
||||||
@@ -2225,9 +2224,7 @@ namespace Barotrauma
|
|||||||
// gap positions ---------------------
|
// gap positions ---------------------
|
||||||
|
|
||||||
var gapPositionGroup = new GUILayoutGroup(new RectTransform(new Vector2(.975f, 0.1f), outpostSettingsContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
var gapPositionGroup = new GUILayoutGroup(new RectTransform(new Vector2(.975f, 0.1f), outpostSettingsContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||||
|
|
||||||
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), gapPositionGroup.RectTransform), TextManager.Get("outpostmodulegappositions"), textAlignment: Alignment.CenterLeft);
|
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), gapPositionGroup.RectTransform), TextManager.Get("outpostmodulegappositions"), textAlignment: Alignment.CenterLeft);
|
||||||
|
|
||||||
var gapPositionDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), gapPositionGroup.RectTransform),
|
var gapPositionDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), gapPositionGroup.RectTransform),
|
||||||
text: "", selectMultiple: true);
|
text: "", selectMultiple: true);
|
||||||
|
|
||||||
@@ -2238,11 +2235,11 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
outpostModuleInfo.DetermineGapPositions(MainSub);
|
outpostModuleInfo.DetermineGapPositions(MainSub);
|
||||||
}
|
}
|
||||||
foreach (var gapPos in Enum.GetValues(typeof(OutpostModuleInfo.GapPosition)))
|
foreach (OutpostModuleInfo.GapPosition gapPos in Enum.GetValues(typeof(OutpostModuleInfo.GapPosition)))
|
||||||
{
|
{
|
||||||
if ((OutpostModuleInfo.GapPosition)gapPos == OutpostModuleInfo.GapPosition.None) { continue; }
|
if (gapPos == OutpostModuleInfo.GapPosition.None) { continue; }
|
||||||
gapPositionDropDown.AddItem(TextManager.Capitalize(gapPos.ToString()), gapPos);
|
gapPositionDropDown.AddItem(TextManager.Capitalize(gapPos.ToString()), gapPos);
|
||||||
if (outpostModuleInfo.GapPositions.HasFlag((OutpostModuleInfo.GapPosition)gapPos))
|
if (outpostModuleInfo.GapPositions.HasFlag(gapPos))
|
||||||
{
|
{
|
||||||
gapPositionDropDown.SelectItem(gapPos);
|
gapPositionDropDown.SelectItem(gapPos);
|
||||||
}
|
}
|
||||||
@@ -2271,6 +2268,49 @@ namespace Barotrauma
|
|||||||
};
|
};
|
||||||
gapPositionGroup.RectTransform.MinSize = new Point(0, gapPositionGroup.RectTransform.Children.Max(c => c.MinSize.Y));
|
gapPositionGroup.RectTransform.MinSize = new Point(0, gapPositionGroup.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||||
|
|
||||||
|
var canAttachToPrevGroup = new GUILayoutGroup(new RectTransform(new Vector2(.975f, 0.1f), outpostSettingsContainer.RectTransform), isHorizontal: true, childAnchor: Anchor.CenterLeft);
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(0.5f, 1f), canAttachToPrevGroup.RectTransform), TextManager.Get("canattachtoprevious"), textAlignment: Alignment.CenterLeft)
|
||||||
|
{
|
||||||
|
ToolTip = TextManager.Get("canattachtoprevious.tooltip")
|
||||||
|
};
|
||||||
|
var canAttachToPrevDropDown = new GUIDropDown(new RectTransform(new Vector2(0.5f, 1f), canAttachToPrevGroup.RectTransform),
|
||||||
|
text: "", selectMultiple: true);
|
||||||
|
if (outpostModuleInfo != null)
|
||||||
|
{
|
||||||
|
foreach (OutpostModuleInfo.GapPosition gapPos in Enum.GetValues(typeof(OutpostModuleInfo.GapPosition)))
|
||||||
|
{
|
||||||
|
if (gapPos == OutpostModuleInfo.GapPosition.None) { continue; }
|
||||||
|
canAttachToPrevDropDown.AddItem(TextManager.Capitalize(gapPos.ToString()), gapPos);
|
||||||
|
if (outpostModuleInfo.CanAttachToPrevious.HasFlag(gapPos))
|
||||||
|
{
|
||||||
|
canAttachToPrevDropDown.SelectItem(gapPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canAttachToPrevDropDown.OnSelected += (_, __) =>
|
||||||
|
{
|
||||||
|
if (Submarine.MainSub.Info?.OutpostModuleInfo == null) { return false; }
|
||||||
|
Submarine.MainSub.Info.OutpostModuleInfo.CanAttachToPrevious = OutpostModuleInfo.GapPosition.None;
|
||||||
|
if (canAttachToPrevDropDown.SelectedDataMultiple.Any())
|
||||||
|
{
|
||||||
|
List<string> gapPosTexts = new List<string>();
|
||||||
|
foreach (OutpostModuleInfo.GapPosition gapPos in canAttachToPrevDropDown.SelectedDataMultiple)
|
||||||
|
{
|
||||||
|
Submarine.MainSub.Info.OutpostModuleInfo.CanAttachToPrevious |= gapPos;
|
||||||
|
gapPosTexts.Add(TextManager.Capitalize(gapPos.ToString()).Value);
|
||||||
|
}
|
||||||
|
canAttachToPrevDropDown.Text = ToolBox.LimitString(string.Join(", ", gapPosTexts), canAttachToPrevDropDown.Font, canAttachToPrevDropDown.Rect.Width);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
canAttachToPrevDropDown.Text = ToolBox.LimitString("None", canAttachToPrevDropDown.Font, canAttachToPrevDropDown.Rect.Width);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
canAttachToPrevGroup.RectTransform.MinSize = new Point(0, gapPositionGroup.RectTransform.Children.Max(c => c.MinSize.Y));
|
||||||
|
|
||||||
|
|
||||||
// -------------------
|
// -------------------
|
||||||
|
|
||||||
var maxModuleCountGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), outpostSettingsContainer.RectTransform), isHorizontal: true)
|
var maxModuleCountGroup = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.5f), outpostSettingsContainer.RectTransform), isHorizontal: true)
|
||||||
@@ -2583,7 +2623,18 @@ namespace Barotrauma
|
|||||||
//don't show content packages that only define submarine files
|
//don't show content packages that only define submarine files
|
||||||
//(it doesn't make sense to require another sub to be installed to install this one)
|
//(it doesn't make sense to require another sub to be installed to install this one)
|
||||||
if (contentPack.Files.All(f => f is SubmarineFile)) { continue; }
|
if (contentPack.Files.All(f => f is SubmarineFile)) { continue; }
|
||||||
if (!contentPacks.Contains(contentPack.Name)) { contentPacks.Add(contentPack.Name); }
|
|
||||||
|
if (!contentPacks.Contains(contentPack.Name))
|
||||||
|
{
|
||||||
|
string altName = contentPack.AltNames.FirstOrDefault(n => contentPacks.Contains(n));
|
||||||
|
if (!string.IsNullOrEmpty(altName))
|
||||||
|
{
|
||||||
|
MainSub.Info.RequiredContentPackages.Remove(altName);
|
||||||
|
MainSub.Info.RequiredContentPackages.Add(contentPack.Name);
|
||||||
|
contentPacks.Remove(altName);
|
||||||
|
}
|
||||||
|
contentPacks.Add(contentPack.Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (string contentPackageName in contentPacks)
|
foreach (string contentPackageName in contentPacks)
|
||||||
@@ -2749,11 +2800,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool hideInMenus = nameBox.Parent.GetChildByUserData("hideinmenus") is GUITickBox hideInMenusTickBox && hideInMenusTickBox.Selected;
|
bool hideInMenus = nameBox.Parent.GetChildByUserData("hideinmenus") is GUITickBox hideInMenusTickBox && hideInMenusTickBox.Selected;
|
||||||
#if DEBUG
|
|
||||||
string saveFolder = ItemAssemblyPrefab.VanillaSaveFolder;
|
|
||||||
#else
|
|
||||||
string saveFolder = Path.Combine(ContentPackage.LocalModsDir, nameBox.Text);
|
string saveFolder = Path.Combine(ContentPackage.LocalModsDir, nameBox.Text);
|
||||||
#endif
|
|
||||||
string filePath = Path.Combine(saveFolder, $"{nameBox.Text}.xml").CleanUpPathCrossPlatform();
|
string filePath = Path.Combine(saveFolder, $"{nameBox.Text}.xml").CleanUpPathCrossPlatform();
|
||||||
if (File.Exists(filePath))
|
if (File.Exists(filePath))
|
||||||
{
|
{
|
||||||
@@ -2782,24 +2829,25 @@ namespace Barotrauma
|
|||||||
|
|
||||||
void Save()
|
void Save()
|
||||||
{
|
{
|
||||||
XDocument doc = new XDocument(ItemAssemblyPrefab.Save(MapEntity.SelectedList.ToList(), nameBox.Text, descriptionBox.Text, hideInMenus));
|
ContentPackage existingContentPackage = ContentPackageManager.LocalPackages.Regular.FirstOrDefault(p => p.Files.Any(f => f.Path == filePath));
|
||||||
#if DEBUG
|
|
||||||
doc.Save(filePath);
|
|
||||||
#else
|
|
||||||
doc.SaveSafe(filePath);
|
|
||||||
#endif
|
|
||||||
ContentPackage existingContentPackage = ContentPackageManager.LocalPackages.FirstOrDefault(p => p.Files.Any(f => f.Path == filePath));
|
|
||||||
if (existingContentPackage == null)
|
if (existingContentPackage == null)
|
||||||
{
|
{
|
||||||
//content package doesn't exist, create one
|
//content package doesn't exist, create one
|
||||||
ModProject modProject = new ModProject() { Name = nameBox.Text };
|
ModProject modProject = new ModProject() { Name = nameBox.Text };
|
||||||
var newFile = ModProject.File.FromPath<ItemAssemblyFile>(filePath);
|
var newFile = ModProject.File.FromPath<ItemAssemblyFile>(Path.Combine(ContentPath.ModDirStr, $"{nameBox.Text}.xml"));
|
||||||
modProject.AddFile(newFile);
|
modProject.AddFile(newFile);
|
||||||
ContentPackageManager.LocalPackages.SaveAndEnableRegularMod(modProject);
|
string newPackagePath = ContentPackageManager.LocalPackages.SaveRegularMod(modProject);
|
||||||
|
existingContentPackage = ContentPackageManager.LocalPackages.GetRegularModByPath(newPackagePath);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
XDocument doc = new XDocument(ItemAssemblyPrefab.Save(MapEntity.SelectedList.ToList(), nameBox.Text, descriptionBox.Text, hideInMenus));
|
||||||
|
doc.SaveSafe(filePath);
|
||||||
|
|
||||||
|
var resultPackage = ContentPackageManager.ReloadContentPackage(existingContentPackage) as RegularPackage;
|
||||||
|
if (!ContentPackageManager.EnabledPackages.Regular.Contains(resultPackage))
|
||||||
{
|
{
|
||||||
EnqueueForReload(existingContentPackage);
|
ContentPackageManager.EnabledPackages.EnableRegular(resultPackage);
|
||||||
|
GameSettings.SaveCurrentConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateEntityList();
|
UpdateEntityList();
|
||||||
@@ -2884,11 +2932,8 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (deleteButtonHolder.FindChild("delete") is GUIButton deleteBtn)
|
if (deleteButtonHolder.FindChild("delete") is GUIButton deleteBtn)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
deleteBtn.Enabled = userData is SubmarineInfo subInfo
|
||||||
deleteBtn.Enabled = true;
|
&& (GetContentPackageIntrinsicallyTiedToSub(subInfo) != null || Path.GetDirectoryName(subInfo.FilePath) == SubmarineInfo.SavePath);
|
||||||
#else
|
|
||||||
deleteBtn.Enabled = userData is SubmarineInfo subInfo && !subInfo.IsVanillaSubmarine();
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -3141,18 +3186,10 @@ namespace Barotrauma
|
|||||||
ReconstructLayers();
|
ReconstructLayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
private RegularPackage GetContentPackageIntrinsicallyTiedToSub(SubmarineInfo sub)
|
private static RegularPackage GetContentPackageIntrinsicallyTiedToSub(SubmarineInfo sub)
|
||||||
{
|
=> ContentPackageManager.LocalPackages.Regular
|
||||||
foreach (RegularPackage regularPackage in ContentPackageManager.RegularPackages)
|
.Where(p => p.Files.Length == 1)
|
||||||
{
|
.FirstOrDefault(regularPackage => regularPackage.Files[0].Path == sub.FilePath);
|
||||||
if (regularPackage.Files.Length == 1 && regularPackage.Files[0].Path == sub.FilePath)
|
|
||||||
{
|
|
||||||
return regularPackage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TryDeleteSub(SubmarineInfo sub)
|
private void TryDeleteSub(SubmarineInfo sub)
|
||||||
{
|
{
|
||||||
@@ -3160,8 +3197,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
//If the sub is included in a content package that only defines that one sub,
|
//If the sub is included in a content package that only defines that one sub,
|
||||||
//check that it's a local content package and only allow deletion if it is.
|
//check that it's a local content package and only allow deletion if it is.
|
||||||
|
//(deleting from the Submarines folder is also currently allowed, but this is temporary)
|
||||||
var subPackage = GetContentPackageIntrinsicallyTiedToSub(sub);
|
var subPackage = GetContentPackageIntrinsicallyTiedToSub(sub);
|
||||||
if (!ContentPackageManager.LocalPackages.Regular.Contains(subPackage)) { return; }
|
bool isInOldSavePath = Path.GetDirectoryName(sub.FilePath) == SubmarineInfo.SavePath;
|
||||||
|
if (!ContentPackageManager.LocalPackages.Regular.Contains(subPackage) && !isInOldSavePath) { return; }
|
||||||
|
|
||||||
var msgBox = new GUIMessageBox(
|
var msgBox = new GUIMessageBox(
|
||||||
TextManager.Get("DeleteDialogLabel"),
|
TextManager.Get("DeleteDialogLabel"),
|
||||||
@@ -3171,10 +3210,18 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Directory.Delete(Path.GetDirectoryName(subPackage.Path), true);
|
if (subPackage != null)
|
||||||
|
{
|
||||||
|
Directory.Delete(Path.GetDirectoryName(subPackage.Path), recursive: true);
|
||||||
|
ContentPackageManager.LocalPackages.Refresh();
|
||||||
|
ContentPackageManager.EnabledPackages.DisableRemovedMods();
|
||||||
|
}
|
||||||
|
else if (isInOldSavePath && File.Exists(sub.FilePath))
|
||||||
|
{
|
||||||
|
File.Delete(sub.FilePath);
|
||||||
|
}
|
||||||
|
|
||||||
sub.Dispose();
|
sub.Dispose();
|
||||||
File.Delete(sub.FilePath);
|
|
||||||
SubmarineInfo.RefreshSavedSubs();
|
SubmarineInfo.RefreshSavedSubs();
|
||||||
CreateLoadScreen();
|
CreateLoadScreen();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -390,13 +390,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
GUIComponent propertyField = null;
|
GUIComponent propertyField = null;
|
||||||
if (value is bool)
|
if (value is bool boolVal)
|
||||||
{
|
{
|
||||||
propertyField = CreateBoolField(entity, property, (bool)value, displayName, toolTip);
|
propertyField = CreateBoolField(entity, property, boolVal, displayName, toolTip);
|
||||||
}
|
}
|
||||||
else if (value is string)
|
else if (value is string stringVal)
|
||||||
{
|
{
|
||||||
propertyField = CreateStringField(entity, property, (string)value, displayName, toolTip);
|
propertyField = CreateStringField(entity, property, stringVal, displayName, toolTip);
|
||||||
}
|
}
|
||||||
else if (value.GetType().IsEnum)
|
else if (value.GetType().IsEnum)
|
||||||
{
|
{
|
||||||
@@ -1277,7 +1277,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void CreateTextPicker(string textTag, ISerializableEntity entity, SerializableProperty property, GUITextBox textBox)
|
public void CreateTextPicker(string textTag, ISerializableEntity entity, SerializableProperty property, GUITextBox textBox)
|
||||||
{
|
{
|
||||||
var msgBox = new GUIMessageBox("", "", new LocalizedString[] { TextManager.Get("Cancel") }, new Vector2(0.2f, 0.5f), new Point(300, 400));
|
var msgBox = new GUIMessageBox("", "", new LocalizedString[] { TextManager.Get("Ok") }, new Vector2(0.2f, 0.5f), new Point(300, 400));
|
||||||
msgBox.Buttons[0].OnClicked = msgBox.Close;
|
msgBox.Buttons[0].OnClicked = msgBox.Close;
|
||||||
|
|
||||||
var textList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), msgBox.Content.RectTransform, Anchor.TopCenter))
|
var textList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), msgBox.Content.RectTransform, Anchor.TopCenter))
|
||||||
@@ -1307,6 +1307,18 @@ namespace Barotrauma
|
|||||||
UserData = tagTextPair.Key.ToString()
|
UserData = tagTextPair.Key.ToString()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (entity is IHasExtraTextPickerEntries hasExtraTextPickerEntries)
|
||||||
|
{
|
||||||
|
foreach (string extraEntry in hasExtraTextPickerEntries.GetExtraTextPickerEntries())
|
||||||
|
{
|
||||||
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), textList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
||||||
|
ToolBox.LimitString(extraEntry, GUIStyle.Font, textList.Content.Rect.Width), GUIStyle.Green)
|
||||||
|
{
|
||||||
|
UserData = extraEntry
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TrySendNetworkUpdate(ISerializableEntity entity, SerializableProperty property)
|
private void TrySendNetworkUpdate(ISerializableEntity entity, SerializableProperty property)
|
||||||
@@ -1445,4 +1457,12 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Implement this interface to insert extra entires to the text pickers created for the SerializableEntityEditors of the entity
|
||||||
|
/// </summary>
|
||||||
|
interface IHasExtraTextPickerEntries
|
||||||
|
{
|
||||||
|
public IEnumerable<string> GetExtraTextPickerEntries();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ namespace Barotrauma
|
|||||||
if (sound?.Sound != null)
|
if (sound?.Sound != null)
|
||||||
{
|
{
|
||||||
loopSound = subElement.GetAttributeBool("loop", false);
|
loopSound = subElement.GetAttributeBool("loop", false);
|
||||||
if (subElement.Attribute("selectionmode") != null)
|
if (subElement.GetAttribute("selectionmode") != null)
|
||||||
{
|
{
|
||||||
if (Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out SoundSelectionMode selectionMode))
|
if (Enum.TryParse(subElement.GetAttributeString("selectionmode", "Random"), out SoundSelectionMode selectionMode))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -534,6 +534,9 @@ namespace Barotrauma.Steam
|
|||||||
{
|
{
|
||||||
taskCancelSrc = taskCancelSrc.IsCancellationRequested ? new CancellationTokenSource() : taskCancelSrc;
|
taskCancelSrc = taskCancelSrc.IsCancellationRequested ? new CancellationTokenSource() : taskCancelSrc;
|
||||||
|
|
||||||
|
var contentPackage
|
||||||
|
= ContentPackageManager.WorkshopPackages.FirstOrDefault(p => p.SteamWorkshopId == workshopItem.Id);
|
||||||
|
|
||||||
var verticalLayout = new GUILayoutGroup(new RectTransform(Vector2.One, parentFrame.RectTransform));
|
var verticalLayout = new GUILayoutGroup(new RectTransform(Vector2.One, parentFrame.RectTransform));
|
||||||
|
|
||||||
var headerLayout = new GUILayoutGroup(new RectTransform((1.0f, 0.1f), verticalLayout.RectTransform),
|
var headerLayout = new GUILayoutGroup(new RectTransform((1.0f, 0.1f), verticalLayout.RectTransform),
|
||||||
@@ -568,33 +571,73 @@ namespace Barotrauma.Steam
|
|||||||
RectTransform rightSideButtonRectT()
|
RectTransform rightSideButtonRectT()
|
||||||
=> new RectTransform(Vector2.One, headerLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight);
|
=> new RectTransform(Vector2.One, headerLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight);
|
||||||
|
|
||||||
|
bool reinstallAction(GUIButton button, object o)
|
||||||
|
{
|
||||||
|
TaskPool.Add($"Reinstall{workshopItem.Id}", SteamManager.Workshop.Reinstall(workshopItem), t =>
|
||||||
|
{
|
||||||
|
ContentPackageManager.WorkshopPackages.Refresh();
|
||||||
|
ContentPackageManager.EnabledPackages.RefreshUpdatedMods();
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var (updateButton, updateSprite) = CreatePaddedButton(
|
||||||
|
rightSideButtonRectT(),
|
||||||
|
"GUIUpdateButton",
|
||||||
|
spriteScale: 0.8f);
|
||||||
|
updateButton.ToolTip = TextManager.Get("WorkshopItemUpdate");
|
||||||
|
updateButton.Visible = false;
|
||||||
|
updateButton.OnClicked = reinstallAction;
|
||||||
|
|
||||||
|
if (contentPackage != null)
|
||||||
|
{
|
||||||
|
TaskPool.Add(
|
||||||
|
$"DetermineUpdateRequired{contentPackage.SteamWorkshopId}",
|
||||||
|
contentPackage.IsUpToDate(),
|
||||||
|
t =>
|
||||||
|
{
|
||||||
|
if (!t.TryGetResult(out bool isUpToDate)) { return; }
|
||||||
|
|
||||||
|
updateButton.Visible = !isUpToDate;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
var (reinstallButton, reinstallSprite) = CreatePaddedButton(
|
var (reinstallButton, reinstallSprite) = CreatePaddedButton(
|
||||||
rightSideButtonRectT(),
|
rightSideButtonRectT(),
|
||||||
"GUIReloadButton",
|
"GUIReloadButton",
|
||||||
spriteScale: 0.8f);
|
spriteScale: 0.8f);
|
||||||
reinstallButton.ToolTip = TextManager.Get("WorkshopItemReinstall");
|
reinstallButton.ToolTip = TextManager.Get("WorkshopItemReinstall");
|
||||||
reinstallButton.OnClicked += (button, o) =>
|
reinstallButton.OnClicked = reinstallAction;
|
||||||
{
|
|
||||||
SteamManager.Workshop.Uninstall(workshopItem);
|
|
||||||
TaskPool.Add($"Reinstall{workshopItem.Id}", SteamManager.Workshop.ForceRedownload(workshopItem), t => { });
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
var reinstallButtonUpdater = new GUICustomComponent(
|
var reinstallButtonUpdater = new GUICustomComponent(
|
||||||
new RectTransform(Vector2.Zero, reinstallButton.RectTransform),
|
new RectTransform(Vector2.Zero, reinstallButton.RectTransform),
|
||||||
onUpdate: (f, component) =>
|
onUpdate: (f, component) =>
|
||||||
{
|
{
|
||||||
reinstallButton.Visible = workshopItem.IsSubscribed;
|
reinstallButton.Visible = workshopItem.IsSubscribed || workshopItem.Owner.Id == SteamManager.GetSteamID();
|
||||||
reinstallButton.Enabled = !workshopItem.IsDownloading && !workshopItem.IsDownloadPending &&
|
reinstallButton.Enabled = !workshopItem.IsDownloading && !workshopItem.IsDownloadPending &&
|
||||||
!SteamManager.Workshop.IsInstalling(workshopItem);
|
!SteamManager.Workshop.IsInstalling(workshopItem);
|
||||||
|
|
||||||
reinstallSprite.Color = reinstallButton.Enabled
|
reinstallSprite.Color = reinstallButton.Enabled
|
||||||
? reinstallSprite.Style.Color
|
? reinstallSprite.Style.Color
|
||||||
: Color.DimGray;
|
: Color.DimGray;
|
||||||
|
updateButton.Enabled = reinstallButton.Enabled && contentPackage != null && ContentPackageManager.WorkshopPackages.Contains(contentPackage);
|
||||||
|
updateSprite.Color = reinstallSprite.Color;
|
||||||
|
|
||||||
|
if (contentPackage != null
|
||||||
|
&& !ContentPackageManager.WorkshopPackages.Contains(contentPackage)
|
||||||
|
&& ContentPackageManager.WorkshopPackages.Any(p => p.SteamWorkshopId == workshopItem.Id))
|
||||||
|
{
|
||||||
|
updateButton.Visible = false;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
CreateSubscribeButton(workshopItem,
|
CreateSubscribeButton(workshopItem,
|
||||||
rightSideButtonRectT(),
|
rightSideButtonRectT(),
|
||||||
spriteScale: 0.8f);
|
spriteScale: 0.8f);
|
||||||
|
|
||||||
var padding = new GUIFrame(new RectTransform((1.0f, 0.015f), verticalLayout.RectTransform), style: null);
|
var padding = new GUIFrame(
|
||||||
|
new RectTransform((0.15f, 1.0f), headerLayout.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
||||||
|
style: null);
|
||||||
|
|
||||||
|
padding = new GUIFrame(new RectTransform((1.0f, 0.015f), verticalLayout.RectTransform), style: null);
|
||||||
|
|
||||||
var horizontalLayout = new GUILayoutGroup(new RectTransform((1.0f, 0.45f), verticalLayout.RectTransform),
|
var horizontalLayout = new GUILayoutGroup(new RectTransform((1.0f, 0.45f), verticalLayout.RectTransform),
|
||||||
isHorizontal: true)
|
isHorizontal: true)
|
||||||
@@ -638,7 +681,7 @@ namespace Barotrauma.Steam
|
|||||||
isHorizontal: true,
|
isHorizontal: true,
|
||||||
childAnchor: Anchor.CenterLeft) { Stretch = true };
|
childAnchor: Anchor.CenterLeft) { Stretch = true };
|
||||||
var starColor = Color.Lerp(
|
var starColor = Color.Lerp(
|
||||||
Color.Lerp(Color.Red, Color.Yellow, Math.Min(workshopItem.Score * 2.0f, 1.0f)),
|
Color.Lerp(Color.White, Color.Yellow, Math.Min(workshopItem.Score * 2.0f, 1.0f)),
|
||||||
Color.Lime, Math.Max(0.0f, (workshopItem.Score - 0.5f) * 2.0f));
|
Color.Lime, Math.Max(0.0f, (workshopItem.Score - 0.5f) * 2.0f));
|
||||||
for (int i = 0; i < 5; i++)
|
for (int i = 0; i < 5; i++)
|
||||||
{
|
{
|
||||||
@@ -652,12 +695,23 @@ namespace Barotrauma.Steam
|
|||||||
star.SelectedColor = starColor;
|
star.SelectedColor = starColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var scoreVoteCountPadding = new GUIFrame(new RectTransform((0.5f, 1.0f), scoreStarContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
var scoreTextPadding = new GUIFrame(new RectTransform((0.5f, 1.0f), scoreStarContainer.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
||||||
style: null);
|
style: null);
|
||||||
|
|
||||||
|
var scoreTextContainer = new GUIFrame(new RectTransform(Vector2.One, scoreStarContainer.RectTransform),
|
||||||
|
style: null);
|
||||||
|
|
||||||
var scoreVoteCount = new GUITextBlock(
|
var scoreVoteCount = new GUITextBlock(
|
||||||
new RectTransform(Vector2.One, scoreStarContainer.RectTransform),
|
new RectTransform((1.0f, 1.5f), scoreTextContainer.RectTransform, Anchor.Center),
|
||||||
TextManager.GetWithVariable("WorkshopItemVotes", "[VoteCount]",
|
TextManager.GetWithVariable("WorkshopItemVotes", "[VoteCount]",
|
||||||
(workshopItem.VotesUp + workshopItem.VotesDown).ToString()), textAlignment: Alignment.CenterLeft)
|
(workshopItem.VotesUp + workshopItem.VotesDown).ToString()), textAlignment: Alignment.BottomLeft)
|
||||||
|
{
|
||||||
|
Padding = Vector4.Zero
|
||||||
|
};
|
||||||
|
var subscriptionCount = new GUITextBlock(
|
||||||
|
new RectTransform((1.0f, 1.5f), scoreTextContainer.RectTransform, Anchor.Center),
|
||||||
|
TextManager.GetWithVariable("WorkshopItemSubscriptions", "[SubscriptionCount]",
|
||||||
|
workshopItem.NumUniqueSubscriptions.ToString()), textAlignment: Alignment.TopLeft)
|
||||||
{
|
{
|
||||||
Padding = Vector4.Zero
|
Padding = Vector4.Zero
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -90,21 +90,20 @@ namespace Barotrauma.Steam
|
|||||||
return (fileCount, byteCount);
|
return (fileCount, byteCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PopulatePublishTab(ItemOrPackage itemOrPackage, GUIFrame parentFrame)
|
private void DeselectPublishedItem()
|
||||||
{
|
{
|
||||||
ContentPackageManager.LocalPackages.Refresh();
|
|
||||||
ContentPackageManager.WorkshopPackages.Refresh();
|
|
||||||
|
|
||||||
var deselectCarrier = selfModsList.Parent.FindChild(c => c.UserData is ActionCarrier { Id: var id } && id == "deselect");
|
var deselectCarrier = selfModsList.Parent.FindChild(c => c.UserData is ActionCarrier { Id: var id } && id == "deselect");
|
||||||
Action? deselectAction = deselectCarrier.UserData is ActionCarrier { Action: var action }
|
Action? deselectAction = deselectCarrier.UserData is ActionCarrier { Action: var action }
|
||||||
? action
|
? action
|
||||||
: null;
|
: null;
|
||||||
|
deselectAction?.Invoke();
|
||||||
|
SelectTab(Tab.Publish);
|
||||||
|
}
|
||||||
|
|
||||||
void deselectItem()
|
private void PopulatePublishTab(ItemOrPackage itemOrPackage, GUIFrame parentFrame)
|
||||||
{
|
{
|
||||||
deselectAction?.Invoke();
|
ContentPackageManager.LocalPackages.Refresh();
|
||||||
SelectTab(Tab.Publish);
|
ContentPackageManager.WorkshopPackages.Refresh();
|
||||||
}
|
|
||||||
|
|
||||||
parentFrame.ClearChildren();
|
parentFrame.ClearChildren();
|
||||||
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(Vector2.One, parentFrame.RectTransform),
|
GUILayoutGroup mainLayout = new GUILayoutGroup(new RectTransform(Vector2.One, parentFrame.RectTransform),
|
||||||
@@ -146,7 +145,7 @@ namespace Barotrauma.Steam
|
|||||||
{
|
{
|
||||||
OnClicked = (button, o) =>
|
OnClicked = (button, o) =>
|
||||||
{
|
{
|
||||||
deselectItem();
|
DeselectPublishedItem();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -285,7 +284,7 @@ namespace Barotrauma.Steam
|
|||||||
RectTransform newButtonRectT()
|
RectTransform newButtonRectT()
|
||||||
=> new RectTransform((0.4f, 1.0f), buttonLayout.RectTransform);
|
=> new RectTransform((0.4f, 1.0f), buttonLayout.RectTransform);
|
||||||
|
|
||||||
var publishItemButton = new GUIButton(newButtonRectT(), TextManager.Get("WorkshopItemPublish"))
|
var publishItemButton = new GUIButton(newButtonRectT(), TextManager.Get(workshopItem.Id != 0 ? "WorkshopItemUpdate" : "WorkshopItemPublish"))
|
||||||
{
|
{
|
||||||
OnClicked = (button, o) =>
|
OnClicked = (button, o) =>
|
||||||
{
|
{
|
||||||
@@ -333,8 +332,9 @@ namespace Barotrauma.Steam
|
|||||||
TaskPool.Add($"Delete{workshopItem.Id}", Steamworks.SteamUGC.DeleteFileAsync(workshopItem.Id),
|
TaskPool.Add($"Delete{workshopItem.Id}", Steamworks.SteamUGC.DeleteFileAsync(workshopItem.Id),
|
||||||
t =>
|
t =>
|
||||||
{
|
{
|
||||||
|
SteamManager.Workshop.Uninstall(workshopItem);
|
||||||
confirmDeletion.Close();
|
confirmDeletion.Close();
|
||||||
deselectItem();
|
DeselectPublishedItem();
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -364,24 +364,10 @@ namespace Barotrauma.Steam
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
var coroutineEval = subcoroutine(messageBox.Text, messageBox);
|
var coroutineEval = subcoroutine(messageBox.Text, messageBox).GetEnumerator();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
bool moveNext = true;
|
var status = coroutineEval.Current;
|
||||||
try
|
|
||||||
{
|
|
||||||
moveNext = coroutineEval.GetEnumerator().MoveNext();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
DebugConsole.ThrowError($"{e.Message} {e.StackTrace.CleanupStackTrace()}");
|
|
||||||
messageBox.Close();
|
|
||||||
}
|
|
||||||
if (!moveNext)
|
|
||||||
{
|
|
||||||
messageBox.Close();
|
|
||||||
}
|
|
||||||
var status = coroutineEval.GetEnumerator().Current;
|
|
||||||
if (messageBox.Closed)
|
if (messageBox.Closed)
|
||||||
{
|
{
|
||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
@@ -397,6 +383,20 @@ namespace Barotrauma.Steam
|
|||||||
{
|
{
|
||||||
yield return status;
|
yield return status;
|
||||||
}
|
}
|
||||||
|
bool moveNext = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
moveNext = coroutineEval.MoveNext();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
DebugConsole.ThrowError($"{e.Message} {e.StackTrace.CleanupStackTrace()}");
|
||||||
|
messageBox.Close();
|
||||||
|
}
|
||||||
|
if (!moveNext)
|
||||||
|
{
|
||||||
|
messageBox.Close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,26 +408,9 @@ namespace Barotrauma.Steam
|
|||||||
{
|
{
|
||||||
if (!SteamManager.Workshop.CanBeInstalled(workshopItem))
|
if (!SteamManager.Workshop.CanBeInstalled(workshopItem))
|
||||||
{
|
{
|
||||||
//Must download!
|
SteamManager.Workshop.NukeDownload(workshopItem);
|
||||||
while (!SteamManager.Workshop.CanBeInstalled(workshopItem))
|
|
||||||
{
|
|
||||||
bool shouldForceInstall = workshopItem.IsInstalled
|
|
||||||
&& Directory.Exists(workshopItem.Directory)
|
|
||||||
&& !SteamManager.Workshop.IsItemDirectoryUpToDate(workshopItem);
|
|
||||||
shouldForceInstall |= workshopItem is
|
|
||||||
{ IsDownloading: false, IsDownloadPending: false, IsInstalled: false };
|
|
||||||
if (shouldForceInstall)
|
|
||||||
{
|
|
||||||
SteamManager.Workshop.ForceRedownload(workshopItem);
|
|
||||||
}
|
|
||||||
currentStepText.Text = TextManager.GetWithVariable("PublishPopupDownload", "[percentage]", Percentage(workshopItem.DownloadAmount));
|
|
||||||
yield return new WaitForSeconds(0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SteamManager.Workshop.DownloadModThenEnqueueInstall(workshopItem);
|
|
||||||
}
|
}
|
||||||
|
SteamManager.Workshop.DownloadModThenEnqueueInstall(workshopItem);
|
||||||
TaskPool.Add($"Install {workshopItem.Title}",
|
TaskPool.Add($"Install {workshopItem.Title}",
|
||||||
SteamManager.Workshop.WaitForInstall(workshopItem),
|
SteamManager.Workshop.WaitForInstall(workshopItem),
|
||||||
(t) =>
|
(t) =>
|
||||||
@@ -436,7 +419,9 @@ namespace Barotrauma.Steam
|
|||||||
});
|
});
|
||||||
while (!ContentPackageManager.WorkshopPackages.Any(p => p.SteamWorkshopId == workshopItem.Id))
|
while (!ContentPackageManager.WorkshopPackages.Any(p => p.SteamWorkshopId == workshopItem.Id))
|
||||||
{
|
{
|
||||||
currentStepText.Text = TextManager.Get("PublishPopupInstall");
|
currentStepText.Text = SteamManager.Workshop.CanBeInstalled(workshopItem)
|
||||||
|
? TextManager.Get("PublishPopupInstall")
|
||||||
|
: TextManager.GetWithVariable("PublishPopupDownload", "[percentage]", Percentage(workshopItem.DownloadAmount));
|
||||||
yield return new WaitForSeconds(0.5f);
|
yield return new WaitForSeconds(0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +442,6 @@ namespace Barotrauma.Steam
|
|||||||
currentStepText.Text = TextManager.Get("PublishPopupCreateLocal");
|
currentStepText.Text = TextManager.Get("PublishPopupCreateLocal");
|
||||||
yield return new WaitForSeconds(0.5f);
|
yield return new WaitForSeconds(0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
PopulatePublishTab(workshopItem, parentFrame);
|
PopulatePublishTab(workshopItem, parentFrame);
|
||||||
|
|
||||||
yield return CoroutineStatus.Success;
|
yield return CoroutineStatus.Success;
|
||||||
@@ -500,7 +484,10 @@ namespace Barotrauma.Steam
|
|||||||
editor.SubmitAsync(),
|
editor.SubmitAsync(),
|
||||||
t =>
|
t =>
|
||||||
{
|
{
|
||||||
t.TryGetResult(out result);
|
if (t.TryGetResult(out Steamworks.Ugc.PublishResult publishResult))
|
||||||
|
{
|
||||||
|
result = publishResult;
|
||||||
|
}
|
||||||
resultException = t.Exception?.GetInnermost();
|
resultException = t.Exception?.GetInnermost();
|
||||||
});
|
});
|
||||||
currentStepText.Text = TextManager.Get("PublishPopupSubmit");
|
currentStepText.Text = TextManager.Get("PublishPopupSubmit");
|
||||||
@@ -523,6 +510,14 @@ namespace Barotrauma.Steam
|
|||||||
$"exception was {downloadTask.Exception?.GetInnermost()?.ToString().CleanupStackTrace() ?? "[NULL]"}");
|
$"exception was {downloadTask.Exception?.GetInnermost()?.ToString().CleanupStackTrace() ?? "[NULL]"}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentPackage? pkgToNuke
|
||||||
|
= ContentPackageManager.WorkshopPackages.FirstOrDefault(p => p.SteamWorkshopId == resultId);
|
||||||
|
if (pkgToNuke != null)
|
||||||
|
{
|
||||||
|
Directory.Delete(pkgToNuke.Dir, recursive: true);
|
||||||
|
ContentPackageManager.WorkshopPackages.Refresh();
|
||||||
|
}
|
||||||
|
|
||||||
bool installed = false;
|
bool installed = false;
|
||||||
TaskPool.Add(
|
TaskPool.Add(
|
||||||
"InstallNewlyPublished",
|
"InstallNewlyPublished",
|
||||||
@@ -537,13 +532,17 @@ namespace Barotrauma.Steam
|
|||||||
yield return new WaitForSeconds(0.5f);
|
yield return new WaitForSeconds(0.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ContentPackageManager.WorkshopPackages.Refresh();
|
||||||
|
ContentPackageManager.EnabledPackages.RefreshUpdatedMods();
|
||||||
|
|
||||||
var localModProject = new ModProject(localPackage)
|
var localModProject = new ModProject(localPackage)
|
||||||
{
|
{
|
||||||
SteamWorkshopId = resultId
|
SteamWorkshopId = resultId
|
||||||
};
|
};
|
||||||
|
localModProject.DiscardHashAndInstallTime();
|
||||||
localModProject.Save(localPackage.Path);
|
localModProject.Save(localPackage.Path);
|
||||||
ContentPackageManager.ReloadContentPackage(localPackage);
|
ContentPackageManager.ReloadContentPackage(localPackage);
|
||||||
ContentPackageManager.WorkshopPackages.Refresh();
|
DeselectPublishedItem();
|
||||||
|
|
||||||
if (result.Value.NeedsWorkshopAgreement)
|
if (result.Value.NeedsWorkshopAgreement)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using System.Collections.Immutable;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using Barotrauma.Extensions;
|
||||||
|
|
||||||
namespace Barotrauma.Steam
|
namespace Barotrauma.Steam
|
||||||
{
|
{
|
||||||
@@ -117,7 +118,7 @@ namespace Barotrauma.Steam
|
|||||||
if (thumbnailUrl.IsNullOrWhiteSpace()) { return null; }
|
if (thumbnailUrl.IsNullOrWhiteSpace()) { return null; }
|
||||||
var client = new RestClient(thumbnailUrl);
|
var client = new RestClient(thumbnailUrl);
|
||||||
var request = new RestRequest(".", Method.GET);
|
var request = new RestRequest(".", Method.GET);
|
||||||
IRestResponse response = await client.ExecuteTaskAsync(request, cancellationToken);
|
IRestResponse response = await client.ExecuteAsync(request, cancellationToken);
|
||||||
if (response is { StatusCode: System.Net.HttpStatusCode.OK, ResponseStatus: ResponseStatus.Completed })
|
if (response is { StatusCode: System.Net.HttpStatusCode.OK, ResponseStatus: ResponseStatus.Completed })
|
||||||
{
|
{
|
||||||
using var dataStream = new System.IO.MemoryStream();
|
using var dataStream = new System.IO.MemoryStream();
|
||||||
@@ -207,6 +208,11 @@ namespace Barotrauma.Steam
|
|||||||
}
|
}
|
||||||
|
|
||||||
string newPath = $"{ContentPackage.LocalModsDir}/{sanitizedName}";
|
string newPath = $"{ContentPackage.LocalModsDir}/{sanitizedName}";
|
||||||
|
if (File.Exists(newPath) || Directory.Exists(newPath))
|
||||||
|
{
|
||||||
|
newPath += $"_{contentPackage.SteamWorkshopId}";
|
||||||
|
}
|
||||||
|
|
||||||
if (File.Exists(newPath) || Directory.Exists(newPath))
|
if (File.Exists(newPath) || Directory.Exists(newPath))
|
||||||
{
|
{
|
||||||
throw new Exception($"{newPath} already exists");
|
throw new Exception($"{newPath} already exists");
|
||||||
@@ -256,6 +262,18 @@ namespace Barotrauma.Steam
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task Reinstall(Steamworks.Ugc.Item workshopItem)
|
||||||
|
{
|
||||||
|
NukeDownload(workshopItem);
|
||||||
|
var toUninstall
|
||||||
|
= ContentPackageManager.WorkshopPackages.Where(p => p.SteamWorkshopId == workshopItem.Id)
|
||||||
|
.ToHashSet();
|
||||||
|
toUninstall.Select(p => p.Dir).ForEach(d => Directory.Delete(d));
|
||||||
|
CrossThread.RequestExecutionOnMainThread(() => ContentPackageManager.WorkshopPackages.Refresh());
|
||||||
|
DownloadModThenEnqueueInstall(workshopItem);
|
||||||
|
await WaitForInstall(workshopItem);
|
||||||
|
}
|
||||||
|
|
||||||
public static async Task WaitForInstall(Steamworks.Ugc.Item item)
|
public static async Task WaitForInstall(Steamworks.Ugc.Item item)
|
||||||
=> await WaitForInstall(item.Id);
|
=> await WaitForInstall(item.Id);
|
||||||
|
|
||||||
@@ -263,6 +281,7 @@ namespace Barotrauma.Steam
|
|||||||
{
|
{
|
||||||
var installWaiter = new InstallWaiter(item);
|
var installWaiter = new InstallWaiter(item);
|
||||||
while (installWaiter.Waiting) { await Task.Delay(500); }
|
while (installWaiter.Waiting) { await Task.Delay(500); }
|
||||||
|
await Task.Delay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void OnItemDownloadComplete(ulong id, bool forceInstall = false)
|
public static void OnItemDownloadComplete(ulong id, bool forceInstall = false)
|
||||||
@@ -276,7 +295,8 @@ namespace Barotrauma.Steam
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (CanBeInstalled(id)
|
else if (CanBeInstalled(id)
|
||||||
&& !ContentPackageManager.WorkshopPackages.Any(p => p.SteamWorkshopId == id))
|
&& !ContentPackageManager.WorkshopPackages.Any(p => p.SteamWorkshopId == id)
|
||||||
|
&& !InstallTaskCounter.IsInstalling(id))
|
||||||
{
|
{
|
||||||
TaskPool.Add($"InstallItem{id}", InstallMod(id), t => InstallWaiter.StopWaiting(id));
|
TaskPool.Add($"InstallItem{id}", InstallMod(id), t => InstallWaiter.StopWaiting(id));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ namespace Barotrauma.Steam
|
|||||||
private readonly GUIListBox enabledRegularModsList;
|
private readonly GUIListBox enabledRegularModsList;
|
||||||
private readonly GUIListBox disabledRegularModsList;
|
private readonly GUIListBox disabledRegularModsList;
|
||||||
private readonly Action<ItemOrPackage> onInstalledInfoButtonHit;
|
private readonly Action<ItemOrPackage> onInstalledInfoButtonHit;
|
||||||
|
private readonly GUITextBox modsListFilter;
|
||||||
|
|
||||||
private CancellationTokenSource taskCancelSrc = new CancellationTokenSource();
|
private CancellationTokenSource taskCancelSrc = new CancellationTokenSource();
|
||||||
private readonly HashSet<SteamManager.Workshop.ItemThumbnail> itemThumbnails = new HashSet<SteamManager.Workshop.ItemThumbnail>();
|
private readonly HashSet<SteamManager.Workshop.ItemThumbnail> itemThumbnails = new HashSet<SteamManager.Workshop.ItemThumbnail>();
|
||||||
@@ -47,7 +48,12 @@ namespace Barotrauma.Steam
|
|||||||
|
|
||||||
contentFrame = new GUIFrame(new RectTransform((1.0f, 0.95f), mainLayout.RectTransform), style: null);
|
contentFrame = new GUIFrame(new RectTransform((1.0f, 0.95f), mainLayout.RectTransform), style: null);
|
||||||
|
|
||||||
CreateInstalledModsTab(out enabledCoreDropdown, out enabledRegularModsList, out disabledRegularModsList, out onInstalledInfoButtonHit);
|
CreateInstalledModsTab(
|
||||||
|
out enabledCoreDropdown,
|
||||||
|
out enabledRegularModsList,
|
||||||
|
out disabledRegularModsList,
|
||||||
|
out onInstalledInfoButtonHit,
|
||||||
|
out modsListFilter);
|
||||||
CreatePopularModsTab(out popularModsList);
|
CreatePopularModsTab(out popularModsList);
|
||||||
CreatePublishTab(out selfModsList);
|
CreatePublishTab(out selfModsList);
|
||||||
|
|
||||||
@@ -176,7 +182,8 @@ namespace Barotrauma.Steam
|
|||||||
out GUIDropDown enabledCoreDropdown,
|
out GUIDropDown enabledCoreDropdown,
|
||||||
out GUIListBox enabledRegularModsList,
|
out GUIListBox enabledRegularModsList,
|
||||||
out GUIListBox disabledRegularModsList,
|
out GUIListBox disabledRegularModsList,
|
||||||
out Action<ItemOrPackage> onInstalledInfoButtonHit)
|
out Action<ItemOrPackage> onInstalledInfoButtonHit,
|
||||||
|
out GUITextBox modsListFilter)
|
||||||
{
|
{
|
||||||
GUIFrame content = CreateNewContentFrame(Tab.InstalledMods);
|
GUIFrame content = CreateNewContentFrame(Tab.InstalledMods);
|
||||||
|
|
||||||
@@ -287,7 +294,7 @@ namespace Barotrauma.Steam
|
|||||||
var searchRectT = NewItemRectT(mainLayout, heightScale: 1.0f);
|
var searchRectT = NewItemRectT(mainLayout, heightScale: 1.0f);
|
||||||
searchRectT.RelativeSize = (0.5f, searchRectT.RelativeSize.Y);
|
searchRectT.RelativeSize = (0.5f, searchRectT.RelativeSize.Y);
|
||||||
var searchHolder = new GUIFrame(searchRectT, style: null);
|
var searchHolder = new GUIFrame(searchRectT, style: null);
|
||||||
var searchBox = new GUITextBox(new RectTransform(Vector2.One, searchHolder.RectTransform), "");
|
var searchBox = new GUITextBox(new RectTransform(Vector2.One, searchHolder.RectTransform), "", createClearButton: true);
|
||||||
var searchTitle = new GUITextBlock(new RectTransform(Vector2.One, searchHolder.RectTransform) {Anchor = Anchor.TopLeft},
|
var searchTitle = new GUITextBlock(new RectTransform(Vector2.One, searchHolder.RectTransform) {Anchor = Anchor.TopLeft},
|
||||||
textColor: Color.DarkGray * 0.6f,
|
textColor: Color.DarkGray * 0.6f,
|
||||||
text: TextManager.Get("Search") + "...",
|
text: TextManager.Get("Search") + "...",
|
||||||
@@ -300,12 +307,10 @@ namespace Barotrauma.Steam
|
|||||||
|
|
||||||
searchBox.OnTextChanged += (sender, str) =>
|
searchBox.OnTextChanged += (sender, str) =>
|
||||||
{
|
{
|
||||||
enabledModsList.Content.Children.Concat(disabledModsList.Content.Children)
|
UpdateModListItemVisibility();
|
||||||
.ForEach(c => c.Visible = str.IsNullOrWhiteSpace()
|
|
||||||
|| (c.UserData is ContentPackage p
|
|
||||||
&& p.Name.Contains(str, StringComparison.OrdinalIgnoreCase)));
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
modsListFilter = searchBox;
|
||||||
|
|
||||||
new GUICustomComponent(new RectTransform(Vector2.Zero, content.RectTransform),
|
new GUICustomComponent(new RectTransform(Vector2.Zero, content.RectTransform),
|
||||||
onUpdate: (f, component) =>
|
onUpdate: (f, component) =>
|
||||||
@@ -320,6 +325,15 @@ namespace Barotrauma.Steam
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateModListItemVisibility()
|
||||||
|
{
|
||||||
|
string str = modsListFilter.Text;
|
||||||
|
enabledRegularModsList.Content.Children.Concat(disabledRegularModsList.Content.Children)
|
||||||
|
.ForEach(c => c.Visible = str.IsNullOrWhiteSpace()
|
||||||
|
|| (c.UserData is ContentPackage p
|
||||||
|
&& p.Name.Contains(str, StringComparison.OrdinalIgnoreCase)));
|
||||||
|
}
|
||||||
|
|
||||||
private void PopulateInstalledModLists()
|
private void PopulateInstalledModLists()
|
||||||
{
|
{
|
||||||
ContentPackageManager.UpdateContentPackageList();
|
ContentPackageManager.UpdateContentPackageList();
|
||||||
@@ -344,15 +358,21 @@ namespace Barotrauma.Steam
|
|||||||
RelativeSpacing = 0.02f
|
RelativeSpacing = 0.02f
|
||||||
};
|
};
|
||||||
|
|
||||||
var dragIndicator = new GUIButton(new RectTransform((0.1f, 0.5f), frameContent.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
var dragIndicator = new GUIButton(new RectTransform((0.5f, 0.5f), frameContent.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
||||||
style: "GUIDragIndicator")
|
style: "GUIDragIndicator")
|
||||||
{
|
{
|
||||||
CanBeFocused = false
|
CanBeFocused = false
|
||||||
};
|
};
|
||||||
|
|
||||||
var modNameScissor
|
var modNameScissor = new GUIScissorComponent(new RectTransform((0.8f, 1.0f), frameContent.RectTransform))
|
||||||
= new GUIScissorComponent(new RectTransform((0.8f, 1.0f), frameContent.RectTransform));
|
{
|
||||||
var modName = new GUITextBlock(new RectTransform(Vector2.One, modNameScissor.Content.RectTransform), text: mod.Name);
|
CanBeFocused = false
|
||||||
|
};
|
||||||
|
var modName = new GUITextBlock(new RectTransform(Vector2.One, modNameScissor.Content.RectTransform),
|
||||||
|
text: mod.Name)
|
||||||
|
{
|
||||||
|
CanBeFocused = false
|
||||||
|
};
|
||||||
if (ContentPackageManager.LocalPackages.Contains(mod))
|
if (ContentPackageManager.LocalPackages.Contains(mod))
|
||||||
{
|
{
|
||||||
var editButton = new GUIButton(new RectTransform(Vector2.One, frameContent.RectTransform, scaleBasis: ScaleBasis.Smallest), "",
|
var editButton = new GUIButton(new RectTransform(Vector2.One, frameContent.RectTransform, scaleBasis: ScaleBasis.Smallest), "",
|
||||||
@@ -418,6 +438,8 @@ namespace Barotrauma.Steam
|
|||||||
if (ContentPackageManager.EnabledPackages.Regular.Contains(mod)) { continue; }
|
if (ContentPackageManager.EnabledPackages.Regular.Contains(mod)) { continue; }
|
||||||
addRegularModToList(mod, disabledRegularModsList);
|
addRegularModToList(mod, disabledRegularModsList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateModListItemVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreatePopularModsTab(out GUIListBox popularModsList)
|
private void CreatePopularModsTab(out GUIListBox popularModsList)
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.17.2.0</Version>
|
<Version>0.17.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="NVorbis" Version="0.8.6" />
|
<PackageReference Include="NVorbis" Version="0.8.6" />
|
||||||
<PackageReference Include="RestSharp" Version="106.12.0" />
|
<PackageReference Include="RestSharp" Version="106.13.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Sourced from https://stackoverflow.com/a/45248069 -->
|
<!-- Sourced from https://stackoverflow.com/a/45248069 -->
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.17.2.0</Version>
|
<Version>0.17.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||||
@@ -128,7 +128,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="NVorbis" Version="0.8.6" />
|
<PackageReference Include="NVorbis" Version="0.8.6" />
|
||||||
<PackageReference Include="RestSharp" Version="106.12.0" />
|
<PackageReference Include="RestSharp" Version="106.13.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<!-- Sourced from https://stackoverflow.com/a/45248069 -->
|
<!-- Sourced from https://stackoverflow.com/a/45248069 -->
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma</Product>
|
<Product>Barotrauma</Product>
|
||||||
<Version>0.17.2.0</Version>
|
<Version>0.17.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>Barotrauma</AssemblyName>
|
<AssemblyName>Barotrauma</AssemblyName>
|
||||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="NVorbis" Version="0.8.6" />
|
<PackageReference Include="NVorbis" Version="0.8.6" />
|
||||||
<PackageReference Include="RestSharp" Version="106.12.0" />
|
<PackageReference Include="RestSharp" Version="106.13.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.17.2.0</Version>
|
<Version>0.17.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.17.2.0</Version>
|
<Version>0.17.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class Character
|
partial class Character
|
||||||
{
|
{
|
||||||
public static Character Controlled = null;
|
public static Character Controlled => null;
|
||||||
|
|
||||||
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun)
|
partial void OnAttackedProjSpecific(Character attacker, AttackResult attackResult, float stun)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -424,7 +424,7 @@ namespace Barotrauma
|
|||||||
msg.Write(owner == c && owner.Character == this);
|
msg.Write(owner == c && owner.Character == this);
|
||||||
msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0);
|
msg.Write(owner != null && owner.Character == this && GameMain.Server.ConnectedClients.Contains(owner) ? owner.ID : (byte)0);
|
||||||
break;
|
break;
|
||||||
case StatusEventData _:
|
case CharacterStatusEventData _:
|
||||||
WriteStatus(msg);
|
WriteStatus(msg);
|
||||||
break;
|
break;
|
||||||
case UpdateSkillsEventData _:
|
case UpdateSkillsEventData _:
|
||||||
@@ -657,6 +657,10 @@ namespace Barotrauma
|
|||||||
int infoLength = msg.LengthBytes - msgLengthBeforeInfo;
|
int infoLength = msg.LengthBytes - msgLengthBeforeInfo;
|
||||||
|
|
||||||
msg.Write((byte)CampaignInteractionType);
|
msg.Write((byte)CampaignInteractionType);
|
||||||
|
if (CampaignInteractionType == CampaignMode.InteractionType.Store)
|
||||||
|
{
|
||||||
|
msg.Write(MerchantIdentifier);
|
||||||
|
}
|
||||||
|
|
||||||
int msgLengthBeforeOrders = msg.LengthBytes;
|
int msgLengthBeforeOrders = msg.LengthBytes;
|
||||||
// Current orders
|
// Current orders
|
||||||
|
|||||||
@@ -7,51 +7,57 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
partial class CargoManager
|
partial class CargoManager
|
||||||
{
|
{
|
||||||
public void SellBackPurchasedItems(List<PurchasedItem> itemsToSell, Client client = null)
|
public void SellBackPurchasedItems(Identifier storeIdentifier, List<PurchasedItem> itemsToSell, Client client = null)
|
||||||
{
|
{
|
||||||
// Check all the prices before starting the transaction
|
// Check all the prices before starting the transaction to make sure the modifiers stay the same for the whole transaction
|
||||||
// to make sure the modifiers stay the same for the whole transaction
|
var buyValues = GetBuyValuesAtCurrentLocation(storeIdentifier, itemsToSell.Select(i => i.ItemPrefab));
|
||||||
Dictionary<ItemPrefab, int> buyValues = GetBuyValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
|
var store = Location.GetStore(storeIdentifier);
|
||||||
foreach (PurchasedItem item in itemsToSell)
|
if (store == null) { return; }
|
||||||
|
var storeSpecificItems = GetPurchasedItems(storeIdentifier);
|
||||||
|
foreach (var item in itemsToSell)
|
||||||
{
|
{
|
||||||
var itemValue = item.Quantity * buyValues[item.ItemPrefab];
|
var itemValue = item.Quantity * buyValues[item.ItemPrefab];
|
||||||
Location.StoreCurrentBalance -= itemValue;
|
store.Balance -= itemValue;
|
||||||
campaign.GetWallet(client).Give(itemValue);
|
campaign.GetWallet(client).Give(itemValue);
|
||||||
PurchasedItems.Remove(item);
|
storeSpecificItems?.Remove(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void BuyBackSoldItems(List<SoldItem> itemsToBuy, Client client)
|
public void BuyBackSoldItems(Identifier storeIdentifier, List<SoldItem> itemsToBuy)
|
||||||
{
|
{
|
||||||
// Check all the prices before starting the transaction
|
var store = Location.GetStore(storeIdentifier);
|
||||||
// to make sure the modifiers stay the same for the whole transaction
|
if (store == null) { return; }
|
||||||
var sellValues = GetSellValuesAtCurrentLocation(itemsToBuy.Select(i => i.ItemPrefab));
|
var storeSpecificItems = SoldItems.GetValueOrDefault(storeIdentifier);
|
||||||
|
// Check all the prices before starting the transaction to make sure the modifiers stay the same for the whole transaction
|
||||||
|
var sellValues = GetSellValuesAtCurrentLocation(storeIdentifier, itemsToBuy.Select(i => i.ItemPrefab));
|
||||||
foreach (var item in itemsToBuy)
|
foreach (var item in itemsToBuy)
|
||||||
{
|
{
|
||||||
int itemValue = sellValues[item.ItemPrefab];
|
int itemValue = sellValues[item.ItemPrefab];
|
||||||
if (Location.StoreCurrentBalance < itemValue || item.Removed) { continue; }
|
if (store.Balance < itemValue || item.Removed) { continue; }
|
||||||
Location.StoreCurrentBalance += itemValue;
|
store.Balance += itemValue;
|
||||||
campaign.Bank.TryDeduct(itemValue);
|
campaign.Bank.TryDeduct(itemValue);
|
||||||
SoldItems.Remove(item);
|
storeSpecificItems.Remove(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SellItems(List<SoldItem> itemsToSell, Client client)
|
public void SellItems(Identifier storeIdentifier, List<SoldItem> itemsToSell, Client client)
|
||||||
{
|
{
|
||||||
|
var store = Location.GetStore(storeIdentifier);
|
||||||
|
if (store == null) { return; }
|
||||||
bool canAddToRemoveQueue = (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && Entity.Spawner != null;
|
bool canAddToRemoveQueue = (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer) && Entity.Spawner != null;
|
||||||
IEnumerable<Item> sellableItemsInSub = Enumerable.Empty<Item>();
|
IEnumerable<Item> sellableItemsInSub = Enumerable.Empty<Item>();
|
||||||
if (canAddToRemoveQueue && itemsToSell.Any(i => i.Origin == SoldItem.SellOrigin.Submarine && i.ID == Entity.NullEntityID && !i.Removed))
|
if (canAddToRemoveQueue && itemsToSell.Any(i => i.Origin == SoldItem.SellOrigin.Submarine && i.ID == Entity.NullEntityID && !i.Removed))
|
||||||
{
|
{
|
||||||
sellableItemsInSub = GetSellableItemsFromSub();
|
sellableItemsInSub = GetSellableItemsFromSub();
|
||||||
}
|
}
|
||||||
// Check all the prices before starting the transaction
|
var itemsSoldAtStore = SoldItems.GetValueOrDefault(storeIdentifier);
|
||||||
// to make sure the modifiers stay the same for the whole transaction
|
// Check all the prices before starting the transaction to make sure the modifiers stay the same for the whole transaction
|
||||||
var sellValues = GetSellValuesAtCurrentLocation(itemsToSell.Select(i => i.ItemPrefab));
|
var sellValues = GetSellValuesAtCurrentLocation(storeIdentifier, itemsToSell.Select(i => i.ItemPrefab));
|
||||||
foreach (var item in itemsToSell)
|
foreach (var item in itemsToSell)
|
||||||
{
|
{
|
||||||
int itemValue = sellValues[item.ItemPrefab];
|
int itemValue = sellValues[item.ItemPrefab];
|
||||||
// check if the store can afford the item and if the item hasn't been removed already
|
// check if the store can afford the item and if the item hasn't been removed already
|
||||||
if (Location.StoreCurrentBalance < itemValue || item.Removed) { continue; }
|
if (store.Balance < itemValue || item.Removed) { continue; }
|
||||||
// Server determines the items that are sold from the sub in multiplayer
|
// Server determines the items that are sold from the sub in multiplayer
|
||||||
if (item.Origin == SoldItem.SellOrigin.Submarine && item.ID == Entity.NullEntityID && !item.Removed)
|
if (item.Origin == SoldItem.SellOrigin.Submarine && item.ID == Entity.NullEntityID && !item.Removed)
|
||||||
{
|
{
|
||||||
@@ -66,8 +72,8 @@ namespace Barotrauma
|
|||||||
item.Removed = true;
|
item.Removed = true;
|
||||||
Entity.Spawner.AddItemToRemoveQueue(entity);
|
Entity.Spawner.AddItemToRemoveQueue(entity);
|
||||||
}
|
}
|
||||||
SoldItems.Add(item);
|
itemsSoldAtStore?.Add(item);
|
||||||
Location.StoreCurrentBalance -= itemValue;
|
store.Balance -= itemValue;
|
||||||
campaign.Bank.Give(itemValue);
|
campaign.Bank.Give(itemValue);
|
||||||
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value);
|
GameAnalyticsManager.AddMoneyGainedEvent(itemValue, GameAnalyticsManager.MoneySource.Store, item.ItemPrefab.Identifier.Value);
|
||||||
}
|
}
|
||||||
|
|||||||
+79
-89
@@ -616,8 +616,17 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store balance
|
// Store balance
|
||||||
msg.Write(true);
|
bool hasStores = map.CurrentLocation.Stores != null && map.CurrentLocation.Stores.Any();
|
||||||
msg.Write((UInt16)map.CurrentLocation.StoreCurrentBalance);
|
msg.Write(hasStores);
|
||||||
|
if (hasStores)
|
||||||
|
{
|
||||||
|
msg.Write((byte)map.CurrentLocation.Stores.Count);
|
||||||
|
foreach (var store in map.CurrentLocation.Stores.Values)
|
||||||
|
{
|
||||||
|
msg.Write(store.Identifier);
|
||||||
|
msg.Write((UInt16)store.Balance);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -626,36 +635,10 @@ namespace Barotrauma
|
|||||||
msg.Write(false);
|
msg.Write(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.ItemsInBuyCrate.Count);
|
WriteItems(msg, CargoManager.ItemsInBuyCrate);
|
||||||
foreach (PurchasedItem pi in CargoManager.ItemsInBuyCrate)
|
WriteItems(msg, CargoManager.ItemsInSellFromSubCrate);
|
||||||
{
|
WriteItems(msg, CargoManager.PurchasedItems);
|
||||||
msg.Write(pi.ItemPrefab.Identifier);
|
WriteItems(msg, CargoManager.SoldItems);
|
||||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.ItemsInSellFromSubCrate.Count);
|
|
||||||
foreach (PurchasedItem pi in CargoManager.ItemsInSellFromSubCrate)
|
|
||||||
{
|
|
||||||
msg.Write(pi.ItemPrefab.Identifier);
|
|
||||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.PurchasedItems.Count);
|
|
||||||
foreach (PurchasedItem pi in CargoManager.PurchasedItems)
|
|
||||||
{
|
|
||||||
msg.Write(pi.ItemPrefab.Identifier);
|
|
||||||
msg.WriteRangedInteger(pi.Quantity, 0, CargoManager.MaxQuantity);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Write((UInt16)CargoManager.SoldItems.Count);
|
|
||||||
foreach (SoldItem si in CargoManager.SoldItems)
|
|
||||||
{
|
|
||||||
msg.Write(si.ItemPrefab.Identifier);
|
|
||||||
msg.Write((UInt16)si.ID);
|
|
||||||
msg.Write(si.Removed);
|
|
||||||
msg.Write(si.SellerID);
|
|
||||||
msg.Write((byte)si.Origin);
|
|
||||||
}
|
|
||||||
|
|
||||||
msg.Write((ushort)UpgradeManager.PendingUpgrades.Count);
|
msg.Write((ushort)UpgradeManager.PendingUpgrades.Count);
|
||||||
foreach (var (prefab, category, level) in UpgradeManager.PendingUpgrades)
|
foreach (var (prefab, category, level) in UpgradeManager.PendingUpgrades)
|
||||||
@@ -700,44 +683,10 @@ namespace Barotrauma
|
|||||||
bool purchasedItemRepairs = msg.ReadBoolean();
|
bool purchasedItemRepairs = msg.ReadBoolean();
|
||||||
bool purchasedLostShuttles = msg.ReadBoolean();
|
bool purchasedLostShuttles = msg.ReadBoolean();
|
||||||
|
|
||||||
UInt16 buyCrateItemCount = msg.ReadUInt16();
|
var buyCrateItems = ReadPurchasedItems(msg, sender);
|
||||||
List<PurchasedItem> buyCrateItems = new List<PurchasedItem>();
|
var subSellCrateItems = ReadPurchasedItems(msg, sender);
|
||||||
for (int i = 0; i < buyCrateItemCount; i++)
|
var purchasedItems = ReadPurchasedItems(msg, sender);
|
||||||
{
|
var soldItems = ReadSoldItems(msg);
|
||||||
string itemPrefabIdentifier = msg.ReadString();
|
|
||||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
|
||||||
buyCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt16 subSellCrateItemCount = msg.ReadUInt16();
|
|
||||||
List<PurchasedItem> subSellCrateItems = new List<PurchasedItem>();
|
|
||||||
for (int i = 0; i < subSellCrateItemCount; i++)
|
|
||||||
{
|
|
||||||
string itemPrefabIdentifier = msg.ReadString();
|
|
||||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
|
||||||
subSellCrateItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt16 purchasedItemCount = msg.ReadUInt16();
|
|
||||||
List<PurchasedItem> purchasedItems = new List<PurchasedItem>();
|
|
||||||
for (int i = 0; i < purchasedItemCount; i++)
|
|
||||||
{
|
|
||||||
string itemPrefabIdentifier = msg.ReadString();
|
|
||||||
int itemQuantity = msg.ReadRangedInteger(0, CargoManager.MaxQuantity);
|
|
||||||
purchasedItems.Add(new PurchasedItem(ItemPrefab.Prefabs[itemPrefabIdentifier], itemQuantity, sender));
|
|
||||||
}
|
|
||||||
|
|
||||||
UInt16 soldItemCount = msg.ReadUInt16();
|
|
||||||
List<SoldItem> soldItems = new List<SoldItem>();
|
|
||||||
for (int i = 0; i < soldItemCount; i++)
|
|
||||||
{
|
|
||||||
string itemPrefabIdentifier = msg.ReadString();
|
|
||||||
UInt16 id = msg.ReadUInt16();
|
|
||||||
bool removed = msg.ReadBoolean();
|
|
||||||
byte sellerId = msg.ReadByte();
|
|
||||||
byte origin = msg.ReadByte();
|
|
||||||
soldItems.Add(new SoldItem(ItemPrefab.Prefabs[itemPrefabIdentifier], id, removed, sellerId, (SoldItem.SellOrigin)origin));
|
|
||||||
}
|
|
||||||
|
|
||||||
ushort purchasedUpgradeCount = msg.ReadUInt16();
|
ushort purchasedUpgradeCount = msg.ReadUInt16();
|
||||||
List<PurchasedUpgrade> purchasedUpgrades = new List<PurchasedUpgrade>();
|
List<PurchasedUpgrade> purchasedUpgrades = new List<PurchasedUpgrade>();
|
||||||
@@ -839,42 +788,83 @@ namespace Barotrauma
|
|||||||
bool allowedToUseStore = AllowedToManageCampaign(sender, ClientPermissions.CampaignStore);
|
bool allowedToUseStore = AllowedToManageCampaign(sender, ClientPermissions.CampaignStore);
|
||||||
if (allowedToManageCampaign || allowedToUseStore || AllowedToManageCampaign(sender, ClientPermissions.BuyItems))
|
if (allowedToManageCampaign || allowedToUseStore || AllowedToManageCampaign(sender, ClientPermissions.BuyItems))
|
||||||
{
|
{
|
||||||
var currentBuyCrateItems = new List<PurchasedItem>(CargoManager.ItemsInBuyCrate);
|
var prevBuyCrateItems = new Dictionary<Identifier, List<PurchasedItem>>(CargoManager.ItemsInBuyCrate);
|
||||||
currentBuyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, -i.Quantity, sender));
|
foreach (var store in prevBuyCrateItems)
|
||||||
buyCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInBuyCrate(i.ItemPrefab, i.Quantity, sender));
|
{
|
||||||
CargoManager.SellBackPurchasedItems(new List<PurchasedItem>(CargoManager.PurchasedItems));
|
foreach (var item in store.Value)
|
||||||
CargoManager.PurchaseItems(purchasedItems, false, sender);
|
{
|
||||||
|
CargoManager.ModifyItemQuantityInBuyCrate(store.Key, item.ItemPrefab, -item.Quantity, sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var store in buyCrateItems)
|
||||||
|
{
|
||||||
|
foreach (var item in store.Value)
|
||||||
|
{
|
||||||
|
CargoManager.ModifyItemQuantityInBuyCrate(store.Key, item.ItemPrefab, item.Quantity, sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var prevPurchasedItems = new Dictionary<Identifier, List<PurchasedItem>>(CargoManager.PurchasedItems);
|
||||||
|
foreach (var store in prevPurchasedItems)
|
||||||
|
{
|
||||||
|
CargoManager.SellBackPurchasedItems(store.Key, store.Value);
|
||||||
|
}
|
||||||
|
foreach (var store in purchasedItems)
|
||||||
|
{
|
||||||
|
CargoManager.PurchaseItems(store.Key, store.Value, false, sender);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allowedToSellSubItems = AllowedToManageCampaign(sender, ClientPermissions.SellSubItems);
|
bool allowedToSellSubItems = AllowedToManageCampaign(sender, ClientPermissions.SellSubItems);
|
||||||
if (allowedToManageCampaign || allowedToUseStore || allowedToSellSubItems)
|
if (allowedToManageCampaign || allowedToUseStore || allowedToSellSubItems)
|
||||||
{
|
{
|
||||||
var currentSubSellCrateItems = new List<PurchasedItem>(CargoManager.ItemsInSellFromSubCrate);
|
var prevSubSellCrateItems = new Dictionary<Identifier, List<PurchasedItem>>(CargoManager.ItemsInSellFromSubCrate);
|
||||||
currentSubSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, -i.Quantity, sender));
|
foreach (var store in prevSubSellCrateItems)
|
||||||
subSellCrateItems.ForEach(i => CargoManager.ModifyItemQuantityInSubSellCrate(i.ItemPrefab, i.Quantity, sender));
|
{
|
||||||
|
foreach (var item in store.Value)
|
||||||
|
{
|
||||||
|
CargoManager.ModifyItemQuantityInSubSellCrate(store.Key, item.ItemPrefab, -item.Quantity, sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (var store in subSellCrateItems)
|
||||||
|
{
|
||||||
|
foreach (var item in store.Value)
|
||||||
|
{
|
||||||
|
CargoManager.ModifyItemQuantityInSubSellCrate(store.Key, item.ItemPrefab, item.Quantity, sender);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allowedToSellInventoryItems = AllowedToManageCampaign(sender, ClientPermissions.SellInventoryItems);
|
bool allowedToSellInventoryItems = AllowedToManageCampaign(sender, ClientPermissions.SellInventoryItems);
|
||||||
if (allowedToManageCampaign || allowedToUseStore || (allowedToSellInventoryItems && allowedToSellSubItems))
|
if (allowedToManageCampaign || allowedToUseStore || (allowedToSellInventoryItems && allowedToSellSubItems))
|
||||||
{
|
{
|
||||||
// for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all
|
// for some reason CargoManager.SoldItem is never cleared by the server, I've added a check to SellItems that ignores all
|
||||||
// sold items that are removed so they should be discarded on the next message
|
// sold items that are removed so they should be discarded on the next message
|
||||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems), sender);
|
var prevSoldItems = new Dictionary<Identifier, List<SoldItem>>(CargoManager.SoldItems);
|
||||||
CargoManager.SellItems(soldItems, sender);
|
foreach (var store in prevSoldItems)
|
||||||
|
{
|
||||||
|
CargoManager.BuyBackSoldItems(store.Key, store.Value);
|
||||||
|
}
|
||||||
|
foreach (var store in soldItems)
|
||||||
|
{
|
||||||
|
CargoManager.SellItems(store.Key, store.Value, sender);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (allowedToSellInventoryItems || allowedToSellSubItems)
|
else if (allowedToSellInventoryItems || allowedToSellSubItems)
|
||||||
{
|
{
|
||||||
if (allowedToSellInventoryItems)
|
var prevSoldItems = new Dictionary<Identifier, List<SoldItem>>(CargoManager.SoldItems);
|
||||||
|
foreach (var store in prevSoldItems)
|
||||||
{
|
{
|
||||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Character)), sender);
|
store.Value.RemoveAll(predicate);
|
||||||
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Character);
|
CargoManager.BuyBackSoldItems(store.Key, store.Value);
|
||||||
}
|
}
|
||||||
else
|
foreach (var store in soldItems)
|
||||||
{
|
{
|
||||||
CargoManager.BuyBackSoldItems(new List<SoldItem>(CargoManager.SoldItems.Where(i => i.Origin == SoldItem.SellOrigin.Submarine)), sender);
|
store.Value.RemoveAll(predicate);
|
||||||
soldItems.RemoveAll(i => i.Origin != SoldItem.SellOrigin.Submarine);
|
|
||||||
}
|
}
|
||||||
CargoManager.SellItems(soldItems, sender);
|
foreach (var store in soldItems)
|
||||||
|
{
|
||||||
|
CargoManager.SellItems(store.Key, store.Value, sender);
|
||||||
|
}
|
||||||
|
bool predicate(SoldItem i) => allowedToSellInventoryItems != (i.Origin == SoldItem.SellOrigin.Character);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowedToManageCampaign)
|
if (allowedToManageCampaign)
|
||||||
@@ -960,7 +950,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public void ServerReadRewardDistribution(IReadMessage msg, Client sender)
|
public void ServerReadRewardDistribution(IReadMessage msg, Client sender)
|
||||||
{
|
{
|
||||||
NetWalletSalaryUpdate update = INetSerializableStruct.Read<NetWalletSalaryUpdate>(msg);
|
NetWalletSetSalaryUpdate update = INetSerializableStruct.Read<NetWalletSetSalaryUpdate>(msg);
|
||||||
|
|
||||||
if (!AllowedToManageCampaign(sender)) { return; }
|
if (!AllowedToManageCampaign(sender)) { return; }
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@ namespace Barotrauma.Items.Components
|
|||||||
msg.Write(item.CurrentHull?.ID ?? Entity.NullEntityID);
|
msg.Write(item.CurrentHull?.ID ?? Entity.NullEntityID);
|
||||||
msg.Write(item.SimPosition.X);
|
msg.Write(item.SimPosition.X);
|
||||||
msg.Write(item.SimPosition.Y);
|
msg.Write(item.SimPosition.Y);
|
||||||
msg.Write(stickJoint.Axis.X);
|
msg.Write(jointAxis.X);
|
||||||
msg.Write(stickJoint.Axis.Y);
|
msg.Write(jointAxis.Y);
|
||||||
if (StickTarget.UserData is Structure structure)
|
if (StickTarget.UserData is Structure structure)
|
||||||
{
|
{
|
||||||
msg.Write(structure.ID);
|
msg.Write(structure.ID);
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ namespace Barotrauma
|
|||||||
if (containerIndex < 0)
|
if (containerIndex < 0)
|
||||||
{
|
{
|
||||||
throw error($"container index out of range ({containerIndex})");
|
throw error($"container index out of range ({containerIndex})");
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
if (!(components[containerIndex] is ItemContainer itemContainer))
|
if (!(components[containerIndex] is ItemContainer itemContainer))
|
||||||
{
|
{
|
||||||
@@ -66,7 +65,7 @@ namespace Barotrauma
|
|||||||
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
msg.Write(GameMain.Server.EntityEventManager.Events.Last()?.ID ?? (ushort)0);
|
||||||
itemContainer.Inventory.ServerEventWrite(msg, c);
|
itemContainer.Inventory.ServerEventWrite(msg, c);
|
||||||
break;
|
break;
|
||||||
case StatusEventData _:
|
case ItemStatusEventData _:
|
||||||
msg.Write(condition);
|
msg.Write(condition);
|
||||||
break;
|
break;
|
||||||
case AssignCampaignInteractionEventData _:
|
case AssignCampaignInteractionEventData _:
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
using Barotrauma.Items.Components;
|
using Barotrauma.Items.Components;
|
||||||
using Barotrauma.Networking;
|
using Barotrauma.Networking;
|
||||||
using System;
|
using System;
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma.MapCreatures.Behavior
|
namespace Barotrauma.MapCreatures.Behavior
|
||||||
{
|
{
|
||||||
partial class BallastFloraBehavior
|
partial class BallastFloraBehavior
|
||||||
{
|
{
|
||||||
|
const float DamageUpdateInterval = 1.0f;
|
||||||
|
|
||||||
private float damageUpdateTimer;
|
private float damageUpdateTimer;
|
||||||
|
|
||||||
partial void LoadPrefab(ContentXElement element)
|
partial void LoadPrefab(ContentXElement element)
|
||||||
@@ -31,16 +32,38 @@ namespace Barotrauma.MapCreatures.Behavior
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
partial void UpdateDamage(float deltaTime)
|
||||||
|
{
|
||||||
|
damageUpdateTimer -= deltaTime;
|
||||||
|
if (damageUpdateTimer > 0.0f) { return; }
|
||||||
|
|
||||||
|
const int maxMessagesPerSecond = 10;
|
||||||
|
int messages = 0;
|
||||||
|
foreach (BallastFloraBranch branch in Branches)
|
||||||
|
{
|
||||||
|
//don't notify about minuscule amounts of damage (<= 1.0f)
|
||||||
|
if (branch.AccumulatedDamage > 1.0f)
|
||||||
|
{
|
||||||
|
CreateNetworkMessage(new BranchDamageEventData(branch));
|
||||||
|
branch.AccumulatedDamage = 0.0f;
|
||||||
|
messages++;
|
||||||
|
//throttle a bit: if a large ballast flora is withering, it can lead to a very large number of events otherwise
|
||||||
|
if (messages > maxMessagesPerSecond) { break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
damageUpdateTimer = DamageUpdateInterval;
|
||||||
|
}
|
||||||
|
|
||||||
public void ServerWrite(IWriteMessage msg, IEventData eventData)
|
public void ServerWrite(IWriteMessage msg, IEventData eventData)
|
||||||
{
|
{
|
||||||
msg.Write((byte)eventData.NetworkHeader);
|
msg.Write((byte)eventData.NetworkHeader);
|
||||||
|
|
||||||
switch (eventData)
|
switch (eventData)
|
||||||
{
|
{
|
||||||
case SpawnEventData spawnEventData:
|
case SpawnEventData _:
|
||||||
ServerWriteSpawn(msg);
|
ServerWriteSpawn(msg);
|
||||||
break;
|
break;
|
||||||
case KillEventData killEventData:
|
case KillEventData _:
|
||||||
//do nothing
|
//do nothing
|
||||||
break;
|
break;
|
||||||
case BranchCreateEventData branchCreateEventData:
|
case BranchCreateEventData branchCreateEventData:
|
||||||
@@ -72,6 +95,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
|||||||
var (x, y) = branch.Position;
|
var (x, y) = branch.Position;
|
||||||
msg.Write(parentId);
|
msg.Write(parentId);
|
||||||
msg.Write((int)branch.ID);
|
msg.Write((int)branch.ID);
|
||||||
|
msg.Write(branch.IsRootGrowth);
|
||||||
msg.WriteRangedInteger((byte)branch.Type, 0b0000, 0b1111);
|
msg.WriteRangedInteger((byte)branch.Type, 0b0000, 0b1111);
|
||||||
msg.WriteRangedInteger((byte)branch.Sides, 0b0000, 0b1111);
|
msg.WriteRangedInteger((byte)branch.Sides, 0b0000, 0b1111);
|
||||||
msg.WriteRangedInteger(branch.FlowerConfig.Serialize(), 0, 0xFFF);
|
msg.WriteRangedInteger(branch.FlowerConfig.Serialize(), 0, 0xFFF);
|
||||||
@@ -103,7 +127,7 @@ namespace Barotrauma.MapCreatures.Behavior
|
|||||||
msg.Write(branch.ID);
|
msg.Write(branch.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SendNetworkMessage(IEventData extraData)
|
public void CreateNetworkMessage(IEventData extraData)
|
||||||
{
|
{
|
||||||
GameMain.Server.CreateEntityEvent(Parent, new Hull.BallastFloraEventData(this, extraData));
|
GameMain.Server.CreateEntityEvent(Parent, new Hull.BallastFloraEventData(this, extraData));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,11 @@ namespace Barotrauma.Networking
|
|||||||
public static string GetCompressedModPath(ContentPackage mod)
|
public static string GetCompressedModPath(ContentPackage mod)
|
||||||
{
|
{
|
||||||
string dir = mod.Dir;
|
string dir = mod.Dir;
|
||||||
string resultFileName = dir.Replace('\\', '_').Replace('/', '_');
|
string resultFileName
|
||||||
|
= dir.StartsWith(ContentPackage.LocalModsDir)
|
||||||
|
? $"Local_{mod.Name}"
|
||||||
|
: $"Workshop_{mod.Name}";
|
||||||
|
resultFileName = ToolBox.RemoveInvalidFileNameChars(resultFileName.Replace('\\', '_').Replace('/', '_'));
|
||||||
resultFileName = $"{resultFileName}{Extension}";
|
resultFileName = $"{resultFileName}{Extension}";
|
||||||
return Path.Combine(UploadFolder, resultFileName);
|
return Path.Combine(UploadFolder, resultFileName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -814,7 +814,7 @@ namespace Barotrauma.Networking
|
|||||||
case ClientPacketHeader.CREW:
|
case ClientPacketHeader.CREW:
|
||||||
ReadCrewMessage(inc, connectedClient);
|
ReadCrewMessage(inc, connectedClient);
|
||||||
break;
|
break;
|
||||||
case ClientPacketHeader.MONEY:
|
case ClientPacketHeader.TRANSFER_MONEY:
|
||||||
ReadMoneyMessage(inc, connectedClient);
|
ReadMoneyMessage(inc, connectedClient);
|
||||||
break;
|
break;
|
||||||
case ClientPacketHeader.REWARD_DISTRIBUTION:
|
case ClientPacketHeader.REWARD_DISTRIBUTION:
|
||||||
|
|||||||
@@ -321,11 +321,16 @@ namespace Barotrauma.Networking
|
|||||||
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
GameMain.NetLobbyScreen.SetTraitorsEnabled(traitorsEnabled);
|
||||||
|
|
||||||
HiddenSubs.UnionWith(doc.Root.GetAttributeStringArray("HiddenSubs", Array.Empty<string>()));
|
HiddenSubs.UnionWith(doc.Root.GetAttributeStringArray("HiddenSubs", Array.Empty<string>()));
|
||||||
|
if (HiddenSubs.Any())
|
||||||
|
{
|
||||||
|
UpdateFlag(NetFlags.HiddenSubs);
|
||||||
|
}
|
||||||
|
|
||||||
SelectedSubmarine = SelectNonHiddenSubmarine(SelectedSubmarine);
|
SelectedSubmarine = SelectNonHiddenSubmarine(SelectedSubmarine);
|
||||||
|
|
||||||
string[] defaultAllowedClientNameChars =
|
string[] defaultAllowedClientNameChars =
|
||||||
new string[] {
|
new string[]
|
||||||
|
{
|
||||||
"32-33",
|
"32-33",
|
||||||
"38-46",
|
"38-46",
|
||||||
"48-57",
|
"48-57",
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Barotrauma
|
|||||||
Role = role;
|
Role = role;
|
||||||
Character = character;
|
Character = character;
|
||||||
Character.IsTraitor = true;
|
Character.IsTraitor = true;
|
||||||
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.StatusEventData());
|
GameMain.NetworkMember.CreateEntityEvent(Character, new Character.CharacterStatusEventData());
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void MessageSender(string message);
|
public delegate void MessageSender(string message);
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<RootNamespace>Barotrauma</RootNamespace>
|
<RootNamespace>Barotrauma</RootNamespace>
|
||||||
<Authors>FakeFish, Undertow Games</Authors>
|
<Authors>FakeFish, Undertow Games</Authors>
|
||||||
<Product>Barotrauma Dedicated Server</Product>
|
<Product>Barotrauma Dedicated Server</Product>
|
||||||
<Version>0.17.2.0</Version>
|
<Version>0.17.4.0</Version>
|
||||||
<Copyright>Copyright © FakeFish 2018-2020</Copyright>
|
<Copyright>Copyright © FakeFish 2018-2022</Copyright>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<AssemblyName>DedicatedServer</AssemblyName>
|
<AssemblyName>DedicatedServer</AssemblyName>
|
||||||
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
<ApplicationIcon>..\BarotraumaShared\Icon.ico</ApplicationIcon>
|
||||||
|
|||||||
Binary file not shown.
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<contentpackage name="PowerTestSub" modversion="1.0.2" corepackage="False" gameversion="0.16.4.0">
|
|
||||||
<Submarine file="%ModDir%/PowerTestSub.sub" />
|
|
||||||
</contentpackage>
|
|
||||||
@@ -56,7 +56,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private readonly float updateTargetsInterval = 1;
|
private readonly float updateTargetsInterval = 1;
|
||||||
private readonly float updateMemoriesInverval = 1;
|
private readonly float updateMemoriesInverval = 1;
|
||||||
private readonly float attackLimbResetInterval = 2;
|
private readonly float attackLimbSelectionInterval = 3;
|
||||||
// Min priority for the memorized targets. The actual value fades gradually, unless kept fresh by selecting the target.
|
// Min priority for the memorized targets. The actual value fades gradually, unless kept fresh by selecting the target.
|
||||||
private const float minPriority = 10;
|
private const float minPriority = 10;
|
||||||
|
|
||||||
@@ -65,10 +65,10 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private float updateTargetsTimer;
|
private float updateTargetsTimer;
|
||||||
private float updateMemoriesTimer;
|
private float updateMemoriesTimer;
|
||||||
private float attackLimbResetTimer;
|
private float attackLimbSelectionTimer;
|
||||||
|
|
||||||
private bool IsAttackRunning => AttackingLimb != null && AttackingLimb.attack.IsRunning;
|
private bool IsAttackRunning => AttackLimb != null && AttackLimb.attack.IsRunning;
|
||||||
private bool IsCoolDownRunning => AttackingLimb != null && AttackingLimb.attack.CoolDownTimer > 0 || _previousAttackingLimb != null && _previousAttackingLimb.attack.CoolDownTimer > 0;
|
private bool IsCoolDownRunning => AttackLimb != null && AttackLimb.attack.CoolDownTimer > 0 || _previousAttackLimb != null && _previousAttackLimb.attack.CoolDownTimer > 0;
|
||||||
public float CombatStrength => AIParams.CombatStrength;
|
public float CombatStrength => AIParams.CombatStrength;
|
||||||
private float Sight => AIParams.Sight;
|
private float Sight => AIParams.Sight;
|
||||||
private float Hearing => AIParams.Hearing;
|
private float Hearing => AIParams.Hearing;
|
||||||
@@ -77,25 +77,25 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private FishAnimController FishAnimController => Character.AnimController as FishAnimController;
|
private FishAnimController FishAnimController => Character.AnimController as FishAnimController;
|
||||||
|
|
||||||
private Limb _attackingLimb;
|
private Limb _attackLimb;
|
||||||
private Limb _previousAttackingLimb;
|
private Limb _previousAttackLimb;
|
||||||
public Limb AttackingLimb
|
public Limb AttackLimb
|
||||||
{
|
{
|
||||||
get { return _attackingLimb; }
|
get { return _attackLimb; }
|
||||||
private set
|
private set
|
||||||
{
|
{
|
||||||
attackLimbResetTimer = 0;
|
if (_attackLimb != value)
|
||||||
if (_attackingLimb != value)
|
|
||||||
{
|
{
|
||||||
_previousAttackingLimb = _attackingLimb;
|
_previousAttackLimb = _attackLimb;
|
||||||
|
_previousAttackLimb?.AttachedRope?.Snap();
|
||||||
}
|
}
|
||||||
if (_attackingLimb != null && value != _attackingLimb && _attackingLimb.attack.CoolDownTimer > 0)
|
else if (_attackLimb != null && _attackLimb.attack.CoolDownTimer <= 0)
|
||||||
{
|
{
|
||||||
SetAimTimer();
|
_attackLimb.AttachedRope?.Snap();
|
||||||
}
|
}
|
||||||
_attackingLimb = value;
|
_attackLimb = value;
|
||||||
attackVector = null;
|
attackVector = null;
|
||||||
Reverse = _attackingLimb != null && _attackingLimb.attack.Reverse;
|
Reverse = _attackLimb != null && _attackLimb.attack.Reverse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -425,7 +425,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
private void ReleaseDragTargets()
|
private void ReleaseDragTargets()
|
||||||
{
|
{
|
||||||
if (Character.Inventory != null)
|
AttackLimb?.AttachedRope?.Snap();
|
||||||
|
if (Character.Params.CanInteract && Character.Inventory != null)
|
||||||
{
|
{
|
||||||
Character.HeldItems.ForEach(i => i.GetComponent<Holdable>()?.GetRope()?.Snap());
|
Character.HeldItems.ForEach(i => i.GetComponent<Holdable>()?.GetRope()?.Snap());
|
||||||
}
|
}
|
||||||
@@ -600,7 +601,7 @@ namespace Barotrauma
|
|||||||
UpdatePatrol(deltaTime);
|
UpdatePatrol(deltaTime);
|
||||||
break;
|
break;
|
||||||
case AIState.Attack:
|
case AIState.Attack:
|
||||||
run = !IsCoolDownRunning || AttackingLimb != null && AttackingLimb.attack.FullSpeedAfterAttack;
|
run = !IsCoolDownRunning || AttackLimb != null && AttackLimb.attack.FullSpeedAfterAttack;
|
||||||
UpdateAttack(deltaTime);
|
UpdateAttack(deltaTime);
|
||||||
break;
|
break;
|
||||||
case AIState.Eat:
|
case AIState.Eat:
|
||||||
@@ -620,7 +621,7 @@ namespace Barotrauma
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
float squaredDistance = Vector2.DistanceSquared(WorldPosition, SelectedAiTarget.WorldPosition);
|
float squaredDistance = Vector2.DistanceSquared(WorldPosition, SelectedAiTarget.WorldPosition);
|
||||||
var attackLimb = AttackingLimb ?? GetAttackLimb(SelectedAiTarget.WorldPosition);
|
var attackLimb = AttackLimb ?? GetAttackLimb(SelectedAiTarget.WorldPosition);
|
||||||
if (attackLimb != null && squaredDistance <= Math.Pow(attackLimb.attack.Range, 2))
|
if (attackLimb != null && squaredDistance <= Math.Pow(attackLimb.attack.Range, 2))
|
||||||
{
|
{
|
||||||
run = true;
|
run = true;
|
||||||
@@ -875,7 +876,10 @@ namespace Barotrauma
|
|||||||
if (followLastTarget)
|
if (followLastTarget)
|
||||||
{
|
{
|
||||||
var target = SelectedAiTarget ?? _lastAiTarget;
|
var target = SelectedAiTarget ?? _lastAiTarget;
|
||||||
if (target?.Entity != null && !target.Entity.Removed && PreviousState == AIState.Attack && Character.CurrentHull == null)
|
if (target?.Entity != null && !target.Entity.Removed &&
|
||||||
|
PreviousState == AIState.Attack && Character.CurrentHull == null &&
|
||||||
|
(_previousAttackLimb?.attack == null ||
|
||||||
|
_previousAttackLimb?.attack is Attack previousAttack && (previousAttack.AfterAttack != AIBehaviorAfterAttack.FallBack || previousAttack.CoolDownTimer <= 0)))
|
||||||
{
|
{
|
||||||
// Keep heading to the last known position of the target
|
// Keep heading to the last known position of the target
|
||||||
var memory = GetTargetMemory(target, false);
|
var memory = GetTargetMemory(target, false);
|
||||||
@@ -1127,30 +1131,41 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
attackLimbSelectionTimer -= deltaTime;
|
||||||
|
if (AttackLimb == null || attackLimbSelectionTimer <= 0)
|
||||||
|
{
|
||||||
|
attackLimbSelectionTimer = attackLimbSelectionInterval * Rand.Range(0.9f, 1.1f);
|
||||||
|
if (!IsAttackRunning && !IsCoolDownRunning)
|
||||||
|
{
|
||||||
|
AttackLimb = GetAttackLimb(attackWorldPos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool canAttack = true;
|
bool canAttack = true;
|
||||||
bool pursue = false;
|
bool pursue = false;
|
||||||
if (IsCoolDownRunning)
|
if (IsCoolDownRunning && (_previousAttackLimb == null || AttackLimb == null || AttackLimb.attack.CoolDownTimer > 0))
|
||||||
{
|
{
|
||||||
var currentAttackLimb = AttackingLimb ?? _previousAttackingLimb;
|
var currentAttackLimb = AttackLimb ?? _previousAttackLimb;
|
||||||
if (currentAttackLimb.attack.CoolDownTimer >= currentAttackLimb.attack.CoolDown + currentAttackLimb.attack.CurrentRandomCoolDown - currentAttackLimb.attack.AfterAttackDelay)
|
if (currentAttackLimb.attack.CoolDownTimer >= currentAttackLimb.attack.CoolDown + currentAttackLimb.attack.CurrentRandomCoolDown - currentAttackLimb.attack.AfterAttackDelay)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (currentAttackLimb.attack.AfterAttack)
|
AIBehaviorAfterAttack activeBehavior = currentAttackLimb.attack.AfterAttack;
|
||||||
|
switch (activeBehavior)
|
||||||
{
|
{
|
||||||
case AIBehaviorAfterAttack.Pursue:
|
case AIBehaviorAfterAttack.Pursue:
|
||||||
case AIBehaviorAfterAttack.PursueIfCanAttack:
|
case AIBehaviorAfterAttack.PursueIfCanAttack:
|
||||||
if (currentAttackLimb.attack.SecondaryCoolDown <= 0)
|
if (currentAttackLimb.attack.SecondaryCoolDown <= 0)
|
||||||
{
|
{
|
||||||
// No (valid) secondary cooldown defined.
|
// No (valid) secondary cooldown defined.
|
||||||
if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
|
if (activeBehavior == AIBehaviorAfterAttack.Pursue)
|
||||||
{
|
{
|
||||||
canAttack = false;
|
canAttack = false;
|
||||||
pursue = true;
|
pursue = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, true);
|
UpdateFallBack(attackWorldPos, deltaTime, followThrough: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1162,13 +1177,13 @@ namespace Barotrauma
|
|||||||
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
||||||
{
|
{
|
||||||
canAttack = false;
|
canAttack = false;
|
||||||
if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.PursueIfCanAttack)
|
if (activeBehavior == AIBehaviorAfterAttack.PursueIfCanAttack)
|
||||||
{
|
{
|
||||||
// Fall back if cannot attack.
|
// Fall back if cannot attack.
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, true);
|
UpdateFallBack(attackWorldPos, deltaTime, followThrough: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AttackingLimb = null;
|
AttackLimb = null;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1177,19 +1192,19 @@ namespace Barotrauma
|
|||||||
if (newLimb != null)
|
if (newLimb != null)
|
||||||
{
|
{
|
||||||
// Attack with the new limb
|
// Attack with the new limb
|
||||||
AttackingLimb = newLimb;
|
AttackLimb = newLimb;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No new limb was found.
|
// No new limb was found.
|
||||||
if (currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.Pursue)
|
if (activeBehavior == AIBehaviorAfterAttack.Pursue)
|
||||||
{
|
{
|
||||||
canAttack = false;
|
canAttack = false;
|
||||||
pursue = true;
|
pursue = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, true);
|
UpdateFallBack(attackWorldPos, deltaTime, followThrough: true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1204,10 +1219,15 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
case AIBehaviorAfterAttack.FallBackUntilCanAttack:
|
case AIBehaviorAfterAttack.FallBackUntilCanAttack:
|
||||||
case AIBehaviorAfterAttack.FollowThroughUntilCanAttack:
|
case AIBehaviorAfterAttack.FollowThroughUntilCanAttack:
|
||||||
|
case AIBehaviorAfterAttack.ReverseUntilCanAttack:
|
||||||
|
if (activeBehavior == AIBehaviorAfterAttack.ReverseUntilCanAttack)
|
||||||
|
{
|
||||||
|
Reverse = true;
|
||||||
|
}
|
||||||
if (currentAttackLimb.attack.SecondaryCoolDown <= 0)
|
if (currentAttackLimb.attack.SecondaryCoolDown <= 0)
|
||||||
{
|
{
|
||||||
// No (valid) secondary cooldown defined.
|
// No (valid) secondary cooldown defined.
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
UpdateFallBack(attackWorldPos, deltaTime, activeBehavior == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1217,7 +1237,7 @@ namespace Barotrauma
|
|||||||
// Don't allow attacking when the attack target has just changed.
|
// Don't allow attacking when the attack target has just changed.
|
||||||
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
if (_previousAiTarget != null && SelectedAiTarget != _previousAiTarget)
|
||||||
{
|
{
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
UpdateFallBack(attackWorldPos, deltaTime, activeBehavior == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1227,12 +1247,12 @@ namespace Barotrauma
|
|||||||
if (newLimb != null)
|
if (newLimb != null)
|
||||||
{
|
{
|
||||||
// Attack with the new limb
|
// Attack with the new limb
|
||||||
AttackingLimb = newLimb;
|
AttackLimb = newLimb;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// No new limb was found.
|
// No new limb was found.
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
UpdateFallBack(attackWorldPos, deltaTime, activeBehavior == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1240,7 +1260,7 @@ namespace Barotrauma
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Cooldown not yet expired -> steer away from the target
|
// Cooldown not yet expired -> steer away from the target
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, currentAttackLimb.attack.AfterAttack == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
UpdateFallBack(attackWorldPos, deltaTime, activeBehavior == AIBehaviorAfterAttack.FollowThroughUntilCanAttack);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1269,7 +1289,7 @@ namespace Barotrauma
|
|||||||
if (newLimb != null)
|
if (newLimb != null)
|
||||||
{
|
{
|
||||||
// Attack with the new limb
|
// Attack with the new limb
|
||||||
AttackingLimb = newLimb;
|
AttackLimb = newLimb;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1291,7 +1311,12 @@ namespace Barotrauma
|
|||||||
UpdateFallBack(attackWorldPos, deltaTime, followThrough: true);
|
UpdateFallBack(attackWorldPos, deltaTime, followThrough: true);
|
||||||
return;
|
return;
|
||||||
case AIBehaviorAfterAttack.FallBack:
|
case AIBehaviorAfterAttack.FallBack:
|
||||||
|
case AIBehaviorAfterAttack.Reverse:
|
||||||
default:
|
default:
|
||||||
|
if (activeBehavior == AIBehaviorAfterAttack.Reverse)
|
||||||
|
{
|
||||||
|
Reverse = true;
|
||||||
|
}
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, followThrough: false);
|
UpdateFallBack(attackWorldPos, deltaTime, followThrough: false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1303,12 +1328,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (canAttack)
|
if (canAttack)
|
||||||
{
|
{
|
||||||
if (AttackingLimb == null || !IsValidAttack(AttackingLimb, Character.GetAttackContexts(), SelectedAiTarget?.Entity as IDamageable))
|
if (AttackLimb == null || !IsValidAttack(AttackLimb, Character.GetAttackContexts(), SelectedAiTarget?.Entity))
|
||||||
{
|
{
|
||||||
AttackingLimb = GetAttackLimb(attackWorldPos);
|
AttackLimb = GetAttackLimb(attackWorldPos);
|
||||||
}
|
}
|
||||||
canAttack = AttackingLimb != null && AttackingLimb.attack.CoolDownTimer <= 0;
|
canAttack = AttackLimb != null && AttackLimb.attack.CoolDownTimer <= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!AIParams.CanOpenDoors)
|
if (!AIParams.CanOpenDoors)
|
||||||
{
|
{
|
||||||
if (!Character.AnimController.SimplePhysicsEnabled && SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null && (!canAttackDoors || !canAttackWalls || !AIParams.TargetOuterWalls))
|
if (!Character.AnimController.SimplePhysicsEnabled && SelectedAiTarget.Entity.Submarine != null && Character.Submarine == null && (!canAttackDoors || !canAttackWalls || !AIParams.TargetOuterWalls))
|
||||||
@@ -1347,8 +1373,8 @@ namespace Barotrauma
|
|||||||
// Target a specific limb instead of the target center position
|
// Target a specific limb instead of the target center position
|
||||||
if (wallTarget == null && targetCharacter != null)
|
if (wallTarget == null && targetCharacter != null)
|
||||||
{
|
{
|
||||||
var targetLimbType = AttackingLimb.Params.Attack.Attack.TargetLimbType;
|
var targetLimbType = AttackLimb.Params.Attack.Attack.TargetLimbType;
|
||||||
attackTargetLimb = GetTargetLimb(AttackingLimb, targetCharacter, targetLimbType);
|
attackTargetLimb = GetTargetLimb(AttackLimb, targetCharacter, targetLimbType);
|
||||||
if (attackTargetLimb == null)
|
if (attackTargetLimb == null)
|
||||||
{
|
{
|
||||||
State = AIState.Idle;
|
State = AIState.Idle;
|
||||||
@@ -1361,7 +1387,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : AttackingLimb.WorldPosition;
|
Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : AttackLimb.WorldPosition;
|
||||||
Vector2 toTarget = attackWorldPos - attackLimbPos;
|
Vector2 toTarget = attackWorldPos - attackLimbPos;
|
||||||
// Add a margin when the target is moving away, because otherwise it might be difficult to reach it if the attack takes some time to execute
|
// Add a margin when the target is moving away, because otherwise it might be difficult to reach it if the attack takes some time to execute
|
||||||
if (wallTarget != null && Character.Submarine == null)
|
if (wallTarget != null && Character.Submarine == null)
|
||||||
@@ -1389,23 +1415,23 @@ namespace Barotrauma
|
|||||||
Vector2 CalculateMargin(Vector2 targetVelocity)
|
Vector2 CalculateMargin(Vector2 targetVelocity)
|
||||||
{
|
{
|
||||||
if (targetVelocity == Vector2.Zero) { return Vector2.Zero; }
|
if (targetVelocity == Vector2.Zero) { return Vector2.Zero; }
|
||||||
float diff = AttackingLimb.attack.Range - AttackingLimb.attack.DamageRange;
|
float diff = AttackLimb.attack.Range - AttackLimb.attack.DamageRange;
|
||||||
if (diff <= 0 || toTarget.LengthSquared() <= MathUtils.Pow2(AttackingLimb.attack.DamageRange)) { return Vector2.Zero; }
|
if (diff <= 0 || toTarget.LengthSquared() <= MathUtils.Pow2(AttackLimb.attack.DamageRange)) { return Vector2.Zero; }
|
||||||
float dot = Vector2.Dot(Vector2.Normalize(targetVelocity), Vector2.Normalize(Character.AnimController.Collider.LinearVelocity));
|
float dot = Vector2.Dot(Vector2.Normalize(targetVelocity), Vector2.Normalize(Character.AnimController.Collider.LinearVelocity));
|
||||||
if (dot <= 0 || !MathUtils.IsValid(dot)) { return Vector2.Zero; }
|
if (dot <= 0 || !MathUtils.IsValid(dot)) { return Vector2.Zero; }
|
||||||
float distanceOffset = diff * AttackingLimb.attack.Duration;
|
float distanceOffset = diff * AttackLimb.attack.Duration;
|
||||||
// Intentionally omit the unit conversion because we use distanceOffset as a multiplier.
|
// Intentionally omit the unit conversion because we use distanceOffset as a multiplier.
|
||||||
return targetVelocity * distanceOffset * dot;
|
return targetVelocity * distanceOffset * dot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check that we can reach the target
|
// Check that we can reach the target
|
||||||
distance = toTarget.Length();
|
distance = toTarget.Length();
|
||||||
canAttack = distance < AttackingLimb.attack.Range;
|
canAttack = distance < AttackLimb.attack.Range;
|
||||||
|
|
||||||
// Crouch if the target is down (only humanoids), so that we can reach it.
|
// Crouch if the target is down (only humanoids), so that we can reach it.
|
||||||
if (Character.AnimController is HumanoidAnimController humanoidAnimController && distance < AttackingLimb.attack.Range * 2)
|
if (Character.AnimController is HumanoidAnimController humanoidAnimController && distance < AttackLimb.attack.Range * 2)
|
||||||
{
|
{
|
||||||
if (Math.Abs(toTarget.Y) > AttackingLimb.attack.Range / 2 && Math.Abs(toTarget.X) <= AttackingLimb.attack.Range)
|
if (Math.Abs(toTarget.Y) > AttackLimb.attack.Range / 2 && Math.Abs(toTarget.X) <= AttackLimb.attack.Range)
|
||||||
{
|
{
|
||||||
humanoidAnimController.Crouching = true;
|
humanoidAnimController.Crouching = true;
|
||||||
}
|
}
|
||||||
@@ -1413,14 +1439,14 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (canAttack)
|
if (canAttack)
|
||||||
{
|
{
|
||||||
if (AttackingLimb.attack.Ranged)
|
if (AttackLimb.attack.Ranged)
|
||||||
{
|
{
|
||||||
// Check that is facing the target
|
// Check that is facing the target
|
||||||
float offset = AttackingLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2;
|
float offset = AttackLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2;
|
||||||
Vector2 forward = VectorExtensions.Forward(AttackingLimb.body.TransformedRotation - offset * Character.AnimController.Dir);
|
Vector2 forward = VectorExtensions.Forward(AttackLimb.body.TransformedRotation - offset * Character.AnimController.Dir);
|
||||||
float angle = VectorExtensions.Angle(forward, toTarget);
|
float angle = VectorExtensions.Angle(forward, toTarget);
|
||||||
canAttack = angle < MathHelper.ToRadians(AttackingLimb.attack.RequiredAngle);
|
canAttack = angle < MathHelper.ToRadians(AttackLimb.attack.RequiredAngle);
|
||||||
if (canAttack && AttackingLimb.attack.AvoidFriendlyFire)
|
if (canAttack && AttackLimb.attack.AvoidFriendlyFire)
|
||||||
{
|
{
|
||||||
float minDistance = MathUtils.Pow(ConvertUnits.ToDisplayUnits(Character.AnimController.Collider.GetMaxExtent() * 3), 2);
|
float minDistance = MathUtils.Pow(ConvertUnits.ToDisplayUnits(Character.AnimController.Collider.GetMaxExtent() * 3), 2);
|
||||||
bool IsFarEnough(Character other) => Vector2.DistanceSquared(Character.WorldPosition, other.WorldPosition) > minDistance;
|
bool IsFarEnough(Character other) => Vector2.DistanceSquared(Character.WorldPosition, other.WorldPosition) > minDistance;
|
||||||
@@ -1434,11 +1460,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (canAttack)
|
if (canAttack)
|
||||||
{
|
{
|
||||||
canAttack = !IsBlocked(attackSimPos) && !IsBlocked(AttackingLimb.SimPosition + forward * ConvertUnits.ToSimUnits(AttackingLimb.attack.Range));
|
canAttack = !IsBlocked(attackSimPos) && !IsBlocked(AttackLimb.SimPosition + forward * ConvertUnits.ToSimUnits(AttackLimb.attack.Range));
|
||||||
|
|
||||||
bool IsBlocked(Vector2 targetPosition)
|
bool IsBlocked(Vector2 targetPosition)
|
||||||
{
|
{
|
||||||
foreach (var body in Submarine.PickBodies(AttackingLimb.SimPosition, targetPosition, myBodies, Physics.CollisionCharacter))
|
foreach (var body in Submarine.PickBodies(AttackLimb.SimPosition, targetPosition, myBodies, Physics.CollisionCharacter))
|
||||||
{
|
{
|
||||||
Character hitTarget = null;
|
Character hitTarget = null;
|
||||||
if (body.UserData is Character c)
|
if (body.UserData is Character c)
|
||||||
@@ -1460,22 +1486,8 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (!IsAttackRunning && !IsCoolDownRunning)
|
|
||||||
{
|
|
||||||
// If not, reset the attacking limb, if the cooldown is not running
|
|
||||||
// Don't use the property, because we don't want cancel reversing, if we are reversing.
|
|
||||||
if (attackLimbResetTimer > attackLimbResetInterval)
|
|
||||||
{
|
|
||||||
_attackingLimb = null;
|
|
||||||
attackLimbResetTimer = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
attackLimbResetTimer += deltaTime;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Limb steeringLimb = canAttack && !AttackingLimb.attack.Ranged ? AttackingLimb : null;
|
Limb steeringLimb = canAttack && !AttackLimb.attack.Ranged ? AttackLimb : null;
|
||||||
if (steeringLimb == null)
|
if (steeringLimb == null)
|
||||||
{
|
{
|
||||||
// If the attacking limb is a hand or claw, for example, using it as the steering limb can end in the result where the character circles around the target.
|
// If the attacking limb is a hand or claw, for example, using it as the steering limb can end in the result where the character circles around the target.
|
||||||
@@ -1490,9 +1502,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var pathSteering = SteeringManager as IndoorsSteeringManager;
|
var pathSteering = SteeringManager as IndoorsSteeringManager;
|
||||||
|
|
||||||
if (AttackingLimb != null && AttackingLimb.attack.Retreat)
|
if (AttackLimb != null && AttackLimb.attack.Retreat)
|
||||||
{
|
{
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, false);
|
UpdateFallBack(attackWorldPos, deltaTime, followThrough: false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1527,7 +1539,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
// When pursuing, we don't want to pursue too close
|
// When pursuing, we don't want to pursue too close
|
||||||
float max = 300;
|
float max = 300;
|
||||||
float margin = AttackingLimb != null ? Math.Min(AttackingLimb.attack.Range * 0.9f, max) : max;
|
float margin = AttackLimb != null ? Math.Min(AttackLimb.attack.Range * 0.9f, max) : max;
|
||||||
if (!canAttack || distance > margin)
|
if (!canAttack || distance > margin)
|
||||||
{
|
{
|
||||||
// Steer towards the target if in the same room and swimming
|
// Steer towards the target if in the same room and swimming
|
||||||
@@ -1558,10 +1570,10 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (AttackingLimb.attack.Ranged)
|
if (AttackLimb.attack.Ranged)
|
||||||
{
|
{
|
||||||
float dir = Character.AnimController.Dir;
|
float dir = Character.AnimController.Dir;
|
||||||
if (dir > 0 && attackWorldPos.X > AttackingLimb.WorldPosition.X + margin || dir < 0 && attackWorldPos.X < AttackingLimb.WorldPosition.X - margin)
|
if (dir > 0 && attackWorldPos.X > AttackLimb.WorldPosition.X + margin || dir < 0 && attackWorldPos.X < AttackLimb.WorldPosition.X - margin)
|
||||||
{
|
{
|
||||||
SteeringManager.Reset();
|
SteeringManager.Reset();
|
||||||
}
|
}
|
||||||
@@ -1658,9 +1670,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CirclePhase.CloseIn:
|
case CirclePhase.CloseIn:
|
||||||
if (AttackingLimb != null && distance > 0 && distance < AttackingLimb.attack.Range * GetStrikeDistanceMultiplier(targetSub.Velocity))
|
if (AttackLimb != null && distance > 0 && distance < AttackLimb.attack.Range * GetStrikeDistanceMultiplier(targetSub.Velocity))
|
||||||
{
|
{
|
||||||
strikeTimer = AttackingLimb.attack.CoolDown;
|
strikeTimer = AttackLimb.attack.CoolDown;
|
||||||
CirclePhase = CirclePhase.Strike;
|
CirclePhase = CirclePhase.Strike;
|
||||||
}
|
}
|
||||||
else if (!breakCircling && sqrDistToSub <= MathUtils.Pow2(subSize + selectedTargetingParams.CircleStartDistance / 2) && targetSub.Velocity.LengthSquared() <= MathUtils.Pow2(GetTargetMaxSpeed()))
|
else if (!breakCircling && sqrDistToSub <= MathUtils.Pow2(subSize + selectedTargetingParams.CircleStartDistance / 2) && targetSub.Velocity.LengthSquared() <= MathUtils.Pow2(GetTargetMaxSpeed()))
|
||||||
@@ -1703,10 +1715,10 @@ namespace Barotrauma
|
|||||||
// When the offset position is outside of the sub it happens that the creature sometimes reaches the target point,
|
// When the offset position is outside of the sub it happens that the creature sometimes reaches the target point,
|
||||||
// which makes it continue circling around the point (as supposed)
|
// which makes it continue circling around the point (as supposed)
|
||||||
// But when there is some offset and the offset is too near, this is not what we want.
|
// But when there is some offset and the offset is too near, this is not what we want.
|
||||||
if (AttackingLimb != null && sqrDistToSub < MathUtils.Pow2(subSize + circleFallbackDistance))
|
if (AttackLimb != null && sqrDistToSub < MathUtils.Pow2(subSize + circleFallbackDistance))
|
||||||
{
|
{
|
||||||
CirclePhase = CirclePhase.Strike;
|
CirclePhase = CirclePhase.Strike;
|
||||||
strikeTimer = AttackingLimb.attack.CoolDown;
|
strikeTimer = AttackLimb.attack.CoolDown;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1741,9 +1753,9 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (AttackingLimb != null && distance > 0 && distance < AttackingLimb.attack.Range * requiredDistMultiplier && IsFacing(margin: MathHelper.Lerp(0.5f, 0.9f, currentAttackIntensity)))
|
if (AttackLimb != null && distance > 0 && distance < AttackLimb.attack.Range * requiredDistMultiplier && IsFacing(margin: MathHelper.Lerp(0.5f, 0.9f, currentAttackIntensity)))
|
||||||
{
|
{
|
||||||
strikeTimer = AttackingLimb.attack.CoolDown;
|
strikeTimer = AttackLimb.attack.CoolDown;
|
||||||
CirclePhase = CirclePhase.Strike;
|
CirclePhase = CirclePhase.Strike;
|
||||||
}
|
}
|
||||||
canAttack = false;
|
canAttack = false;
|
||||||
@@ -1800,7 +1812,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!canAttack || distance > Math.Min(AttackingLimb.attack.Range * 0.9f, 100))
|
if (!canAttack || distance > Math.Min(AttackLimb.attack.Range * 0.9f, 100))
|
||||||
{
|
{
|
||||||
if (pathSteering != null)
|
if (pathSteering != null)
|
||||||
{
|
{
|
||||||
@@ -1811,7 +1823,7 @@ namespace Barotrauma
|
|||||||
SteeringManager.SteeringSeek(steerPos, 10);
|
SteeringManager.SteeringSeek(steerPos, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (AttackingLimb.attack.Ranged)
|
else if (AttackLimb.attack.Ranged)
|
||||||
{
|
{
|
||||||
// Too close
|
// Too close
|
||||||
UpdateFallBack(attackWorldPos, deltaTime, followThrough: false);
|
UpdateFallBack(attackWorldPos, deltaTime, followThrough: false);
|
||||||
@@ -1824,18 +1836,18 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (canAttack)
|
if (canAttack)
|
||||||
{
|
{
|
||||||
if (!UpdateLimbAttack(deltaTime, AttackingLimb, attackSimPos, distance, attackTargetLimb))
|
if (!UpdateLimbAttack(deltaTime, AttackLimb, attackSimPos, distance, attackTargetLimb))
|
||||||
{
|
{
|
||||||
IgnoreTarget(SelectedAiTarget);
|
IgnoreTarget(SelectedAiTarget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (IsAttackRunning)
|
else if (IsAttackRunning)
|
||||||
{
|
{
|
||||||
AttackingLimb.attack.ResetAttackTimer();
|
AttackLimb.attack.ResetAttackTimer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool IsValidAttack(Limb attackingLimb, IEnumerable<AttackContext> currentContexts, IDamageable target)
|
private bool IsValidAttack(Limb attackingLimb, IEnumerable<AttackContext> currentContexts, Entity target)
|
||||||
{
|
{
|
||||||
if (attackingLimb == null) { return false; }
|
if (attackingLimb == null) { return false; }
|
||||||
if (target == null) { return false; }
|
if (target == null) { return false; }
|
||||||
@@ -1854,10 +1866,11 @@ namespace Barotrauma
|
|||||||
// Check that is approximately facing the target
|
// Check that is approximately facing the target
|
||||||
Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : attackingLimb.WorldPosition;
|
Vector2 attackLimbPos = Character.AnimController.SimplePhysicsEnabled ? Character.WorldPosition : attackingLimb.WorldPosition;
|
||||||
Vector2 toTarget = attackWorldPos - attackLimbPos;
|
Vector2 toTarget = attackWorldPos - attackLimbPos;
|
||||||
|
if (attack.MinRange > 0 && toTarget.LengthSquared() < MathUtils.Pow2(attack.MinRange)) { return false; }
|
||||||
float offset = attackingLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2;
|
float offset = attackingLimb.Params.GetSpriteOrientation() - MathHelper.PiOver2;
|
||||||
Vector2 forward = VectorExtensions.Forward(attackingLimb.body.TransformedRotation - offset * Character.AnimController.Dir);
|
Vector2 forward = VectorExtensions.Forward(attackingLimb.body.TransformedRotation - offset * Character.AnimController.Dir);
|
||||||
float angle = VectorExtensions.Angle(forward, toTarget);
|
float angle = MathHelper.ToDegrees(VectorExtensions.Angle(forward, toTarget));
|
||||||
if (angle > MathHelper.ToRadians(attack.RequiredAngle)) { return false; }
|
if (angle > attack.RequiredAngle) { return false; }
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -1867,7 +1880,7 @@ namespace Barotrauma
|
|||||||
private Limb GetAttackLimb(Vector2 attackWorldPos, Limb ignoredLimb = null)
|
private Limb GetAttackLimb(Vector2 attackWorldPos, Limb ignoredLimb = null)
|
||||||
{
|
{
|
||||||
var currentContexts = Character.GetAttackContexts();
|
var currentContexts = Character.GetAttackContexts();
|
||||||
IDamageable target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget?.Entity as IDamageable;
|
Entity target = wallTarget != null ? wallTarget.Structure : SelectedAiTarget?.Entity;
|
||||||
if (target == null) { return null; }
|
if (target == null) { return null; }
|
||||||
Limb selectedLimb = null;
|
Limb selectedLimb = null;
|
||||||
float currentPriority = -1;
|
float currentPriority = -1;
|
||||||
@@ -1901,12 +1914,13 @@ namespace Barotrauma
|
|||||||
|
|
||||||
float CalculatePriority(Limb limb, Vector2 attackPos)
|
float CalculatePriority(Limb limb, Vector2 attackPos)
|
||||||
{
|
{
|
||||||
if (Character.AnimController.SimplePhysicsEnabled) { return 1 + limb.attack.Priority; }
|
float prio = 1 + limb.attack.Priority;
|
||||||
|
if (Character.AnimController.SimplePhysicsEnabled) { return prio; }
|
||||||
float dist = Vector2.Distance(limb.WorldPosition, attackPos);
|
float dist = Vector2.Distance(limb.WorldPosition, attackPos);
|
||||||
// The limb is ignored if the target is not close. Prevents character going in reverse if very far away from it.
|
// The limb is ignored if the target is not close. Prevents character going in reverse if very far away from it.
|
||||||
// We also need a max value that is more than the actual range.
|
// We also need a max value that is more than the actual range.
|
||||||
float distanceFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(0, limb.attack.Range * 3, dist));
|
float distanceFactor = MathHelper.Lerp(1, 0, MathUtils.InverseLerp(0, limb.attack.Range * 3, dist));
|
||||||
return (1 + limb.attack.Priority) * distanceFactor;
|
return prio * distanceFactor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1919,7 +1933,7 @@ namespace Barotrauma
|
|||||||
Character.AnimController.ReleaseStuckLimbs();
|
Character.AnimController.ReleaseStuckLimbs();
|
||||||
LatchOntoAI?.DeattachFromBody(reset: true, cooldown: 1);
|
LatchOntoAI?.DeattachFromBody(reset: true, cooldown: 1);
|
||||||
if (attacker == null || attacker.AiTarget == null || attacker.Removed || attacker.IsDead) { return; }
|
if (attacker == null || attacker.AiTarget == null || attacker.Removed || attacker.IsDead) { return; }
|
||||||
if (Character.Params.CanInteract && attackResult.Damage > 10)
|
if (attackResult.Damage >= AIParams.DamageThreshold)
|
||||||
{
|
{
|
||||||
ReleaseDragTargets();
|
ReleaseDragTargets();
|
||||||
}
|
}
|
||||||
@@ -2007,9 +2021,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (State == AIState.Attack && (IsAttackRunning || IsCoolDownRunning))
|
if (State == AIState.Attack && (IsAttackRunning || IsCoolDownRunning))
|
||||||
{
|
{
|
||||||
// Don't retaliate or escape while performing an attack/under cooldown
|
|
||||||
retaliate = false;
|
retaliate = false;
|
||||||
avoidGunFire = false;
|
if (IsAttackRunning)
|
||||||
|
{
|
||||||
|
avoidGunFire = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (retaliate)
|
if (retaliate)
|
||||||
{
|
{
|
||||||
@@ -2022,7 +2038,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (avoidGunFire)
|
else if (avoidGunFire && attackResult.Damage >= AIParams.DamageThreshold)
|
||||||
{
|
{
|
||||||
State = AIState.Escape;
|
State = AIState.Escape;
|
||||||
avoidTimer = AIParams.AvoidTime * Rand.Range(0.75f, 1.25f);
|
avoidTimer = AIParams.AvoidTime * Rand.Range(0.75f, 1.25f);
|
||||||
@@ -2114,7 +2130,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (attackingLimb.attack.CoolDownTimer > 0)
|
if (attackingLimb.attack.CoolDownTimer > 0)
|
||||||
{
|
{
|
||||||
SetAimTimer();
|
SetAimTimer(Math.Min(attackingLimb.attack.CoolDown, 1.5f));
|
||||||
// Managed to hit a living/non-destroyed target. Increase the priority more if the target is low in health -> dies easily/soon
|
// Managed to hit a living/non-destroyed target. Increase the priority more if the target is low in health -> dies easily/soon
|
||||||
float greed = AIParams.AggressionGreed;
|
float greed = AIParams.AggressionGreed;
|
||||||
if (!(damageTarget is Character))
|
if (!(damageTarget is Character))
|
||||||
@@ -2245,19 +2261,19 @@ namespace Barotrauma
|
|||||||
// TODO: test adding some random variance here?
|
// TODO: test adding some random variance here?
|
||||||
attackVector = attackWorldPos - WorldPosition;
|
attackVector = attackWorldPos - WorldPosition;
|
||||||
}
|
}
|
||||||
Vector2 attackDir = Vector2.Normalize(followThrough ? attackVector.Value : -attackVector.Value);
|
Vector2 dir = Vector2.Normalize(followThrough ? attackVector.Value : -attackVector.Value);
|
||||||
if (!MathUtils.IsValid(attackDir))
|
if (!MathUtils.IsValid(dir))
|
||||||
{
|
{
|
||||||
attackDir = Vector2.UnitY;
|
dir = Vector2.UnitY;
|
||||||
}
|
}
|
||||||
steeringManager.SteeringManual(deltaTime, attackDir);
|
steeringManager.SteeringManual(deltaTime, dir);
|
||||||
if (Character.AnimController.InWater)
|
if (Character.AnimController.InWater && !Reverse)
|
||||||
{
|
{
|
||||||
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15);
|
SteeringManager.SteeringAvoid(deltaTime, lookAheadDistance: avoidLookAheadDistance, weight: 15);
|
||||||
}
|
}
|
||||||
if (checkBlocking)
|
if (checkBlocking)
|
||||||
{
|
{
|
||||||
return !IsBlocked(deltaTime, SimPosition + attackDir * (avoidLookAheadDistance / 2));
|
return !IsBlocked(deltaTime, SimPosition + dir * (avoidLookAheadDistance / 2));
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2810,7 +2826,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (Character.Submarine == null && aiTarget.Entity?.Submarine != null && targetCharacter == null)
|
if (Character.Submarine == null && aiTarget.Entity?.Submarine != null && targetCharacter == null)
|
||||||
{
|
{
|
||||||
if (targetParams.AttackPattern == AttackPattern.Circle || targetParams.AttackPattern == AttackPattern.Sweep)
|
if (targetParams.PrioritizeSubCenter || targetParams.AttackPattern == AttackPattern.Circle || targetParams.AttackPattern == AttackPattern.Sweep)
|
||||||
{
|
{
|
||||||
if (!isAnyTargetClose)
|
if (!isAnyTargetClose)
|
||||||
{
|
{
|
||||||
@@ -2990,7 +3006,7 @@ namespace Barotrauma
|
|||||||
if (HasValidPath(requireNonDirty: true)) { return; }
|
if (HasValidPath(requireNonDirty: true)) { return; }
|
||||||
wallHits.Clear();
|
wallHits.Clear();
|
||||||
Structure wall = null;
|
Structure wall = null;
|
||||||
Vector2 rayStart = AttackingLimb != null ? AttackingLimb.SimPosition : SimPosition;
|
Vector2 rayStart = AttackLimb != null ? AttackLimb.SimPosition : SimPosition;
|
||||||
if (AIParams.WallTargetingMethod.HasFlag(WallTargetingMethod.Target))
|
if (AIParams.WallTargetingMethod.HasFlag(WallTargetingMethod.Target))
|
||||||
{
|
{
|
||||||
Vector2 rayEnd = SelectedAiTarget.SimPosition;
|
Vector2 rayEnd = SelectedAiTarget.SimPosition;
|
||||||
@@ -3303,6 +3319,7 @@ namespace Barotrauma
|
|||||||
foreach (var triggerObject in activeTriggers)
|
foreach (var triggerObject in activeTriggers)
|
||||||
{
|
{
|
||||||
AITrigger trigger = triggerObject.Key;
|
AITrigger trigger = triggerObject.Key;
|
||||||
|
if (trigger.IsPermanent) { continue; }
|
||||||
trigger.UpdateTimer(deltaTime);
|
trigger.UpdateTimer(deltaTime);
|
||||||
if (!trigger.IsActive)
|
if (!trigger.IsActive)
|
||||||
{
|
{
|
||||||
@@ -3471,7 +3488,7 @@ namespace Barotrauma
|
|||||||
disableTailCoroutine = null;
|
disableTailCoroutine = null;
|
||||||
}
|
}
|
||||||
Character.AnimController.ReleaseStuckLimbs();
|
Character.AnimController.ReleaseStuckLimbs();
|
||||||
AttackingLimb = null;
|
AttackLimb = null;
|
||||||
movementMargin = 0;
|
movementMargin = 0;
|
||||||
ResetEscape();
|
ResetEscape();
|
||||||
if (isStateChanged && to == AIState.Idle && from != to)
|
if (isStateChanged && to == AIState.Idle && from != to)
|
||||||
|
|||||||
@@ -148,14 +148,14 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
if (TargetCharacter != null)
|
if (TargetCharacter != null)
|
||||||
{
|
{
|
||||||
if (enemyAI.AttackingLimb?.attack == null)
|
if (enemyAI.AttackLimb?.attack == null)
|
||||||
{
|
{
|
||||||
DeattachFromBody(reset: true, cooldown: 1);
|
DeattachFromBody(reset: true, cooldown: 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
float range = enemyAI.AttackingLimb.attack.DamageRange * 2f;
|
float range = enemyAI.AttackLimb.attack.DamageRange * 2f;
|
||||||
if (Vector2.DistanceSquared(TargetCharacter.WorldPosition, enemyAI.AttackingLimb.WorldPosition) > range * range)
|
if (Vector2.DistanceSquared(TargetCharacter.WorldPosition, enemyAI.AttackLimb.WorldPosition) > range * range)
|
||||||
{
|
{
|
||||||
DeattachFromBody(reset: true, cooldown: 1);
|
DeattachFromBody(reset: true, cooldown: 1);
|
||||||
}
|
}
|
||||||
@@ -265,11 +265,11 @@ namespace Barotrauma
|
|||||||
if (enemyAI.IsSteeringThroughGap) { break; }
|
if (enemyAI.IsSteeringThroughGap) { break; }
|
||||||
if (_attachPos == Vector2.Zero) { break; }
|
if (_attachPos == Vector2.Zero) { break; }
|
||||||
if (!AttachToSub && !AttachToCharacters) { break; }
|
if (!AttachToSub && !AttachToCharacters) { break; }
|
||||||
if (enemyAI.AttackingLimb == null) { break; }
|
if (enemyAI.AttackLimb == null) { break; }
|
||||||
if (targetBody == null) { break; }
|
if (targetBody == null) { break; }
|
||||||
if (IsAttached && AttachJoints[0].BodyB == targetBody) { break; }
|
if (IsAttached && AttachJoints[0].BodyB == targetBody) { break; }
|
||||||
Vector2 referencePos = TargetCharacter != null ? TargetCharacter.WorldPosition : ConvertUnits.ToDisplayUnits(transformedAttachPos);
|
Vector2 referencePos = TargetCharacter != null ? TargetCharacter.WorldPosition : ConvertUnits.ToDisplayUnits(transformedAttachPos);
|
||||||
if (Vector2.DistanceSquared(referencePos, enemyAI.AttackingLimb.WorldPosition) < enemyAI.AttackingLimb.attack.DamageRange * enemyAI.AttackingLimb.attack.DamageRange)
|
if (Vector2.DistanceSquared(referencePos, enemyAI.AttackLimb.WorldPosition) < enemyAI.AttackLimb.attack.DamageRange * enemyAI.AttackLimb.attack.DamageRange)
|
||||||
{
|
{
|
||||||
AttachToBody(transformedAttachPos);
|
AttachToBody(transformedAttachPos);
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-1
@@ -112,6 +112,13 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
foreach (FireSource fs in targetHull.FireSources)
|
foreach (FireSource fs in targetHull.FireSources)
|
||||||
{
|
{
|
||||||
|
if (fs == null) { continue; }
|
||||||
|
if (fs.Removed) { continue; }
|
||||||
|
if (character.CurrentHull == null)
|
||||||
|
{
|
||||||
|
Abandon = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
float xDist = Math.Abs(character.WorldPosition.X - fs.WorldPosition.X) - fs.DamageRange;
|
float xDist = Math.Abs(character.WorldPosition.X - fs.WorldPosition.X) - fs.DamageRange;
|
||||||
float yDist = Math.Abs(character.WorldPosition.Y - fs.WorldPosition.Y);
|
float yDist = Math.Abs(character.WorldPosition.Y - fs.WorldPosition.Y);
|
||||||
bool inRange = xDist + yDist < extinguisher.Range;
|
bool inRange = xDist + yDist < extinguisher.Range;
|
||||||
@@ -153,7 +160,7 @@ namespace Barotrauma
|
|||||||
onAbandon: () => Abandon = true,
|
onAbandon: () => Abandon = true,
|
||||||
onCompleted: () => RemoveSubObjective(ref gotoObjective)))
|
onCompleted: () => RemoveSubObjective(ref gotoObjective)))
|
||||||
{
|
{
|
||||||
gotoObjective.requiredCondition = () => targetHull == null || character.CanSeeTarget(targetHull);
|
gotoObjective.requiredCondition = () => character.CanSeeTarget(targetHull);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|||||||
+1
-1
@@ -164,7 +164,7 @@ namespace Barotrauma
|
|||||||
TargetName = Leak.FlowTargetHull?.DisplayName,
|
TargetName = Leak.FlowTargetHull?.DisplayName,
|
||||||
requiredCondition = () =>
|
requiredCondition = () =>
|
||||||
Leak.Submarine == character.Submarine &&
|
Leak.Submarine == character.Submarine &&
|
||||||
(Leak.FlowTargetHull != null && character.CurrentHull == Leak.FlowTargetHull || character.CanSeeTarget(Leak)),
|
Leak.linkedTo.Any(e => e is Hull h && character.CurrentHull == h),
|
||||||
// The Go To objective can be abandoned if the leak is fixed (in which case we don't want to use the dialogue)
|
// The Go To objective can be abandoned if the leak is fixed (in which case we don't want to use the dialogue)
|
||||||
SpeakCannotReachCondition = () => !CheckObjectiveSpecific()
|
SpeakCannotReachCondition = () => !CheckObjectiveSpecific()
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -99,8 +99,7 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
if (InWater || !CanWalk)
|
if (InWater || !CanWalk)
|
||||||
{
|
{
|
||||||
float avg = (SwimSlowParams.MovementSpeed + SwimFastParams.MovementSpeed) / 2.0f;
|
return TargetMovement.LengthSquared() > SwimSlowParams.MovementSpeed;
|
||||||
return TargetMovement.LengthSquared() > avg * avg;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
+8
-11
@@ -448,21 +448,18 @@ namespace Barotrauma
|
|||||||
movement = TargetMovement;
|
movement = TargetMovement;
|
||||||
bool isMoving = movement.LengthSquared() > 0.00001f;
|
bool isMoving = movement.LengthSquared() > 0.00001f;
|
||||||
var mainLimb = MainLimb;
|
var mainLimb = MainLimb;
|
||||||
if (isMoving)
|
float t = 0.5f;
|
||||||
|
if (isMoving && !SimplePhysicsEnabled && CurrentSwimParams.RotateTowardsMovement)
|
||||||
{
|
{
|
||||||
float t = 0.5f;
|
Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2);
|
||||||
if (!SimplePhysicsEnabled && CurrentSwimParams.RotateTowardsMovement)
|
float dot = Vector2.Dot(forward, Vector2.Normalize(movement));
|
||||||
|
if (dot < 0)
|
||||||
{
|
{
|
||||||
Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2);
|
// Reduce the linear movement speed when not facing the movement direction
|
||||||
float dot = Vector2.Dot(forward, Vector2.Normalize(movement));
|
t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f);
|
||||||
if (dot < 0)
|
|
||||||
{
|
|
||||||
// Reduce the linear movement speed when not facing the movement direction
|
|
||||||
t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t);
|
|
||||||
}
|
}
|
||||||
|
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t);
|
||||||
//limbs are disabled when simple physics is enabled, no need to move them
|
//limbs are disabled when simple physics is enabled, no need to move them
|
||||||
if (SimplePhysicsEnabled) { return; }
|
if (SimplePhysicsEnabled) { return; }
|
||||||
mainLimb.PullJointEnabled = true;
|
mainLimb.PullJointEnabled = true;
|
||||||
|
|||||||
+52
-22
@@ -443,8 +443,6 @@ namespace Barotrauma
|
|||||||
if (CurrentGroundedParams == null) { return; }
|
if (CurrentGroundedParams == null) { return; }
|
||||||
Vector2 handPos;
|
Vector2 handPos;
|
||||||
|
|
||||||
//if you're allergic to magic numbers, stop reading now
|
|
||||||
|
|
||||||
Limb leftFoot = GetLimb(LimbType.LeftFoot);
|
Limb leftFoot = GetLimb(LimbType.LeftFoot);
|
||||||
Limb rightFoot = GetLimb(LimbType.RightFoot);
|
Limb rightFoot = GetLimb(LimbType.RightFoot);
|
||||||
Limb head = GetLimb(LimbType.Head);
|
Limb head = GetLimb(LimbType.Head);
|
||||||
@@ -599,16 +597,20 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
float torsoAngle = TorsoAngle.Value;
|
float torsoAngle = TorsoAngle.Value;
|
||||||
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
|
float herpesStrength = character.CharacterHealth.GetAfflictionStrength("spaceherpes");
|
||||||
if (Crouching && !movingHorizontally) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; }
|
if (Crouching && !movingHorizontally && !aiming) { torsoAngle -= HumanCrouchParams.ExtraTorsoAngleWhenStationary; }
|
||||||
torsoAngle -= herpesStrength / 150.0f;
|
torsoAngle -= herpesStrength / 150.0f;
|
||||||
torso.body.SmoothRotate(torsoAngle * Dir, CurrentGroundedParams.TorsoTorque);
|
torso.body.SmoothRotate(torsoAngle * Dir, CurrentGroundedParams.TorsoTorque);
|
||||||
}
|
}
|
||||||
if (HeadAngle.HasValue)
|
if (!aiming && CurrentGroundedParams.FixedHeadAngle && HeadAngle.HasValue)
|
||||||
{
|
{
|
||||||
float headAngle = HeadAngle.Value;
|
float headAngle = HeadAngle.Value;
|
||||||
if (Crouching && !movingHorizontally) { headAngle -= HumanCrouchParams.ExtraHeadAngleWhenStationary; }
|
if (Crouching && !movingHorizontally) { headAngle -= HumanCrouchParams.ExtraHeadAngleWhenStationary; }
|
||||||
head.body.SmoothRotate(headAngle * Dir, CurrentGroundedParams.HeadTorque);
|
head.body.SmoothRotate(headAngle * Dir, CurrentGroundedParams.HeadTorque);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RotateHead(head);
|
||||||
|
}
|
||||||
|
|
||||||
if (!onGround)
|
if (!onGround)
|
||||||
{
|
{
|
||||||
@@ -883,23 +885,17 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
float targetSpeed = TargetMovement.Length();
|
float targetSpeed = TargetMovement.Length();
|
||||||
if (targetSpeed > 0.1f)
|
if (aiming)
|
||||||
{
|
{
|
||||||
if (!aiming)
|
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
|
||||||
{
|
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
|
||||||
float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2;
|
float newRotation = MathUtils.VectorToAngle(diff);
|
||||||
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
|
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else if (targetSpeed > 0.1f)
|
||||||
{
|
{
|
||||||
if (aiming)
|
float newRotation = MathUtils.VectorToAngle(TargetMovement) - MathHelper.PiOver2;
|
||||||
{
|
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
|
||||||
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
|
|
||||||
Vector2 diff = (mousePos - torso.SimPosition) * Dir;
|
|
||||||
float newRotation = MathUtils.VectorToAngle(diff);
|
|
||||||
Collider.SmoothRotate(newRotation, CurrentSwimParams.SteerTorque * character.SpeedMultiplier);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
torso.body.MoveToPos(Collider.SimPosition + new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * 0.4f, 5.0f);
|
torso.body.MoveToPos(Collider.SimPosition + new Vector2((float)Math.Sin(-Collider.Rotation), (float)Math.Cos(-Collider.Rotation)) * 0.4f, 5.0f);
|
||||||
@@ -914,13 +910,14 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
torso.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.TorsoTorque);
|
torso.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.TorsoTorque);
|
||||||
}
|
}
|
||||||
if (HeadAngle.HasValue)
|
|
||||||
|
if (!aiming && CurrentSwimParams.FixedHeadAngle && HeadAngle.HasValue)
|
||||||
{
|
{
|
||||||
head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.HeadTorque);
|
head.body.SmoothRotate(Collider.Rotation + HeadAngle.Value * Dir, CurrentSwimParams.HeadTorque);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
head.body.SmoothRotate(Collider.Rotation, CurrentSwimParams.HeadTorque);
|
RotateHead(head);
|
||||||
}
|
}
|
||||||
|
|
||||||
//dont try to move upwards if head is already out of water
|
//dont try to move upwards if head is already out of water
|
||||||
@@ -951,7 +948,18 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (isNotRemote)
|
if (isNotRemote)
|
||||||
{
|
{
|
||||||
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, movementLerp);
|
float t = movementLerp;
|
||||||
|
if (targetSpeed > 0.00001f && !SimplePhysicsEnabled)
|
||||||
|
{
|
||||||
|
Vector2 forward = VectorExtensions.Forward(Collider.Rotation + MathHelper.PiOver2);
|
||||||
|
float dot = Vector2.Dot(forward, Vector2.Normalize(movement));
|
||||||
|
if (dot < 0)
|
||||||
|
{
|
||||||
|
// Reduce the linear movement speed when not facing the movement direction
|
||||||
|
t = MathHelper.Clamp((1 + dot) / 10, 0.01f, 0.1f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Collider.LinearVelocity = Vector2.Lerp(Collider.LinearVelocity, movement, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
WalkPos += movement.Length();
|
WalkPos += movement.Length();
|
||||||
@@ -1227,7 +1235,11 @@ namespace Barotrauma
|
|||||||
|
|
||||||
//apply forces to the collider to move the Character up/down
|
//apply forces to the collider to move the Character up/down
|
||||||
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
|
Collider.ApplyForce((climbForce * 20.0f + subSpeed * 50.0f) * Collider.Mass);
|
||||||
if (!aiming)
|
if (aiming)
|
||||||
|
{
|
||||||
|
RotateHead(head);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
float movementMultiplier = targetMovement.Y < 0 ? 0 : 1;
|
float movementMultiplier = targetMovement.Y < 0 ? 0 : 1;
|
||||||
head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, WalkParams.HeadTorque);
|
head.body.SmoothRotate(MathHelper.PiOver4 * movementMultiplier * Dir, WalkParams.HeadTorque);
|
||||||
@@ -1710,6 +1722,24 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RotateHead(Limb head)
|
||||||
|
{
|
||||||
|
Vector2 mousePos = ConvertUnits.ToSimUnits(character.CursorPosition);
|
||||||
|
Vector2 dir = (mousePos - head.SimPosition) * Dir;
|
||||||
|
float rot = MathUtils.VectorToAngle(dir);
|
||||||
|
var neckJoint = GetJointBetweenLimbs(LimbType.Head, LimbType.Torso);
|
||||||
|
if (neckJoint != null)
|
||||||
|
{
|
||||||
|
float offset = MathUtils.WrapAnglePi(GetLimb(LimbType.Torso).body.Rotation);
|
||||||
|
float lowerLimit = neckJoint.LowerLimit + offset;
|
||||||
|
float upperLimit = neckJoint.UpperLimit + offset;
|
||||||
|
float min = Math.Min(lowerLimit, upperLimit);
|
||||||
|
float max = Math.Max(lowerLimit, upperLimit);
|
||||||
|
rot = Math.Clamp(rot, min, max);
|
||||||
|
}
|
||||||
|
head.body.SmoothRotate(rot, CurrentAnimationParams.HeadTorque);
|
||||||
|
}
|
||||||
|
|
||||||
private void FootIK(Limb foot, Vector2 pos, float legTorque, float footTorque, float footAngle)
|
private void FootIK(Limb foot, Vector2 pos, float legTorque, float footTorque, float footAngle)
|
||||||
{
|
{
|
||||||
if (!MathUtils.IsValid(pos))
|
if (!MathUtils.IsValid(pos))
|
||||||
|
|||||||
@@ -805,7 +805,7 @@ namespace Barotrauma
|
|||||||
SeverLimbJointProjSpecific(limbJoint, playSound: true);
|
SeverLimbJointProjSpecific(limbJoint, playSound: true);
|
||||||
if (GameMain.NetworkMember is { IsServer: true })
|
if (GameMain.NetworkMember is { IsServer: true })
|
||||||
{
|
{
|
||||||
GameMain.NetworkMember.CreateEntityEvent(character, new Character.StatusEventData());
|
GameMain.NetworkMember.CreateEntityEvent(character, new Character.CharacterStatusEventData());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,7 +37,9 @@ namespace Barotrauma
|
|||||||
Pursue,
|
Pursue,
|
||||||
FollowThrough,
|
FollowThrough,
|
||||||
FollowThroughUntilCanAttack,
|
FollowThroughUntilCanAttack,
|
||||||
IdleUntilCanAttack
|
IdleUntilCanAttack,
|
||||||
|
Reverse,
|
||||||
|
ReverseUntilCanAttack
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AttackResult
|
struct AttackResult
|
||||||
@@ -102,7 +104,7 @@ namespace Barotrauma
|
|||||||
public bool Retreat { get; private set; }
|
public bool Retreat { get; private set; }
|
||||||
|
|
||||||
private float _range;
|
private float _range;
|
||||||
[Serialize(0.0f, IsPropertySaveable.Yes, description: "The min distance from the attack limb to the target before the AI tries to attack."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2000.0f)]
|
[Serialize(0.0f, IsPropertySaveable.Yes, description: "The min distance from the attack limb to the target before the AI tries to attack."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10000.0f)]
|
||||||
public float Range
|
public float Range
|
||||||
{
|
{
|
||||||
get => _range * RangeMultiplier;
|
get => _range * RangeMultiplier;
|
||||||
@@ -110,13 +112,16 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
|
|
||||||
private float _damageRange;
|
private float _damageRange;
|
||||||
[Serialize(0.0f, IsPropertySaveable.Yes, description: "The min distance from the attack limb to the target to do damage. In distance-based hit detection, the hit will be registered as soon as the target is within the damage range, unless the attack duration has expired."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 2000.0f)]
|
[Serialize(0.0f, IsPropertySaveable.Yes, description: "The min distance from the attack limb to the target to do damage. In distance-based hit detection, the hit will be registered as soon as the target is within the damage range, unless the attack duration has expired."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10000.0f)]
|
||||||
public float DamageRange
|
public float DamageRange
|
||||||
{
|
{
|
||||||
get => _damageRange * RangeMultiplier;
|
get => _damageRange * RangeMultiplier;
|
||||||
set => _damageRange = value;
|
set => _damageRange = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Serialize(0.0f, IsPropertySaveable.Yes, description: ""), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10000.0f)]
|
||||||
|
public float MinRange { get; private set; }
|
||||||
|
|
||||||
[Serialize(0.25f, IsPropertySaveable.Yes, description: "An approximation of the attack duration. Effectively defines the time window in which the hit can be registered. If set to too low value, it's possible that the attack won't hit the target in time."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f, DecimalCount = 2)]
|
[Serialize(0.25f, IsPropertySaveable.Yes, description: "An approximation of the attack duration. Effectively defines the time window in which the hit can be registered. If set to too low value, it's possible that the attack won't hit the target in time."), Editable(MinValueFloat = 0.0f, MaxValueFloat = 10.0f, DecimalCount = 2)]
|
||||||
public float Duration { get; private set; }
|
public float Duration { get; private set; }
|
||||||
|
|
||||||
@@ -356,17 +361,17 @@ namespace Barotrauma
|
|||||||
{
|
{
|
||||||
Deserialize(element);
|
Deserialize(element);
|
||||||
|
|
||||||
if (element.Attribute("damage") != null ||
|
if (element.GetAttribute("damage") != null ||
|
||||||
element.Attribute("bluntdamage") != null ||
|
element.GetAttribute("bluntdamage") != null ||
|
||||||
element.Attribute("burndamage") != null ||
|
element.GetAttribute("burndamage") != null ||
|
||||||
element.Attribute("bleedingdamage") != null)
|
element.GetAttribute("bleedingdamage") != null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error in Attack (" + parentDebugName + ") - Define damage as afflictions instead of using the damage attribute (e.g. <Affliction identifier=\"internaldamage\" strength=\"10\" />).");
|
DebugConsole.ThrowError("Error in Attack (" + parentDebugName + ") - Define damage as afflictions instead of using the damage attribute (e.g. <Affliction identifier=\"internaldamage\" strength=\"10\" />).");
|
||||||
}
|
}
|
||||||
|
|
||||||
//if level wall damage is not defined, default to the structure damage
|
//if level wall damage is not defined, default to the structure damage
|
||||||
if (element.Attribute("LevelWallDamage") == null &&
|
if (element.GetAttribute("LevelWallDamage") == null &&
|
||||||
element.Attribute("levelwalldamage") == null)
|
element.GetAttribute("levelwalldamage") == null)
|
||||||
{
|
{
|
||||||
LevelWallDamage = StructureDamage;
|
LevelWallDamage = StructureDamage;
|
||||||
}
|
}
|
||||||
@@ -382,7 +387,7 @@ namespace Barotrauma
|
|||||||
break;
|
break;
|
||||||
case "affliction":
|
case "affliction":
|
||||||
AfflictionPrefab afflictionPrefab;
|
AfflictionPrefab afflictionPrefab;
|
||||||
if (subElement.Attribute("name") != null)
|
if (subElement.GetAttribute("name") != null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error in Attack (" + parentDebugName + ") - define afflictions using identifiers instead of names.");
|
DebugConsole.ThrowError("Error in Attack (" + parentDebugName + ") - define afflictions using identifiers instead of names.");
|
||||||
string afflictionName = subElement.GetAttributeString("name", "").ToLowerInvariant();
|
string afflictionName = subElement.GetAttributeString("name", "").ToLowerInvariant();
|
||||||
@@ -686,7 +691,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public bool IsValidTarget(AttackTarget targetType) => TargetType == AttackTarget.Any || TargetType == targetType;
|
public bool IsValidTarget(AttackTarget targetType) => TargetType == AttackTarget.Any || TargetType == targetType;
|
||||||
|
|
||||||
public bool IsValidTarget(IDamageable target)
|
public bool IsValidTarget(Entity target)
|
||||||
{
|
{
|
||||||
return TargetType switch
|
return TargetType switch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -893,6 +893,7 @@ namespace Barotrauma
|
|||||||
public bool GodMode = false;
|
public bool GodMode = false;
|
||||||
|
|
||||||
public CampaignMode.InteractionType CampaignInteractionType;
|
public CampaignMode.InteractionType CampaignInteractionType;
|
||||||
|
public Identifier MerchantIdentifier;
|
||||||
|
|
||||||
private bool accessRemovedCharacterErrorShown;
|
private bool accessRemovedCharacterErrorShown;
|
||||||
public override Vector2 SimPosition
|
public override Vector2 SimPosition
|
||||||
@@ -1885,7 +1886,7 @@ namespace Barotrauma
|
|||||||
if (!attack.IsValidContext(currentContexts)) { return false; }
|
if (!attack.IsValidContext(currentContexts)) { return false; }
|
||||||
if (attackTarget != null)
|
if (attackTarget != null)
|
||||||
{
|
{
|
||||||
if (!attack.IsValidTarget(attackTarget)) { return false; }
|
if (!attack.IsValidTarget(attackTarget as Entity)) { return false; }
|
||||||
if (attackTarget is ISerializableEntity se && attackTarget is Character)
|
if (attackTarget is ISerializableEntity se && attackTarget is Character)
|
||||||
{
|
{
|
||||||
if (attack.Conditionals.Any(c => !c.TargetSelf && !c.Matches(se))) { return false; }
|
if (attack.Conditionals.Any(c => !c.TargetSelf && !c.Matches(se))) { return false; }
|
||||||
@@ -2011,6 +2012,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public bool CanSeeCharacter(Character target)
|
public bool CanSeeCharacter(Character target)
|
||||||
{
|
{
|
||||||
|
System.Diagnostics.Debug.Assert(target != null);
|
||||||
|
if (target == null) { return false; }
|
||||||
if (target.Removed) { return false; }
|
if (target.Removed) { return false; }
|
||||||
Limb seeingLimb = GetSeeingLimb();
|
Limb seeingLimb = GetSeeingLimb();
|
||||||
if (CanSeeTarget(target, seeingLimb)) { return true; }
|
if (CanSeeTarget(target, seeingLimb)) { return true; }
|
||||||
@@ -2045,7 +2048,6 @@ namespace Barotrauma
|
|||||||
if (leftExtremity != null && CanSeeTarget(leftExtremity, seeingLimb)) { return true; }
|
if (leftExtremity != null && CanSeeTarget(leftExtremity, seeingLimb)) { return true; }
|
||||||
if (rightExtremity != null && CanSeeTarget(rightExtremity, seeingLimb)) { return true; }
|
if (rightExtremity != null && CanSeeTarget(rightExtremity, seeingLimb)) { return true; }
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2056,6 +2058,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public bool CanSeeTarget(ISpatialEntity target, ISpatialEntity seeingEntity = null)
|
public bool CanSeeTarget(ISpatialEntity target, ISpatialEntity seeingEntity = null)
|
||||||
{
|
{
|
||||||
|
System.Diagnostics.Debug.Assert(target != null);
|
||||||
|
if (target == null) { return false; }
|
||||||
seeingEntity ??= AnimController.SimplePhysicsEnabled ? this : GetSeeingLimb() as ISpatialEntity;
|
seeingEntity ??= AnimController.SimplePhysicsEnabled ? this : GetSeeingLimb() as ISpatialEntity;
|
||||||
if (seeingEntity == null) { return false; }
|
if (seeingEntity == null) { return false; }
|
||||||
ISpatialEntity sourceEntity = seeingEntity ;
|
ISpatialEntity sourceEntity = seeingEntity ;
|
||||||
@@ -3148,7 +3152,8 @@ namespace Barotrauma
|
|||||||
|
|
||||||
var itemContainer = item?.GetComponent<ItemContainer>();
|
var itemContainer = item?.GetComponent<ItemContainer>();
|
||||||
if (itemContainer == null) { return; }
|
if (itemContainer == null) { return; }
|
||||||
foreach (Item inventoryItem in Inventory.AllItemsMod)
|
List<Item> inventoryItems = new List<Item>(Inventory.AllItemsMod);
|
||||||
|
foreach (Item inventoryItem in inventoryItems)
|
||||||
{
|
{
|
||||||
if (!itemContainer.Inventory.TryPutItem(inventoryItem, user: null, createNetworkEvent: createNetworkEvents))
|
if (!itemContainer.Inventory.TryPutItem(inventoryItem, user: null, createNetworkEvent: createNetworkEvents))
|
||||||
{
|
{
|
||||||
@@ -3156,17 +3161,25 @@ namespace Barotrauma
|
|||||||
inventoryItem.Drop(dropper: this, createNetworkEvent: createNetworkEvents);
|
inventoryItem.Drop(dropper: this, createNetworkEvent: createNetworkEvents);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//this needs to happen after the items have been dropped (we can no longer sync dropping the items if the character has been removed)
|
||||||
|
Spawner.AddEntityToRemoveQueue(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
Spawner.AddEntityToRemoveQueue(this);
|
{
|
||||||
|
Spawner.AddEntityToRemoveQueue(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DespawnNow(bool createNetworkEvents = true)
|
public void DespawnNow(bool createNetworkEvents = true)
|
||||||
{
|
{
|
||||||
despawnTimer = GameSettings.CurrentConfig.CorpseDespawnDelay;
|
despawnTimer = GameSettings.CurrentConfig.CorpseDespawnDelay;
|
||||||
UpdateDespawn(1.0f, ignoreThresholds: true, createNetworkEvents: createNetworkEvents);
|
UpdateDespawn(1.0f, ignoreThresholds: true, createNetworkEvents: createNetworkEvents);
|
||||||
Spawner.Update(createNetworkEvents);
|
//update twice: first to spawn the duffel bag and move the items into it, then to remove the character
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
Spawner.Update(createNetworkEvents);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void RemoveByPrefab(CharacterPrefab prefab)
|
public static void RemoveByPrefab(CharacterPrefab prefab)
|
||||||
@@ -4012,7 +4025,7 @@ namespace Barotrauma
|
|||||||
|
|
||||||
if (GameMain.NetworkMember is { IsServer: true })
|
if (GameMain.NetworkMember is { IsServer: true })
|
||||||
{
|
{
|
||||||
GameMain.NetworkMember.CreateEntityEvent(this, new StatusEventData());
|
GameMain.NetworkMember.CreateEntityEvent(this, new CharacterStatusEventData());
|
||||||
}
|
}
|
||||||
|
|
||||||
isDead = true;
|
isDead = true;
|
||||||
@@ -4168,6 +4181,11 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
DebugConsole.Log("Removing character " + Name + " (ID: " + ID + ")");
|
DebugConsole.Log("Removing character " + Name + " (ID: " + ID + ")");
|
||||||
|
|
||||||
|
#if CLIENT
|
||||||
|
//ensure we apply any pending inventory updates to drop any items that need to be dropped when the character despawns
|
||||||
|
Inventory?.ApplyReceivedState();
|
||||||
|
#endif
|
||||||
|
|
||||||
base.Remove();
|
base.Remove();
|
||||||
|
|
||||||
foreach (Item heldItem in HeldItems.ToList())
|
foreach (Item heldItem in HeldItems.ToList())
|
||||||
@@ -4179,12 +4197,12 @@ namespace Barotrauma
|
|||||||
|
|
||||||
#if CLIENT
|
#if CLIENT
|
||||||
GameMain.GameSession?.CrewManager?.KillCharacter(this, resetCrewListIndex: false);
|
GameMain.GameSession?.CrewManager?.KillCharacter(this, resetCrewListIndex: false);
|
||||||
|
|
||||||
|
if (Controlled == this) { Controlled = null; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
CharacterList.Remove(this);
|
CharacterList.Remove(this);
|
||||||
|
|
||||||
if (Controlled == this) { Controlled = null; }
|
|
||||||
|
|
||||||
if (Inventory != null)
|
if (Inventory != null)
|
||||||
{
|
{
|
||||||
foreach (Item item in Inventory.AllItems)
|
foreach (Item item in Inventory.AllItems)
|
||||||
@@ -4266,7 +4284,7 @@ namespace Barotrauma
|
|||||||
if (!MathUtils.NearlyEqual(newItem.Condition, newItem.MaxCondition) &&
|
if (!MathUtils.NearlyEqual(newItem.Condition, newItem.MaxCondition) &&
|
||||||
GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
GameMain.NetworkMember != null && GameMain.NetworkMember.IsServer)
|
||||||
{
|
{
|
||||||
GameMain.NetworkMember.CreateEntityEvent(newItem, new StatusEventData());
|
newItem.CreateStatusEvent();
|
||||||
}
|
}
|
||||||
#if SERVER
|
#if SERVER
|
||||||
newItem.GetComponent<Terminal>()?.SyncHistory();
|
newItem.GetComponent<Terminal>()?.SyncHistory();
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace Barotrauma
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct StatusEventData : IEventData
|
public struct CharacterStatusEventData : IEventData
|
||||||
{
|
{
|
||||||
public EventType EventType => EventType.Status;
|
public EventType EventType => EventType.Status;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -852,6 +852,19 @@ namespace Barotrauma
|
|||||||
#if CLIENT
|
#if CLIENT
|
||||||
public void RecreateHead(MultiplayerPreferences characterSettings)
|
public void RecreateHead(MultiplayerPreferences characterSettings)
|
||||||
{
|
{
|
||||||
|
if (characterSettings.HairIndex == -1 &&
|
||||||
|
characterSettings.BeardIndex == -1 &&
|
||||||
|
characterSettings.MoustacheIndex == -1 &&
|
||||||
|
characterSettings.FaceAttachmentIndex == -1)
|
||||||
|
{
|
||||||
|
//randomize if nothing is set
|
||||||
|
SetAttachments(Rand.RandSync.Unsynced);
|
||||||
|
characterSettings.HairIndex = Head.HairIndex;
|
||||||
|
characterSettings.BeardIndex = Head.BeardIndex;
|
||||||
|
characterSettings.MoustacheIndex = Head.MoustacheIndex;
|
||||||
|
characterSettings.FaceAttachmentIndex = Head.FaceAttachmentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
RecreateHead(
|
RecreateHead(
|
||||||
characterSettings.TagSet.ToImmutableHashSet(),
|
characterSettings.TagSet.ToImmutableHashSet(),
|
||||||
characterSettings.HairIndex,
|
characterSettings.HairIndex,
|
||||||
@@ -859,9 +872,14 @@ namespace Barotrauma
|
|||||||
characterSettings.MoustacheIndex,
|
characterSettings.MoustacheIndex,
|
||||||
characterSettings.FaceAttachmentIndex);
|
characterSettings.FaceAttachmentIndex);
|
||||||
|
|
||||||
Head.SkinColor = characterSettings.SkinColor;
|
Head.SkinColor = ChooseColor(SkinColors, characterSettings.SkinColor);
|
||||||
Head.HairColor = characterSettings.HairColor;
|
Head.HairColor = ChooseColor(HairColors, characterSettings.HairColor);
|
||||||
Head.FacialHairColor = characterSettings.FacialHairColor;
|
Head.FacialHairColor = ChooseColor(FacialHairColors, characterSettings.FacialHairColor);
|
||||||
|
|
||||||
|
Color ChooseColor(in ImmutableArray<(Color Color, float Commonness)> availableColors, Color chosenColor)
|
||||||
|
{
|
||||||
|
return availableColors.Any(c => c.Color == chosenColor) ? chosenColor : SelectRandomColor(availableColors, Rand.RandSync.Unsynced);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -287,7 +287,7 @@ namespace Barotrauma
|
|||||||
StatusEffects.Add(StatusEffect.Load(subElement, parentDebugName));
|
StatusEffects.Add(StatusEffect.Load(subElement, parentDebugName));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (element.Attribute("interval") != null)
|
if (element.GetAttribute("interval") != null)
|
||||||
{
|
{
|
||||||
MinInterval = MaxInterval = Math.Max(element.GetAttributeFloat("interval", 1.0f), 1.0f);
|
MinInterval = MaxInterval = Math.Max(element.GetAttributeFloat("interval", 1.0f), 1.0f);
|
||||||
}
|
}
|
||||||
@@ -409,7 +409,7 @@ namespace Barotrauma
|
|||||||
HealCostMultiplier = element.GetAttributeFloat(nameof(HealCostMultiplier).ToLowerInvariant(), 1f);
|
HealCostMultiplier = element.GetAttributeFloat(nameof(HealCostMultiplier).ToLowerInvariant(), 1f);
|
||||||
BaseHealCost = element.GetAttributeInt(nameof(BaseHealCost).ToLowerInvariant(), 0);
|
BaseHealCost = element.GetAttributeInt(nameof(BaseHealCost).ToLowerInvariant(), 0);
|
||||||
|
|
||||||
if (element.Attribute("nameidentifier") != null)
|
if (element.GetAttribute("nameidentifier") != null)
|
||||||
{
|
{
|
||||||
Name = TextManager.Get(element.GetAttributeString("nameidentifier", string.Empty)).Fallback(Name);
|
Name = TextManager.Get(element.GetAttributeString("nameidentifier", string.Empty)).Fallback(Name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,22 +47,24 @@ namespace Barotrauma
|
|||||||
HighlightSprite = new Sprite(subElement);
|
HighlightSprite = new Sprite(subElement);
|
||||||
break;
|
break;
|
||||||
case "vitalitymultiplier":
|
case "vitalitymultiplier":
|
||||||
if (subElement.Attribute("name") != null)
|
if (subElement.GetAttribute("name") != null)
|
||||||
{
|
{
|
||||||
DebugConsole.ThrowError("Error in character health config (" + characterHealth.Character.Name + ") - define vitality multipliers using affliction identifiers or types instead of names.");
|
DebugConsole.ThrowError("Error in character health config (" + characterHealth.Character.Name + ") - define vitality multipliers using affliction identifiers or types instead of names.");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
var vitalityMultipliers = subElement.GetAttributeIdentifierArray("identifier", null) ?? subElement.GetAttributeIdentifierArray("identifiers", null);
|
||||||
Identifier afflictionIdentifier = subElement.GetAttributeIdentifier("identifier", "");
|
if (vitalityMultipliers == null)
|
||||||
Identifier afflictionType = subElement.GetAttributeIdentifier("type", "");
|
|
||||||
float multiplier = subElement.GetAttributeFloat("multiplier", 1.0f);
|
|
||||||
if (!afflictionIdentifier.IsEmpty)
|
|
||||||
{
|
{
|
||||||
VitalityMultipliers.Add(afflictionIdentifier, multiplier);
|
vitalityMultipliers = subElement.GetAttributeIdentifierArray("type", null) ?? subElement.GetAttributeIdentifierArray("types", null);
|
||||||
|
}
|
||||||
|
if (vitalityMultipliers != null)
|
||||||
|
{
|
||||||
|
float multiplier = subElement.GetAttributeFloat("multiplier", 1.0f);
|
||||||
|
vitalityMultipliers.ForEach(i => VitalityMultipliers.Add(i, multiplier));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
VitalityTypeMultipliers.Add(afflictionType, multiplier);
|
DebugConsole.ThrowError($"Error in character health config {characterHealth.Character.Name}: affliction identifier(s) or type(s) not defined in the \"VitalityMultiplier\" elements!");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -540,6 +540,8 @@ namespace Barotrauma
|
|||||||
private set;
|
private set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Items.Components.Rope AttachedRope { get; set; }
|
||||||
|
|
||||||
public string Name => Params.Name;
|
public string Name => Params.Name;
|
||||||
|
|
||||||
// These properties are exposed for status effects
|
// These properties are exposed for status effects
|
||||||
|
|||||||
+8
@@ -103,6 +103,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
[Serialize(1f, IsPropertySaveable.Yes, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
[Serialize(1f, IsPropertySaveable.Yes, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
public float HandMoveStrength { get; set; }
|
public float HandMoveStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(true, IsPropertySaveable.Yes, description: "Is the head angle fixed or does the angle follow the mouse position?"), Editable]
|
||||||
|
public bool FixedHeadAngle { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class HumanGroundedParams : GroundedMovementParams, IHumanAnimation
|
abstract class HumanGroundedParams : GroundedMovementParams, IHumanAnimation
|
||||||
@@ -156,6 +159,9 @@ namespace Barotrauma
|
|||||||
|
|
||||||
[Serialize(1f, IsPropertySaveable.Yes, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
[Serialize(1f, IsPropertySaveable.Yes, description: "How much force is used to move the hands."), Editable(MinValueFloat = 0, MaxValueFloat = 10, DecimalCount = 2)]
|
||||||
public float HandMoveStrength { get; set; }
|
public float HandMoveStrength { get; set; }
|
||||||
|
|
||||||
|
[Serialize(true, IsPropertySaveable.Yes, description: "Is the head angle fixed or does the angle follow the mouse position?"), Editable]
|
||||||
|
public bool FixedHeadAngle { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IHumanAnimation
|
public interface IHumanAnimation
|
||||||
@@ -166,5 +172,7 @@ namespace Barotrauma
|
|||||||
float ArmMoveStrength { get; set; }
|
float ArmMoveStrength { get; set; }
|
||||||
|
|
||||||
float HandMoveStrength { get; set; }
|
float HandMoveStrength { get; set; }
|
||||||
|
|
||||||
|
bool FixedHeadAngle { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,6 +104,9 @@ namespace Barotrauma
|
|||||||
[Serialize(10f, IsPropertySaveable.Yes, "How frequent the recurring idle and attack sounds are?"), Editable(MinValueFloat = 1f, MaxValueFloat = 100f)]
|
[Serialize(10f, IsPropertySaveable.Yes, "How frequent the recurring idle and attack sounds are?"), Editable(MinValueFloat = 1f, MaxValueFloat = 100f)]
|
||||||
public float SoundInterval { get; set; }
|
public float SoundInterval { get; set; }
|
||||||
|
|
||||||
|
[Serialize(false, IsPropertySaveable.Yes), Editable]
|
||||||
|
public bool DrawLast { get; set; }
|
||||||
|
|
||||||
public readonly CharacterFile File;
|
public readonly CharacterFile File;
|
||||||
|
|
||||||
public XDocument VariantFile { get; private set; }
|
public XDocument VariantFile { get; private set; }
|
||||||
@@ -127,31 +130,36 @@ namespace Barotrauma
|
|||||||
|
|
||||||
public override ContentXElement MainElement => base.MainElement.IsOverride() ? base.MainElement.FirstElement() : base.MainElement;
|
public override ContentXElement MainElement => base.MainElement.IsOverride() ? base.MainElement.FirstElement() : base.MainElement;
|
||||||
|
|
||||||
public static XElement CreateVariantXml(XElement selfXml, XElement parentXml)
|
public static XElement CreateVariantXml(XElement variantXML, XElement baseXML)
|
||||||
{
|
{
|
||||||
XElement newXml = selfXml.CreateVariantXML(parentXml);
|
XElement newXml = variantXML.CreateVariantXML(baseXML);
|
||||||
|
XElement variantAi = variantXML.GetChildElement("ai");
|
||||||
XElement selfAi = selfXml.GetChildElement("ai");
|
XElement baseAi = baseXML.GetChildElement("ai");
|
||||||
XElement parentAi = parentXml.GetChildElement("ai");
|
if (baseAi is null || baseAi.Elements().None()
|
||||||
|
|| variantAi is null || variantAi.Elements().None())
|
||||||
if (parentAi is null || parentAi.Elements().None()
|
|
||||||
|| selfAi is null || selfAi.Elements().None())
|
|
||||||
{
|
{
|
||||||
return newXml;
|
return newXml;
|
||||||
}
|
}
|
||||||
|
// CreateVariantXML seems to merge the ai targets so that in the new xml we have both the old and the new target definitions.
|
||||||
//discard the inherited targets, just keep the new ones
|
|
||||||
var finalAiElement = newXml.GetChildElement("ai");
|
var finalAiElement = newXml.GetChildElement("ai");
|
||||||
foreach (var finalTarget in finalAiElement!.Elements().ToArray())
|
var processedTags = new HashSet<string>();
|
||||||
|
foreach (var aiTarget in finalAiElement.Elements().ToArray())
|
||||||
{
|
{
|
||||||
finalTarget.Remove();
|
string tag = aiTarget.GetAttributeString("tag", null);
|
||||||
|
if (tag == null) { continue; }
|
||||||
|
if (processedTags.Contains(tag))
|
||||||
|
{
|
||||||
|
aiTarget.Remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
processedTags.Add(tag);
|
||||||
|
var matchInSelf = variantAi.Elements().FirstOrDefault(e => e.GetAttributeString("tag", null) == tag);
|
||||||
|
var matchInParent = baseAi.Elements().FirstOrDefault(e => e.GetAttributeString("tag", null) == tag);
|
||||||
|
if (matchInSelf != null && matchInParent != null)
|
||||||
|
{
|
||||||
|
aiTarget.ReplaceWith(new XElement(matchInSelf));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var inheritorTarget in selfAi.Elements())
|
|
||||||
{
|
|
||||||
finalAiElement.Add(new XElement(inheritorTarget));
|
|
||||||
}
|
|
||||||
|
|
||||||
return newXml;
|
return newXml;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,6 +582,9 @@ namespace Barotrauma
|
|||||||
[Serialize(false, IsPropertySaveable.Yes, description: "The character will flee for a brief moment when being shot at if not performing an attack."), Editable]
|
[Serialize(false, IsPropertySaveable.Yes, description: "The character will flee for a brief moment when being shot at if not performing an attack."), Editable]
|
||||||
public bool AvoidGunfire { get; private set; }
|
public bool AvoidGunfire { get; private set; }
|
||||||
|
|
||||||
|
[Serialize(0f, IsPropertySaveable.Yes, description: "How much damage is required for single attack to trigger avoiding/releasing targets."), Editable(minValue: 0f, maxValue: 1000f)]
|
||||||
|
public float DamageThreshold { get; private set; }
|
||||||
|
|
||||||
[Serialize(3f, IsPropertySaveable.Yes, description: "How long the creature avoids gunfire. Also used when the creature is unlatched."), Editable(minValue: 0f, maxValue: 100f)]
|
[Serialize(3f, IsPropertySaveable.Yes, description: "How long the creature avoids gunfire. Also used when the creature is unlatched."), Editable(minValue: 0f, maxValue: 100f)]
|
||||||
public float AvoidTime { get; private set; }
|
public float AvoidTime { get; private set; }
|
||||||
|
|
||||||
@@ -785,6 +796,9 @@ namespace Barotrauma
|
|||||||
[Serialize(AttackPattern.Straight, IsPropertySaveable.Yes), Editable]
|
[Serialize(AttackPattern.Straight, IsPropertySaveable.Yes), Editable]
|
||||||
public AttackPattern AttackPattern { get; set; }
|
public AttackPattern AttackPattern { get; set; }
|
||||||
|
|
||||||
|
[Serialize(false, IsPropertySaveable.Yes, description: "If enabled, the AI will give more priority to targets close to the horizontal middle of the sub. Only applies to walls, hulls, and items like sonar. Circle and Sweep always does this regardless of this property."), Editable]
|
||||||
|
public bool PrioritizeSubCenter { get; set; }
|
||||||
|
|
||||||
#region Sweep
|
#region Sweep
|
||||||
[Serialize(0f, IsPropertySaveable.Yes, description: "Use to define a distance at which the creature starts the sweeping movement."), Editable(MinValueFloat = 0, MaxValueFloat = 10000, ValueStep = 1, DecimalCount = 0)]
|
[Serialize(0f, IsPropertySaveable.Yes, description: "Use to define a distance at which the creature starts the sweeping movement."), Editable(MinValueFloat = 0, MaxValueFloat = 10000, ValueStep = 1, DecimalCount = 0)]
|
||||||
public float SweepDistance { get; private set; }
|
public float SweepDistance { get; private set; }
|
||||||
|
|||||||
+1
-1
@@ -8,7 +8,7 @@ namespace Barotrauma.Abilities
|
|||||||
|
|
||||||
public AbilityConditionItemInSubmarine(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
|
public AbilityConditionItemInSubmarine(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
|
||||||
{
|
{
|
||||||
if (conditionElement.Attribute("submarinetype") != null)
|
if (conditionElement.GetAttribute("submarinetype") != null)
|
||||||
{
|
{
|
||||||
submarineType = conditionElement.GetAttributeEnum<SubmarineType>("submarinetype", SubmarineType.Player);
|
submarineType = conditionElement.GetAttributeEnum<SubmarineType>("submarinetype", SubmarineType.Player);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ namespace Barotrauma.Abilities
|
|||||||
|
|
||||||
public AbilityConditionLocation(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
|
public AbilityConditionLocation(CharacterTalent characterTalent, ContentXElement conditionElement) : base(characterTalent, conditionElement)
|
||||||
{
|
{
|
||||||
if (conditionElement.Attribute("hasoutpost") != null)
|
if (conditionElement.GetAttribute("hasoutpost") != null)
|
||||||
{
|
{
|
||||||
hasOutpost = conditionElement.GetAttributeBool("hasoutpost", false);
|
hasOutpost = conditionElement.GetAttributeBool("hasoutpost", false);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-4
@@ -1,7 +1,4 @@
|
|||||||
|
namespace Barotrauma.Abilities
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma.Abilities
|
|
||||||
{
|
{
|
||||||
class AbilityConditionInHull : AbilityConditionDataless
|
class AbilityConditionInHull : AbilityConditionDataless
|
||||||
{
|
{
|
||||||
|
|||||||
+1
-4
@@ -1,7 +1,4 @@
|
|||||||
|
namespace Barotrauma.Abilities
|
||||||
using System.Xml.Linq;
|
|
||||||
|
|
||||||
namespace Barotrauma.Abilities
|
|
||||||
{
|
{
|
||||||
class AbilityConditionInWater : AbilityConditionDataless
|
class AbilityConditionInWater : AbilityConditionDataless
|
||||||
{
|
{
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user