Client LuaCsForBarotrauma
BarotraumaShared/SharedSource/GameSession/Data/Wallet.cs
1 using System;
2 using System.Xml.Linq;
4 
5 namespace Barotrauma
6 {
7  internal readonly struct WalletChangedEvent
8  {
9  public readonly Option<Character> Owner;
10  public readonly Wallet Wallet;
11  public readonly WalletInfo Info;
12  public readonly WalletChangedData ChangedData;
13 
14  public WalletChangedEvent(Wallet wallet, WalletChangedData changedData, WalletInfo info)
15  {
16  Wallet = wallet;
17  Info = info;
18  ChangedData = changedData;
19  Owner = wallet.Owner;
20  }
21  }
22 
23  [NetworkSerialize]
24  internal struct WalletInfo : INetSerializableStruct
25  {
26  public int RewardDistribution;
27  public int Balance;
28  }
29 
33  internal struct NetWalletUpdate : INetSerializableStruct
34  {
35  [NetworkSerialize(ArrayMaxSize = 256)]
36  public NetWalletTransaction[] Transactions;
37  }
38 
42  [NetworkSerialize]
43  internal struct NetWalletTransfer : INetSerializableStruct
44  {
45  public Option<ushort> Sender;
46  public Option<ushort> Receiver;
47  public int Amount;
48  }
49 
53  internal struct NetWalletSetSalaryUpdate : INetSerializableStruct
54  {
55  [NetworkSerialize]
56  public Option<ushort> Target;
57 
58  [NetworkSerialize(MinValueInt = 0, MaxValueInt = 100)]
59  public int NewRewardDistribution;
60  }
61 
66  [NetworkSerialize]
67  internal struct WalletChangedData : INetSerializableStruct
68  {
69  public Option<int> RewardDistributionChanged;
70  public Option<int> BalanceChanged;
71 
72  public readonly WalletChangedData MergeInto(WalletChangedData other)
73  {
74  other.BalanceChanged = AddOptionalInt(other.BalanceChanged, BalanceChanged);
75  other.RewardDistributionChanged = AddOptionalInt(other.RewardDistributionChanged, RewardDistributionChanged);
76 
77  other.BalanceChanged = TurnToNoneIfZero(other.BalanceChanged);
78  other.RewardDistributionChanged = TurnToNoneIfZero(other.RewardDistributionChanged);
79  return other;
80 
81  static Option<int> AddOptionalInt(Option<int> a, Option<int> b)
82  {
83  bool hasValue1 = a.TryUnwrap(out var value1);
84  bool hasValue2 = b.TryUnwrap(out var value2);
85  return hasValue1
86  ? hasValue2
87  ? Option.Some(value1 + value2)
88  : Option.Some(value1)
89  : hasValue2
90  ? Option.Some(value2)
91  : Option.None;
92  }
93 
94  static Option<int> TurnToNoneIfZero(Option<int> option)
95  {
96  return option.Bind(i => i == 0 ? Option.None : Option.Some(i));
97  }
98  }
99  }
100 
104  [NetworkSerialize]
105  internal struct NetWalletTransaction : INetSerializableStruct
106  {
107  public Option<ushort> CharacterID;
108  public WalletChangedData ChangedData;
109  public WalletInfo Info;
110  }
111 
112  // ReSharper disable ValueParameterNotUsed
113  internal sealed class InvalidWallet : Wallet
114  {
115  public InvalidWallet(): base(Option<Character>.None()) { }
116 
117  public override int Balance
118  {
119  get => 0;
120  set => throw new InvalidOperationException("Tried to set the balance on an invalid wallet");
121  }
122 
123  public override int RewardDistribution
124  {
125  get => 0;
126  set => throw new InvalidOperationException("Tried to set the reward distribution on an invalid wallet");
127  }
128  }
129 
130  internal partial class Wallet
131  {
132  public static readonly Wallet Invalid = new InvalidWallet();
133 
134  public const string LowerCaseSaveElementName = "wallet";
135 
136  private const string AttributeNameBalance = "balance",
137  AttributeNameRewardDistribution = "rewarddistribution",
138  SaveElementName = "Wallet";
139 
140  public readonly Option<Character> Owner;
141 
142  private int balance;
143 
144  public virtual int Balance
145  {
146  get => balance;
147  set => balance = ClampBalance(value);
148  }
149 
150  private int rewardDistribution;
151 
152  public virtual int RewardDistribution
153  {
154  get => rewardDistribution;
155  set
156  {
157  rewardDistribution = ClampRewardDistribution(value);
158 
159  if (Owner.TryUnwrap(out var character) && character.Info is { } info)
160  {
161  info.LastRewardDistribution = Option.Some(rewardDistribution);
162  }
163  }
164  }
165 
166  public Wallet(Option<Character> owner)
167  {
168  Owner = owner;
169  }
170 
171  public Wallet(Option<Character> owner, XElement element): this(owner)
172  {
173  balance = ClampBalance(element.GetAttributeInt(AttributeNameBalance, 0));
174  rewardDistribution = ClampBalance(element.GetAttributeInt(AttributeNameRewardDistribution, 0));
175  }
176 
177  public XElement Save()
178  {
179  XElement element = new XElement(SaveElementName,
180  new XAttribute(AttributeNameBalance, Balance),
181  new XAttribute(AttributeNameRewardDistribution, RewardDistribution));
182  return element;
183  }
184 
185  public bool TryDeduct(int price)
186  {
187  if (!CanAfford(price)) { return false; }
188 
189  Deduct(price);
190  return true;
191  }
192 
193  public bool CanAfford(int price) => Balance >= price;
194  public void Refund(int price) => Give(price);
195 
196  public void Give(int amount)
197  {
198  Balance += amount;
199  SettingsChanged(balanceChanged: Option<int>.Some(amount), rewardChanged: Option<int>.None());
200  }
201 
202  public void Deduct(int price)
203  {
204  Balance -= price;
205  SettingsChanged(balanceChanged: Option<int>.Some(-price), rewardChanged: Option<int>.None());
206  }
207 
213  public void SetRewardDistribution(int value)
214  {
215  int oldValue = RewardDistribution;
216  RewardDistribution = value;
217  SettingsChanged(balanceChanged: Option<int>.None(), rewardChanged: Option<int>.Some(RewardDistribution - oldValue));
218  }
219 
220  public WalletInfo CreateWalletInfo()
221  {
222  return new WalletInfo
223  {
224  Balance = Balance,
225  RewardDistribution = RewardDistribution
226  };
227  }
228 
229  public string GetOwnerLogName()
230  => Owner.TryUnwrap(out var character) ? character.Name : "the bank";
231 
232  partial void SettingsChanged(Option<int> balanceChanged, Option<int> rewardChanged);
233 
234  private static int ClampBalance(int value) => Math.Clamp(value, 0, CampaignMode.MaxMoney);
235  private static int ClampRewardDistribution(int value) => Math.Clamp(value, 0, 100);
236  }
237 }