Skip to content

Commit 3be415e

Browse files
committed
added support for taking into account hero values/ hero items. Haven't yet added them into the actual simulation
1 parent 3a16bdf commit 3be415e

File tree

11 files changed

+220
-72
lines changed

11 files changed

+220
-72
lines changed

TbsCore/Helpers/HeroHelper.cs

Lines changed: 55 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using TbsCore.Models.AccModels;
77
using TbsCore.Models.ResourceModels;
88
using TbsCore.Models.VillageModels;
9+
using TbsCore.TravianData;
910
using TravBotSharp.Files.Parsers;
1011
using TravBotSharp.Files.Tasks.LowLevel;
1112
using static TravBotSharp.Files.Helpers.Classificator;
@@ -43,10 +44,10 @@ public static Village GetHeroHomeVillage(Account acc) =>
4344
/// <param name="acc">Account</param>
4445
public static void AutoEquipHero(Account acc)
4546
{
46-
foreach (Classificator.HeroItemCategory category
47-
in (Classificator.HeroItemCategory[])Enum.GetValues(typeof(Classificator.HeroItemCategory)))
47+
foreach (HeroItemCategory category
48+
in (HeroItemCategory[])Enum.GetValues(typeof(HeroItemCategory)))
4849
{
49-
if (category == Classificator.HeroItemCategory.Others) continue; // Don't equip into hero bag
50+
if (category == HeroItemCategory.Others) continue; // Don't equip into hero bag
5051
int currentTier = 0;
5152
if (acc.Hero.Equipt.TryGetValue(category, out var item))
5253
{
@@ -66,7 +67,7 @@ public static void AutoEquipHero(Account acc)
6667
TaskExecutor.AddTaskIfNotExists(acc, new HeroEquip()
6768
{
6869
ExecuteAt = DateTime.Now,
69-
Items = new List<(Classificator.HeroItemEnum, int)>()
70+
Items = new List<(HeroItemEnum, int)>()
7071
{
7172
(equipWith.Item, 0)
7273
}
@@ -80,33 +81,64 @@ public static void AutoEquipHero(Account acc)
8081
/// </summary>
8182
/// <param name="item">Hero item enum</param>
8283
/// <returns>Hero item (category, name, tier)</returns>
83-
public static (Classificator.HeroItemCategory, string, int) ParseHeroItem(Classificator.HeroItemEnum item)
84+
public static (HeroItemCategory, string, int) ParseHeroItem(HeroItemEnum item)
8485
{
8586
var attr = item.ToString().Split('_');
8687

87-
Enum.TryParse(attr[0], out Classificator.HeroItemCategory category);
88+
Enum.TryParse(attr[0], out HeroItemCategory category);
8889
string name = attr[1];
8990
int tier = int.Parse(attr[2]);
9091

9192
return (category, name, tier);
9293
}
9394

95+
/// <summary>
96+
/// Parses hero weapon
97+
/// </summary>
98+
/// <param name="item">Hero item</param>
99+
/// <returns>(Troop boost, boost)</returns>
100+
public static (TroopsEnum, int) ParseWeapon(HeroItemEnum item)
101+
{
102+
var (_, name, tier) = ParseHeroItem(item);
103+
if(Enum.TryParse(name, out TroopsEnum troop))
104+
{
105+
return (troop, GetWeaponBoost(troop, tier));
106+
}
107+
return (TroopsEnum.None, 0);
108+
}
109+
110+
public static int GetArmorBaseStrength(string name)
111+
{
112+
switch (name)
113+
{
114+
case "Breastplate": return 500;
115+
case "Segmented": return 250;
116+
default: return 0;
117+
}
118+
}
119+
120+
private static int GetWeaponBoost(TroopsEnum troop, int tier)
121+
{
122+
var upkeep = TroopsData.GetTroopUpkeep(troop);
123+
return (tier + 2) * upkeep;
124+
}
125+
94126
/// <summary>
95127
/// Gets the tier of the hero item
96128
/// </summary>
97129
/// <param name="item">HeroItem</param>
98130
/// <returns>Tier</returns>
99-
public static int GetHeroItemTier(Classificator.HeroItemEnum item)
131+
public static int GetHeroItemTier(HeroItemEnum item)
100132
{
101133
var (_, _, itemTier) = ParseHeroItem(item);
102134
return itemTier;
103135
}
104-
public static string GetHeroItemName(Classificator.HeroItemEnum item)
136+
public static string GetHeroItemName(HeroItemEnum item)
105137
{
106138
var (_, name, _) = ParseHeroItem(item);
107139
return name;
108140
}
109-
public static Classificator.HeroItemCategory GetHeroItemCategory(Classificator.HeroItemEnum item)
141+
public static HeroItemCategory GetHeroItemCategory(HeroItemEnum item)
110142
{
111143
var (category, _, _) = ParseHeroItem(item);
112144
return category;
@@ -127,7 +159,7 @@ public static void ParseHeroPage(Account acc)
127159

128160
if (acc.Hero.Settings.AutoEquip)
129161
{
130-
HeroHelper.AutoEquipHero(acc);
162+
AutoEquipHero(acc);
131163
}
132164
}
133165

@@ -138,10 +170,10 @@ public static void UpdateHeroVillage(Account acc)
138170

139171
switch (acc.AccInfo.ServerVersion)
140172
{
141-
case Classificator.ServerVersionEnum.T4_4:
173+
case ServerVersionEnum.T4_4:
142174
acc.Hero.HomeVillageId = hrefId ?? 0;
143175
return;
144-
case Classificator.ServerVersionEnum.T4_5:
176+
case ServerVersionEnum.T4_5:
145177
// Convert from coordinates id -> coordinates -> villageId
146178
var coordinates = MapHelper.CoordinatesFromKid(hrefId ?? 0, acc);
147179
var vill = acc.Villages.FirstOrDefault(x => x.Coordinates.Equals(coordinates));
@@ -156,10 +188,10 @@ public static long[] GetHeroResources(Account acc)
156188
var heroItems = acc.Hero.Items;
157189
return new long[]
158190
{
159-
heroItems.FirstOrDefault(x => x.Item == Classificator.HeroItemEnum.Others_Wood_0)?.Count ?? 0,
160-
heroItems.FirstOrDefault(x => x.Item == Classificator.HeroItemEnum.Others_Clay_0)?.Count ?? 0,
161-
heroItems.FirstOrDefault(x => x.Item == Classificator.HeroItemEnum.Others_Iron_0)?.Count ?? 0,
162-
heroItems.FirstOrDefault(x => x.Item == Classificator.HeroItemEnum.Others_Crop_0)?.Count ?? 0
191+
heroItems.FirstOrDefault(x => x.Item == HeroItemEnum.Others_Wood_0)?.Count ?? 0,
192+
heroItems.FirstOrDefault(x => x.Item == HeroItemEnum.Others_Clay_0)?.Count ?? 0,
193+
heroItems.FirstOrDefault(x => x.Item == HeroItemEnum.Others_Iron_0)?.Count ?? 0,
194+
heroItems.FirstOrDefault(x => x.Item == HeroItemEnum.Others_Crop_0)?.Count ?? 0
163195
};
164196
}
165197

@@ -169,21 +201,21 @@ public static long[] GetHeroResources(Account acc)
169201
/// <param name="acc">Account</param>
170202
/// <param name="troop">Troop to train</param>
171203
/// <returns>Whether to switch helmets first</returns>
172-
public static bool SwitchHelmet(Account acc, Village trainVill, Classificator.BuildingEnum building, TrainTroops task)
204+
public static bool SwitchHelmet(Account acc, Village trainVill, BuildingEnum building, TrainTroops task)
173205
{
174206
if (!acc.Hero.Settings.AutoSwitchHelmets) return false;
175207

176208
// In T4.5, helmet will only have effect in hero home village
177209
// In TTWars, helmets have acc-wide effect
178210
// TODO: for T4.5, add auto-move hero feature (for helmet effect purposes)
179211
if (GetHeroHomeVillage(acc) != trainVill &&
180-
acc.AccInfo.ServerVersion != Classificator.ServerVersionEnum.T4_4) return false;
212+
acc.AccInfo.ServerVersion != ServerVersionEnum.T4_4) return false;
181213

182214
string type = "";
183-
if (building == Classificator.BuildingEnum.Barracks ||
184-
building == Classificator.BuildingEnum.GreatBarracks) type = "Infantry";
185-
if (building == Classificator.BuildingEnum.Stable ||
186-
building == Classificator.BuildingEnum.GreatStable) type = "Cavalry";
215+
if (building == BuildingEnum.Barracks ||
216+
building == BuildingEnum.GreatBarracks) type = "Infantry";
217+
if (building == BuildingEnum.Stable ||
218+
building == BuildingEnum.GreatStable) type = "Cavalry";
187219

188220
// No helmet helps us for training in workshop
189221
if (string.IsNullOrEmpty(type)) return false;
@@ -196,7 +228,7 @@ public static bool SwitchHelmet(Account acc, Village trainVill, Classificator.Bu
196228

197229
var (equipCategory, equipName, equipTier) = ParseHeroItem(equipWith.Item);
198230

199-
if (acc.Hero.Equipt.TryGetValue(Classificator.HeroItemCategory.Helmet, out var equiped))
231+
if (acc.Hero.Equipt.TryGetValue(HeroItemCategory.Helmet, out var equiped))
200232
{
201233
var (category, name, tier) = ParseHeroItem(equiped);
202234
if (name == type &&

TbsCore/Helpers/TroopsHelper.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,8 +323,8 @@ public static long GetTroopsUpkeep(Account acc, int[] troops)
323323
long upkeep = 0;
324324
for (int i = 0; i < 10; i++)
325325
{
326-
var troop = TroopsHelper.TroopFromInt(acc, i);
327-
upkeep += troops[i] * TroopSpeed.GetTroopUpkeep(troop);
326+
var troop = TroopFromInt(acc, i);
327+
upkeep += troops[i] * TroopsData.GetTroopUpkeep(troop);
328328
}
329329
return upkeep;
330330
}

TbsCore/Models/AccModels/Hero.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@ public void init()
3535
public int HomeVillageId { get; set; }
3636
public HeroInfo HeroInfo { get; set; }
3737
public HeroSettings Settings { get; set; }
38+
3839
/// <summary>
3940
/// Hero items in the inventory
4041
/// </summary>
4142
public List<HeroItem> Items { get; set; }
43+
4244
/// <summary>
4345
/// Items currently equipt
4446
/// </summary>

TbsCore/Models/CombatModels/CombatAttacker.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,10 @@ public class CombatAttacker
1515
/// Population of the attacker, morale bonus depends on it
1616
/// </summary>
1717
public int Population { get; set; }
18+
19+
/// <summary>
20+
/// Ally metalurgy percentage (2% => 2, 4% => 4)
21+
/// </summary>
22+
public int Metalurgy { get; set; }
1823
}
1924
}

TbsCore/Models/CombatModels/CombatDeffender.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,10 @@ public class CombatDeffender
2626
/// Which tribe is the deffender. Wall bonus depends on the tribe
2727
/// </summary>
2828
public Classificator.TribeEnum DeffTribe { get; set; }
29+
30+
/// <summary>
31+
/// Ally metalurgy percentage (2% => 2, 4% => 4)
32+
/// </summary>
33+
public int Metalurgy { get; set; }
2934
}
3035
}
Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
1-
namespace TbsCore.Models.CombatModels
1+
using System.Collections.Generic;
2+
using TbsCore.Models.AccModels;
3+
using TbsCore.Models.TroopsModels;
4+
using TravBotSharp.Files.Helpers;
5+
6+
namespace TbsCore.Models.CombatModels
27
{
38
public class CombatHero
49
{
5-
// TODO: add hero left hand item, hero off / deff bonus, natar horn
10+
/// <summary>
11+
/// Hero power, offensive / deffensive bonus
12+
/// </summary>
13+
public HeroInfo Info { get; set; }
14+
15+
/// <summary>
16+
/// Hero items (natar horn, shield, right hand items)
17+
/// </summary>
18+
public Dictionary<Classificator.HeroItemCategory, Classificator.HeroItemEnum> Items { get; set; }
619
}
720
}

TbsCore/Tasks/SecondLevel/SendDeff.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public bool TroopsCountRecieved(Account acc, int[] troopsAtHome)
5151
var troop = TroopsHelper.TroopFromInt(acc, i);
5252
if (!TroopsData.IsTroopDefensive(troop) || troopsAtHome[i] == 0) continue;
5353

54-
var upkeep = TroopSpeed.GetTroopUpkeep(troop);
54+
var upkeep = TroopsData.GetTroopUpkeep(troop);
5555
int sendAmount = troopsAtHome[i];
5656

5757
int toSend = this.DeffAmount.Amount / upkeep;

TbsCore/TravianData/CombatSimulator.cs

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using TbsCore.Models.CombatModels;
55
using TravBotSharp.Files.Helpers;
66
using TravBotSharp.Files.TravianData;
7+
using static TravBotSharp.Files.Helpers.Classificator;
78

89
namespace TbsCore.TravianData
910
{
@@ -73,7 +74,7 @@ public static (double, double) GetCasualties(CombatAttacker attacker, CombatDeff
7374
/// </summary>
7475
private static double GetPopBonus(CombatAttacker attacker, CombatDeffender deffender, double off, double deff)
7576
{
76-
if (deffender.DeffTribe == Classificator.TribeEnum.Nature)
77+
if (deffender.DeffTribe == TribeEnum.Nature)
7778
{
7879
// Note: Nature, the 'account' for unoccupied oases, has its own population (500).
7980
deffender.Population = 500;
@@ -157,7 +158,7 @@ public static double GetRealOffense(CombatAttacker attacker) =>
157158
public static double GetRealOffense(CombatBase army)
158159
{
159160
var (inf, cav) = GetArmyOffense(army);
160-
return inf + cav;
161+
return (inf + cav);
161162
}
162163

163164
private static (double, double) GetArmyDeffense(List<CombatBase> armies)
@@ -178,9 +179,12 @@ private static (double, double) GetArmyOffense(CombatBase army)
178179
{
179180
if (army.Troops[i] == 0) continue;
180181
var troop = TroopsHelper.TroopFromInt(army.Tribe, i);
182+
181183
var lvl = army.Improvements == null ? 1 : army.Improvements[i];
182184
var off = TroopsData.GetTroopOff(troop, lvl);
183-
185+
186+
if (troop == troopBoost) off += boost;
187+
184188
if (TroopsData.IsInfantry(troop)) inf += off * army.Troops[i];
185189
else cav += off * army.Troops[i];
186190
}
@@ -189,18 +193,73 @@ private static (double, double) GetArmyOffense(CombatBase army)
189193

190194
private static (double, double) GetArmyDeffense(CombatBase army)
191195
{
196+
var (troopBoost, boost) = GetWeaponBoost(army.Hero);
197+
192198
double inf = 0, cav = 0;
193199
for (int i = 0; i < 10; i++)
194200
{
195201
if (army.Troops[i] == 0) continue;
196202
var troop = TroopsHelper.TroopFromInt(army.Tribe, i);
197203
var lvl = army.Improvements == null ? 1 : army.Improvements[i];
198204
var (deffInf, deffCav) = TroopsData.GetTroopDeff(troop, lvl);
205+
206+
if(troop == troopBoost)
207+
{
208+
inf += boost;
209+
cav += boost;
210+
}
211+
199212
inf += deffInf * army.Troops[i];
200213
cav += deffCav * army.Troops[i];
201214
}
202215
return (inf, cav);
203216
}
217+
218+
private static (TroopsEnum, int) GetWeaponBoost(CombatHero hero)
219+
{
220+
if (hero == null) return (TroopsEnum.None, 0);
221+
if (hero.Items.TryGetValue(HeroItemCategory.Weapon, out var weapon))
222+
{
223+
return HeroHelper.ParseWeapon(weapon);
224+
}
225+
return (TroopsEnum.None, 0);
226+
}
227+
228+
/// <summary>
229+
/// Gets hero bonus, power and whether it's on the horse
230+
/// </summary>
231+
/// <returns>(bonus, power)</returns>
232+
private static (double, int, bool) GetHeroBoost(CombatBase army, bool attack)
233+
{
234+
var hero = army.Hero;
235+
if (hero == null || hero.Info == null || hero.Items == null) return (1.0, 0, false);
236+
237+
int power = 100; // Base hero power
238+
if (hero.Items.TryGetValue(HeroItemCategory.Weapon, out var weapon))
239+
{
240+
var (_, _, tier) = HeroHelper.ParseHeroItem(weapon);
241+
power += tier * 500;
242+
}
243+
if (hero.Items.TryGetValue(HeroItemCategory.Armor, out var armor))
244+
{
245+
var (_, name, tier) = HeroHelper.ParseHeroItem(armor);
246+
power += HeroHelper.GetArmorBaseStrength(name) * tier;
247+
}
248+
if (hero.Items.TryGetValue(HeroItemCategory.Left, out var left))
249+
{
250+
var (_, name, tier) = HeroHelper.ParseHeroItem(left);
251+
if (name == "Shield") power += tier * 500;
252+
}
253+
var levelMultiplier = army.Tribe == TribeEnum.Romans ? 100 : 80;
254+
power += levelMultiplier * hero.Info.FightingStrengthPoints;
255+
256+
double bonus = 0.2F * (attack ? hero.Info.OffBonusPoints : hero.Info.DeffBonusPoints);
257+
bonus += 1.0F;
258+
259+
bool horse = hero.Items.TryGetValue(HeroItemCategory.Horse, out _);
260+
261+
return (bonus, power, horse);
262+
}
204263
#endregion Private methods
205264
}
206265
}

TbsCore/TravianData/TroopSpeed.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

0 commit comments

Comments
 (0)