Unstable 0.17.1.0
This commit is contained in:
@@ -168,7 +168,7 @@ namespace Barotrauma
|
||||
foreach (Item spawnedItem in spawnedItems)
|
||||
{
|
||||
#if SERVER
|
||||
Entity.Spawner.CreateNetworkEvent(spawnedItem, remove: false);
|
||||
Entity.Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(spawnedItem));
|
||||
#endif
|
||||
foreach (ItemComponent ic in spawnedItem.Components)
|
||||
{
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
#if SERVER
|
||||
using Barotrauma.Networking;
|
||||
#endif
|
||||
@@ -18,12 +19,34 @@ namespace Barotrauma
|
||||
public int Quantity { get; set; }
|
||||
public bool? IsStoreComponentEnabled { get; set; }
|
||||
|
||||
public PurchasedItem(ItemPrefab itemPrefab, int quantity)
|
||||
public readonly int BuyerCharacterInfoId;
|
||||
|
||||
public PurchasedItem(ItemPrefab itemPrefab, int quantity, int buyerCharacterInfoId)
|
||||
{
|
||||
ItemPrefab = itemPrefab;
|
||||
Quantity = quantity;
|
||||
IsStoreComponentEnabled = null;
|
||||
BuyerCharacterInfoId = buyerCharacterInfoId;
|
||||
}
|
||||
|
||||
#if CLIENT
|
||||
public PurchasedItem(ItemPrefab itemPrefab, int quantity, Client buyer = null)
|
||||
{
|
||||
ItemPrefab = itemPrefab;
|
||||
Quantity = quantity;
|
||||
IsStoreComponentEnabled = null;
|
||||
BuyerCharacterInfoId = buyer?.Character?.Info?.ID ?? Character.Controlled?.Info?.ID ?? 0;
|
||||
}
|
||||
#elif SERVER
|
||||
public PurchasedItem(ItemPrefab itemPrefab, int quantity, Client buyer)
|
||||
{
|
||||
ItemPrefab = itemPrefab;
|
||||
Quantity = quantity;
|
||||
IsStoreComponentEnabled = null;
|
||||
BuyerCharacterInfoId = buyer?.Character?.Info?.ID ?? 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
class SoldItem
|
||||
@@ -156,7 +179,7 @@ namespace Barotrauma
|
||||
OnPurchasedItemsChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void ModifyItemQuantityInBuyCrate(ItemPrefab itemPrefab, int changeInQuantity)
|
||||
public void ModifyItemQuantityInBuyCrate(ItemPrefab itemPrefab, int changeInQuantity, Client client = null)
|
||||
{
|
||||
var itemInCrate = ItemsInBuyCrate.Find(i => i.ItemPrefab == itemPrefab);
|
||||
if (itemInCrate != null)
|
||||
@@ -167,15 +190,15 @@ namespace Barotrauma
|
||||
ItemsInBuyCrate.Remove(itemInCrate);
|
||||
}
|
||||
}
|
||||
else if(changeInQuantity > 0)
|
||||
else if (changeInQuantity > 0)
|
||||
{
|
||||
itemInCrate = new PurchasedItem(itemPrefab, changeInQuantity);
|
||||
itemInCrate = new PurchasedItem(itemPrefab, changeInQuantity, client);
|
||||
ItemsInBuyCrate.Add(itemInCrate);
|
||||
}
|
||||
OnItemsInBuyCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void ModifyItemQuantityInSubSellCrate(ItemPrefab itemPrefab, int changeInQuantity)
|
||||
public void ModifyItemQuantityInSubSellCrate(ItemPrefab itemPrefab, int changeInQuantity, Client client = null)
|
||||
{
|
||||
var itemInCrate = ItemsInSellFromSubCrate.Find(i => i.ItemPrefab == itemPrefab);
|
||||
if (itemInCrate != null)
|
||||
@@ -188,13 +211,13 @@ namespace Barotrauma
|
||||
}
|
||||
else if (changeInQuantity > 0)
|
||||
{
|
||||
itemInCrate = new PurchasedItem(itemPrefab, changeInQuantity);
|
||||
itemInCrate = new PurchasedItem(itemPrefab, changeInQuantity, client);
|
||||
ItemsInSellFromSubCrate.Add(itemInCrate);
|
||||
}
|
||||
OnItemsInSellFromSubCrateChanged?.Invoke();
|
||||
}
|
||||
|
||||
public void PurchaseItems(List<PurchasedItem> itemsToPurchase, bool removeFromCrate)
|
||||
public void PurchaseItems(List<PurchasedItem> itemsToPurchase, bool removeFromCrate, Client client = null)
|
||||
{
|
||||
// Check all the prices before starting the transaction
|
||||
// to make sure the modifiers stay the same for the whole transaction
|
||||
@@ -210,13 +233,13 @@ namespace Barotrauma
|
||||
}
|
||||
else
|
||||
{
|
||||
purchasedItem = new PurchasedItem(item.ItemPrefab, item.Quantity);
|
||||
purchasedItem = new PurchasedItem(item.ItemPrefab, item.Quantity, client);
|
||||
PurchasedItems.Add(purchasedItem);
|
||||
}
|
||||
|
||||
// Exchange money
|
||||
var itemValue = item.Quantity * buyValues[item.ItemPrefab];
|
||||
campaign.Money -= itemValue;
|
||||
campaign.GetWallet(client).TryDeduct(itemValue);
|
||||
GameAnalyticsManager.AddMoneySpentEvent(itemValue, GameAnalyticsManager.MoneySink.Store, item.ItemPrefab.Identifier.Value);
|
||||
Location.StoreCurrentBalance += itemValue;
|
||||
|
||||
@@ -427,7 +450,7 @@ namespace Barotrauma
|
||||
#if SERVER
|
||||
if (GameMain.Server != null)
|
||||
{
|
||||
Entity.Spawner.CreateNetworkEvent(itemContainer.Item, false);
|
||||
Entity.Spawner.CreateNetworkEvent(new EntitySpawner.SpawnEntity(itemContainer.Item));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -438,7 +461,7 @@ namespace Barotrauma
|
||||
|
||||
itemSpawned(item);
|
||||
#if SERVER
|
||||
Entity.Spawner?.CreateNetworkEvent(item, false);
|
||||
Entity.Spawner?.CreateNetworkEvent(new EntitySpawner.SpawnEntity(item));
|
||||
#endif
|
||||
(itemContainer?.Item ?? item).CampaignInteractionType = CampaignMode.InteractionType.Cargo;
|
||||
static void itemSpawned(Item item)
|
||||
@@ -491,7 +514,8 @@ namespace Barotrauma
|
||||
if (item?.ItemPrefab == null) { continue; }
|
||||
itemsElement.Add(new XElement("item",
|
||||
new XAttribute("id", item.ItemPrefab.Identifier),
|
||||
new XAttribute("qty", item.Quantity)));
|
||||
new XAttribute("qty", item.Quantity),
|
||||
new XAttribute("buyer", item.BuyerCharacterInfoId)));
|
||||
}
|
||||
parentElement.Add(itemsElement);
|
||||
}
|
||||
@@ -503,12 +527,15 @@ namespace Barotrauma
|
||||
{
|
||||
foreach (XElement itemElement in element.GetChildElements("item"))
|
||||
{
|
||||
var id = itemElement.GetAttributeString("id", null);
|
||||
string id = itemElement.GetAttributeString("id", null);
|
||||
if (string.IsNullOrWhiteSpace(id)) { continue; }
|
||||
var prefab = ItemPrefab.Prefabs.Find(p => p.Identifier == id);
|
||||
if (prefab == null) { continue; }
|
||||
var qty = itemElement.GetAttributeInt("qty", 0);
|
||||
purchasedItems.Add(new PurchasedItem(prefab, qty));
|
||||
int qty = itemElement.GetAttributeInt("qty", 0);
|
||||
int buyerId = itemElement.GetAttributeInt("buyer", 0);
|
||||
|
||||
purchasedItems.Add(new PurchasedItem(prefab, qty, buyerId));
|
||||
|
||||
}
|
||||
}
|
||||
SetPurchasedItems(purchasedItems);
|
||||
|
||||
@@ -20,6 +20,16 @@ namespace Barotrauma
|
||||
private readonly List<CharacterInfo> characterInfos = new List<CharacterInfo>();
|
||||
private readonly List<Character> characters = new List<Character>();
|
||||
|
||||
public IEnumerable<Character> GetCharacters()
|
||||
{
|
||||
return characters;
|
||||
}
|
||||
|
||||
public IEnumerable<CharacterInfo> GetCharacterInfos()
|
||||
{
|
||||
return characterInfos;
|
||||
}
|
||||
|
||||
private Character welcomeMessageNPC;
|
||||
|
||||
public List<CharacterInfo> CharacterInfos => characterInfos;
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -27,6 +25,8 @@ namespace Barotrauma
|
||||
public LocalizedString Description { get; }
|
||||
public LocalizedString ShortDescription { get; }
|
||||
|
||||
public int MenuOrder { get; }
|
||||
|
||||
/// <summary>
|
||||
/// How low the reputation can drop on this faction
|
||||
/// </summary>
|
||||
@@ -52,6 +52,7 @@ namespace Barotrauma
|
||||
|
||||
public FactionPrefab(ContentXElement element, FactionsFile file) : base(file, element.GetAttributeIdentifier("identifier", string.Empty))
|
||||
{
|
||||
MenuOrder = element.GetAttributeInt("menuorder", 0);
|
||||
MinReputation = element.GetAttributeInt("minreputation", -100);
|
||||
MaxReputation = element.GetAttributeInt("maxreputation", 100);
|
||||
InitialReputation = element.GetAttributeInt("initialreputation", 0);
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace Barotrauma
|
||||
("[reputationvalue]", ((int)Math.Round(value)).ToString()));
|
||||
if (addColorTags)
|
||||
{
|
||||
formattedReputation = $"‖color:{XMLExtensions.ColorToString(GetReputationColor(normalizedValue))}‖"+ formattedReputation+"‖end‖";
|
||||
formattedReputation = $"‖color:{XMLExtensions.ToStringHex(GetReputationColor(normalizedValue))}‖{formattedReputation}‖end‖";
|
||||
}
|
||||
return formattedReputation;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
using System;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
internal readonly struct WalletChangedEvent
|
||||
{
|
||||
public readonly Wallet Wallet;
|
||||
public readonly WalletInfo Info;
|
||||
public readonly WalletChangedData ChangedData;
|
||||
|
||||
public WalletChangedEvent(Wallet wallet, WalletChangedData changedData, WalletInfo info)
|
||||
{
|
||||
Wallet = wallet;
|
||||
Info = info;
|
||||
ChangedData = changedData;
|
||||
}
|
||||
}
|
||||
|
||||
[NetworkSerialize]
|
||||
internal struct WalletInfo : INetSerializableStruct
|
||||
{
|
||||
public int RewardDistribution;
|
||||
public int Balance;
|
||||
}
|
||||
|
||||
internal struct NetWalletUpdate : INetSerializableStruct
|
||||
{
|
||||
[NetworkSerialize(ArrayMaxSize = NetConfig.MaxPlayers + 1)]
|
||||
public NetWalletTransaction[] Transactions;
|
||||
}
|
||||
|
||||
[NetworkSerialize]
|
||||
internal struct NetWalletTransfer : INetSerializableStruct
|
||||
{
|
||||
public Option<ushort> Sender;
|
||||
public Option<ushort> Receiver;
|
||||
public int Amount;
|
||||
}
|
||||
|
||||
internal struct NetWalletSalaryUpdate : INetSerializableStruct
|
||||
{
|
||||
[NetworkSerialize]
|
||||
public ushort Target;
|
||||
|
||||
[NetworkSerialize(MinValueInt = 0, MaxValueInt = 100)]
|
||||
public int NewRewardDistribution;
|
||||
}
|
||||
|
||||
[NetworkSerialize]
|
||||
internal struct WalletChangedData : INetSerializableStruct
|
||||
{
|
||||
public Option<int> RewardDistributionChanged;
|
||||
public Option<int> BalanceChanged;
|
||||
|
||||
public WalletChangedData MergeInto(WalletChangedData other)
|
||||
{
|
||||
other.BalanceChanged = AddOptionalInt(other.BalanceChanged, BalanceChanged);
|
||||
other.RewardDistributionChanged = AddOptionalInt(other.RewardDistributionChanged, RewardDistributionChanged);
|
||||
return other;
|
||||
|
||||
static Option<int> AddOptionalInt(Option<int> a, Option<int> b)
|
||||
{
|
||||
return a switch
|
||||
{
|
||||
Some<int> some1 => b switch
|
||||
{
|
||||
Some<int> some2 => Option<int>.Some(some1.Value + some2.Value),
|
||||
None<int> _ => Option<int>.Some(some1.Value),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(b))
|
||||
},
|
||||
None<int> _ => b switch
|
||||
{
|
||||
Some<int> some1 => Option<int>.Some(some1.Value),
|
||||
None<int> _ => Option<int>.None(),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(b))
|
||||
},
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(a))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[NetworkSerialize]
|
||||
internal struct NetWalletTransaction : INetSerializableStruct
|
||||
{
|
||||
public Option<ushort> CharacterID;
|
||||
public WalletChangedData ChangedData;
|
||||
public WalletInfo Info;
|
||||
}
|
||||
|
||||
// ReSharper disable ValueParameterNotUsed
|
||||
internal sealed class InvalidWallet : Wallet
|
||||
{
|
||||
public override int Balance
|
||||
{
|
||||
get => 0;
|
||||
set => 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");
|
||||
}
|
||||
}
|
||||
|
||||
internal partial class Wallet
|
||||
{
|
||||
public static readonly Wallet Invalid = new InvalidWallet();
|
||||
|
||||
public const string LowerCaseSaveElementName = "wallet";
|
||||
|
||||
private const string AttributeNameBalance = "balance",
|
||||
AttrubuteNameRewardDistribution = "rewarddistribution",
|
||||
SaveElementName = "Wallet";
|
||||
|
||||
private int balance;
|
||||
|
||||
public virtual int Balance
|
||||
{
|
||||
get => balance;
|
||||
set => balance = ClampBalance(value);
|
||||
}
|
||||
|
||||
private int rewardDistribution;
|
||||
|
||||
public virtual int RewardDistribution
|
||||
{
|
||||
get => rewardDistribution;
|
||||
set => rewardDistribution = ClampRewardDistribution(value);
|
||||
}
|
||||
|
||||
public Wallet() { }
|
||||
|
||||
public Wallet(XElement element)
|
||||
{
|
||||
balance = ClampBalance(element.GetAttributeInt(AttributeNameBalance, 0));
|
||||
rewardDistribution = ClampBalance(element.GetAttributeInt(AttrubuteNameRewardDistribution, 0));
|
||||
}
|
||||
|
||||
public XElement Save()
|
||||
{
|
||||
XElement element = new XElement(SaveElementName, new XAttribute(AttributeNameBalance, Balance), new XAttribute(AttrubuteNameRewardDistribution, RewardDistribution));
|
||||
return element;
|
||||
}
|
||||
|
||||
public bool TryDeduct(int price)
|
||||
{
|
||||
if (!CanAfford(price)) { return false; }
|
||||
|
||||
Deduct(price);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool CanAfford(int price) => Balance >= price;
|
||||
public void Refund(int price) => Give(price);
|
||||
|
||||
public void Give(int amount)
|
||||
{
|
||||
Balance += amount;
|
||||
SettingsChanged(balanceChanged: Option<int>.Some(amount), rewardChanged: Option<int>.None());
|
||||
}
|
||||
|
||||
public void Deduct(int price)
|
||||
{
|
||||
Balance -= price;
|
||||
SettingsChanged(balanceChanged: Option<int>.Some(-price), rewardChanged: Option<int>.None());
|
||||
}
|
||||
|
||||
public void SetRewardDistrubiton(int value)
|
||||
{
|
||||
int oldValue = RewardDistribution;
|
||||
RewardDistribution = value;
|
||||
SettingsChanged(balanceChanged: Option<int>.None(), rewardChanged: Option<int>.Some(RewardDistribution - oldValue));
|
||||
}
|
||||
|
||||
public WalletInfo CreateWalletInfo()
|
||||
{
|
||||
return new WalletInfo
|
||||
{
|
||||
Balance = Balance,
|
||||
RewardDistribution = RewardDistribution
|
||||
};
|
||||
}
|
||||
|
||||
partial void SettingsChanged(Option<int> balanceChanged, Option<int> rewardChanged);
|
||||
|
||||
private static int ClampBalance(int value) => Math.Clamp(value, 0, CampaignMode.MaxMoney);
|
||||
private static int ClampRewardDistribution(int value) => Math.Clamp(value, 0, 100);
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ namespace Barotrauma
|
||||
|
||||
abstract partial class CampaignMode : GameMode
|
||||
{
|
||||
const int MaxMoney = int.MaxValue / 2; //about 1 billion
|
||||
public const int MaxMoney = int.MaxValue / 2; //about 1 billion
|
||||
public const int InitialMoney = 8500;
|
||||
|
||||
//duration of the cinematic + credits at the end of the campaign
|
||||
@@ -102,6 +102,8 @@ namespace Barotrauma
|
||||
|
||||
private readonly List<Mission> extraMissions = new List<Mission>();
|
||||
|
||||
public readonly NamedEvent<WalletChangedEvent> OnMoneyChanged = new NamedEvent<WalletChangedEvent>();
|
||||
|
||||
public enum TransitionType
|
||||
{
|
||||
None,
|
||||
@@ -167,12 +169,7 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
private int money;
|
||||
public int Money
|
||||
{
|
||||
get { return money; }
|
||||
set { money = MathHelper.Clamp(value, 0, MaxMoney); }
|
||||
}
|
||||
public Wallet Bank;
|
||||
|
||||
public LevelData NextLevel
|
||||
{
|
||||
@@ -183,11 +180,20 @@ namespace Barotrauma
|
||||
protected CampaignMode(GameModePreset preset)
|
||||
: base(preset)
|
||||
{
|
||||
Money = InitialMoney;
|
||||
Bank = new Wallet
|
||||
{
|
||||
Balance = InitialMoney
|
||||
};
|
||||
|
||||
CargoManager = new CargoManager(this);
|
||||
MedicalClinic = new MedicalClinic(this);
|
||||
}
|
||||
|
||||
public virtual Wallet GetWallet(Client client = null)
|
||||
{
|
||||
return Bank;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The location that's displayed as the "current one" in the map screen. Normally the current outpost or the location at the start of the level,
|
||||
/// but when selecting the next destination at the end of the level at an uninhabited location we use the location at the end
|
||||
@@ -200,7 +206,7 @@ namespace Barotrauma
|
||||
{
|
||||
return Level.Loaded.EndLocation;
|
||||
}
|
||||
return Level.Loaded?.StartLocation ?? Map.CurrentLocation;
|
||||
return Level.Loaded?.StartLocation ?? Map.CurrentLocation;
|
||||
}
|
||||
|
||||
public List<Submarine> GetSubsToLeaveBehind(Submarine leavingSub)
|
||||
@@ -255,8 +261,6 @@ namespace Barotrauma
|
||||
PurchasedLostShuttles = false;
|
||||
var connectedSubs = Submarine.MainSub.GetConnectedSubs();
|
||||
wasDocked = Level.Loaded.StartOutpost != null && connectedSubs.Contains(Level.Loaded.StartOutpost);
|
||||
|
||||
ResetTalentData();
|
||||
}
|
||||
|
||||
public void InitCampaignData()
|
||||
@@ -702,21 +706,20 @@ namespace Barotrauma
|
||||
string eventId = "FinishCampaign:";
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "Submarine:" + (Submarine.MainSub?.Info?.Name ?? "none"));
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "CrewSize:" + (CrewManager?.CharacterInfos?.Count() ?? 0));
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "Money", Money);
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "Money", Bank.Balance);
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "Playtime", TotalPlayTime);
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "PassedLevels", TotalPassedLevels);
|
||||
}
|
||||
|
||||
protected virtual void EndCampaignProjSpecific() { }
|
||||
|
||||
public bool TryHireCharacter(Location location, CharacterInfo characterInfo)
|
||||
public bool TryHireCharacter(Location location, CharacterInfo characterInfo, Client client = null)
|
||||
{
|
||||
if (characterInfo == null) { return false; }
|
||||
if (Money < characterInfo.Salary) { return false; }
|
||||
if (!GetWallet(client).TryDeduct(characterInfo.Salary)) { return false; }
|
||||
characterInfo.IsNewHire = true;
|
||||
location.RemoveHireableCharacter(characterInfo);
|
||||
CrewManager.AddCharacterInfo(characterInfo);
|
||||
Money -= characterInfo.Salary;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(characterInfo.Salary, GameAnalyticsManager.MoneySink.Crew, characterInfo.Job?.Prefab.Identifier.Value ?? "unknown");
|
||||
return true;
|
||||
}
|
||||
@@ -740,8 +743,7 @@ namespace Barotrauma
|
||||
HumanAIController humanAI = npc.AIController as HumanAIController;
|
||||
if (humanAI == null) { yield return CoroutineStatus.Success; }
|
||||
|
||||
var waitOrderPrefab = OrderPrefab.Prefabs["wait"];
|
||||
var waitOrder = new Order(waitOrderPrefab, Identifier.Empty, null, orderGiver: null);
|
||||
var waitOrder = OrderPrefab.Prefabs["wait"].CreateInstance(OrderPrefab.OrderTargetType.Entity);
|
||||
humanAI.SetForcedOrder(waitOrder);
|
||||
var waitObjective = humanAI.ObjectiveManager.ForcedOrder;
|
||||
humanAI.FaceTarget(interactor);
|
||||
@@ -856,7 +858,7 @@ namespace Barotrauma
|
||||
{
|
||||
|
||||
GameMain.Server.SendDirectChatMessage(Networking.ChatMessage.Create(
|
||||
TextManager.Get("RadioAnnouncerName").Value,
|
||||
TextManager.Get("RadioAnnouncerName").Value,
|
||||
TextManager.Get("TooFarFromOutpostWarning").Value, Networking.ChatMessageType.Default, null), c);
|
||||
}
|
||||
#endif
|
||||
@@ -906,7 +908,7 @@ namespace Barotrauma
|
||||
public void LogState()
|
||||
{
|
||||
DebugConsole.NewMessage("********* CAMPAIGN STATUS *********", Color.White);
|
||||
DebugConsole.NewMessage(" Money: " + Money, Color.White);
|
||||
DebugConsole.NewMessage(" Money: " + Bank.Balance, Color.White);
|
||||
DebugConsole.NewMessage(" Current location: " + map.CurrentLocation.Name, Color.White);
|
||||
|
||||
DebugConsole.NewMessage(" Available destinations: ", Color.White);
|
||||
@@ -960,13 +962,5 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
// Talent relevant data, only stored for the duration of the mission
|
||||
private void ResetTalentData()
|
||||
{
|
||||
CrewHasDied = false;
|
||||
}
|
||||
|
||||
public bool CrewHasDied { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+1
-28
@@ -26,33 +26,6 @@ namespace Barotrauma
|
||||
private XElement itemData;
|
||||
private XElement healthData;
|
||||
public XElement OrderData { get; private set; }
|
||||
|
||||
public void Refresh(Character character)
|
||||
{
|
||||
healthData = new XElement("health");
|
||||
character.CharacterHealth.Save(healthData);
|
||||
if (character.Inventory != null)
|
||||
{
|
||||
itemData = new XElement("inventory");
|
||||
Character.SaveInventory(character.Inventory, itemData);
|
||||
}
|
||||
OrderData = new XElement("orders");
|
||||
CharacterInfo.SaveOrderData(character.Info, OrderData);
|
||||
}
|
||||
|
||||
public XElement Save()
|
||||
{
|
||||
XElement element = new XElement("CharacterCampaignData",
|
||||
new XAttribute("name", Name),
|
||||
new XAttribute("endpoint", ClientEndPoint),
|
||||
new XAttribute("steamid", SteamID));
|
||||
|
||||
CharacterInfo?.Save(element);
|
||||
if (itemData != null) { element.Add(itemData); }
|
||||
if (healthData != null) { element.Add(healthData); }
|
||||
if (OrderData != null) { element.Add(OrderData); }
|
||||
|
||||
return element;
|
||||
}
|
||||
public XElement WalletData;
|
||||
}
|
||||
}
|
||||
|
||||
+12
-1
@@ -99,7 +99,6 @@ namespace Barotrauma
|
||||
/// </summary>
|
||||
private void Load(XElement element)
|
||||
{
|
||||
Money = element.GetAttributeInt("money", 0);
|
||||
PurchasedLostShuttles = element.GetAttributeBool("purchasedlostshuttles", false);
|
||||
PurchasedHullRepairs = element.GetAttributeBool("purchasedhullrepairs", false);
|
||||
PurchasedItemRepairs = element.GetAttributeBool("purchaseditemrepairs", false);
|
||||
@@ -166,6 +165,9 @@ namespace Barotrauma
|
||||
case "stats":
|
||||
LoadStats(subElement);
|
||||
break;
|
||||
case Wallet.LowerCaseSaveElementName:
|
||||
Bank = new Wallet(subElement);
|
||||
break;
|
||||
#if SERVER
|
||||
case "savedexperiencepoints":
|
||||
foreach (XElement savedExp in subElement.Elements())
|
||||
@@ -177,6 +179,15 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
int oldMoney = element.GetAttributeInt("money", 0);
|
||||
if (oldMoney > 0)
|
||||
{
|
||||
Bank = new Wallet
|
||||
{
|
||||
Balance = oldMoney
|
||||
};
|
||||
}
|
||||
|
||||
CampaignMetadata ??= new CampaignMetadata(this);
|
||||
UpgradeManager ??= new UpgradeManager(this);
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -30,10 +31,14 @@ namespace Barotrauma
|
||||
private readonly List<Mission> missions = new List<Mission>();
|
||||
public IEnumerable<Mission> Missions { get { return missions; } }
|
||||
|
||||
private readonly HashSet<Character> casualties = new HashSet<Character>();
|
||||
public IEnumerable<Character> Casualties { get { return casualties; } }
|
||||
|
||||
|
||||
public CharacterTeamType? WinningTeam;
|
||||
|
||||
public bool IsRunning { get; private set; }
|
||||
|
||||
|
||||
public bool RoundEnding { get; private set; }
|
||||
|
||||
public Level? Level { get; private set; }
|
||||
@@ -201,7 +206,8 @@ namespace Barotrauma
|
||||
var campaign = MultiPlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub, settings);
|
||||
if (selectedSub != null)
|
||||
{
|
||||
campaign.Money = Math.Max(MultiPlayerCampaign.MinimumInitialMoney, campaign.Money - selectedSub.Price);
|
||||
campaign.Bank.TryDeduct(selectedSub.Price);
|
||||
campaign.Bank.Balance = Math.Max(campaign.Bank.Balance, MultiPlayerCampaign.MinimumInitialMoney);
|
||||
}
|
||||
return campaign;
|
||||
}
|
||||
@@ -211,7 +217,8 @@ namespace Barotrauma
|
||||
var campaign = SinglePlayerCampaign.StartNew(seed ?? ToolBox.RandomSeed(8), selectedSub, settings);
|
||||
if (selectedSub != null)
|
||||
{
|
||||
campaign.Money = Math.Max(SinglePlayerCampaign.MinimumInitialMoney, campaign.Money - selectedSub.Price);
|
||||
campaign.Bank.TryDeduct(selectedSub.Price);
|
||||
campaign.Bank.Balance = Math.Max(campaign.Bank.Balance, MultiPlayerCampaign.MinimumInitialMoney);
|
||||
}
|
||||
return campaign;
|
||||
}
|
||||
@@ -264,7 +271,7 @@ namespace Barotrauma
|
||||
/// <summary>
|
||||
/// Switch to another submarine. The sub is loaded when the next round starts.
|
||||
/// </summary>
|
||||
public SubmarineInfo SwitchSubmarine(SubmarineInfo newSubmarine, int cost)
|
||||
public SubmarineInfo SwitchSubmarine(SubmarineInfo newSubmarine, int cost, Client? client = null)
|
||||
{
|
||||
if (!OwnedSubmarines.Any(s => s.Name == newSubmarine.Name))
|
||||
{
|
||||
@@ -283,19 +290,21 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Campaign!.Money -= cost;
|
||||
if ((GameMain.NetworkMember is null || GameMain.NetworkMember is { IsServer: true }) && cost > 0)
|
||||
{
|
||||
Campaign!.GetWallet(client).TryDeduct(cost);
|
||||
}
|
||||
GameAnalyticsManager.AddMoneySpentEvent(cost, GameAnalyticsManager.MoneySink.SubmarineSwitch, newSubmarine.Name);
|
||||
|
||||
return newSubmarine;
|
||||
}
|
||||
|
||||
public void PurchaseSubmarine(SubmarineInfo newSubmarine)
|
||||
public void PurchaseSubmarine(SubmarineInfo newSubmarine, Client? client = null)
|
||||
{
|
||||
if (Campaign is null) { return; }
|
||||
if (Campaign.Money < newSubmarine.Price) { return; }
|
||||
if ((GameMain.NetworkMember is null || GameMain.NetworkMember is { IsServer: true }) && !Campaign.GetWallet(client).TryDeduct(newSubmarine.Price)) { return; }
|
||||
if (!OwnedSubmarines.Any(s => s.Name == newSubmarine.Name))
|
||||
{
|
||||
Campaign.Money -= newSubmarine.Price;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(newSubmarine.Price, GameAnalyticsManager.MoneySink.SubmarinePurchase, newSubmarine.Name);
|
||||
OwnedSubmarines.Add(newSubmarine);
|
||||
}
|
||||
@@ -346,7 +355,7 @@ namespace Barotrauma
|
||||
public void StartRound(LevelData? levelData, bool mirrorLevel = false, SubmarineInfo? startOutpost = null, SubmarineInfo? endOutpost = null)
|
||||
{
|
||||
AfflictionPrefab.LoadAllEffects();
|
||||
|
||||
|
||||
MirrorLevel = mirrorLevel;
|
||||
if (SubmarineInfo == null)
|
||||
{
|
||||
@@ -411,9 +420,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
//Clear out the stored grids
|
||||
Powered.Grids.Clear();
|
||||
|
||||
Level? level = null;
|
||||
if (levelData != null)
|
||||
{
|
||||
@@ -422,6 +428,11 @@ namespace Barotrauma
|
||||
|
||||
InitializeLevel(level);
|
||||
|
||||
//Clear out the cached grids and force update
|
||||
Powered.Grids.Clear();
|
||||
|
||||
casualties.Clear();
|
||||
|
||||
GameAnalyticsManager.AddProgressionEvent(
|
||||
GameAnalyticsManager.ProgressionStatus.Start,
|
||||
GameMode?.Preset?.Identifier.Value ?? "none");
|
||||
@@ -480,7 +491,7 @@ namespace Barotrauma
|
||||
existingRoundSummary.ContinueButton.Visible = true;
|
||||
}
|
||||
|
||||
RoundSummary = new RoundSummary(Submarine.Info, GameMode, Missions, StartLocation, EndLocation);
|
||||
RoundSummary = new RoundSummary(GameMode, Missions, StartLocation, EndLocation);
|
||||
|
||||
if (!(GameMode is TutorialMode) && !(GameMode is TestGameMode))
|
||||
{
|
||||
@@ -723,7 +734,7 @@ namespace Barotrauma
|
||||
}
|
||||
|
||||
partial void UpdateProjSpecific(float deltaTime);
|
||||
|
||||
|
||||
public static IEnumerable<Character> GetSessionCrewCharacters()
|
||||
{
|
||||
#if SERVER
|
||||
@@ -745,7 +756,7 @@ namespace Barotrauma
|
||||
{
|
||||
IEnumerable<Character> crewCharacters = GetSessionCrewCharacters();
|
||||
|
||||
int prevMoney = (GameMode as CampaignMode)?.Money ?? 0;
|
||||
int prevMoney = (GameMode as CampaignMode)?.Bank.Balance ?? 0; // FIXME personal wallets - reward distribution
|
||||
|
||||
foreach (Mission mission in missions)
|
||||
{
|
||||
@@ -759,14 +770,13 @@ namespace Barotrauma
|
||||
|
||||
if (missions.Any())
|
||||
{
|
||||
if (missions.Any())
|
||||
if (missions.Any(m => m.Completed))
|
||||
{
|
||||
foreach (Character character in crewCharacters)
|
||||
{
|
||||
character.CheckTalents(AbilityEffectType.OnAnyMissionCompleted);
|
||||
}
|
||||
}
|
||||
|
||||
if (missions.All(m => m.Completed))
|
||||
{
|
||||
foreach (Character character in crewCharacters)
|
||||
@@ -818,7 +828,7 @@ namespace Barotrauma
|
||||
LogEndRoundStats(eventId);
|
||||
if (GameMode is CampaignMode campaignMode)
|
||||
{
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "MoneyEarned", campaignMode.Money - prevMoney);
|
||||
GameAnalyticsManager.AddDesignEvent(eventId + "MoneyEarned", campaignMode.Bank.Balance - prevMoney); // FIXME personal wallets - reward distrubiton
|
||||
campaignMode.TotalPlayTime += roundDuration;
|
||||
}
|
||||
#if CLIENT
|
||||
@@ -910,6 +920,10 @@ namespace Barotrauma
|
||||
|
||||
public void KillCharacter(Character character)
|
||||
{
|
||||
if (CrewManager != null && CrewManager.GetCharacters().Contains(character))
|
||||
{
|
||||
casualties.Add(character);
|
||||
}
|
||||
#if CLIENT
|
||||
CrewManager?.KillCharacter(character);
|
||||
#endif
|
||||
@@ -917,6 +931,7 @@ namespace Barotrauma
|
||||
|
||||
public void ReviveCharacter(Character character)
|
||||
{
|
||||
casualties.Remove(character);
|
||||
#if CLIENT
|
||||
CrewManager?.ReviveCharacter(character);
|
||||
#endif
|
||||
@@ -939,7 +954,7 @@ namespace Barotrauma
|
||||
List<string> excessPackages = new List<string>();
|
||||
foreach (ContentPackage cp in ContentPackageManager.EnabledPackages.All)
|
||||
{
|
||||
//if (!cp.HasMultiplayerIncompatibleContent) { continue; }
|
||||
if (!cp.HasMultiplayerSyncedContent) { continue; }
|
||||
if (!contentPackagePaths.Any(p => p == cp.Path))
|
||||
{
|
||||
excessPackages.Add(cp.Name);
|
||||
@@ -949,7 +964,7 @@ namespace Barotrauma
|
||||
bool orderMismatch = false;
|
||||
if (missingPackages.Count == 0 && missingPackages.Count == 0)
|
||||
{
|
||||
var enabledPackages = ContentPackageManager.EnabledPackages.All/*.Where(cp => cp.HasMultiplayerIncompatibleContent)*/.ToImmutableArray();
|
||||
var enabledPackages = ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent).ToImmutableArray();
|
||||
for (int i = 0; i < contentPackagePaths.Count && i < enabledPackages.Length; i++)
|
||||
{
|
||||
if (contentPackagePaths[i] != enabledPackages[i].Path)
|
||||
@@ -1015,7 +1030,7 @@ namespace Barotrauma
|
||||
}
|
||||
if (Map != null) { rootElement.Add(new XAttribute("mapseed", Map.Seed)); }
|
||||
rootElement.Add(new XAttribute("selectedcontentpackages",
|
||||
string.Join("|", ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerIncompatibleContent).Select(cp => cp.Path))));
|
||||
string.Join("|", ContentPackageManager.EnabledPackages.All.Where(cp => cp.HasMultiplayerSyncedContent).Select(cp => cp.Path))));
|
||||
|
||||
((CampaignMode)GameMode).Save(doc.Root);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using Barotrauma.Extensions;
|
||||
using Barotrauma.Networking;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
@@ -177,17 +178,20 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
public readonly List<NetCrewMember> PendingHeals = new List<NetCrewMember>();
|
||||
|
||||
public Action? OnUpdate;
|
||||
|
||||
private readonly CampaignMode? campaign;
|
||||
|
||||
public MedicalClinic(CampaignMode campaign)
|
||||
{
|
||||
this.campaign = campaign;
|
||||
#if CLIENT
|
||||
campaign.OnMoneyChanged.RegisterOverwriteExisting(nameof(MedicalClinic).ToIdentifier(), OnMoneyChanged);
|
||||
#endif
|
||||
}
|
||||
|
||||
public readonly List<NetCrewMember> PendingHeals = new List<NetCrewMember>();
|
||||
|
||||
public Action? OnUpdate;
|
||||
|
||||
private static bool IsOutpostInCombat()
|
||||
{
|
||||
if (!(Level.Loaded is { Type: LevelData.LevelType.Outpost })) { return false; }
|
||||
@@ -203,14 +207,13 @@ namespace Barotrauma
|
||||
return false;
|
||||
}
|
||||
|
||||
private HealRequestResult HealAllPending(bool force = false)
|
||||
private HealRequestResult HealAllPending(bool force = false, Client? client = null)
|
||||
{
|
||||
int totalCost = GetTotalCost();
|
||||
if (!force)
|
||||
{
|
||||
if (GetMoney() < totalCost) { return HealRequestResult.InsufficientFunds; }
|
||||
|
||||
if (IsOutpostInCombat()) { return HealRequestResult.Refused; }
|
||||
if (!GetWallet(client).TryDeduct(totalCost)) { return HealRequestResult.InsufficientFunds; }
|
||||
}
|
||||
|
||||
ImmutableArray<CharacterInfo> crew = GetCrewCharacters();
|
||||
@@ -225,11 +228,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
if (campaign != null)
|
||||
{
|
||||
campaign.Money -= totalCost;
|
||||
}
|
||||
|
||||
ClearPendingHeals();
|
||||
|
||||
return HealRequestResult.Success;
|
||||
@@ -316,7 +314,10 @@ namespace Barotrauma
|
||||
|
||||
private int GetAdjustedPrice(int price) => campaign?.Map?.CurrentLocation is { Type: { HasOutpost: true } } currentLocation ? currentLocation.GetAdjustedHealCost(price) : int.MaxValue;
|
||||
|
||||
public int GetMoney() => campaign?.Money ?? 0;
|
||||
public Wallet GetWallet(Client? c = null)
|
||||
{
|
||||
return campaign?.GetWallet(c) ?? Wallet.Invalid;
|
||||
}
|
||||
|
||||
public static ImmutableArray<CharacterInfo> GetCrewCharacters()
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml.Linq;
|
||||
using Barotrauma.Networking;
|
||||
using Barotrauma.Extensions;
|
||||
using Microsoft.Xna.Framework;
|
||||
|
||||
@@ -178,7 +179,7 @@ namespace Barotrauma
|
||||
/// Purchased upgrades are temporarily stored in <see cref="PendingUpgrades"/> and they are applied
|
||||
/// after the next round starts similarly how items are spawned in the stowage room after the round starts.
|
||||
/// </remarks>
|
||||
public void PurchaseUpgrade(UpgradePrefab prefab, UpgradeCategory category, bool force = false)
|
||||
public void PurchaseUpgrade(UpgradePrefab prefab, UpgradeCategory category, bool force = false, Client? client = null)
|
||||
{
|
||||
if (!CanUpgradeSub())
|
||||
{
|
||||
@@ -215,7 +216,7 @@ namespace Barotrauma
|
||||
price = 0;
|
||||
}
|
||||
|
||||
if (Campaign.Money >= price)
|
||||
if (Campaign.GetWallet(client).TryDeduct(price)) // FIXME personal wallets
|
||||
{
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
{
|
||||
@@ -227,7 +228,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Campaign.Money -= price;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(price, GameAnalyticsManager.MoneySink.SubmarineUpgrade, prefab.Identifier.Value);
|
||||
|
||||
PurchasedUpgrade? upgrade = FindMatchingUpgrade(prefab, category);
|
||||
@@ -253,14 +253,14 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to purchase an upgrade with insufficient funds, the transaction has not been completed.\n" +
|
||||
$"Upgrade: {prefab.Name}, Cost: {price}, Have: {Campaign.Money}");
|
||||
$"Upgrade: {prefab.Name}, Cost: {price}, Have: {Campaign.GetWallet(client).Balance}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Purchases an item swap and handles logic for deducting the credit.
|
||||
/// </summary>
|
||||
public void PurchaseItemSwap(Item itemToRemove, ItemPrefab itemToInstall, bool force = false)
|
||||
public void PurchaseItemSwap(Item itemToRemove, ItemPrefab itemToInstall, bool force = false, Client? client = null)
|
||||
{
|
||||
if (!CanUpgradeSub())
|
||||
{
|
||||
@@ -313,7 +313,7 @@ namespace Barotrauma
|
||||
price = 0;
|
||||
}
|
||||
|
||||
if (Campaign.Money >= price)
|
||||
if (Campaign.GetWallet(client).TryDeduct(price))
|
||||
{
|
||||
PurchasedItemSwaps.RemoveAll(p => linkedItems.Contains(p.ItemToRemove));
|
||||
if (GameMain.NetworkMember == null || GameMain.NetworkMember.IsServer)
|
||||
@@ -326,7 +326,6 @@ namespace Barotrauma
|
||||
}
|
||||
}
|
||||
|
||||
Campaign.Money -= price;
|
||||
GameAnalyticsManager.AddMoneySpentEvent(price, GameAnalyticsManager.MoneySink.SubmarineWeapon, itemToInstall.Identifier.Value);
|
||||
|
||||
foreach (Item itemToSwap in linkedItems)
|
||||
@@ -355,7 +354,7 @@ namespace Barotrauma
|
||||
else
|
||||
{
|
||||
DebugConsole.ThrowError("Tried to swap an item with insufficient funds, the transaction has not been completed.\n" +
|
||||
$"Item to remove: {itemToRemove.Name}, Item to install: {itemToInstall.Name}, Cost: {price}, Have: {Campaign.Money}");
|
||||
$"Item to remove: {itemToRemove.Name}, Item to install: {itemToInstall.Name}, Cost: {price}, Have: {Campaign.GetWallet(client).Balance}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user