237 lines
7.6 KiB
C#
237 lines
7.6 KiB
C#
using System;
|
|
using System.Xml.Linq;
|
|
using Barotrauma.Networking;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
internal readonly struct WalletChangedEvent
|
|
{
|
|
public readonly Option<Character> Owner;
|
|
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;
|
|
Owner = wallet.Owner;
|
|
}
|
|
}
|
|
|
|
[NetworkSerialize]
|
|
internal struct WalletInfo : INetSerializableStruct
|
|
{
|
|
public int RewardDistribution;
|
|
public int Balance;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Network message for the server to update wallet values to clients
|
|
/// </summary>
|
|
internal struct NetWalletUpdate : INetSerializableStruct
|
|
{
|
|
[NetworkSerialize(ArrayMaxSize = 256)]
|
|
public NetWalletTransaction[] Transactions;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Network message for the client to transfer money between wallets
|
|
/// </summary>
|
|
[NetworkSerialize]
|
|
internal struct NetWalletTransfer : INetSerializableStruct
|
|
{
|
|
public Option<ushort> Sender;
|
|
public Option<ushort> Receiver;
|
|
public int Amount;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Network message for the client to set the salary of someone
|
|
/// </summary>
|
|
internal struct NetWalletSetSalaryUpdate : INetSerializableStruct
|
|
{
|
|
[NetworkSerialize]
|
|
public Option<ushort> Target;
|
|
|
|
[NetworkSerialize(MinValueInt = 0, MaxValueInt = 100)]
|
|
public int NewRewardDistribution;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents the difference in balance and salary when a wallet gets updated
|
|
/// Not really used right now but could be used for notifications when receiving funds similar to how talents do it
|
|
/// </summary>
|
|
[NetworkSerialize]
|
|
internal struct WalletChangedData : INetSerializableStruct
|
|
{
|
|
public Option<int> RewardDistributionChanged;
|
|
public Option<int> BalanceChanged;
|
|
|
|
public readonly WalletChangedData MergeInto(WalletChangedData other)
|
|
{
|
|
other.BalanceChanged = AddOptionalInt(other.BalanceChanged, BalanceChanged);
|
|
other.RewardDistributionChanged = AddOptionalInt(other.RewardDistributionChanged, RewardDistributionChanged);
|
|
|
|
other.BalanceChanged = TurnToNoneIfZero(other.BalanceChanged);
|
|
other.RewardDistributionChanged = TurnToNoneIfZero(other.RewardDistributionChanged);
|
|
return other;
|
|
|
|
static Option<int> AddOptionalInt(Option<int> a, Option<int> b)
|
|
{
|
|
bool hasValue1 = a.TryUnwrap(out var value1);
|
|
bool hasValue2 = b.TryUnwrap(out var value2);
|
|
return hasValue1
|
|
? hasValue2
|
|
? Option.Some(value1 + value2)
|
|
: Option.Some(value1)
|
|
: hasValue2
|
|
? Option.Some(value2)
|
|
: Option.None;
|
|
}
|
|
|
|
static Option<int> TurnToNoneIfZero(Option<int> option)
|
|
{
|
|
return option.Bind(i => i == 0 ? Option.None : Option.Some(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Represents an update that changed the amount of money or salary of the wallet
|
|
/// </summary>
|
|
[NetworkSerialize]
|
|
internal struct NetWalletTransaction : INetSerializableStruct
|
|
{
|
|
public Option<ushort> CharacterID;
|
|
public WalletChangedData ChangedData;
|
|
public WalletInfo Info;
|
|
}
|
|
|
|
// ReSharper disable ValueParameterNotUsed
|
|
internal sealed class InvalidWallet : Wallet
|
|
{
|
|
public InvalidWallet(): base(Option<Character>.None()) { }
|
|
|
|
public override int Balance
|
|
{
|
|
get => 0;
|
|
set => throw new InvalidOperationException("Tried to set the balance on an invalid wallet");
|
|
}
|
|
|
|
public override int RewardDistribution
|
|
{
|
|
get => 0;
|
|
set => throw 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",
|
|
AttributeNameRewardDistribution = "rewarddistribution",
|
|
SaveElementName = "Wallet";
|
|
|
|
public readonly Option<Character> Owner;
|
|
|
|
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);
|
|
|
|
if (Owner.TryUnwrap(out var character) && character.Info is { } info)
|
|
{
|
|
info.LastRewardDistribution = Option.Some(rewardDistribution);
|
|
}
|
|
}
|
|
}
|
|
|
|
public Wallet(Option<Character> owner)
|
|
{
|
|
Owner = owner;
|
|
}
|
|
|
|
public Wallet(Option<Character> owner, XElement element): this(owner)
|
|
{
|
|
balance = ClampBalance(element.GetAttributeInt(AttributeNameBalance, 0));
|
|
rewardDistribution = ClampBalance(element.GetAttributeInt(AttributeNameRewardDistribution, 0));
|
|
}
|
|
|
|
public XElement Save()
|
|
{
|
|
XElement element = new XElement(SaveElementName,
|
|
new XAttribute(AttributeNameBalance, Balance),
|
|
new XAttribute(AttributeNameRewardDistribution, 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());
|
|
}
|
|
|
|
/// <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;
|
|
RewardDistribution = value;
|
|
SettingsChanged(balanceChanged: Option<int>.None(), rewardChanged: Option<int>.Some(RewardDistribution - oldValue));
|
|
}
|
|
|
|
public WalletInfo CreateWalletInfo()
|
|
{
|
|
return new WalletInfo
|
|
{
|
|
Balance = Balance,
|
|
RewardDistribution = RewardDistribution
|
|
};
|
|
}
|
|
|
|
public string GetOwnerLogName()
|
|
=> Owner.TryUnwrap(out var character) ? character.Name : "the bank";
|
|
|
|
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);
|
|
}
|
|
} |