forked from Katarn2000x/DiplomacyFixes
-
Notifications
You must be signed in to change notification settings - Fork 6
/
WarExhaustionManager.cs
264 lines (225 loc) · 9.33 KB
/
WarExhaustionManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
using System;
using System.Collections.Generic;
using System.Linq;
using TaleWorlds.CampaignSystem;
using TaleWorlds.Core;
using TaleWorlds.Library;
using TaleWorlds.SaveSystem;
namespace DiplomacyFixes
{
[SaveableClass(2)]
class WarExhaustionManager
{
// legacy war exhaustion dictionary using stringId
[SaveableField(0)]
private Dictionary<string, float> _warExhaustion;
// new war exhaustion dictionary using Id
[SaveableField(1)]
private Dictionary<string, float> _warExhaustionById;
private HashSet<Tuple<Kingdom, Kingdom>> _knownKingdomCombinations;
private HashSet<Kingdom> _knownKingdoms;
public static WarExhaustionManager Instance { get; internal set; }
internal static float MaxWarExhaustion { get { return Settings.Instance.MaxWarExhaustion; } }
internal static float MinWarExhaustion { get { return 0f; } }
private float Fuzziness { get { return MBRandom.RandomFloatRanged(BaseFuzzinessMin, BaseFuzzinessMax); } }
private float BaseFuzzinessMin { get { return 0.5f; } }
private float BaseFuzzinessMax { get { return 1.5f; } }
public static float DefaultMaxWarExhaustion { get; } = 100f;
internal WarExhaustionManager()
{
this._warExhaustionById = new Dictionary<string, float>();
this._knownKingdomCombinations = new HashSet<Tuple<Kingdom, Kingdom>>();
this._knownKingdoms = new HashSet<Kingdom>();
Instance = this;
}
public float GetWarExhaustion(Kingdom kingdom1, Kingdom kingdom2)
{
string key = CreateKey(kingdom1, kingdom2);
if (key != null && _warExhaustionById.TryGetValue(key, out float warExhaustion))
{
return warExhaustion;
}
else
{
return 0f;
}
}
private static bool KingdomsAreValid(Kingdom kingdom1, Kingdom kingdom2)
{
return kingdom1.Id != null && kingdom2.Id != null;
}
private string CreateKey(Kingdom kingdom1, Kingdom kingdom2)
{
return CreateKey(new Tuple<Kingdom, Kingdom>(kingdom1, kingdom2));
}
private string CreateKey(Tuple<Kingdom, Kingdom> kingdoms)
{
if (KingdomsAreValid(kingdoms.Item1, kingdoms.Item2))
{
return string.Join("+", kingdoms.Item1.Id, kingdoms.Item2.Id);
}
else
{
return null;
}
}
private void AddDailyWarExhaustion(Tuple<Kingdom, Kingdom> kingdoms)
{
float warExhaustionToAdd = GetDailyWarExhaustionDelta();
AddWarExhaustion(kingdoms.Item1, kingdoms.Item2, warExhaustionToAdd, WarExhaustionType.Daily);
}
public void AddCasualtyWarExhaustion(Kingdom kingdom1, Kingdom kingdom2, int casualties)
{
float warExhaustionToAdd = Settings.Instance.WarExhaustionPerCasualty * casualties;
AddWarExhaustion(kingdom1, kingdom2, warExhaustionToAdd, WarExhaustionType.Casualty);
}
public void AddSiegeWarExhaustion(Kingdom kingdom1, Kingdom kingdom2)
{
float warExhaustionToAdd = Settings.Instance.WarExhaustionPerSiege;
AddWarExhaustion(kingdom1, kingdom2, warExhaustionToAdd, WarExhaustionType.Siege);
}
public void AddRaidWarExhaustion(Kingdom kingdom1, Kingdom kingdom2)
{
float warExhaustionToAdd = Settings.Instance.WarExhaustionPerRaid;
AddWarExhaustion(kingdom1, kingdom2, warExhaustionToAdd, WarExhaustionType.Raid);
}
private void AddWarExhaustion(Kingdom kingdom1, Kingdom kingdom2, float warExhaustionToAdd, WarExhaustionType warExhaustionType, bool addFuzziness = true)
{
string key = CreateKey(kingdom1, kingdom2);
if (key != null)
{
float finalWarExhaustionDelta = warExhaustionToAdd;
if (addFuzziness)
{
finalWarExhaustionDelta *= Fuzziness;
}
if (_warExhaustionById.TryGetValue(key, out float currentValue))
{
_warExhaustionById[key] = MBMath.ClampFloat(currentValue += finalWarExhaustionDelta, MinWarExhaustion, MaxWarExhaustion);
}
else
{
_warExhaustionById[key] = MBMath.ClampFloat(finalWarExhaustionDelta, MinWarExhaustion, MaxWarExhaustion);
}
if (Settings.Instance.EnableWarExhaustionDebugMessages && kingdom1 == Hero.MainHero.MapFaction)
{
string information = string.Format("Added {0} {1} war exhaustion to {2}'s war with {3}", finalWarExhaustionDelta, Enum.GetName(typeof(WarExhaustionType), warExhaustionType), kingdom1.Name, kingdom2.Name);
InformationManager.DisplayMessage(new InformationMessage(information, Color.FromUint(4282569842U)));
}
}
}
private float GetDailyWarExhaustionDelta()
{
return Settings.Instance.WarExhaustionPerDay;
}
private void RemoveDailyWarExhaustion(Tuple<Kingdom, Kingdom> kingdoms)
{
string key = CreateKey(kingdoms);
if (key != null && _warExhaustionById.TryGetValue(key, out float currentValue))
{
float warExhaustionToRemove = Settings.Instance.WarExhaustionDecayPerDay;
_warExhaustionById[key] = MBMath.ClampFloat(currentValue -= warExhaustionToRemove, MinWarExhaustion, MaxWarExhaustion);
}
}
public void UpdateDailyWarExhaustionForAllKingdoms()
{
UpdateKnownKingdoms();
foreach (Tuple<Kingdom, Kingdom> kingdoms in _knownKingdomCombinations)
{
UpdateDailyWarExhaustion(kingdoms);
}
}
private void UpdateKnownKingdoms()
{
IEnumerable<Kingdom> kingdomsToAdd;
if (_knownKingdoms == null)
{
_knownKingdoms = new HashSet<Kingdom>();
_knownKingdomCombinations = new HashSet<Tuple<Kingdom, Kingdom>>();
kingdomsToAdd = Kingdom.All;
}
else
{
kingdomsToAdd = Kingdom.All.Except(_knownKingdoms);
}
if (kingdomsToAdd.Any())
{
_knownKingdomCombinations.UnionWith(
from item1 in Kingdom.All
from item2 in Kingdom.All
where item1.Id != item2.Id
select new Tuple<Kingdom, Kingdom>(item1, item2));
_knownKingdoms.UnionWith(kingdomsToAdd);
}
}
private void UpdateDailyWarExhaustion(Tuple<Kingdom, Kingdom> kingdoms)
{
StanceLink stanceLink = kingdoms.Item1.GetStanceWith(kingdoms.Item2);
if (stanceLink?.IsAtWar ?? false && (float)Math.Round(stanceLink.WarStartDate.ElapsedDaysUntilNow) >= 1.0f)
{
AddDailyWarExhaustion(kingdoms);
}
else
{
RemoveDailyWarExhaustion(kingdoms);
}
}
public bool HasMaxWarExhaustion(Kingdom kingdom1, Kingdom kingdom2)
{
return GetWarExhaustion(kingdom1, kingdom2) >= MaxWarExhaustion;
}
public bool HasLowWarExhaustion(Kingdom kingdom1, Kingdom kingdom2)
{
return GetWarExhaustion(kingdom1, kingdom2) <= GetLowWarExhaustion();
}
public static double GetLowWarExhaustion()
{
return (0.5 * MaxWarExhaustion);
}
public void Sync()
{
Instance = this;
if (this._warExhaustionById == null)
{
this._warExhaustionById = new Dictionary<string, float>();
}
MigrateLegacyWarExhaustionDictionary();
}
/// <summary>
/// Migrates old-style war exhaustion dictionaries that are keyed by stringId to new ones keyed by MBGUID internal id.
/// </summary>
private void MigrateLegacyWarExhaustionDictionary()
{
if (_warExhaustion != null)
{
foreach (string oldKey in _warExhaustion.Keys)
{
string[] kingdomNames = oldKey.Split(new char[] { '+' });
if (kingdomNames.Length != 2)
{
continue;
}
Kingdom kingdom1 = Kingdom.All.FirstOrDefault(kingdom => kingdomNames[0] == kingdom.StringId);
Kingdom kingdom2 = Kingdom.All.FirstOrDefault(kingdom => kingdomNames[1] == kingdom.StringId);
if (kingdom1 == null || kingdom2 == null)
{
continue;
}
string newKey = CreateKey(kingdom1, kingdom2);
if (newKey != null)
{
_warExhaustionById[newKey] = _warExhaustion[oldKey];
}
}
_warExhaustion = null;
}
}
private enum WarExhaustionType
{
Casualty,
Raid,
Siege,
Daily
}
}
}