Merge remote-tracking branch 'upstream/master' into develop
This commit is contained in:
@@ -533,7 +533,7 @@ namespace Barotrauma
|
||||
.Distinct();
|
||||
|
||||
public static IEnumerable<Item> FilterCargoCrates(IEnumerable<Item> items, Func<Item, bool> conditional = null)
|
||||
=> items.Where(it => it.HasTag(Tags.Crate) && !it.NonInteractable && !it.NonPlayerTeamInteractable && !it.HiddenInGame && !it.Removed && (conditional == null || conditional(it)));
|
||||
=> items.Where(it => it.HasTag(Tags.Crate) && !it.NonInteractable && !it.NonPlayerTeamInteractable && !it.IsHidden && !it.Removed && (conditional == null || conditional(it)));
|
||||
|
||||
public static IEnumerable<ItemContainer> FindReusableCargoContainers(IEnumerable<Submarine> subs, IEnumerable<Hull> cargoRooms = null) =>
|
||||
FilterCargoCrates(Item.ItemList, it => subs.Contains(it.Submarine) && !it.HasTag(Tags.CargoMissionItem) && (cargoRooms == null || cargoRooms.Contains(it.CurrentHull)))
|
||||
@@ -685,7 +685,14 @@ namespace Barotrauma
|
||||
var idCard = item.GetComponent<IdCard>();
|
||||
if (cargoManager != null && idCard != null && purchased.BuyerCharacterInfoIdentifier != 0)
|
||||
{
|
||||
cargoManager.purchasedIDCards.Add((purchased, idCard));
|
||||
if (purchased.DeliverImmediately)
|
||||
{
|
||||
InitPurchasedIDCard(purchased, idCard);
|
||||
}
|
||||
else
|
||||
{
|
||||
cargoManager.purchasedIDCards.Add((purchased, idCard));
|
||||
}
|
||||
}
|
||||
|
||||
Submarine sub = item.Submarine ?? item.RootContainer?.Submarine;
|
||||
@@ -703,18 +710,23 @@ namespace Barotrauma
|
||||
{
|
||||
foreach ((PurchasedItem purchased, IdCard idCard) in purchasedIDCards)
|
||||
{
|
||||
if (idCard != null && purchased.BuyerCharacterInfoIdentifier != 0)
|
||||
{
|
||||
var owner = Character.CharacterList.Find(c => c.Info?.GetIdentifier() == purchased.BuyerCharacterInfoIdentifier);
|
||||
if (owner?.Info != null)
|
||||
{
|
||||
var mainSubSpawnPoints = WayPoint.SelectCrewSpawnPoints(new List<CharacterInfo>() { owner.Info }, Submarine.MainSub);
|
||||
idCard.Initialize(mainSubSpawnPoints.FirstOrDefault(), owner);
|
||||
}
|
||||
}
|
||||
InitPurchasedIDCard(purchased, idCard);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitPurchasedIDCard(PurchasedItem purchased, IdCard idCard)
|
||||
{
|
||||
if (idCard != null && purchased.BuyerCharacterInfoIdentifier != 0)
|
||||
{
|
||||
var owner = Character.CharacterList.Find(c => c.Info?.GetIdentifier() == purchased.BuyerCharacterInfoIdentifier);
|
||||
if (owner?.Info != null)
|
||||
{
|
||||
var mainSubSpawnPoints = WayPoint.SelectCrewSpawnPoints(new List<CharacterInfo>() { owner.Info }, Submarine.MainSub);
|
||||
idCard.Initialize(mainSubSpawnPoints.FirstOrDefault(), owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector2 GetCargoPos(Hull hull, ItemPrefab itemPrefab)
|
||||
{
|
||||
float floorPos = hull.Rect.Y - hull.Rect.Height;
|
||||
|
||||
@@ -99,14 +99,20 @@ namespace Barotrauma
|
||||
{
|
||||
if (order.Identifier == Tags.DeconstructThis)
|
||||
{
|
||||
Item.DeconstructItems.Add(item);
|
||||
foreach (var stackedItem in item.GetStackedItems())
|
||||
{
|
||||
Item.DeconstructItems.Add(stackedItem);
|
||||
}
|
||||
#if CLIENT
|
||||
HintManager.OnItemMarkedForDeconstruction(order.OrderGiver);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
Item.DeconstructItems.Remove(item);
|
||||
foreach (var stackedItem in item.GetStackedItems())
|
||||
{
|
||||
Item.DeconstructItems.Remove(stackedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,6 +186,17 @@ namespace Barotrauma
|
||||
DebugConsole.ThrowError("Tried to add a dead character to CrewManager!\n" + Environment.StackTrace.CleanupStackTrace());
|
||||
return;
|
||||
}
|
||||
if (character.Info == null)
|
||||
{
|
||||
if (character.Prefab.ContentPackage == GameMain.VanillaContent)
|
||||
{
|
||||
DebugConsole.ThrowError($"Added a character with no {nameof(CharacterInfo)} to the crew." + Environment.StackTrace.CleanupStackTrace());
|
||||
}
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError($"Added add a character with no {nameof(CharacterInfo)} to the crew. This may lead to issues: consider adding {nameof(CharacterPrefab.HasCharacterInfo)}=\"True\" to the character config.");
|
||||
}
|
||||
}
|
||||
|
||||
if (!characters.Contains(character))
|
||||
{
|
||||
@@ -275,11 +292,7 @@ namespace Barotrauma
|
||||
|
||||
if (Level.Loaded != null && Level.Loaded.ShouldSpawnCrewInsideOutpost())
|
||||
{
|
||||
spawnWaypoints = WayPoint.WayPointList.FindAll(wp =>
|
||||
wp.SpawnType == SpawnType.Human &&
|
||||
wp.Submarine == Level.Loaded.StartOutpost &&
|
||||
wp.CurrentHull != null &&
|
||||
wp.CurrentHull.OutpostModuleTags.Contains("airlock".ToIdentifier()));
|
||||
spawnWaypoints = GetOutpostSpawnpoints();
|
||||
while (spawnWaypoints.Count > characterInfos.Count)
|
||||
{
|
||||
spawnWaypoints.RemoveAt(Rand.Int(spawnWaypoints.Count));
|
||||
@@ -301,46 +314,8 @@ namespace Barotrauma
|
||||
var info = characterInfos[i];
|
||||
info.TeamID = CharacterTeamType.Team1;
|
||||
Character character = Character.Create(info, spawnWaypoints[i].WorldPosition, info.Name);
|
||||
if (character.Info != null)
|
||||
{
|
||||
if (!character.Info.StartItemsGiven && character.Info.InventoryData != null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error when initializing a round: character \"{character.Name}\" has not been given their initial items but has saved inventory data. Using the saved inventory data instead of giving the character new items.");
|
||||
}
|
||||
if (character.Info.InventoryData != null)
|
||||
{
|
||||
character.SpawnInventoryItems(character.Inventory, character.Info.InventoryData.FromPackage(null));
|
||||
}
|
||||
else if (!character.Info.StartItemsGiven)
|
||||
{
|
||||
character.GiveJobItems(mainSubWaypoints[i]);
|
||||
foreach (Item item in character.Inventory.AllItems)
|
||||
{
|
||||
//if the character is loaded from a human prefab with preconfigured items, its ID card gets assigned to the sub it spawns in
|
||||
//we don't want that in this case, the crew's cards shouldn't be submarine-specific
|
||||
var idCard = item.GetComponent<Items.Components.IdCard>();
|
||||
if (idCard != null)
|
||||
{
|
||||
idCard.SubmarineSpecificID = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (character.Info.HealthData != null)
|
||||
{
|
||||
CharacterInfo.ApplyHealthData(character, character.Info.HealthData);
|
||||
}
|
||||
InitializeCharacter(character, mainSubWaypoints[i], spawnWaypoints[i]);
|
||||
|
||||
character.LoadTalents();
|
||||
|
||||
character.GiveIdCardTags(mainSubWaypoints[i]);
|
||||
character.GiveIdCardTags(spawnWaypoints[i]);
|
||||
character.Info.StartItemsGiven = true;
|
||||
if (character.Info.OrderData != null)
|
||||
{
|
||||
character.Info.ApplyOrderData();
|
||||
}
|
||||
}
|
||||
|
||||
AddCharacter(character, sortCrewList: false);
|
||||
#if CLIENT
|
||||
if (IsSinglePlayer && (Character.Controlled == null || character.Info.LastControlled)) { Character.Controlled = character; }
|
||||
@@ -355,6 +330,61 @@ namespace Barotrauma
|
||||
conversationTimer = IsSinglePlayer ? Rand.Range(5.0f, 10.0f) : Rand.Range(45.0f, 60.0f);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the potential crew spawnpositions for the crew in the loaded outpost
|
||||
/// </summary>
|
||||
public List<WayPoint> GetOutpostSpawnpoints()
|
||||
{
|
||||
return WayPoint.WayPointList.FindAll(wp =>
|
||||
wp.SpawnType == SpawnType.Human &&
|
||||
wp.Submarine == Level.Loaded.StartOutpost &&
|
||||
wp.CurrentHull != null &&
|
||||
wp.CurrentHull.OutpostModuleTags.Contains("airlock".ToIdentifier()));
|
||||
}
|
||||
|
||||
public void InitializeCharacter(Character character, WayPoint mainSubWaypoint, WayPoint spawnWaypoint)
|
||||
{
|
||||
if (character.Info != null)
|
||||
{
|
||||
if (!character.Info.StartItemsGiven && character.Info.InventoryData != null)
|
||||
{
|
||||
DebugConsole.AddWarning($"Error when initializing a round: character \"{character.Name}\" has not been given their initial items but has saved inventory data. Using the saved inventory data instead of giving the character new items.");
|
||||
}
|
||||
if (character.Info.InventoryData != null)
|
||||
{
|
||||
character.SpawnInventoryItems(character.Inventory, character.Info.InventoryData.FromPackage(null));
|
||||
}
|
||||
else if (!character.Info.StartItemsGiven)
|
||||
{
|
||||
character.GiveJobItems(mainSubWaypoint);
|
||||
foreach (Item item in character.Inventory.AllItems)
|
||||
{
|
||||
//if the character is loaded from a human prefab with preconfigured items, its ID card gets assigned to the sub it spawns in
|
||||
//we don't want that in this case, the crew's cards shouldn't be submarine-specific
|
||||
var idCard = item.GetComponent<Items.Components.IdCard>();
|
||||
if (idCard != null)
|
||||
{
|
||||
idCard.SubmarineSpecificID = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (character.Info.HealthData != null)
|
||||
{
|
||||
CharacterInfo.ApplyHealthData(character, character.Info.HealthData);
|
||||
}
|
||||
|
||||
character.LoadTalents();
|
||||
|
||||
character.GiveIdCardTags(mainSubWaypoint);
|
||||
character.GiveIdCardTags(spawnWaypoint);
|
||||
character.Info.StartItemsGiven = true;
|
||||
if (character.Info.OrderData != null)
|
||||
{
|
||||
character.Info.ApplyOrderData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void RenameCharacter(CharacterInfo characterInfo, string newName)
|
||||
{
|
||||
int identifier = characterInfo.GetIdentifierUsingOriginalName();
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace Barotrauma
|
||||
internal struct NetWalletSetSalaryUpdate : INetSerializableStruct
|
||||
{
|
||||
[NetworkSerialize]
|
||||
public ushort Target;
|
||||
public Option<ushort> Target;
|
||||
|
||||
[NetworkSerialize(MinValueInt = 0, MaxValueInt = 100)]
|
||||
public int NewRewardDistribution;
|
||||
@@ -117,13 +117,13 @@ namespace Barotrauma
|
||||
public override int Balance
|
||||
{
|
||||
get => 0;
|
||||
set => new InvalidOperationException("Tried to set the balance on an invalid wallet");
|
||||
set => throw new InvalidOperationException("Tried to set the balance on an invalid wallet");
|
||||
}
|
||||
|
||||
public override int RewardDistribution
|
||||
{
|
||||
get => 0;
|
||||
set => new InvalidOperationException("Tried to set the reward distribution on an invalid wallet");
|
||||
set => throw new InvalidOperationException("Tried to set the reward distribution on an invalid wallet");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +134,7 @@ namespace Barotrauma
|
||||
public const string LowerCaseSaveElementName = "wallet";
|
||||
|
||||
private const string AttributeNameBalance = "balance",
|
||||
AttrubuteNameRewardDistribution = "rewarddistribution",
|
||||
AttributeNameRewardDistribution = "rewarddistribution",
|
||||
SaveElementName = "Wallet";
|
||||
|
||||
public readonly Option<Character> Owner;
|
||||
@@ -152,7 +152,15 @@ namespace Barotrauma
|
||||
public virtual int RewardDistribution
|
||||
{
|
||||
get => rewardDistribution;
|
||||
set => rewardDistribution = ClampRewardDistribution(value);
|
||||
set
|
||||
{
|
||||
rewardDistribution = ClampRewardDistribution(value);
|
||||
|
||||
if (Owner.TryUnwrap(out var character) && character.Info is { } info)
|
||||
{
|
||||
info.LastRewardDistribution = Option.Some(rewardDistribution);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Wallet(Option<Character> owner)
|
||||
@@ -163,12 +171,14 @@ namespace Barotrauma
|
||||
public Wallet(Option<Character> owner, XElement element): this(owner)
|
||||
{
|
||||
balance = ClampBalance(element.GetAttributeInt(AttributeNameBalance, 0));
|
||||
rewardDistribution = ClampBalance(element.GetAttributeInt(AttrubuteNameRewardDistribution, 0));
|
||||
rewardDistribution = ClampBalance(element.GetAttributeInt(AttributeNameRewardDistribution, 0));
|
||||
}
|
||||
|
||||
public XElement Save()
|
||||
{
|
||||
XElement element = new XElement(SaveElementName, new XAttribute(AttributeNameBalance, Balance), new XAttribute(AttrubuteNameRewardDistribution, RewardDistribution));
|
||||
XElement element = new XElement(SaveElementName,
|
||||
new XAttribute(AttributeNameBalance, Balance),
|
||||
new XAttribute(AttributeNameRewardDistribution, RewardDistribution));
|
||||
return element;
|
||||
}
|
||||
|
||||
@@ -195,6 +205,11 @@ namespace Barotrauma
|
||||
SettingsChanged(balanceChanged: Option<int>.Some(-price), rewardChanged: Option<int>.None());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets how much salary the wallet owner should receive from mission rewards.
|
||||
/// Bank's salary determines the default salary for new characters.
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
public void SetRewardDistribution(int value)
|
||||
{
|
||||
int oldValue = RewardDistribution;
|
||||
|
||||
@@ -347,6 +347,10 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
public event Action BeforeLevelLoading;
|
||||
|
||||
/// <summary>
|
||||
/// Triggers when saving and quitting mid-round (as in, not just transferring to a new level). Automatically cleared after triggering -> no need to unregister
|
||||
/// </summary>
|
||||
public event Action OnSaveAndQuit;
|
||||
|
||||
public override void AddExtraMissions(LevelData levelData)
|
||||
{
|
||||
@@ -472,7 +476,7 @@ namespace Barotrauma
|
||||
var missionPrefabs = MissionPrefab.Prefabs.Where(m => m.Tags.Any(t => t == automaticMission.MissionTag)).OrderBy(m => m.UintIdentifier);
|
||||
if (missionPrefabs.Any())
|
||||
{
|
||||
var missionPrefab = ToolBox.SelectWeightedRandom(missionPrefabs, p => (float)p.Commonness, rand);
|
||||
var missionPrefab = ToolBox.SelectWeightedRandom(missionPrefabs, p => p.Commonness, rand);
|
||||
if (missionPrefab.Type == MissionType.Pirate && Missions.Any(m => m.Prefab.Type == MissionType.Pirate))
|
||||
{
|
||||
continue;
|
||||
@@ -515,8 +519,8 @@ namespace Barotrauma
|
||||
if (endLevelMissionPrefabs.Any())
|
||||
{
|
||||
Random rand = new MTRandom(ToolBox.StringToInt(levelData.Seed));
|
||||
var endLevelMissionPrefab = ToolBox.SelectWeightedRandom(endLevelMissionPrefabs, p => (float)p.Commonness, rand);
|
||||
if (!Missions.Any(m => m.Prefab.Type == endLevelMissionPrefab.Type))
|
||||
var endLevelMissionPrefab = ToolBox.SelectWeightedRandom(endLevelMissionPrefabs, p => p.Commonness, rand);
|
||||
if (Missions.All(m => m.Prefab.Type != endLevelMissionPrefab.Type))
|
||||
{
|
||||
if (levelData.Type == LevelData.LevelType.LocationConnection)
|
||||
{
|
||||
@@ -913,6 +917,20 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles updating store stock, registering event history and relocating items (i.e. things that need to be done when saving and quitting mid-round)
|
||||
/// </summary>
|
||||
public void HandleSaveAndQuit()
|
||||
{
|
||||
OnSaveAndQuit?.Invoke();
|
||||
OnSaveAndQuit = null;
|
||||
if (Level.IsLoadedFriendlyOutpost)
|
||||
{
|
||||
UpdateStoreStock();
|
||||
}
|
||||
GameMain.GameSession.EventManager?.RegisterEventHistory(registerFinishedOnly: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates store stock before saving the game
|
||||
/// </summary>
|
||||
@@ -1368,13 +1386,13 @@ namespace Barotrauma
|
||||
{
|
||||
if (item.Removed) { continue; }
|
||||
if (item.NonInteractable || item.NonPlayerTeamInteractable) { continue; }
|
||||
if (item.HiddenInGame) { continue; }
|
||||
if (item.IsHidden) { continue; }
|
||||
if (!connectedSubs.Contains(item.Submarine)) { continue; }
|
||||
if (item.Prefab.DontTransferBetweenSubs) { continue; }
|
||||
if (AnyParentInventoryDisableTransfer(item)) { continue; }
|
||||
var rootOwner = item.GetRootInventoryOwner();
|
||||
if (rootOwner is Character) { continue; }
|
||||
if (rootOwner is Item ownerItem && (ownerItem.NonInteractable || item.NonPlayerTeamInteractable || ownerItem.HiddenInGame)) { continue; }
|
||||
if (rootOwner is Item ownerItem && (ownerItem.NonInteractable || item.NonPlayerTeamInteractable || ownerItem.IsHidden)) { continue; }
|
||||
if (item.GetComponent<Door>() != null) { continue; }
|
||||
if (item.Components.None(c => c is Pickable)) { continue; }
|
||||
if (item.Components.Any(c => c is Pickable p && p.IsAttached)) { continue; }
|
||||
|
||||
@@ -29,7 +29,7 @@ namespace Barotrauma
|
||||
: base(preset)
|
||||
{
|
||||
Location[] locations = { GameMain.GameSession.StartLocation, GameMain.GameSession.EndLocation };
|
||||
var mission = Mission.LoadRandom(locations, seed, false, missionType);
|
||||
var mission = Mission.LoadRandom(locations, seed, requireCorrectLocationType: false, missionType, difficultyLevel: GameMain.NetworkMember.ServerSettings.SelectedLevelDifficulty);
|
||||
if (mission != null)
|
||||
{
|
||||
missions.Add(mission);
|
||||
|
||||
@@ -231,6 +231,12 @@ namespace Barotrauma
|
||||
{
|
||||
campaign.Bank.Deduct(selectedSub.Price);
|
||||
campaign.Bank.Balance = Math.Max(campaign.Bank.Balance, 0);
|
||||
#if SERVER
|
||||
if (GameMain.Server?.ServerSettings?.NewCampaignDefaultSalary is { } salary)
|
||||
{
|
||||
campaign.Bank.SetRewardDistribution((int)Math.Round(salary, digits: 0));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return campaign;
|
||||
}
|
||||
@@ -970,6 +976,8 @@ namespace Barotrauma
|
||||
{
|
||||
ToggleTabMenu();
|
||||
}
|
||||
DeathPrompt?.Close();
|
||||
DeathPrompt.CloseBotPanel();
|
||||
|
||||
GUI.PreventPauseMenuToggle = true;
|
||||
|
||||
|
||||
@@ -42,16 +42,25 @@ namespace Barotrauma
|
||||
{
|
||||
AvailableCharacters.ForEach(c => c.Remove());
|
||||
AvailableCharacters.Clear();
|
||||
|
||||
foreach (var missingJob in location.Type.GetHireablesMissingFromCrew())
|
||||
{
|
||||
AddCharacter(missingJob);
|
||||
amount--;
|
||||
}
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
JobPrefab job = location.Type.GetRandomHireable();
|
||||
if (job == null) { return; }
|
||||
|
||||
var variant = Rand.Range(0, job.Variants, Rand.RandSync.ServerAndClient);
|
||||
AvailableCharacters.Add(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: job, variant: variant));
|
||||
AddCharacter(location.Type.GetRandomHireable());
|
||||
}
|
||||
if (location.Faction != null) { GenerateFactionCharacters(location.Faction.Prefab); }
|
||||
if (location.SecondaryFaction != null) { GenerateFactionCharacters(location.SecondaryFaction.Prefab); }
|
||||
|
||||
void AddCharacter(JobPrefab job)
|
||||
{
|
||||
if (job == null) { return; }
|
||||
int variant = Rand.Range(0, job.Variants, Rand.RandSync.ServerAndClient);
|
||||
AvailableCharacters.Add(new CharacterInfo(CharacterPrefab.HumanSpeciesName, jobOrJobPrefab: job, variant: variant));
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateFactionCharacters(FactionPrefab faction)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -125,7 +125,7 @@ namespace Barotrauma
|
||||
|
||||
public NetCrewMember(CharacterInfo info)
|
||||
{
|
||||
CharacterInfoID = info.GetIdentifierUsingOriginalName();
|
||||
CharacterInfoID = info.ID;
|
||||
Afflictions = ImmutableArray<NetAffliction>.Empty;
|
||||
}
|
||||
|
||||
@@ -138,7 +138,7 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (CharacterInfo info in crew)
|
||||
{
|
||||
if (info.GetIdentifierUsingOriginalName() == CharacterInfoID)
|
||||
if (info.ID == CharacterInfoID)
|
||||
{
|
||||
return info;
|
||||
}
|
||||
@@ -159,6 +159,14 @@ namespace Barotrauma
|
||||
|
||||
private readonly CampaignMode? campaign;
|
||||
|
||||
/// <summary>
|
||||
/// Characters whose afflictions have changed (processed periodically, refreshing the UI client-side, sending updates to clients server-side
|
||||
/// </summary>
|
||||
private readonly HashSet<Character> charactersWithAfflictionChanges = new HashSet<Character>();
|
||||
|
||||
private float processAfflictionChangesTimer;
|
||||
private const float ProcessAfflictionChangesInterval = 1.0f;
|
||||
|
||||
public MedicalClinic(CampaignMode campaign)
|
||||
{
|
||||
this.campaign = campaign;
|
||||
@@ -305,35 +313,8 @@ namespace Barotrauma
|
||||
|
||||
private void OnAfflictionCountChangedPrivate(Character character)
|
||||
{
|
||||
if (character is not { CharacterHealth: { } health, Info: { } info }) { return; }
|
||||
|
||||
ImmutableArray<NetAffliction> afflictions = GetAllAfflictions(health);
|
||||
|
||||
#if CLIENT
|
||||
if (GameMain.NetworkMember is null)
|
||||
{
|
||||
ui?.UpdateAfflictions(new NetCrewMember(info, afflictions));
|
||||
}
|
||||
|
||||
ui?.UpdateCrewPanel();
|
||||
#elif SERVER
|
||||
foreach (AfflictionSubscriber sub in afflictionSubscribers.ToList())
|
||||
{
|
||||
if (sub.Expiry < DateTimeOffset.Now)
|
||||
{
|
||||
afflictionSubscribers.Remove(sub);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sub.Target == info)
|
||||
{
|
||||
ServerSend(new NetCrewMember(info, afflictions),
|
||||
header: NetworkHeader.AFFLICTION_UPDATE,
|
||||
deliveryMethod: DeliveryMethod.Unreliable,
|
||||
targetClient: sub.Subscriber);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (character?.Info == null) { return; }
|
||||
charactersWithAfflictionChanges.Add(character);
|
||||
}
|
||||
|
||||
public int GetTotalCost() => PendingHeals.SelectMany(static h => h.Afflictions).Aggregate(0, static (current, affliction) => current + affliction.Price);
|
||||
|
||||
@@ -295,7 +295,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Purchases an item swap and handles logic for deducting the credit.
|
||||
/// </summary>
|
||||
public void PurchaseItemSwap(Item itemToRemove, ItemPrefab itemToInstall, bool force = false, Client? client = null)
|
||||
public void PurchaseItemSwap(Item itemToRemove, ItemPrefab itemToInstall, bool isNetworkMessage = false, Client? client = null)
|
||||
{
|
||||
if (!CanUpgradeSub())
|
||||
{
|
||||
@@ -343,12 +343,14 @@ namespace Barotrauma
|
||||
price = itemToInstall.SwappableItem.GetPrice(Campaign.Map?.CurrentLocation) * linkedItems.Count;
|
||||
}
|
||||
|
||||
if (force)
|
||||
if (isNetworkMessage)
|
||||
{
|
||||
price = 0;
|
||||
}
|
||||
|
||||
if (Campaign.TryPurchase(client, price))
|
||||
//do not try to purchase if this is a network message (if the server is telling us that an item swap was purchased)
|
||||
//we want to do the purchase no matter what, and the server handles deducting the money
|
||||
if (isNetworkMessage || Campaign.TryPurchase(client, price))
|
||||
{
|
||||
PurchasedItemSwaps.RemoveAll(p => linkedItems.Contains(p.ItemToRemove));
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
@@ -433,8 +435,7 @@ namespace Barotrauma
|
||||
{
|
||||
if (itemToCancel.PendingItemSwap == null)
|
||||
{
|
||||
var replacement = MapEntityPrefab.Find("", swappableItem.ReplacementOnUninstall) as ItemPrefab;
|
||||
if (replacement == null)
|
||||
if (MapEntityPrefab.FindByIdentifier(swappableItem.ReplacementOnUninstall) is not ItemPrefab replacement)
|
||||
{
|
||||
DebugConsole.ThrowError($"Failed to uninstall item \"{itemToCancel.Name}\". Could not find the replacement item \"{swappableItem.ReplacementOnUninstall}\".");
|
||||
return;
|
||||
@@ -786,11 +787,10 @@ namespace Barotrauma
|
||||
|
||||
private void LoadPendingUpgrades(XElement? element, bool isSingleplayer = true)
|
||||
{
|
||||
if (!(element is { HasElements: true })) { return; }
|
||||
if (element is not { HasElements: true }) { return; }
|
||||
|
||||
List<PurchasedUpgrade> pendingUpgrades = new List<PurchasedUpgrade>();
|
||||
|
||||
// ReSharper disable once LoopCanBeConvertedToQuery
|
||||
|
||||
foreach (XElement upgrade in element.Elements())
|
||||
{
|
||||
Identifier categoryIdentifier = upgrade.GetAttributeIdentifier("category", Identifier.Empty);
|
||||
|
||||
Reference in New Issue
Block a user