From 35cefc2cb88be32c401db21b25612d69418f51cd Mon Sep 17 00:00:00 2001 From: Asval Date: Mon, 3 Jun 2019 02:12:11 +0200 Subject: [PATCH] added some basic stats to all weapon icons excluding pickaxes --- FModel/App.config | 12 +- FModel/FModel.csproj | 6 +- FModel/MainWindow.cs | 256 +-------- FModel/Methods/BackPAKs/DynamicPAKs.cs | 9 +- .../BackPAKs/Parser/AccessTokenParser.cs | 96 ---- ...{ExchangeTokenParser.cs => TokenParser.cs} | 12 +- FModel/Methods/IconGenerator/DrawText.cs | 326 +++++++++++ FModel/Parser/Items/ItemIDParser.cs | 12 + FModel/Parser/Weapons/WeaponStatParser.cs | 538 ++++++++++++++++++ FModel/Properties/Resources.Designer.cs | 10 + FModel/Properties/Resources.resx | 3 + FModel/Resources/Quest.png | Bin 77902 -> 0 bytes FModel/Resources/dmg64.png | Bin 0 -> 3572 bytes 13 files changed, 917 insertions(+), 363 deletions(-) delete mode 100644 FModel/Methods/BackPAKs/Parser/AccessTokenParser.cs rename FModel/Methods/BackPAKs/Parser/{ExchangeTokenParser.cs => TokenParser.cs} (78%) create mode 100644 FModel/Methods/IconGenerator/DrawText.cs create mode 100644 FModel/Parser/Weapons/WeaponStatParser.cs delete mode 100644 FModel/Resources/Quest.png create mode 100644 FModel/Resources/dmg64.png diff --git a/FModel/App.config b/FModel/App.config index f02f0150..7e47646f 100644 --- a/FModel/App.config +++ b/FModel/App.config @@ -1,7 +1,7 @@ - + - +
@@ -132,4 +132,12 @@ + + + + + + + + \ No newline at end of file diff --git a/FModel/FModel.csproj b/FModel/FModel.csproj index 609cf788..a7658de7 100644 --- a/FModel/FModel.csproj +++ b/FModel/FModel.csproj @@ -120,13 +120,13 @@ - - + + @@ -179,6 +179,7 @@ + @@ -233,6 +234,7 @@ + diff --git a/FModel/MainWindow.cs b/FModel/MainWindow.cs index 474f6a9a..6ffa5f9e 100644 --- a/FModel/MainWindow.cs +++ b/FModel/MainWindow.cs @@ -27,6 +27,7 @@ namespace FModel { public partial class MainWindow : Form { + #region to refactor private static Stopwatch StopWatch { get; set; } private static string[] _paksArray { get; set; } public static string[] PakAsTxt { get; set; } @@ -36,6 +37,7 @@ namespace FModel private static List _itemsToDisplay { get; set; } public static string ExtractedFilePath { get; set; } public static string[] SelectedItemsArray { get; set; } + #endregion public MainWindow() { @@ -1217,257 +1219,7 @@ namespace FModel Image bg512 = Resources.BG512; g.DrawImage(bg512, new Point(5, 383)); - #region DRAW TEXT - try - { - g.DrawString(theItem.DisplayName, new Font(FontUtilities.pfc.Families[0], 35), new SolidBrush(Color.White), new Point(522 / 2, 395), FontUtilities.centeredString); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("DisplayName ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //NAME - try - { - g.DrawString(theItem.Description, new Font("Arial", 10), new SolidBrush(Color.White), new RectangleF(5, 441, 512, 49), FontUtilities.centeredStringLine); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("Description ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //DESCRIPTION - if (specialMode == "athIteDef") - { - try - { - g.DrawString(theItem.ShortDescription, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(5, 500)); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("ShortDescription ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //TYPE - try - { - g.DrawString(theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.Source."))].Substring(17), new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(522 - 5, 500), FontUtilities.rightString); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("GameplayTags ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } - catch (IndexOutOfRangeException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("GameplayTags ", Color.SteelBlue); - AppendText("as ", Color.Black); - AppendText("Cosmetics.Source ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //COSMETIC SOURCE - if (theItem.ExportType == "AthenaItemWrapDefinition" && Checking.WasFeatured && ItemIcon.ItemIconPath.Contains("WeaponRenders")) //ONLY TRIGGER IF THE WEAPON RENDER IS TRIGGERED - { - string wrapAddImg = theItem.LargePreviewImage.AssetPathName.Substring(theItem.LargePreviewImage.AssetPathName.LastIndexOf(".", StringComparison.Ordinal) + 1); - - UpdateConsole("Additional image " + wrapAddImg, Color.FromArgb(255, 244, 132, 66), "Waiting"); - ItemIcon.ItemIconPath = JohnWick.AssetToTexture2D(wrapAddImg); - - if (File.Exists(ItemIcon.ItemIconPath)) - { - Image itemIcon; - using (var bmpTemp = new Bitmap(ItemIcon.ItemIconPath)) - { - itemIcon = new Bitmap(bmpTemp); - } - g.DrawImage(ImageUtilities.ResizeImage(itemIcon, 122, 122), new Point(395, 282)); - } - } - } - if (specialMode == "consAndWeap") - { - try - { - g.DrawString(theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Athena.ItemAction."))].Substring(18), new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(522 - 5, 500), FontUtilities.rightString); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("GameplayTags ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } - catch (IndexOutOfRangeException) - { - try - { - g.DrawString(theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Weapon."))].Substring(7), new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(522 - 5, 500), FontUtilities.rightString); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("GameplayTags ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } - catch (IndexOutOfRangeException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("GameplayTags ", Color.SteelBlue); - AppendText("as ", Color.Black); - AppendText("Athena.ItemAction ", Color.SteelBlue); - AppendText("or ", Color.Black); - AppendText("Weapon ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } - } //ACTION - if (ExtractedFilePath.Contains("Items\\Consumables")) - { - try - { - g.DrawString("Max Stack Size: " + theItem.MaxStackSize, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(5, 500)); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("MaxStackSize ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //MAX STACK SIZE - } - if (theItem.AmmoData != null && theItem.AmmoData.AssetPathName.Contains("Ammo")) //TO AVOID TRIGGERING CONSUMABLES, NAME SHOULD CONTAIN "AMMO" - { - ItemIcon.GetAmmoData(theItem.AmmoData.AssetPathName, g); - } - } - if (specialMode == "variant") - { - try - { - g.DrawString(theItem.ShortDescription, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(5, 500)); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("ShortDescription ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //TYPE - try - { - g.DrawString(theItem.CosmeticItem, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(522 - 5, 500), FontUtilities.rightString); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("Cosmetic Item ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //COSMETIC ITEM - } - try - { - if (theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.UserFacingFlags."))].Contains("Animated")) - { - Image animatedLogo = Resources.T_Icon_Animated_64; - g.DrawImage(ImageUtilities.ResizeImage(animatedLogo, 32, 32), new Point(6, -2)); - } - else if (theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.UserFacingFlags."))].Contains("HasUpgradeQuests") && theItem.ExportType != "AthenaPetCarrierItemDefinition") - { - Image questLogo = Resources.T_Icon_Quests_64; - g.DrawImage(ImageUtilities.ResizeImage(questLogo, 32, 32), new Point(6, 6)); - } - else if (theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.UserFacingFlags."))].Contains("HasUpgradeQuests") && theItem.ExportType == "AthenaPetCarrierItemDefinition") - { - Image petLogo = Resources.T_Icon_Pets_64; - g.DrawImage(ImageUtilities.ResizeImage(petLogo, 32, 32), new Point(6, 6)); - } - else if (theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.UserFacingFlags."))].Contains("HasVariants")) - { - Image variantsLogo = Resources.T_Icon_Variant_64; - g.DrawImage(ImageUtilities.ResizeImage(variantsLogo, 32, 32), new Point(6, 6)); - } - else if (theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.UserFacingFlags."))].Contains("Reactive")) - { - Image reactiveLogo = Resources.T_Icon_Adaptive_64; - g.DrawImage(ImageUtilities.ResizeImage(reactiveLogo, 32, 32), new Point(7, 7)); - } - else if (theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.UserFacingFlags."))].Contains("Traversal")) - { - Image traversalLogo = Resources.T_Icon_Traversal_64; - g.DrawImage(ImageUtilities.ResizeImage(traversalLogo, 32, 32), new Point(6, 3)); - } - } - catch (Exception) { } //COSMETIC USER FACING FLAGS - - if (specialMode == "stwHeroes") - { - try - { - g.DrawString(theItem.AttributeInitKey.AttributeInitCategory, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(522 - 5, 500), FontUtilities.rightString); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("AttributeInitCategory ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //CHARACTER TYPE - try - { - g.DrawString("Power " + theItem.MinLevel + " to " + theItem.MaxLevel, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(5, 500)); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("Level ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //LEVEL - } - if (specialMode == "stwDefenders") - { - try - { - g.DrawString(theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("NPC.CharacterType.Survivor.Defender."))].Substring(36), new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(522 - 5, 500), FontUtilities.rightString); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("GameplayTags ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } - catch (IndexOutOfRangeException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("GameplayTags ", Color.SteelBlue); - AppendText("as ", Color.Black); - AppendText("NPC.CharacterType.Survivor.Defender ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //CHARACTER TYPE - try - { - g.DrawString("Power " + theItem.MinLevel + " to " + theItem.MaxLevel, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(5, 500)); - } - catch (NullReferenceException) - { - AppendText(ThePak.CurrentUsedItem + " ", Color.Red); - AppendText("No ", Color.Black); - AppendText("Level ", Color.SteelBlue); - AppendText("found", Color.Black, true); - } //LEVEL - } - #endregion + DrawText.DrawTexts(theItem, g, specialMode); UpdateConsole(theItem.DisplayName, Color.FromArgb(255, 66, 244, 66), "Success"); if (autoSaveImagesToolStripMenuItem.Checked || updateModeToolStripMenuItem.Checked) @@ -1654,7 +1406,7 @@ namespace FModel ExtractButton.Enabled = true; })); } - public void ExtractButton_Click(object sender, EventArgs e) + private void ExtractButton_Click(object sender, EventArgs e) { scintilla1.Text = ""; pictureBox1.Image = null; diff --git a/FModel/Methods/BackPAKs/DynamicPAKs.cs b/FModel/Methods/BackPAKs/DynamicPAKs.cs index 67046578..c6f296b0 100644 --- a/FModel/Methods/BackPAKs/DynamicPAKs.cs +++ b/FModel/Methods/BackPAKs/DynamicPAKs.cs @@ -1,6 +1,5 @@ -using FModel.Methods.BackupPAKs.Parser.AccessTokenParser; -using FModel.Methods.BackupPAKs.Parser.AccessCodeParser; -using FModel.Methods.BackupPAKs.Parser.ExchangeTokenParser; +using FModel.Methods.BackupPAKs.Parser.AccessCodeParser; +using FModel.Methods.BackupPAKs.Parser.TokenParser; using RestSharp; using System; using Newtonsoft.Json.Linq; @@ -54,7 +53,7 @@ namespace FModel getAccessTokenRequest.AddHeader("Authorization", "basic MzQ0NmNkNzI2OTRjNGE0NDg1ZDgxYjc3YWRiYjIxNDE6OTIwOWQ0YTVlMjVhNDU3ZmI5YjA3NDg5ZDMxM2I0MWE="); getAccessTokenRequest.AddHeader("Content-Type", "application/x-www-form-urlencoded"); - return AccessTokenParser.FromJson(getAccessTokenClient.Execute(getAccessTokenRequest).Content).AccessToken; + return TokenParser.FromJson(getAccessTokenClient.Execute(getAccessTokenRequest).Content).AccessToken; } private static string getAccessCode(string accessToken) { @@ -77,7 +76,7 @@ namespace FModel getExchangeTokenRequest.AddParameter("includePerms", true); getExchangeTokenRequest.AddParameter("token_type", "eg1"); - return ExchangeTokenParser.FromJson(getExchangeTokenClient.Execute(getExchangeTokenRequest).Content).AccessToken; + return TokenParser.FromJson(getExchangeTokenClient.Execute(getExchangeTokenRequest).Content).AccessToken; } private static IEnumerable SplitGuid(string str, int chunkSize) diff --git a/FModel/Methods/BackPAKs/Parser/AccessTokenParser.cs b/FModel/Methods/BackPAKs/Parser/AccessTokenParser.cs deleted file mode 100644 index afcbd1f5..00000000 --- a/FModel/Methods/BackPAKs/Parser/AccessTokenParser.cs +++ /dev/null @@ -1,96 +0,0 @@ -// -// -// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do: -// -// using FModel.Methods.BackupPAKs.Parser.AccessTokenParser; -// -// var accessTokenParser = AccessTokenParser.FromJson(jsonString); - -namespace FModel.Methods.BackupPAKs.Parser.AccessTokenParser -{ - using System; - - using System.Globalization; - using Newtonsoft.Json; - using Newtonsoft.Json.Converters; - - public partial class AccessTokenParser - { - [JsonProperty("access_token")] - public string AccessToken { get; set; } - - [JsonProperty("expires_in")] - public long ExpiresIn { get; set; } - - [JsonProperty("expires_at")] - public DateTimeOffset ExpiresAt { get; set; } - - [JsonProperty("token_type")] - public string TokenType { get; set; } - - [JsonProperty("refresh_token")] - public string RefreshToken { get; set; } - - [JsonProperty("refresh_expires")] - public long RefreshExpires { get; set; } - - [JsonProperty("refresh_expires_at")] - public DateTimeOffset RefreshExpiresAt { get; set; } - - [JsonProperty("account_id")] - public string AccountId { get; set; } - - [JsonProperty("client_id")] - public string ClientId { get; set; } - - [JsonProperty("internal_client")] - public bool InternalClient { get; set; } - - [JsonProperty("client_service")] - public string ClientService { get; set; } - - [JsonProperty("lastPasswordValidation")] - public DateTimeOffset LastPasswordValidation { get; set; } - - [JsonProperty("perms")] - public Perm[] Perms { get; set; } - - [JsonProperty("app")] - public string App { get; set; } - - [JsonProperty("in_app_id")] - public string InAppId { get; set; } - } - - public partial class Perm - { - [JsonProperty("resource")] - public string Resource { get; set; } - - [JsonProperty("action")] - public long Action { get; set; } - } - - public partial class AccessTokenParser - { - public static AccessTokenParser FromJson(string json) => JsonConvert.DeserializeObject(json, FModel.Methods.BackupPAKs.Parser.AccessTokenParser.Converter.Settings); - } - - public static class Serialize - { - public static string ToJson(this AccessTokenParser self) => JsonConvert.SerializeObject(self, FModel.Methods.BackupPAKs.Parser.AccessTokenParser.Converter.Settings); - } - - internal static class Converter - { - public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings - { - MetadataPropertyHandling = MetadataPropertyHandling.Ignore, - DateParseHandling = DateParseHandling.None, - Converters = - { - new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } - }, - }; - } -} diff --git a/FModel/Methods/BackPAKs/Parser/ExchangeTokenParser.cs b/FModel/Methods/BackPAKs/Parser/TokenParser.cs similarity index 78% rename from FModel/Methods/BackPAKs/Parser/ExchangeTokenParser.cs rename to FModel/Methods/BackPAKs/Parser/TokenParser.cs index 2834e648..082ef63d 100644 --- a/FModel/Methods/BackPAKs/Parser/ExchangeTokenParser.cs +++ b/FModel/Methods/BackPAKs/Parser/TokenParser.cs @@ -4,9 +4,9 @@ // // using FModel.Methods.BackupPAKs.Parser.ExchangeTokenParser; // -// var exchangeTokenParser = ExchangeTokenParser.FromJson(jsonString); +// var TokenParser = ExchangeTokenParser.FromJson(jsonString); -namespace FModel.Methods.BackupPAKs.Parser.ExchangeTokenParser +namespace FModel.Methods.BackupPAKs.Parser.TokenParser { using System; @@ -14,7 +14,7 @@ namespace FModel.Methods.BackupPAKs.Parser.ExchangeTokenParser using Newtonsoft.Json; using Newtonsoft.Json.Converters; - public partial class ExchangeTokenParser + public partial class TokenParser { [JsonProperty("access_token")] public string AccessToken { get; set; } @@ -68,14 +68,14 @@ namespace FModel.Methods.BackupPAKs.Parser.ExchangeTokenParser public long Action { get; set; } } - public partial class ExchangeTokenParser + public partial class TokenParser { - public static ExchangeTokenParser FromJson(string json) => JsonConvert.DeserializeObject(json, FModel.Methods.BackupPAKs.Parser.ExchangeTokenParser.Converter.Settings); + public static TokenParser FromJson(string json) => JsonConvert.DeserializeObject(json, FModel.Methods.BackupPAKs.Parser.TokenParser.Converter.Settings); } public static class Serialize { - public static string ToJson(this ExchangeTokenParser self) => JsonConvert.SerializeObject(self, FModel.Methods.BackupPAKs.Parser.ExchangeTokenParser.Converter.Settings); + public static string ToJson(this TokenParser self) => JsonConvert.SerializeObject(self, FModel.Methods.BackupPAKs.Parser.TokenParser.Converter.Settings); } internal static class Converter diff --git a/FModel/Methods/IconGenerator/DrawText.cs b/FModel/Methods/IconGenerator/DrawText.cs new file mode 100644 index 00000000..a2b55aca --- /dev/null +++ b/FModel/Methods/IconGenerator/DrawText.cs @@ -0,0 +1,326 @@ +using csharp_wick; +using FModel.Parser.Items; +using FModel.Properties; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System; +using System.Drawing; +using System.IO; + +namespace FModel +{ + static class DrawText + { + private static string cosmeticSource { get; set; } + private static string shortDescription { get; set; } + private static string cosmeticId { get; set; } + private static string maxStackSize { get; set; } + private static string itemAction { get; set; } + private static string weaponRowName { get; set; } + private static string cosmeticUFF { get; set; } + private static string heroType { get; set; } + private static string defenderType { get; set; } + private static string minToMax { get; set; } + + public static void DrawTexts(ItemsIdParser theItem, Graphics myGraphic, string Mode) + { + DrawDisplayName(theItem, myGraphic); + DrawDescription(theItem, myGraphic); + + setTexts(theItem); + + switch (Mode) + { + case "athIteDef": + DrawToLeft(shortDescription, myGraphic); + DrawToRight(cosmeticSource, myGraphic); + break; + case "consAndWeap": + DrawToRight(itemAction, myGraphic); + if (MainWindow.ExtractedFilePath.Contains("Items\\Consumables\\")) + { + DrawToLeft(maxStackSize, myGraphic); + } + break; + case "variant": + DrawToLeft(shortDescription, myGraphic); + DrawToRight(cosmeticId, myGraphic); + break; + case "stwHeroes": + DrawToRight(heroType, myGraphic); + DrawToLeft(minToMax, myGraphic); + break; + case "stwDefenders": + DrawToRight(defenderType, myGraphic); + DrawToLeft(minToMax, myGraphic); + break; + } + + if (theItem.ExportType == "AthenaItemWrapDefinition" && Checking.WasFeatured && ItemIcon.ItemIconPath.Contains("WeaponRenders")) + { + DrawAdditionalImage(theItem, myGraphic); + } + if (theItem.AmmoData != null && theItem.AmmoData.AssetPathName.Contains("Ammo")) //TO AVOID TRIGGERING CONSUMABLES, NAME SHOULD CONTAIN "AMMO" + { + ItemIcon.GetAmmoData(theItem.AmmoData.AssetPathName, myGraphic); + DrawWeaponStat(weaponRowName, myGraphic); + } + + DrawCosmeticUFF(theItem, myGraphic); + } + + private static void setTexts(ItemsIdParser theItem) + { + cosmeticSource = ""; + shortDescription = ""; + cosmeticId = ""; + maxStackSize = ""; + itemAction = ""; + weaponRowName = ""; + cosmeticUFF = ""; + heroType = ""; + defenderType = ""; + minToMax = ""; + + try + { + shortDescription = theItem.ShortDescription; + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + cosmeticSource = theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.Source."))].Substring(17); + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + cosmeticId = theItem.CosmeticItem; + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + maxStackSize = "Max Stack Size: " + theItem.MaxStackSize; + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + itemAction = theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Athena.ItemAction."))].Substring(18); + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + if (theItem.WeaponStatHandle.RowName != "Harvest_Pickaxe_Athena_C_T01") + { + weaponRowName = theItem.WeaponStatHandle.RowName; + } + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + cosmeticUFF = theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("Cosmetics.UserFacingFlags."))]; + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + heroType = theItem.AttributeInitKey.AttributeInitCategory; + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + defenderType = theItem.GameplayTags.GameplayTagsGameplayTags[Array.FindIndex(theItem.GameplayTags.GameplayTagsGameplayTags, x => x.StartsWith("NPC.CharacterType.Survivor.Defender."))].Substring(36); + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + try + { + minToMax = "Power " + theItem.MinLevel + " to " + theItem.MaxLevel; + } + catch (Exception) + { + //avoid generator to stop when a string isn't found + } + } + + /// + /// search for a known Cosmetics.UserFacingFlags, if found draw the uff icon + /// Cosmetics.UserFacingFlags icons are basically the style icon or the animated/reactive/traversal icon + /// + /// + /// + private static void DrawCosmeticUFF(ItemsIdParser theItem, Graphics myGraphic) + { + if (cosmeticUFF != null) + { + if (cosmeticUFF.Contains("Animated")) + { + Image animatedLogo = Resources.T_Icon_Animated_64; + myGraphic.DrawImage(ImageUtilities.ResizeImage(animatedLogo, 32, 32), new Point(6, -2)); + } + else if (cosmeticUFF.Contains("HasUpgradeQuests") && theItem.ExportType != "AthenaPetCarrierItemDefinition") + { + Image questLogo = Resources.T_Icon_Quests_64; + myGraphic.DrawImage(ImageUtilities.ResizeImage(questLogo, 32, 32), new Point(6, 6)); + } + else if (cosmeticUFF.Contains("HasUpgradeQuests") && theItem.ExportType == "AthenaPetCarrierItemDefinition") + { + Image petLogo = Resources.T_Icon_Pets_64; + myGraphic.DrawImage(ImageUtilities.ResizeImage(petLogo, 32, 32), new Point(6, 6)); + } + else if (cosmeticUFF.Contains("HasVariants")) + { + Image variantsLogo = Resources.T_Icon_Variant_64; + myGraphic.DrawImage(ImageUtilities.ResizeImage(variantsLogo, 32, 32), new Point(6, 6)); + } + else if (cosmeticUFF.Contains("Reactive")) + { + Image reactiveLogo = Resources.T_Icon_Adaptive_64; + myGraphic.DrawImage(ImageUtilities.ResizeImage(reactiveLogo, 32, 32), new Point(7, 7)); + } + else if (cosmeticUFF.Contains("Traversal")) + { + Image traversalLogo = Resources.T_Icon_Traversal_64; + myGraphic.DrawImage(ImageUtilities.ResizeImage(traversalLogo, 32, 32), new Point(6, 3)); + } + } + } + + /// + /// draw item name if exist + /// + /// + /// + private static void DrawDisplayName(ItemsIdParser theItem, Graphics myGraphic) + { + if (theItem.DisplayName != null) + { + myGraphic.DrawString(theItem.DisplayName, new Font(FontUtilities.pfc.Families[0], 35), new SolidBrush(Color.White), new Point(522 / 2, 395), FontUtilities.centeredString); + } + } + + /// + /// draw item description if exist + /// + /// + /// + private static void DrawDescription(ItemsIdParser theItem, Graphics myGraphic) + { + if (theItem.Description != null) + { + myGraphic.DrawString(theItem.Description, new Font("Arial", 10), new SolidBrush(Color.White), new RectangleF(5, 441, 512, 49), FontUtilities.centeredStringLine); + } + } + + /// + /// draw text at bottom right + /// + /// + /// + private static void DrawToRight(string text, Graphics myGraphic) + { + myGraphic.DrawString(text, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(522 - 5, 500), FontUtilities.rightString); + } + + /// + /// draw text at bottom left + /// + /// + /// + private static void DrawToLeft(string text, Graphics myGraphic) + { + myGraphic.DrawString(text, new Font(FontUtilities.pfc.Families[0], 13), new SolidBrush(Color.White), new Point(5, 500)); + } + + /// + /// this is only triggered for wraps, in case the featured (weapon render) image is drawn + /// also draw the non featured image to make it clear it's a wrap, not a weapon + /// + /// + /// + private static void DrawAdditionalImage(ItemsIdParser theItem, Graphics myGraphic) + { + string wrapAddImg = theItem.LargePreviewImage.AssetPathName.Substring(theItem.LargePreviewImage.AssetPathName.LastIndexOf(".", StringComparison.Ordinal) + 1); + + ItemIcon.ItemIconPath = JohnWick.AssetToTexture2D(wrapAddImg); + + if (File.Exists(ItemIcon.ItemIconPath)) + { + Image itemIcon; + using (var bmpTemp = new Bitmap(ItemIcon.ItemIconPath)) + { + itemIcon = new Bitmap(bmpTemp); + } + myGraphic.DrawImage(ImageUtilities.ResizeImage(itemIcon, 122, 122), new Point(395, 282)); + } + } + + /// + /// this is only triggered for weapons + /// draw the damage per bullet as well as the reload time + /// + /// + /// + public static void DrawWeaponStat(string weaponName, Graphics myGraphic) + { + ItemIcon.ItemIconPath = string.Empty; + string extractedWeaponsStatPath = JohnWick.ExtractAsset(ThePak.AllpaksDictionary["AthenaRangedWeapons"], "AthenaRangedWeapons"); + if (extractedWeaponsStatPath != null) + { + if (extractedWeaponsStatPath.Contains(".uasset") || extractedWeaponsStatPath.Contains(".uexp") || extractedWeaponsStatPath.Contains(".ubulk")) + { + JohnWick.MyAsset = new PakAsset(extractedWeaponsStatPath.Substring(0, extractedWeaponsStatPath.LastIndexOf('.'))); + try + { + if (JohnWick.MyAsset.GetSerialized() != null) + { + string parsedJson = JToken.Parse(JohnWick.MyAsset.GetSerialized()).ToString().TrimStart('[').TrimEnd(']'); + JObject jo = JObject.Parse(parsedJson); + foreach (JToken token in jo.FindTokens(weaponName)) + { + var statParsed = Parser.Weapons.WeaponStatParser.FromJson(token.ToString()); + + Image bulletImage = Resources.dmg64; + myGraphic.DrawImage(ImageUtilities.ResizeImage(bulletImage, 15, 15), new Point(5, 500)); + + if (statParsed.DmgPb != 0 && statParsed.ClipSize != 0) + { + DrawToRight("Reload Time: " + statParsed.ReloadTime + " seconds", myGraphic); + DrawToLeft(" " + statParsed.DmgPb, myGraphic); //damage per bullet + } + } + } + } + catch (JsonSerializationException) + { + //do not crash when JsonSerialization does weird stuff + } + } + } + } + } +} diff --git a/FModel/Parser/Items/ItemIDParser.cs b/FModel/Parser/Items/ItemIDParser.cs index 9e246b33..b3227b84 100644 --- a/FModel/Parser/Items/ItemIDParser.cs +++ b/FModel/Parser/Items/ItemIDParser.cs @@ -62,6 +62,9 @@ namespace FModel.Parser.Items [JsonProperty("MaxLevel")] public long MaxLevel { get; set; } + + [JsonProperty("WeaponStatHandle")] + public WeaponStatHandle WeaponStatHandle { get; set; } } public class GameplayTags @@ -106,6 +109,15 @@ namespace FModel.Parser.Items public string AttributeInitSubCategory { get; set; } } + public partial class WeaponStatHandle + { + [JsonProperty("DataTable")] + public string DataTable { get; set; } + + [JsonProperty("RowName")] + public string RowName { get; set; } + } + public partial class ItemsIdParser { public static ItemsIdParser[] FromJson(string json) => JsonConvert.DeserializeObject(json, Converter.Settings); diff --git a/FModel/Parser/Weapons/WeaponStatParser.cs b/FModel/Parser/Weapons/WeaponStatParser.cs new file mode 100644 index 00000000..1626ed42 --- /dev/null +++ b/FModel/Parser/Weapons/WeaponStatParser.cs @@ -0,0 +1,538 @@ +// +// +// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do: +// +// using FModel.Parser.Weapons; +// +// var weaponStatParser = WeaponStatParser.FromJson(jsonString); + +namespace FModel.Parser.Weapons +{ + using System; + + using System.Globalization; + using Newtonsoft.Json; + using Newtonsoft.Json.Converters; + + public partial class WeaponStatParser + { + [JsonProperty("export_type")] + public string ExportType { get; set; } + + [JsonProperty("Spread")] + public double Spread { get; set; } + + [JsonProperty("SpreadDownsights")] + public double SpreadDownsights { get; set; } + + [JsonProperty("StandingStillSpreadMultiplier")] + public double StandingStillSpreadMultiplier { get; set; } + + [JsonProperty("AthenaCrouchingSpreadMultiplier")] + public double AthenaCrouchingSpreadMultiplier { get; set; } + + [JsonProperty("AthenaJumpingFallingSpreadMultiplier")] + public long AthenaJumpingFallingSpreadMultiplier { get; set; } + + [JsonProperty("AthenaSprintingSpreadMultiplier")] + public double AthenaSprintingSpreadMultiplier { get; set; } + + [JsonProperty("MinSpeedForSpreadMultiplier")] + public long MinSpeedForSpreadMultiplier { get; set; } + + [JsonProperty("MaxSpeedForSpreadMultiplier")] + public long MaxSpeedForSpreadMultiplier { get; set; } + + [JsonProperty("SpreadDownsightsAdditionalCooldownTime")] + public long SpreadDownsightsAdditionalCooldownTime { get; set; } + + [JsonProperty("HeatX1")] + public double HeatX1 { get; set; } + + [JsonProperty("HeatY1")] + public double HeatY1 { get; set; } + + [JsonProperty("HeatX2")] + public double HeatX2 { get; set; } + + [JsonProperty("HeatY2")] + public double HeatY2 { get; set; } + + [JsonProperty("HeatX3")] + public long HeatX3 { get; set; } + + [JsonProperty("HeatY3")] + public double HeatY3 { get; set; } + + [JsonProperty("HeatXScale")] + public long HeatXScale { get; set; } + + [JsonProperty("HeatYScale")] + public long HeatYScale { get; set; } + + [JsonProperty("CoolX1")] + public double CoolX1 { get; set; } + + [JsonProperty("CoolY1")] + public double CoolY1 { get; set; } + + [JsonProperty("CoolX2")] + public double CoolX2 { get; set; } + + [JsonProperty("CoolY2")] + public long CoolY2 { get; set; } + + [JsonProperty("CoolX3")] + public long CoolX3 { get; set; } + + [JsonProperty("CoolY3")] + public long CoolY3 { get; set; } + + [JsonProperty("CoolXScale")] + public long CoolXScale { get; set; } + + [JsonProperty("CoolYScale")] + public long CoolYScale { get; set; } + + [JsonProperty("PerfectAimCooldown")] + public long PerfectAimCooldown { get; set; } + + [JsonProperty("BulletsPerCartridge")] + public long BulletsPerCartridge { get; set; } + + [JsonProperty("FiringRate")] + public double FiringRate { get; set; } + + [JsonProperty("ROFScale")] + public long RofScale { get; set; } + + [JsonProperty("BurstFiringRate")] + public long BurstFiringRate { get; set; } + + [JsonProperty("FiringRateDownsightsMultiplier")] + public long FiringRateDownsightsMultiplier { get; set; } + + [JsonProperty("AutofireAcquisitionDelay")] + public double AutofireAcquisitionDelay { get; set; } + + [JsonProperty("AutofireCooldown")] + public long AutofireCooldown { get; set; } + + [JsonProperty("RecoilVert")] + public double RecoilVert { get; set; } + + [JsonProperty("RecoilVertScale")] + public long RecoilVertScale { get; set; } + + [JsonProperty("RecoilVertScaleGamepad")] + public double RecoilVertScaleGamepad { get; set; } + + [JsonProperty("VertRecoilDownChance")] + public long VertRecoilDownChance { get; set; } + + [JsonProperty("RecoilHoriz")] + public double RecoilHoriz { get; set; } + + [JsonProperty("RecoilHorizScale")] + public long RecoilHorizScale { get; set; } + + [JsonProperty("RecoilHorizScaleGamepad")] + public long RecoilHorizScaleGamepad { get; set; } + + [JsonProperty("RecoilInterpSpeed")] + public long RecoilInterpSpeed { get; set; } + + [JsonProperty("RecoilRecoveryInterpSpeed")] + public double RecoilRecoveryInterpSpeed { get; set; } + + [JsonProperty("RecoilRecoveryDelay")] + public long RecoilRecoveryDelay { get; set; } + + [JsonProperty("RecoilRecoveryFraction")] + public long RecoilRecoveryFraction { get; set; } + + [JsonProperty("RecoilDownsightsMultiplier")] + public double RecoilDownsightsMultiplier { get; set; } + + [JsonProperty("AthenaRecoilMagnitudeMin")] + public long AthenaRecoilMagnitudeMin { get; set; } + + [JsonProperty("AthenaRecoilMagnitudeMax")] + public long AthenaRecoilMagnitudeMax { get; set; } + + [JsonProperty("AthenaRecoilMagnitudeScale")] + public long AthenaRecoilMagnitudeScale { get; set; } + + [JsonProperty("AthenaRecoilAngleMin")] + public long AthenaRecoilAngleMin { get; set; } + + [JsonProperty("AthenaRecoilAngleMax")] + public long AthenaRecoilAngleMax { get; set; } + + [JsonProperty("AthenaRecoilRollMagnitudeMin")] + public long AthenaRecoilRollMagnitudeMin { get; set; } + + [JsonProperty("AthenaRecoilRollMagnitudeMax")] + public long AthenaRecoilRollMagnitudeMax { get; set; } + + [JsonProperty("AthenaRecoilInterpSpeed")] + public long AthenaRecoilInterpSpeed { get; set; } + + [JsonProperty("AthenaRecoilRecoveryInterpSpeed")] + public long AthenaRecoilRecoveryInterpSpeed { get; set; } + + [JsonProperty("AthenaRecoilDownsightsMultiplier")] + public double AthenaRecoilDownsightsMultiplier { get; set; } + + [JsonProperty("AthenaRecoilHipFireMultiplier")] + public long AthenaRecoilHipFireMultiplier { get; set; } + + [JsonProperty("AthenaAimAssistRange")] + public long AthenaAimAssistRange { get; set; } + + [JsonProperty("ADSTransitionInTime")] + public double AdsTransitionInTime { get; set; } + + [JsonProperty("ADSTransitionOutTime")] + public double AdsTransitionOutTime { get; set; } + + [JsonProperty("MaxSpareAmmo")] + public long MaxSpareAmmo { get; set; } + + [JsonProperty("BulletsPerTracer")] + public long BulletsPerTracer { get; set; } + + [JsonProperty("AIDelayBeforeFiringMin")] + public long AiDelayBeforeFiringMin { get; set; } + + [JsonProperty("AIDelayBeforeFiringMax")] + public double AiDelayBeforeFiringMax { get; set; } + + [JsonProperty("AIFireDurationMin")] + public double AiFireDurationMin { get; set; } + + [JsonProperty("AIFireDurationMax")] + public double AiFireDurationMax { get; set; } + + [JsonProperty("AIMinSpreadDuration")] + public long AiMinSpreadDuration { get; set; } + + [JsonProperty("AIMaxSpreadDuration")] + public long AiMaxSpreadDuration { get; set; } + + [JsonProperty("AIDurationSpreadMultiplier")] + public long AiDurationSpreadMultiplier { get; set; } + + [JsonProperty("AIAdditionalSpreadForTargetMovingLaterally")] + public long AiAdditionalSpreadForTargetMovingLaterally { get; set; } + + [JsonProperty("AIAthenaHearFiringNoiseRange")] + public long AiAthenaHearFiringNoiseRange { get; set; } + + [JsonProperty("EQSDensity")] + public long EqsDensity { get; set; } + + [JsonProperty("MinApproachRange")] + public long MinApproachRange { get; set; } + + [JsonProperty("MinActualRange")] + public long MinActualRange { get; set; } + + [JsonProperty("MinPreferredRange")] + public long MinPreferredRange { get; set; } + + [JsonProperty("MinPreferredRangeEQS")] + public long MinPreferredRangeEqs { get; set; } + + [JsonProperty("MaxPreferredRangeEQS")] + public long MaxPreferredRangeEqs { get; set; } + + [JsonProperty("MaxPreferredRange")] + public long MaxPreferredRange { get; set; } + + [JsonProperty("MaxActualRange")] + public long MaxActualRange { get; set; } + + [JsonProperty("MaxApproachRange")] + public long MaxApproachRange { get; set; } + + [JsonProperty("SweepRadius")] + public long SweepRadius { get; set; } + + [JsonProperty("AutoReloadDelayOverride")] + public long AutoReloadDelayOverride { get; set; } + + [JsonProperty("OverheatingMaxValue")] + public long OverheatingMaxValue { get; set; } + + [JsonProperty("OverheatHeatingValue")] + public long OverheatHeatingValue { get; set; } + + [JsonProperty("OverheatingCoolingValue")] + public long OverheatingCoolingValue { get; set; } + + [JsonProperty("HeatingCooldownDelay")] + public long HeatingCooldownDelay { get; set; } + + [JsonProperty("OverheatedCooldownDelay")] + public long OverheatedCooldownDelay { get; set; } + + [JsonProperty("FortHomingTurnSpeedMin")] + public long FortHomingTurnSpeedMin { get; set; } + + [JsonProperty("FortHomingTurnSpeedMax")] + public long FortHomingTurnSpeedMax { get; set; } + + [JsonProperty("FortHomingTimeUntilMaxTurnSpeed")] + public long FortHomingTimeUntilMaxTurnSpeed { get; set; } + + [JsonProperty("BaseLevel")] + public long BaseLevel { get; set; } + + [JsonProperty("NamedWeightRow")] + public string NamedWeightRow { get; set; } + + [JsonProperty("DmgPB")] + public long DmgPb { get; set; } + + [JsonProperty("DmgMid")] + public double DmgMid { get; set; } + + [JsonProperty("DmgLong")] + public double DmgLong { get; set; } + + [JsonProperty("DmgMaxRange")] + public double DmgMaxRange { get; set; } + + [JsonProperty("EnvDmgPB")] + public long EnvDmgPb { get; set; } + + [JsonProperty("EnvDmgMid")] + public long EnvDmgMid { get; set; } + + [JsonProperty("EnvDmgLong")] + public long EnvDmgLong { get; set; } + + [JsonProperty("EnvDmgMaxRange")] + public long EnvDmgMaxRange { get; set; } + + [JsonProperty("ImpactDmgPB")] + public long ImpactDmgPb { get; set; } + + [JsonProperty("ImpactDmgMid")] + public long ImpactDmgMid { get; set; } + + [JsonProperty("ImpactDmgLong")] + public double ImpactDmgLong { get; set; } + + [JsonProperty("ImpactDmgMaxRange")] + public double ImpactDmgMaxRange { get; set; } + + [JsonProperty("bForceControl")] + public bool BForceControl { get; set; } + + [JsonProperty("RngPB")] + public long RngPb { get; set; } + + [JsonProperty("RngMid")] + public long RngMid { get; set; } + + [JsonProperty("RngLong")] + public long RngLong { get; set; } + + [JsonProperty("RngMax")] + public long RngMax { get; set; } + + [JsonProperty("DmgScaleTable")] + [JsonConverter(typeof(ParseStringConverter))] + public long DmgScaleTable { get; set; } + + [JsonProperty("DmgScaleTableRow")] + public string DmgScaleTableRow { get; set; } + + [JsonProperty("DmgScale")] + public long DmgScale { get; set; } + + [JsonProperty("EnvDmgScaleTable")] + [JsonConverter(typeof(ParseStringConverter))] + public long EnvDmgScaleTable { get; set; } + + [JsonProperty("EnvDmgScaleTableRow")] + public string EnvDmgScaleTableRow { get; set; } + + [JsonProperty("EnvDmgScale")] + public long EnvDmgScale { get; set; } + + [JsonProperty("ImpactDmgScaleTable")] + [JsonConverter(typeof(ParseStringConverter))] + public long ImpactDmgScaleTable { get; set; } + + [JsonProperty("ImpactDmgScaleTableRow")] + public string ImpactDmgScaleTableRow { get; set; } + + [JsonProperty("ImpactDmgScale")] + public long ImpactDmgScale { get; set; } + + [JsonProperty("SurfaceRatioRowName")] + public string SurfaceRatioRowName { get; set; } + + [JsonProperty("DamageZone_Light")] + public long DamageZoneLight { get; set; } + + [JsonProperty("DamageZone_Normal")] + public long DamageZoneNormal { get; set; } + + [JsonProperty("DamageZone_Critical")] + public long DamageZoneCritical { get; set; } + + [JsonProperty("DamageZone_Vulnerability")] + public long DamageZoneVulnerability { get; set; } + + [JsonProperty("KnockbackMagnitude")] + public long KnockbackMagnitude { get; set; } + + [JsonProperty("MidRangeKnockbackMagnitude")] + public long MidRangeKnockbackMagnitude { get; set; } + + [JsonProperty("LongRangeKnockbackMagnitude")] + public long LongRangeKnockbackMagnitude { get; set; } + + [JsonProperty("KnockbackZAngle")] + public long KnockbackZAngle { get; set; } + + [JsonProperty("StunTime")] + public long StunTime { get; set; } + + [JsonProperty("StunScale")] + public long StunScale { get; set; } + + [JsonProperty("Durability")] + public string Durability { get; set; } + + [JsonProperty("DurabilityRowName")] + public string DurabilityRowName { get; set; } + + [JsonProperty("DurabilityScale")] + public long DurabilityScale { get; set; } + + [JsonProperty("DurabilityPerUse")] + public long DurabilityPerUse { get; set; } + + [JsonProperty("DiceCritChance")] + public long DiceCritChance { get; set; } + + [JsonProperty("DiceCritDamageMultiplier")] + public long DiceCritDamageMultiplier { get; set; } + + [JsonProperty("ReloadTime")] + public double ReloadTime { get; set; } + + [JsonProperty("ReloadScale")] + public long ReloadScale { get; set; } + + [JsonProperty("ReloadType")] + public string ReloadType { get; set; } + + [JsonProperty("bAllowReloadInterrupt")] + public bool BAllowReloadInterrupt { get; set; } + + [JsonProperty("bReloadInterruptIsImmediate")] + public bool BReloadInterruptIsImmediate { get; set; } + + [JsonProperty("NumIndividualBulletsToReload")] + public long NumIndividualBulletsToReload { get; set; } + + [JsonProperty("ClipSize")] + public long ClipSize { get; set; } + + [JsonProperty("ClipScale")] + public long ClipScale { get; set; } + + [JsonProperty("InitialClips")] + public long InitialClips { get; set; } + + [JsonProperty("CartridgePerFire")] + public long CartridgePerFire { get; set; } + + [JsonProperty("AmmoCostPerFire")] + public long AmmoCostPerFire { get; set; } + + [JsonProperty("MaxAmmoCostPerFire")] + public long MaxAmmoCostPerFire { get; set; } + + [JsonProperty("MinChargeTime")] + public long MinChargeTime { get; set; } + + [JsonProperty("MaxChargeTime")] + public long MaxChargeTime { get; set; } + + [JsonProperty("ChargeDownTime")] + public long ChargeDownTime { get; set; } + + [JsonProperty("MinChargeDamageMultiplier")] + public long MinChargeDamageMultiplier { get; set; } + + [JsonProperty("MaxChargeDamageMultiplier")] + public long MaxChargeDamageMultiplier { get; set; } + + [JsonProperty("EquipAnimRate")] + public long EquipAnimRate { get; set; } + + [JsonProperty("QuickBarSlotCooldownDuration")] + public long QuickBarSlotCooldownDuration { get; set; } + } + + public partial class WeaponStatParser + { + public static WeaponStatParser FromJson(string json) => JsonConvert.DeserializeObject(json, FModel.Parser.Weapons.Converter.Settings); + } + + public static class Serialize + { + public static string ToJson(this WeaponStatParser self) => JsonConvert.SerializeObject(self, FModel.Parser.Weapons.Converter.Settings); + } + + internal static class Converter + { + public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings + { + MetadataPropertyHandling = MetadataPropertyHandling.Ignore, + DateParseHandling = DateParseHandling.None, + Converters = + { + new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } + }, + }; + } + + internal class ParseStringConverter : JsonConverter + { + public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?); + + public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) return null; + var value = serializer.Deserialize(reader); + long l; + if (Int64.TryParse(value, out l)) + { + return l; + } + throw new Exception("Cannot unmarshal type long"); + } + + public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer) + { + if (untypedValue == null) + { + serializer.Serialize(writer, null); + return; + } + var value = (long)untypedValue; + serializer.Serialize(writer, value.ToString()); + return; + } + + public static readonly ParseStringConverter Singleton = new ParseStringConverter(); + } +} diff --git a/FModel/Properties/Resources.Designer.cs b/FModel/Properties/Resources.Designer.cs index 170fccad..d70beca0 100644 --- a/FModel/Properties/Resources.Designer.cs +++ b/FModel/Properties/Resources.Designer.cs @@ -110,6 +110,16 @@ namespace FModel.Properties { } } + /// + /// Recherche une ressource localisée de type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap dmg64 { + get { + object obj = ResourceManager.GetObject("dmg64", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + /// /// Recherche une ressource localisée de type System.Drawing.Bitmap. /// diff --git a/FModel/Properties/Resources.resx b/FModel/Properties/Resources.resx index 3bb7f365..6e2d18d3 100644 --- a/FModel/Properties/Resources.resx +++ b/FModel/Properties/Resources.resx @@ -208,4 +208,7 @@ ..\Resources\Challenges_Slider.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\dmg64.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + \ No newline at end of file diff --git a/FModel/Resources/Quest.png b/FModel/Resources/Quest.png deleted file mode 100644 index e1770444f6cde08c4cc0eb82b56337a256d73103..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 77902 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