diff --git a/README.md b/README.md
index f88fef48..db04a5b6 100644
--- a/README.md
+++ b/README.md
@@ -13,12 +13,14 @@ Works with all expansions!
- Powerful search
- Cheats
- Items
- - Extract relic/charm from items at no cost, keeping both
- - Modify the relic/charm/artefact completion bonus
- - Complete relic/charm from a single piece
- - Craft an artifact from its recipe
- - Create missing set pieces
+ - [Extract relic/charm from items at no cost, keeping both](documentation/AFFIXES.md#RelicRemoval)
+ - [Modify the relic/charm/artefact completion bonus](documentation/AFFIXES.md#RelicCompletion)
+ - [Complete relic/charm from a single piece](documentation/AFFIXES.md#RelicCompleteStack)
+ - [Craft an artifact from its recipe](documentation/AFFIXES.md#Formula)
+ - [Change item seed](documentation/AFFIXES.md#Seed)
+ - [Create missing set pieces](documentation/AFFIXES.md#MissingSetPiece)
- [Craft custom items](/documentation/FORGE.md)
+ - [Change items affixes](documentation/AFFIXES.md)
- Duplicate any item
- Characters
- Redisribute attribute points
diff --git a/TQVaultAE.sln b/TQVaultAE.sln
index 90d2a3e0..e2eb44c2 100644
--- a/TQVaultAE.sln
+++ b/TQVaultAE.sln
@@ -11,6 +11,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TQVaultAE.GUI", "src\TQVaul
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{20915EFE-C25B-499E-9CB6-5888F29BC32F}"
ProjectSection(SolutionItems) = preProject
+ documentation\AFFIXES.md = documentation\AFFIXES.md
CHANGELOG.md = CHANGELOG.md
CONTRIBUTING.md = CONTRIBUTING.md
documentation\FORGE.md = documentation\FORGE.md
diff --git a/documentation/AFFIXES.md b/documentation/AFFIXES.md
new file mode 100644
index 00000000..b12df3d3
--- /dev/null
+++ b/documentation/AFFIXES.md
@@ -0,0 +1,106 @@
+# Item editing features
+
+Beside the [Forge](FORGE.md) that can be overkill, TQvault let you tweek some items in a respectful manner.
+
+You can choose item affixes from regular loot table instead of farming duplicate and using the forge.
+
+### _Theory crafting made easy!!_
+
+_**Note : "Item editing feature" must be enable in the settings.**_
+
+---
+
+## Table of contents
+* [Prefix change](#Prefix)
+* [Suffix change](#Suffix)
+* [Broken items](#Broken)
+* [Affixes removal](#Remove)
+* [Affixes display mode](#DisplayMode)
+* [Artefact creation](#Formula)
+* [Artefact completion bonus change](#Artefact)
+* [Relic and charm completion](#RelicCompleteStack)
+* [Relic and charm completion bonus change](#RelicCompletion)
+* [Relics removal](#RelicRemoval)
+* [Socketed relic and charm completion bonus change](#SocketedRelicCompletion)
+* [Item seed change](#Seed)
+* [Create missing set pieces](#MissingSetPiece)
+
+---
+
+### Prefix change
+
+
+
+---
+
+### Suffix change
+
+
+
+---
+
+### Broken affix when available
+
+
+
+---
+
+### Affixes removal
+
+
+
+---
+
+### Affixes display mode
+
+
+
+---
+
+### Artefact creation
+
+
+
+---
+
+### Artefact completion bonus change
+
+
+
+---
+
+### Relic and charm completion
+
+
+
+---
+
+### Relic and charm completion bonus change
+
+
+
+---
+
+### Socketed relic and charm completion bonus change
+
+
+
+---
+
+### Relics removal
+
+
+
+---
+
+### Item seed change
+
+|  | 
+
+---
+
+### Create missing set pieces
+
+
+
+
diff --git a/documentation/affixes/artefactcompletion.png b/documentation/affixes/artefactcompletion.png
new file mode 100644
index 00000000..658eb4c8
Binary files /dev/null and b/documentation/affixes/artefactcompletion.png differ
diff --git a/documentation/affixes/artefactcreation.png b/documentation/affixes/artefactcreation.png
new file mode 100644
index 00000000..b1cc4a7b
Binary files /dev/null and b/documentation/affixes/artefactcreation.png differ
diff --git a/documentation/affixes/broken.png b/documentation/affixes/broken.png
new file mode 100644
index 00000000..09e32ad0
Binary files /dev/null and b/documentation/affixes/broken.png differ
diff --git a/documentation/affixes/displaymode.png b/documentation/affixes/displaymode.png
new file mode 100644
index 00000000..7db6dc07
Binary files /dev/null and b/documentation/affixes/displaymode.png differ
diff --git a/documentation/affixes/missingset.png b/documentation/affixes/missingset.png
new file mode 100644
index 00000000..96a7590a
Binary files /dev/null and b/documentation/affixes/missingset.png differ
diff --git a/documentation/affixes/prefix.png b/documentation/affixes/prefix.png
new file mode 100644
index 00000000..ac7a50f7
Binary files /dev/null and b/documentation/affixes/prefix.png differ
diff --git a/documentation/affixes/reliccompletestack.png b/documentation/affixes/reliccompletestack.png
new file mode 100644
index 00000000..89201fec
Binary files /dev/null and b/documentation/affixes/reliccompletestack.png differ
diff --git a/documentation/affixes/reliccompletion.png b/documentation/affixes/reliccompletion.png
new file mode 100644
index 00000000..3f4a7c94
Binary files /dev/null and b/documentation/affixes/reliccompletion.png differ
diff --git a/documentation/affixes/removeaffixes.png b/documentation/affixes/removeaffixes.png
new file mode 100644
index 00000000..52614250
Binary files /dev/null and b/documentation/affixes/removeaffixes.png differ
diff --git a/documentation/affixes/removerelic.png b/documentation/affixes/removerelic.png
new file mode 100644
index 00000000..6457c913
Binary files /dev/null and b/documentation/affixes/removerelic.png differ
diff --git a/documentation/affixes/seed1.png b/documentation/affixes/seed1.png
new file mode 100644
index 00000000..b8bad89c
Binary files /dev/null and b/documentation/affixes/seed1.png differ
diff --git a/documentation/affixes/seed2.png b/documentation/affixes/seed2.png
new file mode 100644
index 00000000..5fefa8a9
Binary files /dev/null and b/documentation/affixes/seed2.png differ
diff --git a/documentation/affixes/socketedreliccompletion.png b/documentation/affixes/socketedreliccompletion.png
new file mode 100644
index 00000000..22031b9a
Binary files /dev/null and b/documentation/affixes/socketedreliccompletion.png differ
diff --git a/documentation/affixes/suffix.png b/documentation/affixes/suffix.png
new file mode 100644
index 00000000..03c1c213
Binary files /dev/null and b/documentation/affixes/suffix.png differ
diff --git a/src/TQVaultAE.Data/Database.cs b/src/TQVaultAE.Data/Database.cs
index d6131739..62fa3b00 100644
--- a/src/TQVaultAE.Data/Database.cs
+++ b/src/TQVaultAE.Data/Database.cs
@@ -3,700 +3,856 @@
// Copyright (c) Brandon Wallace and Jesse Calhoun. All rights reserved.
//
//-----------------------------------------------------------------------
-namespace TQVaultAE.Data
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Text.RegularExpressions;
+using TQVaultAE.Config;
+using TQVaultAE.Domain.Contracts.Providers;
+using TQVaultAE.Domain.Contracts.Services;
+using TQVaultAE.Domain.Entities;
+using TQVaultAE.Domain.Helpers;
+using TQVaultAE.Logs;
+
+namespace TQVaultAE.Data;
+
+///
+/// Reads a Titan Quest database file.
+///
+public class Database : IDatabase
{
- using Microsoft.Extensions.Logging;
- using System;
- using System.Collections.Concurrent;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Text.RegularExpressions;
- using TQVaultAE.Config;
- using TQVaultAE.Domain.Contracts.Providers;
- using TQVaultAE.Domain.Contracts.Services;
- using TQVaultAE.Domain.Entities;
- using TQVaultAE.Domain.Helpers;
- using TQVaultAE.Logs;
+ private const StringComparison noCase = StringComparison.OrdinalIgnoreCase;
+
+ #region Record Class Names
+
+ private const string RCLASS_LOOTRANDOMIZER = "LootRandomizer";
+ private const string RCLASS_LOOTITEMTABLE_FIXEDWEIGHT = "LootItemTable_FixedWeight";
+ private const string RCLASS_LOOTITEMTABLE_DYNWEIGHT = "LootItemTable_DynWeight";
+
+ #endregion
+
+ private readonly ILogger Log = null;
+
+ #region Database Fields
+
+ ///
+ /// Dictionary of all database info records
+ ///
+ private LazyConcurrentDictionary infoDB = new LazyConcurrentDictionary();
+
+ ///
+ /// Dictionary of all text database entries
+ ///
+ private ConcurrentDictionary textDB = new ConcurrentDictionary();
+
+ ///
+ /// Dictionary of all associated arc files in the database.
+ ///
+ private LazyConcurrentDictionary arcFiles = new LazyConcurrentDictionary();
+
+ ///
+ /// Dictionary of all records dataset loaded from the database.
+ ///
+ private LazyConcurrentDictionary resourcesData = new LazyConcurrentDictionary();
+
+ ///
+ /// Dictionary of all record collections loaded from the database.
+ ///
+ private LazyConcurrentDictionary dbRecordCollections = new LazyConcurrentDictionary();
///
- /// Reads a Titan Quest database file.
+ /// Game language to support setting language in UI
///
- public class Database : IDatabase
+ private string gameLanguage;
+
+ private readonly IArcFileProvider arcProv;
+ private readonly IArzFileProvider arzProv;
+ private readonly IItemAttributeProvider ItemAttributeProvider;
+ private readonly IGamePathService GamePathResolver;
+ private readonly ITQDataService TQData;
+
+ #endregion Database Fields
+
+ ///
+ /// Initializes a new instance of the Database class.
+ ///
+ public Database(
+ ILogger log
+ , IArcFileProvider arcFileProvider
+ , IArzFileProvider arzFileProvider
+ , IItemAttributeProvider itemAttributeProvider
+ , IGamePathService gamePathResolver
+ , ITQDataService tQData
+ )
{
- private readonly ILogger Log = null;
-
- #region Database Fields
-
- ///
- /// Dictionary of all database info records
- ///
- private LazyConcurrentDictionary infoDB = new LazyConcurrentDictionary();
-
- ///
- /// Dictionary of all text database entries
- ///
- private ConcurrentDictionary textDB = new ConcurrentDictionary();
-
- ///
- /// Dictionary of all associated arc files in the database.
- ///
- private LazyConcurrentDictionary arcFiles = new LazyConcurrentDictionary();
-
- ///
- /// Dictionary of all records dataset loaded from the database.
- ///
- private LazyConcurrentDictionary resourcesData = new LazyConcurrentDictionary();
-
- ///
- /// Dictionary of all record collections loaded from the database.
- ///
- private LazyConcurrentDictionary dbRecordCollections = new LazyConcurrentDictionary();
-
- ///
- /// Game language to support setting language in UI
- ///
- private string gameLanguage;
-
- private readonly IArcFileProvider arcProv;
- private readonly IArzFileProvider arzProv;
- private readonly IItemAttributeProvider ItemAttributeProvider;
- private readonly IGamePathService GamePathResolver;
- private readonly ITQDataService TQData;
-
- #endregion Database Fields
-
- ///
- /// Initializes a new instance of the Database class.
- ///
- public Database(
- ILogger log
- , IArcFileProvider arcFileProvider
- , IArzFileProvider arzFileProvider
- , IItemAttributeProvider itemAttributeProvider
- , IGamePathService gamePathResolver
- , ITQDataService tQData
- )
- {
- this.Log = log;
- this.AutoDetectLanguage = Config.Settings.Default.AutoDetectLanguage;
- this.TQLanguage = Config.Settings.Default.TQLanguage;
- this.arcProv = arcFileProvider;
- this.arzProv = arzFileProvider;
- this.ItemAttributeProvider = itemAttributeProvider;
- this.GamePathResolver = gamePathResolver;
- this.TQData = tQData;
- this.LoadDBFile();
- }
+ this.Log = log;
+ this.AutoDetectLanguage = Config.Settings.Default.AutoDetectLanguage;
+ this.TQLanguage = Config.Settings.Default.TQLanguage;
+ this.arcProv = arcFileProvider;
+ this.arzProv = arzFileProvider;
+ this.ItemAttributeProvider = itemAttributeProvider;
+ this.GamePathResolver = gamePathResolver;
+ this.TQData = tQData;
+ this.LoadDBFile();
+ }
- #region Database Properties
+ #region Database Properties
- ///
- /// Gets or sets a value indicating whether the game language is being auto detected.
- ///
- public bool AutoDetectLanguage { get; set; }
+ ///
+ /// Mapping between ItemId and Affixes LootTable
+ ///
+ private static ReadOnlyDictionary> ItemAffixTableMap;
- ///
- /// Gets or sets the game language from the config file.
- ///
- public string TQLanguage { get; set; }
+ ///
+ /// Gets or sets a value indicating whether the game language is being auto detected.
+ ///
+ public bool AutoDetectLanguage { get; set; }
+ ///
+ /// Gets or sets the game language from the config file.
+ ///
+ public string TQLanguage { get; set; }
- ///
- /// Gets the instance of the Titan Quest Database ArzFile.
- ///
- public ArzFile ArzFile { get; private set; }
- ///
- /// Gets the instance of the Immortal Throne Database ArzFile.
- ///
- public ArzFile ArzFileIT { get; private set; }
+ ///
+ /// Gets the instance of the Titan Quest Database ArzFile.
+ ///
+ public ArzFile ArzFile { get; private set; }
+
+ ///
+ /// Gets the instance of the Immortal Throne Database ArzFile.
+ ///
+ public ArzFile ArzFileIT { get; private set; }
- ///
- /// Gets the instance of a custom map Database ArzFile.
- ///
- public ArzFile ArzFileMod { get; private set; }
+ ///
+ /// Gets the instance of a custom map Database ArzFile.
+ ///
+ public ArzFile ArzFileMod { get; private set; }
- ///
- /// Gets the game language setting as a an English DisplayName.
- ///
- /// Changed to property by VillageIdiot to support changing of Language in UI
- public string GameLanguage
+ ///
+ /// Gets the game language setting as a an English DisplayName.
+ ///
+ /// Changed to property by VillageIdiot to support changing of Language in UI
+ public string GameLanguage
+ {
+ get
{
- get
+ // Added by VillageIdiot
+ // Check if the user configured the language
+ if (this.gameLanguage == null)
{
- // Added by VillageIdiot
- // Check if the user configured the language
- if (this.gameLanguage == null)
- {
- if (!this.AutoDetectLanguage)
- this.gameLanguage = this.TQLanguage;
- }
+ if (!this.AutoDetectLanguage)
+ this.gameLanguage = this.TQLanguage;
+ }
- // Try to read the language from the settings file
- if (string.IsNullOrEmpty(this.gameLanguage))
+ // Try to read the language from the settings file
+ if (string.IsNullOrEmpty(this.gameLanguage))
+ {
+ try
{
- try
+ string optionsFile = GamePathResolver.TQSettingsFile;
+ if (!File.Exists(optionsFile))
{
- string optionsFile = GamePathResolver.TQSettingsFile;
- if (!File.Exists(optionsFile))
- {
- // Try IT Folder if there is no settings file in TQ Folder
- optionsFile = GamePathResolver.ITSettingsFile;
- }
- if (File.Exists(optionsFile))
+ // Try IT Folder if there is no settings file in TQ Folder
+ optionsFile = GamePathResolver.ITSettingsFile;
+ }
+ if (File.Exists(optionsFile))
+ {
+ var fileContent = File.ReadAllText(optionsFile);
+ var match = Regex.Match(fileContent, @"(?i)language\s*=\s*(""(?[^""]+)""|(?[^\r\n]*))[\r\n]");
+ if (match.Success)
{
- var fileContent = File.ReadAllText(optionsFile);
- var match = Regex.Match(fileContent, @"(?i)language\s*=\s*(""(?[^""]+)""|(?[^\r\n]*))[\r\n]");
- if (match.Success)
- {
- this.gameLanguage = match.Groups["Language"].Value.ToUpperInvariant();
- return this.gameLanguage;
- }
-
- return null;
+ this.gameLanguage = match.Groups["Language"].Value.ToUpperInvariant();
+ return this.gameLanguage;
}
return null;
}
- catch (IOException exception)
- {
- Log.ErrorException(exception);
- return null;
- }
- }
- // Added by VillageIdiot
- // We have something so we need to return it
- // This was added to support setting the language in the config file
- return this.gameLanguage;
+ return null;
+ }
+ catch (IOException exception)
+ {
+ Log.ErrorException(exception);
+ return null;
+ }
}
+
+ // Added by VillageIdiot
+ // We have something so we need to return it
+ // This was added to support setting the language in the config file
+ return this.gameLanguage;
}
+ }
- #endregion Database Properties
+ #endregion Database Properties
- #region Database Public Methods
+ #region Database Public Methods
- #region Database Public Static Methods
+ #region Database Public Static Methods
- ///
- /// Used to Extract an ARC file into the destination directory.
- /// The ARC file will not be added to the cache.
- ///
- /// Added by VillageIdiot
- /// Name of the arc file
- /// Destination path for extracted data
- /// Returns true on success otherwise false
- public bool ExtractArcFile(string arcFileName, string destination)
+ ///
+ /// Used to Extract an ARC file into the destination directory.
+ /// The ARC file will not be added to the cache.
+ ///
+ /// Added by VillageIdiot
+ /// Name of the arc file
+ /// Destination path for extracted data
+ /// Returns true on success otherwise false
+ public bool ExtractArcFile(string arcFileName, string destination)
+ {
+ bool result = false;
+
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Database.ExtractARCFile('{0}', '{1}')", arcFileName, destination);
+
+ try
{
- bool result = false;
+ ArcFile arcFile = new ArcFile(arcFileName);
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Database.ExtractARCFile('{0}', '{1}')", arcFileName, destination);
+ // Extract the files
+ result = arcProv.ExtractArcFile(arcFile, destination);
+ }
+ catch (IOException exception)
+ {
+ Log.LogError(exception, "Exception occurred");
+ result = false;
+ }
- try
- {
- ArcFile arcFile = new ArcFile(arcFileName);
+ if (TQDebug.DatabaseDebugLevel > 1)
+ Log.LogDebug("Extraction Result = {0}", result);
- // Extract the files
- result = arcProv.ExtractArcFile(arcFile, destination);
- }
- catch (IOException exception)
- {
- Log.LogError(exception, "Exception occurred");
- result = false;
- }
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Exiting Database.ReadARCFile()");
- if (TQDebug.DatabaseDebugLevel > 1)
- Log.LogDebug("Extraction Result = {0}", result);
+ return result;
+ }
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exiting Database.ReadARCFile()");
+ #endregion Database Public Static Methods
- return result;
- }
+ ///
+ /// Gets the Infor for a specific item id.
+ ///
+ /// Item ID which we are looking up. Will be normalized internally.
+ /// Returns Infor for item ID and NULL if not found.
+ public Info GetInfo(string itemId)
+ {
+ if (string.IsNullOrEmpty(itemId))
+ return null;
- #endregion Database Public Static Methods
+ itemId = TQData.NormalizeRecordPath(itemId);
- ///
- /// Gets the Infor for a specific item id.
- ///
- /// Item ID which we are looking up. Will be normalized internally.
- /// Returns Infor for item ID and NULL if not found.
- public Info GetInfo(string itemId)
+ return this.infoDB.GetOrAddAtomic(itemId, k =>
{
- if (string.IsNullOrEmpty(itemId))
+ DBRecordCollection record = GetRecordFromFile(k);
+
+ if (record == null)
return null;
- itemId = TQData.NormalizeRecordPath(itemId);
+ return new Info(record);
+ });
+ }
- return this.infoDB.GetOrAddAtomic(itemId, k =>
- {
- DBRecordCollection record = GetRecordFromFile(k);
+ ///
+ /// Uses the text database to convert the tag to a name in the localized language.
+ /// The tag is normalized to upper case internally.
+ ///
+ /// Tag to be looked up in the text database normalized to upper case.
+ /// Returns localized string, empty string if it cannot find a string or "?ErrorName?" in case of uncaught exception.
+ public string GetFriendlyName(string tagId)
+ => this.textDB.TryGetValue(tagId.ToUpperInvariant(), out var text) ? text : string.Empty;
- if (record == null)
- return null;
+ ///
+ /// Gets the formatted string for the variable attribute.
+ ///
+ /// variable for which we are making a nice string.
+ /// Formatted string in the format of: Attribute: value
+ public string VariableToStringNice(Variable variable)
+ => $"{this.GetItemAttributeFriendlyText(variable.Name)}: {variable.ToStringValue()}";
- return new Info(record);
- });
+ ///
+ /// Converts the item attribute to a name in the localized language
+ ///
+ /// Item attribure to be looked up.
+ /// Flag for whether the variable is added to the text string.
+ /// Returns localized item attribute
+ public string GetItemAttributeFriendlyText(string itemAttribute, bool addVariable = true)
+ {
+ ItemAttributesData data = ItemAttributeProvider.GetAttributeData(itemAttribute);
+ if (data == null)
+ {
+ this.Log.LogDebug($"Attribute unknown : {itemAttribute}");
+ return string.Concat("?", itemAttribute, "?");
}
- ///
- /// Uses the text database to convert the tag to a name in the localized language.
- /// The tag is normalized to upper case internally.
- ///
- /// Tag to be looked up in the text database normalized to upper case.
- /// Returns localized string, empty string if it cannot find a string or "?ErrorName?" in case of uncaught exception.
- public string GetFriendlyName(string tagId)
- => this.textDB.TryGetValue(tagId.ToUpperInvariant(), out var text) ? text : string.Empty;
-
- ///
- /// Gets the formatted string for the variable attribute.
- ///
- /// variable for which we are making a nice string.
- /// Formatted string in the format of: Attribute: value
- public string VariableToStringNice(Variable variable)
- => $"{this.GetItemAttributeFriendlyText(variable.Name)}: {variable.ToStringValue()}";
-
- ///
- /// Converts the item attribute to a name in the localized language
- ///
- /// Item attribure to be looked up.
- /// Flag for whether the variable is added to the text string.
- /// Returns localized item attribute
- public string GetItemAttributeFriendlyText(string itemAttribute, bool addVariable = true)
- {
- ItemAttributesData data = ItemAttributeProvider.GetAttributeData(itemAttribute);
- if (data == null)
- {
- this.Log.LogDebug($"Attribute unknown : {itemAttribute}");
- return string.Concat("?", itemAttribute, "?");
- }
+ string attributeTextTag = ItemAttributeProvider.GetAttributeTextTag(data);
+ if (string.IsNullOrEmpty(attributeTextTag))
+ {
+ this.Log.LogDebug($"Attribute unknown : {itemAttribute}");
+ return string.Concat("?", itemAttribute, "?");
+ }
+
+ string textFromTag = this.GetFriendlyName(attributeTextTag);
+ if (string.IsNullOrEmpty(textFromTag))
+ {
+ textFromTag = string.Concat("ATTR<", itemAttribute, "> TAG<");
+ textFromTag = string.Concat(textFromTag, attributeTextTag, ">");
+ }
- string attributeTextTag = ItemAttributeProvider.GetAttributeTextTag(data);
- if (string.IsNullOrEmpty(attributeTextTag))
+ if (addVariable && data.Variable.Length > 0)
+ textFromTag = string.Concat(textFromTag, " ", data.Variable);
+
+ return textFromTag;
+ }
+
+ ///
+ /// Load our data from the db file.
+ ///
+ private void LoadDBFile()
+ {
+ this.LoadTextDB();
+ this.LoadARZFile();
+ this.BuildItemAffixTableMap();
+ }
+
+ ///
+ /// Extract all LootRandomizer
+ ///
+ ///
+ public ReadOnlyCollection ReadLootRandomizerList()
+ {
+ // Load all available loot randomizer
+ var lootRandomizerList = new[] { this.ArzFileMod, this.ArzFile }
+ .Where(db => db is not null)
+ .SelectMany(db =>
+ db.RecordInfo.Where(r => r.Value.RecordType.Equals(RCLASS_LOOTRANDOMIZER, noCase))
+ )
+ .Select(r =>
{
- this.Log.LogDebug($"Attribute unknown : {itemAttribute}");
- return string.Concat("?", itemAttribute, "?");
- }
+ var rec = GetRecordFromFile(r.Key);
+
+ string Tag = rec.GetString(Variable.KEY_LOOTRANDNAME, 0);
+ int Cost = rec.GetInt32(Variable.KEY_LOOTRANDCOST, 0);
+ int LevelRequirement = rec.GetInt32(Variable.KEY_LEVELREQ, 0);
+ string ItemClass = rec.GetString(Variable.KEY_ITEMCLASS, 0);
+ string FileDescription = rec.GetString(Variable.KEY_FILEDESC, 0);
+
+ var IsEmpty = string.IsNullOrWhiteSpace(Tag)
+ && string.IsNullOrWhiteSpace(ItemClass)
+ && string.IsNullOrWhiteSpace(FileDescription)
+ && Cost == 0
+ && LevelRequirement == 0;
+
+ if (IsEmpty) return null;
+
+ var prettyFileName = r.Value.ID.PrettyFileName();// Use r.Value.ID because i need the non Normalized record Id
+ var exploded = prettyFileName.ExplodePrettyFileName();
+ var val = new LootRandomizerItem(
+ r.Key
+ , Tag
+ , Cost
+ , LevelRequirement
+ , ItemClass
+ , FileDescription
+ , string.Empty // Translation
+ , prettyFileName
+ , exploded.Effect
+ , exploded.Number
+ );
+
+ return val;
+ })
+ .Where(db => db is not null)
+ .ToList().AsReadOnly();
+
+ return lootRandomizerList;
+ }
+
+ #region ItemAffixTableMap
+
- string textFromTag = this.GetFriendlyName(attributeTextTag);
- if (string.IsNullOrEmpty(textFromTag))
+ ///
+ /// Create a map between Items and affix loot tables
+ ///
+ private void BuildItemAffixTableMap()
+ {
+ // Load all available loot table
+ var data = new[] { this.ArzFileMod, this.ArzFile }
+ .Where(db => db is not null)
+ .SelectMany(db => db.RecordInfo
+ .Where(r =>
+ r.Value.RecordType.Equals(RCLASS_LOOTITEMTABLE_FIXEDWEIGHT, noCase)
+ || r.Value.RecordType.Equals(RCLASS_LOOTITEMTABLE_DYNWEIGHT, noCase)
+ )
+ )
+ .Select(r =>
{
- textFromTag = string.Concat("ATTR<", itemAttribute, "> TAG<");
- textFromTag = string.Concat(textFromTag, attributeTextTag, ">");
- }
+ var rec = GetRecordFromFile(r.Key);
+ var lootNames = new List();
+ var records = new List<(string brokenTable, string prefixTable, string suffixTable, List lootNames)>();
- if (addVariable && data.Variable.Length > 0)
- textFromTag = string.Concat(textFromTag, " ", data.Variable);
+ int forceReadMax = 3, lootTableIdx = 1;
- return textFromTag;
- }
+ // Read loot names
+ switch (r.Value.RecordType)
+ {
+ case RCLASS_LOOTITEMTABLE_FIXEDWEIGHT:
+ int lootNameIdx = 0;
+ bool noMore = false;
+ do // Because sometimes it start at "lootName2"
+ {
+ var name = "lootName" + ++lootNameIdx;
+ var lootName = rec.GetString(name, 0);
+ var haslootName = !string.IsNullOrWhiteSpace(lootName);
+ if (!haslootName)
+ {
+ if (lootNameIdx <= forceReadMax) continue;
+
+ noMore = true; continue;
+ }
+
+ lootNames.Add(lootName);
+ }
+ while (!noMore);
+
+ break;
+ default: // LootItemTable_DynWeight
+ var itemNames = rec.GetAllStrings("itemNames");
+ if (itemNames is not null && itemNames.Length > 0)
+ lootNames.AddRange(itemNames);
+ break;
+ }
+
+ // Read loot tables
+ bool isOver;
+ do
+ {
+ var brokenTable = rec.GetString("brokenRandomizerName" + lootTableIdx, 0);
+ var prefixTable = rec.GetString("prefixRandomizerName" + lootTableIdx, 0);
+ var suffixTable = rec.GetString("suffixRandomizerName" + lootTableIdx, 0);
+
+ isOver = string.IsNullOrWhiteSpace(brokenTable)
+ && string.IsNullOrWhiteSpace(prefixTable)
+ && string.IsNullOrWhiteSpace(suffixTable);
+
+ if (isOver) continue;
+
+ if (lootNames.Count > 0)
+ records.Add((brokenTable, prefixTable, suffixTable, lootNames));
+
+ lootTableIdx++;
+ }
+ while (!isOver);
+
+ return records;
+ })
+ .SelectMany(i => i)
+ .SelectMany(itemAffix => itemAffix.lootNames
+ .Select(itemId => new
+ {
+ itemId = TQData.NormalizeRecordPath(itemId),
+ itemAffix.suffixTable,
+ itemAffix.prefixTable,
+ itemAffix.brokenTable
+ })
+ ) // Flatten
+ .GroupBy(i => i.itemId)
+ .ToDictionary(i =>
+ i.Key
+ , j => j
+ .Select(k => new AffixTableMapItem(k.brokenTable, k.prefixTable, k.suffixTable)).Distinct()
+ .ToList().AsReadOnly()
+ );
+
+ ItemAffixTableMap = new ReadOnlyDictionary>(data);
+ }
+
+ public ReadOnlyCollection GetItemAffixTableMap(string itemId)
+ {
+ itemId = TQData.NormalizeRecordPath(itemId);
+
+ var affixmap = ItemAffixTableMap.SingleOrDefault(i => i.Key == itemId);
+ if (affixmap.Key is null) return null;
+
+ return affixmap.Value;
+ }
+
+ #endregion
+
+ ///
+ /// Gets a DBRecord for the specified item ID string.
+ ///
+ ///
+ /// Changed by VillageIdiot
+ /// Changed search order so that IT records have precedence of TQ records.
+ /// Add Custom Map database. Custom Map records have precedence over IT records.
+ ///
+ /// Item Id which we are looking up
+ /// Returns the DBRecord for the item Id
+ public DBRecordCollection GetRecordFromFile(string itemId)
+ {
+ itemId = TQData.NormalizeRecordPath(itemId);
- ///
- /// Load our data from the db file.
- ///
- private void LoadDBFile()
+ var cachedDBRecordCollection = this.dbRecordCollections.GetOrAddAtomic(itemId, key =>
{
- this.LoadTextDB();
- this.LoadARZFile();
- }
- ///
- /// Gets a DBRecord for the specified item ID string.
- ///
- ///
- /// Changed by VillageIdiot
- /// Changed search order so that IT records have precedence of TQ records.
- /// Add Custom Map database. Custom Map records have precedence over IT records.
- ///
- /// Item Id which we are looking up
- /// Returns the DBRecord for the item Id
- public DBRecordCollection GetRecordFromFile(string itemId)
- {
- itemId = TQData.NormalizeRecordPath(itemId);
-
- var cachedDBRecordCollection = this.dbRecordCollections.GetOrAddAtomic(itemId, key =>
+ if (this.ArzFileMod != null)
{
-
- if (this.ArzFileMod != null)
+ DBRecordCollection recordMod = arzProv.GetItem(this.ArzFileMod, key);
+ if (recordMod != null)
{
- DBRecordCollection recordMod = arzProv.GetItem(this.ArzFileMod, key);
- if (recordMod != null)
- {
- // Custom Map records have highest precedence.
- return recordMod;
- }
+ // Custom Map records have highest precedence.
+ return recordMod;
}
+ }
- if (this.ArzFileIT != null)
+ if (this.ArzFileIT != null)
+ {
+ // see if it's in IT ARZ file
+ DBRecordCollection recordIT = arzProv.GetItem(this.ArzFileIT, key);
+ if (recordIT != null)
{
- // see if it's in IT ARZ file
- DBRecordCollection recordIT = arzProv.GetItem(this.ArzFileIT, key);
- if (recordIT != null)
- {
- // IT file takes precedence over TQ.
- return recordIT;
- }
+ // IT file takes precedence over TQ.
+ return recordIT;
}
+ }
- return arzProv.GetItem(ArzFile, key);
- });
+ return arzProv.GetItem(ArzFile, key);
+ });
+
+ return cachedDBRecordCollection;
+ }
- return cachedDBRecordCollection;
- }
+ ///
+ /// Gets a resource from the database using the resource Id.
+ /// Modified by VillageIdiot to support loading resources from a custom map folder.
+ ///
+ /// Resource which we are fetching
+ /// Retruns a byte array of the resource.
+ public byte[] LoadResource(string resourceId)
+ {
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Database.LoadResource({0})", resourceId);
+
+ resourceId = TQData.NormalizeRecordPath(resourceId);
- ///
- /// Gets a resource from the database using the resource Id.
- /// Modified by VillageIdiot to support loading resources from a custom map folder.
- ///
- /// Resource which we are fetching
- /// Retruns a byte array of the resource.
- public byte[] LoadResource(string resourceId)
+ if (TQDebug.DatabaseDebugLevel > 1)
+ Log.LogDebug(" Normalized({0})", resourceId);
+
+ byte[] cachedArcFileData = this.resourcesData.GetOrAddAtomic(resourceId, key =>
{
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Database.LoadResource({0})", resourceId);
+ var resourceIdSplited = key.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);// hguy : easier to understand than substring everywhere
- resourceId = TQData.NormalizeRecordPath(resourceId);
+ // not a proper resourceID.
+ if (resourceIdSplited.Length == 1)
+ return null;
+
+ // First we need to figure out the correct file to
+ // open, by grabbing it off the front of the resourceID
+
+ string arcFile; bool isDLC = false;
+ string rootFolder;
+ byte[] arcFileData = null;
+ string arcFileBase = resourceIdSplited.First();
if (TQDebug.DatabaseDebugLevel > 1)
- Log.LogDebug(" Normalized({0})", resourceId);
+ Log.LogDebug("arcFileBase = {0}", arcFileBase);
- byte[] cachedArcFileData = this.resourcesData.GetOrAddAtomic(resourceId, key =>
+ // Added by VillageIdiot
+ // Check the mod folder for the image resource.
+ if (GamePathResolver.IsCustom)
{
- var resourceIdSplited = key.Split(new[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);// hguy : easier to understand than substring everywhere
+ if (TQDebug.DatabaseDebugLevel > 1)
+ Log.LogDebug("Checking Custom Resources.");
- // not a proper resourceID.
- if (resourceIdSplited.Length == 1)
- return null;
+ rootFolder = Path.Combine(GamePathResolver.MapName, "resources");
- // First we need to figure out the correct file to
- // open, by grabbing it off the front of the resourceID
+ arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
+ arcFileData = this.ReadARCFile(arcFile, key);
- string arcFile; bool isDLC = false;
- string rootFolder;
- byte[] arcFileData = null;
- string arcFileBase = resourceIdSplited.First();
+ if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
+ Log.LogDebug(@"Custom resource found ""{resourceId}"" into ""{arcFile}""", key, arcFile);
+ }
+ // We either didn't load the resource or didn't find what we were looking for so check the normal game resources.
+ if (arcFileData == null)
+ {
+ // See if this guy is from Immortal Throne expansion pack.
if (TQDebug.DatabaseDebugLevel > 1)
- Log.LogDebug("arcFileBase = {0}", arcFileBase);
+ Log.LogDebug("Checking IT Resources.");
- // Added by VillageIdiot
- // Check the mod folder for the image resource.
- if (GamePathResolver.IsCustom)
+ (arcFile, isDLC) = this.GamePathResolver.ResolveArcFileName(key);
+ if (isDLC)
{
- if (TQDebug.DatabaseDebugLevel > 1)
- Log.LogDebug("Checking Custom Resources.");
+ // not a proper resourceID.
+ if (resourceIdSplited.Length == 2)
+ return null;
- rootFolder = Path.Combine(GamePathResolver.MapName, "resources");
+ arcFileBase = resourceIdSplited[1];
+ key = resourceIdSplited.Skip(1).JoinString("\\");
+ }
- arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
- arcFileData = this.ReadARCFile(arcFile, key);
+ arcFileData = this.ReadARCFile(arcFile, key);
- if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
- Log.LogDebug(@"Custom resource found ""{resourceId}"" into ""{arcFile}""", key, arcFile);
- }
+ if (TQDebug.DatabaseDebugLevel > 0 && arcFileData is null)
+ Log.LogError(@"Resource not found ""{resourceId}"" into ""{arcFile}""", key, arcFile);
+ }
- // We either didn't load the resource or didn't find what we were looking for so check the normal game resources.
- if (arcFileData == null)
- {
- // See if this guy is from Immortal Throne expansion pack.
- if (TQDebug.DatabaseDebugLevel > 1)
- Log.LogDebug("Checking IT Resources.");
+ #region Fallback : It looks like we never go there
- (arcFile, isDLC) = this.GamePathResolver.ResolveArcFileName(key);
- if (isDLC)
- {
- // not a proper resourceID.
- if (resourceIdSplited.Length == 2)
- return null;
+ // Added by VillageIdiot
+ // Maybe the arc file is in the XPack folder even though the record does not state it.
+ // Also could be that it says xpack in the record but the file is in the root.
+ if (arcFileData == null)
+ {
+ rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources", "XPack");
+ arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
+ arcFileData = this.ReadARCFile(arcFile, key);
- arcFileBase = resourceIdSplited[1];
- key = resourceIdSplited.Skip(1).JoinString("\\");
- }
+ if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
+ Log.LogError(@"Resource misplaced ""{resourceId}"" into ""{arcFile}""", key, arcFile);
+ }
- arcFileData = this.ReadARCFile(arcFile, key);
+ // Now, let's check if the item is in Ragnarok DLC
+ if (arcFileData == null && GamePathResolver.IsRagnarokInstalled)
+ {
+ rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources", "XPack2");
+ arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
+ arcFileData = this.ReadARCFile(arcFile, key);
- if (TQDebug.DatabaseDebugLevel > 0 && arcFileData is null)
- Log.LogError(@"Resource not found ""{resourceId}"" into ""{arcFile}""", key, arcFile);
- }
+ if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
+ Log.LogError(@"Resource misplaced ""{resourceId}"" into ""{arcFile}""", key, arcFile);
+ }
- #region Fallback : It looks like we never go there
+ if (arcFileData == null && GamePathResolver.IsAtlantisInstalled)
+ {
+ rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources", "XPack3");
+ arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
+ arcFileData = this.ReadARCFile(arcFile, key);
- // Added by VillageIdiot
- // Maybe the arc file is in the XPack folder even though the record does not state it.
- // Also could be that it says xpack in the record but the file is in the root.
- if (arcFileData == null)
- {
- rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources", "XPack");
- arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
- arcFileData = this.ReadARCFile(arcFile, key);
+ if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
+ Log.LogError(@"Resource misplaced ""{resourceId}"" into ""{arcFile}""", key, arcFile);
+ }
- if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
- Log.LogError(@"Resource misplaced ""{resourceId}"" into ""{arcFile}""", key, arcFile);
- }
+ if (arcFileData == null && GamePathResolver.IsEmbersInstalled)
+ {
+ rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources", "XPack4");
+ arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
+ arcFileData = this.ReadARCFile(arcFile, key);
- // Now, let's check if the item is in Ragnarok DLC
- if (arcFileData == null && GamePathResolver.IsRagnarokInstalled)
- {
- rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources", "XPack2");
- arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
- arcFileData = this.ReadARCFile(arcFile, key);
+ if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
+ Log.LogError(@"Resource misplaced ""{resourceId}"" into ""{arcFile}""", key, arcFile);
+ }
- if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
- Log.LogError(@"Resource misplaced ""{resourceId}"" into ""{arcFile}""", key, arcFile);
- }
+ if (arcFileData == null)
+ {
+ // We are either vanilla TQ or have not found our resource yet.
+ // from the original TQ folder
+ if (TQDebug.DatabaseDebugLevel > 1)
+ Log.LogDebug("Checking TQ Resources.");
- if (arcFileData == null && GamePathResolver.IsAtlantisInstalled)
- {
- rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources", "XPack3");
- arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
- arcFileData = this.ReadARCFile(arcFile, key);
+ rootFolder = GamePathResolver.TQPath;
+ rootFolder = Path.Combine(rootFolder, "Resources");
- if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
- Log.LogError(@"Resource misplaced ""{resourceId}"" into ""{arcFile}""", key, arcFile);
- }
+ arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
+ arcFileData = this.ReadARCFile(arcFile, key);
- if (arcFileData == null && GamePathResolver.IsEmbersInstalled)
- {
- rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources", "XPack4");
- arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
- arcFileData = this.ReadARCFile(arcFile, key);
+ if (TQDebug.DatabaseDebugLevel > 0 && arcFileData is null)
+ Log.LogError(@"Resource unknown ""{resourceId}""", key);
+ }
- if (TQDebug.DatabaseDebugLevel > 1 && arcFileData is not null)
- Log.LogError(@"Resource misplaced ""{resourceId}"" into ""{arcFile}""", key, arcFile);
- }
+ #endregion
- if (arcFileData == null)
- {
- // We are either vanilla TQ or have not found our resource yet.
- // from the original TQ folder
- if (TQDebug.DatabaseDebugLevel > 1)
- Log.LogDebug("Checking TQ Resources.");
+ return arcFileData;
+ });
- rootFolder = GamePathResolver.TQPath;
- rootFolder = Path.Combine(rootFolder, "Resources");
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Exiting Database.LoadResource()");
- arcFile = Path.Combine(rootFolder, Path.ChangeExtension(arcFileBase, ".arc"));
- arcFileData = this.ReadARCFile(arcFile, key);
+ return cachedArcFileData;
+ }
- if (TQDebug.DatabaseDebugLevel > 0 && arcFileData is null)
- Log.LogError(@"Resource unknown ""{resourceId}""", key);
- }
- #endregion
+ #endregion Database Public Methods
- return arcFileData;
- });
+ #region Database Private Methods
+
+ ///
+ /// Reads data from an ARC file and puts it into a Byte array
+ ///
+ /// Name of the arc file.
+ /// Id of data which we are getting from the arc file
+ /// Byte array of the data from the arc file.
+ private byte[] ReadARCFile(string arcFileName, string dataId)
+ {
+ // See if we have this arcfile already and if not create it.
+ try
+ {
if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exiting Database.LoadResource()");
+ Log.LogDebug("Database.ReadARCFile('{0}', '{1}')", arcFileName, dataId);
- return cachedArcFileData;
- }
+ ArcFile arcFile = ReadARCFile(arcFileName);
+ // Now retrieve the data
+ byte[] ans = arcProv.GetData(arcFile, dataId);
- #endregion Database Public Methods
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Exiting Database.ReadARCFile()");
- #region Database Private Methods
+ return ans;
+ }
+ catch (Exception e)
+ {
+ Log.LogError(e, "Exception occurred");
+ throw;
+ }
+ }
+ ///
+ /// Read ARC file
+ ///
+ ///
+ ///
+ public ArcFile ReadARCFile(string arcFileName)
+ {
+ // See if we have this arcfile already and if not create it.
- ///
- /// Reads data from an ARC file and puts it into a Byte array
- ///
- /// Name of the arc file.
- /// Id of data which we are getting from the arc file
- /// Byte array of the data from the arc file.
- private byte[] ReadARCFile(string arcFileName, string dataId)
+ ArcFile arcFile = this.arcFiles.GetOrAddAtomic(arcFileName, k =>
{
- // See if we have this arcfile already and if not create it.
- try
- {
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Database.ReadARCFile('{0}', '{1}')", arcFileName, dataId);
+ var file = new ArcFile(k);
+ arcProv.ReadARCToC(file);// Heavy lifting in GetOrAddAtomic
+ return file;
+ });
- ArcFile arcFile = ReadARCFile(arcFileName);
+ return arcFile;
+ }
- // Now retrieve the data
- byte[] ans = arcProv.GetData(arcFile, dataId);
+ ///
+ /// Tries to determine the name of the text database file.
+ /// This is based on the game language and the UI language.
+ /// Will use English if all else fails.
+ ///
+ /// Signals whether we are looking for Immortal Throne files or vanilla Titan Quest files.
+ /// Path to the text db file
+ private string FigureDBFileToUse(bool isImmortalThrone)
+ {
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Database.FigureDBFileToUse({0})", isImmortalThrone);
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exiting Database.ReadARCFile()");
+ string rootFolder;
+ if (isImmortalThrone)
+ {
+ if (GamePathResolver.ImmortalThronePath.Contains("Anniversary"))
+ rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Text");
+ else
+ rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources");
- return ans;
- }
- catch (Exception e)
+ if (TQDebug.DatabaseDebugLevel > 1)
{
- Log.LogError(e, "Exception occurred");
- throw;
+ Log.LogDebug("Detecting Immortal Throne text files");
+ Log.LogDebug("rootFolder = {0}", rootFolder);
}
}
-
- ///
- /// Read ARC file
- ///
- ///
- ///
- public ArcFile ReadARCFile(string arcFileName)
+ else
{
- // See if we have this arcfile already and if not create it.
+ // from the original TQ folder
+ rootFolder = Path.Combine(GamePathResolver.TQPath, "Text");
- ArcFile arcFile = this.arcFiles.GetOrAddAtomic(arcFileName, k =>
+ if (TQDebug.DatabaseDebugLevel > 1)
{
- var file = new ArcFile(k);
- arcProv.ReadARCToC(file);// Heavy lifting in GetOrAddAtomic
- return file;
- });
-
- return arcFile;
+ Log.LogDebug("Detecting Titan Quest text files");
+ Log.LogDebug("rootFolder = {0}", rootFolder);
+ }
}
- ///
- /// Tries to determine the name of the text database file.
- /// This is based on the game language and the UI language.
- /// Will use English if all else fails.
- ///
- /// Signals whether we are looking for Immortal Throne files or vanilla Titan Quest files.
- /// Path to the text db file
- private string FigureDBFileToUse(bool isImmortalThrone)
+ // make sure the damn directory exists
+ if (!Directory.Exists(rootFolder))
{
if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Database.FigureDBFileToUse({0})", isImmortalThrone);
-
- string rootFolder;
- if (isImmortalThrone)
- {
- if (GamePathResolver.ImmortalThronePath.Contains("Anniversary"))
- rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Text");
- else
- rootFolder = Path.Combine(GamePathResolver.ImmortalThronePath, "Resources");
-
- if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("Detecting Immortal Throne text files");
- Log.LogDebug("rootFolder = {0}", rootFolder);
- }
- }
- else
- {
- // from the original TQ folder
- rootFolder = Path.Combine(GamePathResolver.TQPath, "Text");
-
- if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("Detecting Titan Quest text files");
- Log.LogDebug("rootFolder = {0}", rootFolder);
- }
- }
+ Log.LogDebug("Error - Root Folder does not exist");
- // make sure the damn directory exists
- if (!Directory.Exists(rootFolder))
- {
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Error - Root Folder does not exist");
+ return null; // silently fail
+ }
- return null; // silently fail
- }
+ string baseFile = Path.Combine(rootFolder, "Text_");
+ string suffix = ".arc";
- string baseFile = Path.Combine(rootFolder, "Text_");
- string suffix = ".arc";
+ // Added explicit set to null though may not be needed
+ string cultureID = null;
- // Added explicit set to null though may not be needed
- string cultureID = null;
+ // Moved this declaration since the first use is inside of the loop.
+ string filename = null;
- // Moved this declaration since the first use is inside of the loop.
- string filename = null;
+ // First see if we can use the game setting
+ string gameLanguage = this.GameLanguage;
+ if (TQDebug.DatabaseDebugLevel > 1)
+ {
+ Log.LogDebug("gameLanguage = {0}", gameLanguage == null ? "NULL" : gameLanguage);
+ Log.LogDebug("baseFile = {0}", baseFile);
+ }
- // First see if we can use the game setting
- string gameLanguage = this.GameLanguage;
- if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("gameLanguage = {0}", gameLanguage == null ? "NULL" : gameLanguage);
- Log.LogDebug("baseFile = {0}", baseFile);
- }
+ if (gameLanguage != null)
+ {
+ // Try this method of getting the culture
+ if (TQDebug.DatabaseDebugLevel > 2)
+ Log.LogDebug("Try looking up cultureID");
- if (gameLanguage != null)
+ foreach (CultureInfo cultureInfo in CultureInfo.GetCultures(CultureTypes.NeutralCultures))
{
- // Try this method of getting the culture
if (TQDebug.DatabaseDebugLevel > 2)
- Log.LogDebug("Try looking up cultureID");
+ Log.LogDebug("Trying {0}", cultureInfo.EnglishName.ToUpperInvariant());
- foreach (CultureInfo cultureInfo in CultureInfo.GetCultures(CultureTypes.NeutralCultures))
+ if (cultureInfo.EnglishName.ToUpperInvariant().Equals(gameLanguage.ToUpperInvariant()) || cultureInfo.DisplayName.ToUpperInvariant().Equals(gameLanguage.ToUpperInvariant()))
{
- if (TQDebug.DatabaseDebugLevel > 2)
- Log.LogDebug("Trying {0}", cultureInfo.EnglishName.ToUpperInvariant());
-
- if (cultureInfo.EnglishName.ToUpperInvariant().Equals(gameLanguage.ToUpperInvariant()) || cultureInfo.DisplayName.ToUpperInvariant().Equals(gameLanguage.ToUpperInvariant()))
- {
- cultureID = cultureInfo.TwoLetterISOLanguageName;
- break;
- }
+ cultureID = cultureInfo.TwoLetterISOLanguageName;
+ break;
}
+ }
- // Titan Quest doesn't use the ISO language code for some languages
- // Added null check to fix exception when there is no culture found.
- if (cultureID != null)
+ // Titan Quest doesn't use the ISO language code for some languages
+ // Added null check to fix exception when there is no culture found.
+ if (cultureID != null)
+ {
+ if (cultureID.ToUpperInvariant() == "CS")
{
- if (cultureID.ToUpperInvariant() == "CS")
- {
- // Force Czech to use CZ instead of CS for the 2 letter code.
- cultureID = "CZ";
- }
- else if (cultureID.ToUpperInvariant() == "PT")
- {
- // Force brazilian portuguese to use BR instead of PT
- cultureID = "BR";
- }
- else if (cultureID.ToUpperInvariant() == "ZH")
- {
- // Force chinese to use CH instead of ZH
- cultureID = "CH";
- }
+ // Force Czech to use CZ instead of CS for the 2 letter code.
+ cultureID = "CZ";
}
-
- if (TQDebug.DatabaseDebugLevel > 1)
- Log.LogDebug("cultureID = {0}", cultureID);
-
- // Moved this inital check for the file into the loop
- // and added a check to verify that we actually have a cultureID
- if (cultureID != null)
+ else if (cultureID.ToUpperInvariant() == "PT")
{
- filename = string.Concat(baseFile, cultureID, suffix);
- if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("Detected cultureID from gameLanguage");
- Log.LogDebug("filename = {0}", filename);
- }
-
- if (File.Exists(filename))
- {
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exiting Database.FigureDBFileToUse()");
-
- return filename;
- }
+ // Force brazilian portuguese to use BR instead of PT
+ cultureID = "BR";
+ }
+ else if (cultureID.ToUpperInvariant() == "ZH")
+ {
+ // Force chinese to use CH instead of ZH
+ cultureID = "CH";
}
}
- // try to use the default culture for the OS
- cultureID = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("Using cultureID from OS");
Log.LogDebug("cultureID = {0}", cultureID);
- }
- // Added a check to verify that we actually have a cultureID
- // though it may not be needed
+ // Moved this inital check for the file into the loop
+ // and added a check to verify that we actually have a cultureID
if (cultureID != null)
{
filename = string.Concat(baseFile, cultureID, suffix);
if (TQDebug.DatabaseDebugLevel > 1)
+ {
+ Log.LogDebug("Detected cultureID from gameLanguage");
Log.LogDebug("filename = {0}", filename);
+ }
if (File.Exists(filename))
{
@@ -706,277 +862,302 @@ private string FigureDBFileToUse(bool isImmortalThrone)
return filename;
}
}
+ }
- // Now just try EN
- cultureID = "EN";
+ // try to use the default culture for the OS
+ cultureID = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
+ if (TQDebug.DatabaseDebugLevel > 1)
+ {
+ Log.LogDebug("Using cultureID from OS");
+ Log.LogDebug("cultureID = {0}", cultureID);
+ }
+
+ // Added a check to verify that we actually have a cultureID
+ // though it may not be needed
+ if (cultureID != null)
+ {
filename = string.Concat(baseFile, cultureID, suffix);
if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("Forcing English Language");
- Log.LogDebug("cultureID = {0}", cultureID);
Log.LogDebug("filename = {0}", filename);
- }
if (File.Exists(filename))
{
if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Database.Exiting FigureDBFileToUse()");
+ Log.LogDebug("Exiting Database.FigureDBFileToUse()");
return filename;
}
+ }
- // Now just see if we can find anything.
+ // Now just try EN
+ cultureID = "EN";
+ filename = string.Concat(baseFile, cultureID, suffix);
+ if (TQDebug.DatabaseDebugLevel > 1)
+ {
+ Log.LogDebug("Forcing English Language");
+ Log.LogDebug("cultureID = {0}", cultureID);
+ Log.LogDebug("filename = {0}", filename);
+ }
+
+ if (File.Exists(filename))
+ {
if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Detection Failed - searching for files");
+ Log.LogDebug("Database.Exiting FigureDBFileToUse()");
- string[] files = Directory.GetFiles(rootFolder, "Text_??.arc");
+ return filename;
+ }
- // Added check that files is not null.
- if (files != null && files.Length > 0)
- {
- if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("Found some files");
- Log.LogDebug("filename = {0}", files[0]);
- }
+ // Now just see if we can find anything.
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Detection Failed - searching for files");
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exiting Database.FigureDBFileToUse()");
+ string[] files = Directory.GetFiles(rootFolder, "Text_??.arc");
- return files[0];
+ // Added check that files is not null.
+ if (files != null && files.Length > 0)
+ {
+ if (TQDebug.DatabaseDebugLevel > 1)
+ {
+ Log.LogDebug("Found some files");
+ Log.LogDebug("filename = {0}", files[0]);
}
if (TQDebug.DatabaseDebugLevel > 0)
- {
- Log.LogDebug("Failed to determine Language file!");
Log.LogDebug("Exiting Database.FigureDBFileToUse()");
- }
- return null;
+ return files[0];
}
- ///
- /// Loads the Text database
- ///
- private void LoadTextDB()
+ if (TQDebug.DatabaseDebugLevel > 0)
{
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Database.LoadTextDB()");
+ Log.LogDebug("Failed to determine Language file!");
+ Log.LogDebug("Exiting Database.FigureDBFileToUse()");
+ }
- string databaseFile = this.FigureDBFileToUse(false);
- if (TQDebug.DatabaseDebugLevel > 1)
+ return null;
+ }
+
+ ///
+ /// Loads the Text database
+ ///
+ private void LoadTextDB()
+ {
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Database.LoadTextDB()");
+
+ string databaseFile = this.FigureDBFileToUse(false);
+ if (TQDebug.DatabaseDebugLevel > 1)
+ {
+ Log.LogDebug("Find Titan Quest text file");
+ Log.LogDebug("dbFile = {0}", databaseFile);
+ }
+
+ if (!string.IsNullOrEmpty(databaseFile))
+ {
+ string fileName = Path.GetFileNameWithoutExtension(databaseFile);
+ }
+
+ if (databaseFile != null)
+ {
+ // Try to suck what we want into memory and then parse it.
+ this.ParseTextDB(databaseFile, "text\\commonequipment.txt");
+ this.ParseTextDB(databaseFile, "text\\uniqueequipment.txt");
+ this.ParseTextDB(databaseFile, "text\\quest.txt");
+ this.ParseTextDB(databaseFile, "text\\ui.txt");
+ this.ParseTextDB(databaseFile, "text\\skills.txt");
+ this.ParseTextDB(databaseFile, "text\\monsters.txt"); // Added by VillageIdiot
+ this.ParseTextDB(databaseFile, "text\\menu.txt"); // Added by VillageIdiot
+ this.ParseTextDB(databaseFile, "text\\tutorial.txt");
+
+ // Immortal Throne data
+ this.ParseTextDB(databaseFile, "text\\xcommonequipment.txt");
+ this.ParseTextDB(databaseFile, "text\\xuniqueequipment.txt");
+ this.ParseTextDB(databaseFile, "text\\xquest.txt");
+ this.ParseTextDB(databaseFile, "text\\xui.txt");
+ this.ParseTextDB(databaseFile, "text\\xskills.txt");
+ this.ParseTextDB(databaseFile, "text\\xmonsters.txt"); // Added by VillageIdiot
+ this.ParseTextDB(databaseFile, "text\\xmenu.txt"); // Added by VillageIdiot
+ this.ParseTextDB(databaseFile, "text\\xnpc.txt"); // Added by VillageIdiot
+ this.ParseTextDB(databaseFile, "text\\modstrings.txt"); // Added by VillageIdiot
+ this.ParseTextDB(databaseFile, "text\\xtutorial.txt"); // Added by hguy
+
+ if (GamePathResolver.IsRagnarokInstalled)
{
- Log.LogDebug("Find Titan Quest text file");
- Log.LogDebug("dbFile = {0}", databaseFile);
+ this.ParseTextDB(databaseFile, "text\\x2commonequipment.txt");
+ this.ParseTextDB(databaseFile, "text\\x2uniqueequipment.txt");
+ this.ParseTextDB(databaseFile, "text\\x2quest.txt");
+ this.ParseTextDB(databaseFile, "text\\x2ui.txt");
+ this.ParseTextDB(databaseFile, "text\\x2skills.txt");
+ this.ParseTextDB(databaseFile, "text\\x2monsters.txt"); // Added by VillageIdiot
+ this.ParseTextDB(databaseFile, "text\\x2menu.txt"); // Added by VillageIdiot
+ this.ParseTextDB(databaseFile, "text\\x2npc.txt"); // Added by VillageIdiot
}
- if (!string.IsNullOrEmpty(databaseFile))
+ if (GamePathResolver.IsAtlantisInstalled)
{
- string fileName = Path.GetFileNameWithoutExtension(databaseFile);
+ this.ParseTextDB(databaseFile, "text\\x3basegame_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x3items_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x3mainquest_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x3misctags_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x3sidequests_nonvoiced.txt");
}
- if (databaseFile != null)
+ if (GamePathResolver.IsEmbersInstalled)
{
- // Try to suck what we want into memory and then parse it.
- this.ParseTextDB(databaseFile, "text\\commonequipment.txt");
- this.ParseTextDB(databaseFile, "text\\uniqueequipment.txt");
- this.ParseTextDB(databaseFile, "text\\quest.txt");
- this.ParseTextDB(databaseFile, "text\\ui.txt");
- this.ParseTextDB(databaseFile, "text\\skills.txt");
- this.ParseTextDB(databaseFile, "text\\monsters.txt"); // Added by VillageIdiot
- this.ParseTextDB(databaseFile, "text\\menu.txt"); // Added by VillageIdiot
- this.ParseTextDB(databaseFile, "text\\tutorial.txt");
-
- // Immortal Throne data
- this.ParseTextDB(databaseFile, "text\\xcommonequipment.txt");
- this.ParseTextDB(databaseFile, "text\\xuniqueequipment.txt");
- this.ParseTextDB(databaseFile, "text\\xquest.txt");
- this.ParseTextDB(databaseFile, "text\\xui.txt");
- this.ParseTextDB(databaseFile, "text\\xskills.txt");
- this.ParseTextDB(databaseFile, "text\\xmonsters.txt"); // Added by VillageIdiot
- this.ParseTextDB(databaseFile, "text\\xmenu.txt"); // Added by VillageIdiot
- this.ParseTextDB(databaseFile, "text\\xnpc.txt"); // Added by VillageIdiot
- this.ParseTextDB(databaseFile, "text\\modstrings.txt"); // Added by VillageIdiot
- this.ParseTextDB(databaseFile, "text\\xtutorial.txt"); // Added by hguy
-
- if (GamePathResolver.IsRagnarokInstalled)
- {
- this.ParseTextDB(databaseFile, "text\\x2commonequipment.txt");
- this.ParseTextDB(databaseFile, "text\\x2uniqueequipment.txt");
- this.ParseTextDB(databaseFile, "text\\x2quest.txt");
- this.ParseTextDB(databaseFile, "text\\x2ui.txt");
- this.ParseTextDB(databaseFile, "text\\x2skills.txt");
- this.ParseTextDB(databaseFile, "text\\x2monsters.txt"); // Added by VillageIdiot
- this.ParseTextDB(databaseFile, "text\\x2menu.txt"); // Added by VillageIdiot
- this.ParseTextDB(databaseFile, "text\\x2npc.txt"); // Added by VillageIdiot
- }
+ this.ParseTextDB(databaseFile, "text\\x4basegame_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x4items_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x4mainquest_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x4misctags_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x4nametags_nonvoiced.txt");
+ this.ParseTextDB(databaseFile, "text\\x4sidequests_nonvoiced.txt");
+ }
+ }
- if (GamePathResolver.IsAtlantisInstalled)
- {
- this.ParseTextDB(databaseFile, "text\\x3basegame_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x3items_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x3mainquest_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x3misctags_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x3sidequests_nonvoiced.txt");
- }
+ // For loading custom map text database.
+ if (GamePathResolver.IsCustom)
+ {
+ databaseFile = Path.Combine(GamePathResolver.MapName, "resources", "text.arc");
- if (GamePathResolver.IsEmbersInstalled)
- {
- this.ParseTextDB(databaseFile, "text\\x4basegame_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x4items_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x4mainquest_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x4misctags_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x4nametags_nonvoiced.txt");
- this.ParseTextDB(databaseFile, "text\\x4sidequests_nonvoiced.txt");
- }
+ if (TQDebug.DatabaseDebugLevel > 1)
+ {
+ Log.LogDebug("Find Custom Map text file");
+ Log.LogDebug("dbFile = {0}", databaseFile);
}
- // For loading custom map text database.
- if (GamePathResolver.IsCustom)
- {
- databaseFile = Path.Combine(GamePathResolver.MapName, "resources", "text.arc");
+ if (databaseFile != null)
+ this.ParseTextDB(databaseFile, "text\\modstrings.txt");
+ }
- if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("Find Custom Map text file");
- Log.LogDebug("dbFile = {0}", databaseFile);
- }
+ // Added this check to see if anything was loaded.
+ if (this.textDB.Count == 0)
+ {
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Exception - Could not load Text DB.");
- if (databaseFile != null)
- this.ParseTextDB(databaseFile, "text\\modstrings.txt");
- }
+ throw new FileLoadException("Could not load Text DB.");
+ }
- // Added this check to see if anything was loaded.
- if (this.textDB.Count == 0)
- {
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exception - Could not load Text DB.");
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Exiting Database.LoadTextDB()");
+ }
- throw new FileLoadException("Could not load Text DB.");
- }
+ ///
+ /// Parses the text database to put the entries into a hash table.
+ ///
+ /// Database file name (arc file)
+ /// Name of the text DB file within the arc file
+ private void ParseTextDB(string databaseFile, string filename)
+ {
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Database.ParseTextDB({0}, {1})", databaseFile, filename);
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exiting Database.LoadTextDB()");
- }
+ byte[] data = this.ReadARCFile(databaseFile, filename);
- ///
- /// Parses the text database to put the entries into a hash table.
- ///
- /// Database file name (arc file)
- /// Name of the text DB file within the arc file
- private void ParseTextDB(string databaseFile, string filename)
+ if (data == null)
{
+ // Changed for mod support. Sometimes the text file has more entries than just the x or non-x prefix files.
if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Database.ParseTextDB({0}, {1})", databaseFile, filename);
+ Log.LogDebug("Error in ARC File: {0} does not contain an entry for '{1}'", databaseFile, filename);
- byte[] data = this.ReadARCFile(databaseFile, filename);
+ return;
+ }
- if (data == null)
+ // now read it like a text file
+ // Changed to system default encoding since there might be extended ascii (or something else) in the text db.
+ using (StreamReader reader = new StreamReader(new MemoryStream(data), Encoding.Default))
+ {
+ char delimiter = '=';
+ string line;
+ while ((line = reader.ReadLine()) != null)
{
- // Changed for mod support. Sometimes the text file has more entries than just the x or non-x prefix files.
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Error in ARC File: {0} does not contain an entry for '{1}'", databaseFile, filename);
+ line = line.Trim();
- return;
- }
+ // delete short lines
+ if (line.Length < 2)
+ continue;
- // now read it like a text file
- // Changed to system default encoding since there might be extended ascii (or something else) in the text db.
- using (StreamReader reader = new StreamReader(new MemoryStream(data), Encoding.Default))
- {
- char delimiter = '=';
- string line;
- while ((line = reader.ReadLine()) != null)
- {
- line = line.Trim();
+ // comment line
+ if (line.StartsWith("//", StringComparison.Ordinal))
+ continue;
- // delete short lines
- if (line.Length < 2)
- continue;
+ // split on the equal sign
+ string[] fields = line.Split(delimiter);
- // comment line
- if (line.StartsWith("//", StringComparison.Ordinal))
- continue;
+ // bad line
+ if (fields.Length < 2)
+ continue;
- // split on the equal sign
- string[] fields = line.Split(delimiter);
+ string label = fields[1].Trim();
- // bad line
- if (fields.Length < 2)
- continue;
+ // Now for the foreign languages there is a bunch of crap in here so the proper version of the adjective can be used with the proper
+ // noun form. I don' want to code all that so this next code will just take the first version of the adjective and then
+ // throw away all the metadata.
- string label = fields[1].Trim();
+ // hguy : one expression to rule them all
+ if (Regex.Match(label, @"^(?\[\w+\])(?[^\\[]+)|^\[(?[^\]]+)\]$") is { Success: true } match)
+ label = match.Groups["Label"].Value.Trim();
- // Now for the foreign languages there is a bunch of crap in here so the proper version of the adjective can be used with the proper
- // noun form. I don' want to code all that so this next code will just take the first version of the adjective and then
- // throw away all the metadata.
+ // If this field is already in the db, then replace it
+ string key = fields[0].Trim().ToUpperInvariant();
- // hguy : one expression to rule them all
- if (Regex.Match(label, @"^(?\[\w+\])(?[^\\[]+)|^\[(?[^\]]+)\]$") is { Success: true } match)
- label = match.Groups["Label"].Value.Trim();
+ //if (!this.textDB.TryAdd(key, label))
+ // Log.LogDebug(@"TextDB Overlap ! Try to override ""{key}"" = ""{oldvalue}"" with ""{newvalue}"" !", key, this.textDB[key], label);
- // If this field is already in the db, then replace it
- string key = fields[0].Trim().ToUpperInvariant();
+ this.textDB.AddOrUpdate(key, label, (k, v) => label);// Override with the new "label"
+ }
+ }
- //if (!this.textDB.TryAdd(key, label))
- // Log.LogDebug(@"TextDB Overlap ! Try to override ""{key}"" = ""{oldvalue}"" with ""{newvalue}"" !", key, this.textDB[key], label);
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Exiting Database.ParseTextDB()");
+ }
- this.textDB.AddOrUpdate(key, label, (k, v) => label);// Override with the new "label"
- }
- }
+ ///
+ /// Loads a database arz file.
+ ///
+ private void LoadARZFile()
+ {
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Database.LoadARZFile()");
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exiting Database.ParseTextDB()");
- }
+ // from the original TQ folder
+ string file = Path.Combine(GamePathResolver.TQPath, "Database", "database.arz");
- ///
- /// Loads a database arz file.
- ///
- private void LoadARZFile()
+ if (TQDebug.DatabaseDebugLevel > 1)
{
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Database.LoadARZFile()");
+ Log.LogDebug("Load Titan Quest database arz file");
+ Log.LogDebug("file = {0}", file);
+ }
- // from the original TQ folder
- string file = Path.Combine(GamePathResolver.TQPath, "Database", "database.arz");
+ this.ArzFile = new ArzFile(file);
+ arzProv.Read(this.ArzFile);
+
+ // now Immortal Throne expansion pack
+ this.ArzFileIT = this.ArzFile;
+
+ // Added to load a custom map database file.
+ if (GamePathResolver.IsCustom)
+ {
+ file = Path.Combine(GamePathResolver.MapName, "database", $"{Path.GetFileName(GamePathResolver.MapName)}.arz");
if (TQDebug.DatabaseDebugLevel > 1)
{
- Log.LogDebug("Load Titan Quest database arz file");
+ Log.LogDebug("Load Custom Map database arz file");
Log.LogDebug("file = {0}", file);
}
- this.ArzFile = new ArzFile(file);
- arzProv.Read(this.ArzFile);
-
- // now Immortal Throne expansion pack
- this.ArzFileIT = this.ArzFile;
-
- // Added to load a custom map database file.
- if (GamePathResolver.IsCustom)
+ if (File.Exists(file))
{
- file = Path.Combine(GamePathResolver.MapName, "database", $"{Path.GetFileName(GamePathResolver.MapName)}.arz");
-
- if (TQDebug.DatabaseDebugLevel > 1)
- {
- Log.LogDebug("Load Custom Map database arz file");
- Log.LogDebug("file = {0}", file);
- }
-
- if (File.Exists(file))
- {
- this.ArzFileMod = new ArzFile(file);
- arzProv.Read(this.ArzFileMod);
- }
- else
- this.ArzFileMod = null;
+ this.ArzFileMod = new ArzFile(file);
+ arzProv.Read(this.ArzFileMod);
}
-
- if (TQDebug.DatabaseDebugLevel > 0)
- Log.LogDebug("Exiting Database.LoadARZFile()");
+ else
+ this.ArzFileMod = null;
}
- #endregion Database Private Methods
-
+ if (TQDebug.DatabaseDebugLevel > 0)
+ Log.LogDebug("Exiting Database.LoadARZFile()");
}
+
+ #endregion Database Private Methods
+
}
\ No newline at end of file
diff --git a/src/TQVaultAE.Data/ItemProvider.cs b/src/TQVaultAE.Data/ItemProvider.cs
index 1d69b2e8..a19c11fb 100644
--- a/src/TQVaultAE.Data/ItemProvider.cs
+++ b/src/TQVaultAE.Data/ItemProvider.cs
@@ -3,434 +3,579 @@
// Copyright (c) Brandon Wallace and Jesse Calhoun. All rights reserved.
//
//-----------------------------------------------------------------------
-namespace TQVaultAE.Data
+
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text.RegularExpressions;
+using TQVaultAE.Config;
+using TQVaultAE.Domain.Contracts.Providers;
+using TQVaultAE.Domain.Contracts.Services;
+using TQVaultAE.Domain.Entities;
+using TQVaultAE.Domain.Helpers;
+using TQVaultAE.Domain.Results;
+
+namespace TQVaultAE.Data;
+
+///
+/// Class for holding item information
+///
+public class ItemProvider : IItemProvider
{
- using Microsoft.Extensions.Logging;
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Text.RegularExpressions;
- using TQVaultAE.Config;
- using TQVaultAE.Domain.Contracts.Providers;
- using TQVaultAE.Domain.Contracts.Services;
- using TQVaultAE.Domain.Entities;
- using TQVaultAE.Domain.Helpers;
- using TQVaultAE.Domain.Results;
+ private const StringComparison noCase = StringComparison.OrdinalIgnoreCase;
+
+ private readonly ILogger Log;
+ private readonly IDatabase Database;
+ private readonly ILootTableCollectionProvider LootTableCollectionProvider;
+ private readonly IItemAttributeProvider ItemAttributeProvider;
+ private readonly ITQDataService TQData;
+ private readonly ITranslationService TranslationService;
+ private readonly IGamePathService GamePathService;
+ private readonly LazyConcurrentDictionary<(Item Item, FriendlyNamesExtraScopes? Scope, bool FilterExtra), ToFriendlyNameResult> FriendlyNamesCache = new LazyConcurrentDictionary<(Item, FriendlyNamesExtraScopes?, bool), ToFriendlyNameResult>();
+ private readonly LazyConcurrentDictionary ItemAffixesCache = new LazyConcurrentDictionary();
+
+ internal static readonly string[] unwantedTags =
+ {
+ "MAXTRANSPARENCY",
+ "SCALE",
+ "CASTSSHADOWS",
+ "MARKETADJUSTMENTPERCENT",
+ "LOOTRANDOMIZERCOST",
+ "LOOTRANDOMIZERJITTER",
+ "ACTORHEIGHT",
+ "ACTORRADIUS",
+ "SHADOWBIAS",
+ "ITEMLEVEL",
+ "ITEMCOST",
+ "COMPLETEDRELICLEVEL",
+ "CHARACTERBASEATTACKSPEED",
+ "HIDESUFFIXNAME",
+ "HIDEPREFIXNAME",
+ "AMULET",
+ "RING",
+ "HELMET",
+ "GREAVES",
+ "ARMBAND",
+ "BODYARMOR",
+ "BOW",
+ "SPEAR",
+ "STAFF",
+ "MACE",
+ "SWORD",
+ "RANGEDONEHAND",
+ "AXE",
+ "SHIELD",
+ "BRACELET",
+ "AMULET",
+ "RING",
+ "BLOCKABSORPTION",
+ "ITEMCOSTSCALEPERCENT",
+ "ITEMSKILLLEVEL",
+ "USEDELAYTIME",
+ "CAMERASHAKEAMPLITUDE",
+ "SKILLMAXLEVEL",
+ "EXPANSIONTIME",
+ "SKILLTIER",
+ "CAMERASHAKEDURATIONSECS",
+ "SKILLULTIMATELEVEL",
+ "SKILLCONNECTIONSPACING",
+ "PETBURSTSPAWN",
+ "PETLIMIT",
+ "ISPETDISPLAYABLE",
+ "SPAWNOBJECTSTIMETOLIVE",
+ "SKILLPROJECTILENUMBER",
+ "SKILLMASTERYLEVELREQUIRED",
+ "EXCLUDERACIALDAMAGE",
+ "SKILLWEAPONTINTRED",
+ "SKILLWEAPONTINTGREEN",
+ "SKILLWEAPONTINTBLUE",
+ "DEBUFSKILL",
+ "HIDEFROMUI",
+ "INSTANTCAST",
+ "WAVEENDWIDTH",
+ "WAVEDISTANCE",
+ "WAVEDEPTH",
+ "WAVESTARTWIDTH",
+ "RAGDOLLAMPLIFICATION",
+ "WAVETIME",
+ "SPARKGAP",
+ "SPARKCHANCE",
+ "PROJECTILEUSESALLDAMAGE",
+ "DROPOFFSET",
+ "DROPHEIGHT",
+ "NUMPROJECTILES",
+ "SWORD",
+ "AXE",
+ "SPEAR",
+ "MACE",
+ "QUEST",
+ "CANNOTPICKUPMULTIPLE",
+ "BONUSLIFEPERCENT",
+ "BONUSLIFEPOINTS",
+ "BONUSMANAPERCENT",
+ "BONUSMANAPOINTS",
+ "DISPLAYASQUESTITEM", // New tags from the latest expansions.
+ "ACTORSCALE",
+ "ACTORSCALETIME",
+ "SPAWNOBJECTSDISTANCEINCREMENT", // AMS: Additional tags to ignore
+ "SPAWNOBJECTSDISTANCEINNERCIRCLE",
+ "SPAWNOBJECTSNUMBEROFRINGS",
+ "SPAWNOBJECTSSPACINGANGLE",
+ "CONTAGIONINTERVAL",
+ "CONTAGIONLIMIT",
+ "CONTAGIONMAXSPREAD",
+ "CONTAGIONRADIUS",
+ "NOHIGHLIGHTDEFAULTCOLORA" // AMS: New property on most EE items
+ };
+
+ internal static readonly string[] requirementTags =
+ {
+ "LEVELREQUIREMENT",
+ "INTELLIGENCEREQUIREMENT",
+ "DEXTERITYREQUIREMENT",
+ "STRENGTHREQUIREMENT",
+ };
+
+ internal static readonly string[] statBonusTags =
+ {
+ "CHARACTERSTRENGTH",
+ "CHARACTERSTRENGTHMODIFIER",
+ "CHARACTERDEXTERITY",
+ "CHARACTERDEXTERITYMODIFIER",
+ "CHARACTERINTELLIGENCE",
+ "CHARACTERINTELLIGENCEMODIFIER",
+ "CHARACTERLIFE",
+ "CHARACTERLIFEMODIFIER",
+ "CHARACTERMANA",
+ "CHARACTERMANAMODIFIER",
+ };
+
+ internal static readonly string[] durationIndependentEffects =
+ {
+ "OFFENSIVESLOWTOTALSPEED",
+ "OFFENSIVESLOWATTACKSPEED",
+ "OFFENSIVESLOWRUNSPEED",
+ "OFFENSIVESLOWOFFENSIVEABILITY",
+ "OFFENSIVESLOWDEFENSIVEABILITY",
+ "OFFENSIVESLOWOFFENSIVEREDUCTION",
+ "OFFENSIVESLOWDEFENSIVEREDUCTION",
+ "OFFENSIVETOTALDAMAGEREDUCTIONPERCENT",
+ "OFFENSIVETOTALDAMAGEREDUCTIONABSOLUTE",
+ "OFFENSIVETOTALRESISTANCEREDUCTIONPERCENT",
+ "OFFENSIVETOTALRESISTANCEREDUCTIONABSOLUTE"
+ };
+
+ public ItemProvider(
+ ILogger log
+ , IDatabase database
+ , ILootTableCollectionProvider lootTableCollectionProvider
+ , IItemAttributeProvider itemAttributeProvider
+ , ITQDataService tQData
+ , ITranslationService translationService
+ , IGamePathService gamePathService
+ )
+ {
+ this.Log = log;
+ this.Database = database;
+ this.LootTableCollectionProvider = lootTableCollectionProvider;
+ this.ItemAttributeProvider = itemAttributeProvider;
+ this.TQData = tQData;
+ this.TranslationService = translationService;
+ this.GamePathService = gamePathService;
+ }
+
+
+ public ItemAffixes GetItemAffixes(string itemId)
+ {
+ return ItemAffixesCache.GetOrAddAtomic(itemId, k =>
+ {
+ var affixmap = this.Database.GetItemAffixTableMap(k);
+ if (affixmap is null || affixmap.All(a => a.IsEmpty)) return null;
+
+ Dictionary> Broken, Prefix, Suffix;
+
+ List<(GameExtension Dlc, LootTableCollection Table)>
+ LBroken = new List<(GameExtension, LootTableCollection)>(),
+ LPrefix = new List<(GameExtension, LootTableCollection)>(),
+ LSuffix = new List<(GameExtension, LootTableCollection)>();
+
+ LootTableCollection table;
+ GameExtension dlc;
+ foreach (var map in affixmap)
+ {
+ if (!string.IsNullOrWhiteSpace(map.BrokenTable))
+ {
+ dlc = GamePathService.ResolveExtensionFromPath(map.BrokenTable);
+ table = this.LootTableCollectionProvider.LoadTable(map.BrokenTable);
+ if (table is not null) LBroken.Add((dlc, table));
+ }
+
+ if (!string.IsNullOrWhiteSpace(map.PrefixTable))
+ {
+ dlc = GamePathService.ResolveExtensionFromPath(map.PrefixTable);
+ table = this.LootTableCollectionProvider.LoadTable(map.PrefixTable);
+ if (table is not null) LPrefix.Add((dlc, table));
+ }
+ if (!string.IsNullOrWhiteSpace(map.SuffixTable))
+ {
+ dlc = GamePathService.ResolveExtensionFromPath(map.SuffixTable);
+ table = this.LootTableCollectionProvider.LoadTable(map.SuffixTable);
+ if (table is not null) LSuffix.Add((dlc, table));
+ }
+ }
+ Broken = LBroken.GroupBy(i => i.Dlc).OrderBy(i => i.Key)
+ .ToDictionary(i => i.Key, j => j.Select(k => k.Table).ToList().AsReadOnly());
+ Prefix = LPrefix.GroupBy(i => i.Dlc).OrderBy(i => i.Key)
+ .ToDictionary(i => i.Key, j => j.Select(k => k.Table).ToList().AsReadOnly());
+ Suffix = LSuffix.GroupBy(i => i.Dlc).OrderBy(i => i.Key)
+ .ToDictionary(i => i.Key, j => j.Select(k => k.Table).ToList().AsReadOnly());
+ return new ItemAffixes(
+ new ReadOnlyDictionary>(Broken)
+ , new ReadOnlyDictionary>(Prefix)
+ , new ReadOnlyDictionary>(Suffix)
+ );
+ });
+ }
+
+ public bool InvalidateFriendlyNamesCache(params Item[] items)
+ {
+ items = items.Where(i => i != null).ToArray();
+ var keylist = this.FriendlyNamesCache.Where(i => items.Contains(i.Key.Item)).Select(i => i.Key).ToList();
+ keylist.ForEach(k => this.FriendlyNamesCache.TryRemove(k, out var outVal));
+ return keylist.Any();
+ }
+
+ #region Must be a flat prop
///
- /// Class for holding item information
+ /// Gets the socketed charm/relic bonus loot table
///
- public class ItemProvider : IItemProvider
+ ///
+ ///
+ ///
+ /// Returns false if the item does not contain a charm/relic
+ public bool BonusTableSocketedRelic(Item Item, out LootTableCollection RelicTable1, out LootTableCollection RelicTable2)
{
- private const StringComparison noCase = StringComparison.OrdinalIgnoreCase;
-
- private readonly ILogger Log;
- private readonly IDatabase Database;
- private readonly ILootTableCollectionProvider LootTableCollectionProvider;
- private readonly IItemAttributeProvider ItemAttributeProvider;
- private readonly ITQDataService TQData;
- private readonly ITranslationService TranslationService;
- private readonly LazyConcurrentDictionary<(Item Item, FriendlyNamesExtraScopes? Scope, bool FilterExtra), ToFriendlyNameResult> FriendlyNamesCache = new LazyConcurrentDictionary<(Item, FriendlyNamesExtraScopes?, bool), ToFriendlyNameResult>();
-
- internal static readonly string[] unwantedTags =
- {
- "MAXTRANSPARENCY",
- "SCALE",
- "CASTSSHADOWS",
- "MARKETADJUSTMENTPERCENT",
- "LOOTRANDOMIZERCOST",
- "LOOTRANDOMIZERJITTER",
- "ACTORHEIGHT",
- "ACTORRADIUS",
- "SHADOWBIAS",
- "ITEMLEVEL",
- "ITEMCOST",
- "COMPLETEDRELICLEVEL",
- "CHARACTERBASEATTACKSPEED",
- "HIDESUFFIXNAME",
- "HIDEPREFIXNAME",
- "AMULET",
- "RING",
- "HELMET",
- "GREAVES",
- "ARMBAND",
- "BODYARMOR",
- "BOW",
- "SPEAR",
- "STAFF",
- "MACE",
- "SWORD",
- "RANGEDONEHAND",
- "AXE",
- "SHIELD",
- "BRACELET",
- "AMULET",
- "RING",
- "BLOCKABSORPTION",
- "ITEMCOSTSCALEPERCENT",
- "ITEMSKILLLEVEL",
- "USEDELAYTIME",
- "CAMERASHAKEAMPLITUDE",
- "SKILLMAXLEVEL",
- "EXPANSIONTIME",
- "SKILLTIER",
- "CAMERASHAKEDURATIONSECS",
- "SKILLULTIMATELEVEL",
- "SKILLCONNECTIONSPACING",
- "PETBURSTSPAWN",
- "PETLIMIT",
- "ISPETDISPLAYABLE",
- "SPAWNOBJECTSTIMETOLIVE",
- "SKILLPROJECTILENUMBER",
- "SKILLMASTERYLEVELREQUIRED",
- "EXCLUDERACIALDAMAGE",
- "SKILLWEAPONTINTRED",
- "SKILLWEAPONTINTGREEN",
- "SKILLWEAPONTINTBLUE",
- "DEBUFSKILL",
- "HIDEFROMUI",
- "INSTANTCAST",
- "WAVEENDWIDTH",
- "WAVEDISTANCE",
- "WAVEDEPTH",
- "WAVESTARTWIDTH",
- "RAGDOLLAMPLIFICATION",
- "WAVETIME",
- "SPARKGAP",
- "SPARKCHANCE",
- "PROJECTILEUSESALLDAMAGE",
- "DROPOFFSET",
- "DROPHEIGHT",
- "NUMPROJECTILES",
- "SWORD",
- "AXE",
- "SPEAR",
- "MACE",
- "QUEST",
- "CANNOTPICKUPMULTIPLE",
- "BONUSLIFEPERCENT",
- "BONUSLIFEPOINTS",
- "BONUSMANAPERCENT",
- "BONUSMANAPOINTS",
- "DISPLAYASQUESTITEM", // New tags from the latest expansions.
- "ACTORSCALE",
- "ACTORSCALETIME",
- "SPAWNOBJECTSDISTANCEINCREMENT", // AMS: Additional tags to ignore
- "SPAWNOBJECTSDISTANCEINNERCIRCLE",
- "SPAWNOBJECTSNUMBEROFRINGS",
- "SPAWNOBJECTSSPACINGANGLE",
- "CONTAGIONINTERVAL",
- "CONTAGIONLIMIT",
- "CONTAGIONMAXSPREAD",
- "CONTAGIONRADIUS",
- "NOHIGHLIGHTDEFAULTCOLORA" // AMS: New property on most EE items
- };
-
- internal static readonly string[] requirementTags =
- {
- "LEVELREQUIREMENT",
- "INTELLIGENCEREQUIREMENT",
- "DEXTERITYREQUIREMENT",
- "STRENGTHREQUIREMENT",
- };
-
- internal static readonly string[] statBonusTags =
- {
- "CHARACTERSTRENGTH",
- "CHARACTERSTRENGTHMODIFIER",
- "CHARACTERDEXTERITY",
- "CHARACTERDEXTERITYMODIFIER",
- "CHARACTERINTELLIGENCE",
- "CHARACTERINTELLIGENCEMODIFIER",
- "CHARACTERLIFE",
- "CHARACTERLIFEMODIFIER",
- "CHARACTERMANA",
- "CHARACTERMANAMODIFIER",
- };
-
- internal static readonly string[] durationIndependentEffects =
- {
- "OFFENSIVESLOWTOTALSPEED",
- "OFFENSIVESLOWATTACKSPEED",
- "OFFENSIVESLOWRUNSPEED",
- "OFFENSIVESLOWOFFENSIVEABILITY",
- "OFFENSIVESLOWDEFENSIVEABILITY",
- "OFFENSIVESLOWOFFENSIVEREDUCTION",
- "OFFENSIVESLOWDEFENSIVEREDUCTION",
- "OFFENSIVETOTALDAMAGEREDUCTIONPERCENT",
- "OFFENSIVETOTALDAMAGEREDUCTIONABSOLUTE",
- "OFFENSIVETOTALRESISTANCEREDUCTIONPERCENT",
- "OFFENSIVETOTALRESISTANCEREDUCTIONABSOLUTE"
- };
-
- public ItemProvider(
- ILogger log
- , IDatabase database
- , ILootTableCollectionProvider lootTableCollectionProvider
- , IItemAttributeProvider itemAttributeProvider
- , ITQDataService tQData
- , ITranslationService translationService
- )
+ RelicTable1 = RelicTable2 = null;
+ var hasCompleteRelic1 = Item.HasRelicSlot1 && Item.RelicInfo is not null && Item.IsRelicBonus1Complete;
+ var hasCompleteRelic2 = Item.HasRelicSlot2 && Item.Relic2Info is not null && Item.IsRelicBonus2Complete;
+
+ if (Item.baseItemInfo is null
+ || (!hasCompleteRelic1 && !hasCompleteRelic2)
+ ) return false;
+
+ string tableId = null;
+
+ if (hasCompleteRelic1)
{
- this.Log = log;
- this.Database = database;
- this.LootTableCollectionProvider = lootTableCollectionProvider;
- this.ItemAttributeProvider = itemAttributeProvider;
- this.TQData = tQData;
- this.TranslationService = translationService;
+ tableId = Item.RelicInfo.GetString("bonusTableName");
+ RelicTable1 = LootTableCollectionProvider.LoadTable(tableId);
}
- public bool InvalidateFriendlyNamesCache(params Item[] items)
+ if (hasCompleteRelic2)
{
- items = items.Where(i => i != null).ToArray();
- var keylist = this.FriendlyNamesCache.Where(i => items.Contains(i.Key.Item)).Select(i => i.Key).ToList();
- keylist.ForEach(k => this.FriendlyNamesCache.TryRemove(k, out var outVal));
- return keylist.Any();
+ tableId = Item.Relic2Info.GetString("bonusTableName");
+ RelicTable2 = LootTableCollectionProvider.LoadTable(tableId);
}
- #region Must be a flat prop
+ return RelicTable1 is not null || RelicTable2 is not null;
+ }
+
+ ///
+ /// Gets the artifact/charm/relic bonus loot table
+ ///
+ ///
+ /// returns null if the item is not an artifact/charm/relic
+ public LootTableCollection BonusTable(Item itm)
+ {
+ if (itm.baseItemInfo == null)
+ return null;
- ///
- /// Gets the artifact/charm/relic bonus loot table
- /// returns null if the item is not an artifact/charm/relic or does not contain a charm/relic
- ///
- public LootTableCollection BonusTable(Item itm)
+ string lootTableID = null;
+ if (itm.IsRelic)
+ lootTableID = itm.baseItemInfo.GetString("bonusTableName");
+ else if (itm.IsArtifact)
{
- if (itm.baseItemInfo == null)
- return null;
+ // for artifacts we need to find the formulae that was used to create the artifact. sucks to be us
+ // The formulas seem to always be in the arcaneformulae subfolder with a _formula on the end
+ // of the filename
+ string folder = Path.GetDirectoryName(itm.BaseItemId);
+ folder = Path.Combine(folder, "arcaneformulae");
+ string file = Path.GetFileNameWithoutExtension(itm.BaseItemId);
+
+ // Damn it, IL did not keep the filename consistent on Kingslayer (Sands of Kronos)
+ if (file.ToUpperInvariant() == "E_GA_SANDOFKRONOS")
+ file = file.Insert(9, "s");
+
+ file = string.Concat(file, "_formula");
+ file = Path.Combine(folder, file);
+ file = Path.ChangeExtension(file, Path.GetExtension(itm.BaseItemId));
+
+ // Now lookup itm record.
+ DBRecordCollection record = Database.GetRecordFromFile(file);
+ if (record is not null)
+ lootTableID = record.GetString("artifactBonusTableName", 0);
+ }
- string lootTableID = null;
- if (itm.IsRelic)
- lootTableID = itm.baseItemInfo.GetString("bonusTableName");
- else if (itm.HasRelicSlot1)
- {
- if (itm.RelicInfo != null)
- lootTableID = itm.RelicInfo.GetString("bonusTableName");
- }
- else if (itm.IsArtifact)
- {
- // for artifacts we need to find the formulae that was used to create the artifact. sucks to be us
- // The formulas seem to always be in the arcaneformulae subfolder with a _formula on the end
- // of the filename
- string folder = Path.GetDirectoryName(itm.BaseItemId);
- folder = Path.Combine(folder, "arcaneformulae");
- string file = Path.GetFileNameWithoutExtension(itm.BaseItemId);
+ if (!string.IsNullOrWhiteSpace(lootTableID))
+ return LootTableCollectionProvider.LoadTable(lootTableID);
- // Damn it, IL did not keep the filename consistent on Kingslayer (Sands of Kronos)
- if (file.ToUpperInvariant() == "E_GA_SANDOFKRONOS")
- file = file.Insert(9, "s");
+ return null;
+ }
- file = string.Concat(file, "_formula");
- file = Path.Combine(folder, file);
- file = Path.ChangeExtension(file, Path.GetExtension(itm.BaseItemId));
+ #endregion
- // Now lookup itm record.
- DBRecordCollection record = Database.GetRecordFromFile(file);
- if (record != null)
- lootTableID = record.GetString("artifactBonusTableName", 0);
- }
+ #region Item Public Methods
+
+ ///
+ /// Removes the first relic from this item
+ ///
+ /// Returns the removed relic as a new Item
+ public Item RemoveRelic1(Item itm)
+ {
+ if (!itm.HasRelicSlot1)
+ return null;
+
+ Item newRelic = itm.MakeEmptyCopy(itm.relicID);
+ newRelic.RelicBonusId = itm.RelicBonusId;
+ newRelic.RelicBonusInfo = itm.RelicBonusInfo;
+ newRelic.Var1 = itm.Var1;
+ GetDBData(newRelic);
- if (lootTableID != null && lootTableID.Length > 0)
- return LootTableCollectionProvider.LoadTable(lootTableID);
+ // Now clear out our relic data
+ itm.relicID = string.Empty;
+ itm.RelicBonusId = string.Empty;
+ itm.Var1 = 0;
+ itm.RelicInfo = null;
+ itm.RelicBonusInfo = null;
+ itm.IsModified = true;
+
+ return newRelic;
+ }
+
+ ///
+ /// Removes the second relic from this item
+ ///
+ /// Returns the removed relic as a new Item
+ public Item RemoveRelic2(Item itm)
+ {
+ if (!itm.HasRelicSlot2)
return null;
- }
- #endregion
+ Item newRelic = itm.MakeEmptyCopy(itm.relic2ID);
+ newRelic.RelicBonusId = itm.RelicBonus2Id;
+ newRelic.RelicBonusInfo = itm.RelicBonus2Info;
+ newRelic.Var1 = itm.Var2;
+ GetDBData(newRelic);
- #region Item Public Methods
+ // Now clear out our relic data
+ itm.relic2ID = string.Empty;
+ itm.RelicBonus2Id = string.Empty;
+ itm.Var2 = Item.var2Default;
+ itm.Relic2Info = null;
+ itm.RelicBonus2Info = null;
- ///
- /// Removes the first relic from this item
- ///
- /// Returns the removed relic as a new Item
- public Item RemoveRelic1(Item itm)
- {
- if (!itm.HasRelicSlot1)
- return null;
+ itm.IsModified = true;
- Item newRelic = itm.MakeEmptyCopy(itm.relicID);
- GetDBData(newRelic);
- newRelic.RelicBonusId = itm.RelicBonusId;
- newRelic.RelicBonusInfo = itm.RelicBonusInfo;
- newRelic.Var1 = itm.Var1;
+ return newRelic;
+ }
- // Now clear out our relic data
- itm.relicID = string.Empty;
- itm.RelicBonusId = string.Empty;
- itm.Var1 = 0;
- itm.RelicInfo = null;
- itm.RelicBonusInfo = null;
+ ///
+ /// Create an artifact from its formulae
+ ///
+ /// A new artifact
+ public Item CraftArtifact(Item itm)
+ {
+ if (itm.IsFormulae && itm.baseItemInfo != null)
+ {
+ string artifactID = itm.baseItemInfo.GetString("artifactName");
+ Item newArtifact = itm.MakeEmptyCopy(artifactID);
+ GetDBData(newArtifact);
itm.IsModified = true;
- return newRelic;
+ return newArtifact;
}
+ return null;
+ }
- ///
- /// Removes the second relic from this item
- ///
- /// Returns the removed relic as a new Item
- public Item RemoveRelic2(Item itm)
+ public SortedList GetRequirementVariables(Item itm)
+ {
+ var RequirementVariables = new SortedList();
+ if (itm.baseItemInfo != null)
{
- if (!itm.HasRelicSlot2)
- return null;
+ GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.BaseItemId));
+ GetDynamicRequirementsFromRecord(itm, RequirementVariables, itm.baseItemInfo);
+ }
- Item newRelic = itm.MakeEmptyCopy(itm.relic2ID);
- GetDBData(newRelic);
- newRelic.RelicBonusId = itm.RelicBonus2Id;
- newRelic.RelicBonusInfo = itm.RelicBonus2Info;
- newRelic.Var1 = itm.Var2;
+ if (itm.prefixInfo != null)
+ GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.prefixID));
- // Now clear out our relic data
- itm.relic2ID = string.Empty;
- itm.RelicBonus2Id = string.Empty;
- itm.Var2 = Item.var2Default;
- itm.Relic2Info = null;
- itm.RelicBonus2Info = null;
+ if (itm.suffixInfo != null)
+ GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.suffixID));
- itm.IsModified = true;
+ if (itm.RelicInfo != null)
+ GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.relicID));
- return newRelic;
- }
+ if (itm.Relic2Info != null)
+ GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.relic2ID));
- ///
- /// Create an artifact from its formulae
- ///
- /// A new artifact
- public Item CraftArtifact(Item itm)
+ // Add Artifact level requirement to formula
+ if (itm.IsFormulae && itm.baseItemInfo != null)
{
- if (itm.IsFormulae && itm.baseItemInfo != null)
- {
- string artifactID = itm.baseItemInfo.GetString("artifactName");
- Item newArtifact = itm.MakeEmptyCopy(artifactID);
- GetDBData(newArtifact);
+ string artifactID = itm.baseItemInfo.GetString("artifactName");
+ GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(artifactID));
+ }
- itm.IsModified = true;
+ return RequirementVariables;
+ }
- return newArtifact;
- }
+ ///
+ /// Gets the character stat bonuses for an item
+ ///
+ /// Item that needs stat bonuses looked up
+ /// Sorted List containing all of the stat bonuses
+ public SortedList GetStatBonuses(Item item)
+ {
+ var statBonuses = new SortedList();
+
+ if (item.baseItemInfo != null)
+ GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.BaseItemId));
+
+ if (item.prefixInfo != null)
+ GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.prefixID));
+
+ if (item.suffixInfo != null)
+ GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.suffixID));
+
+ if (item.RelicInfo != null)
+ GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.relicID), item.RelicInfo.CompletedRelicLevel);
+
+ if (item.Relic2Info != null)
+ GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.relic2ID), item.Relic2Info.CompletedRelicLevel);
+
+ return statBonuses;
+ }
+
+ ///
+ /// Gets the itemID's of all the items in the set.
+ ///
+ /// Flag to include the set name in the returned array
+ /// Returns a string array containing the remaining set items or null if the item is not part of a set.
+ public string[] GetSetItems(Item itm, bool includeName)
+ {
+ if (itm.baseItemInfo == null)
return null;
- }
- public SortedList GetRequirementVariables(Item itm)
- {
- var RequirementVariables = new SortedList();
- if (itm.baseItemInfo != null)
- {
- GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.BaseItemId));
- GetDynamicRequirementsFromRecord(itm, RequirementVariables, itm.baseItemInfo);
- }
+ string setID = itm.baseItemInfo.GetString("itemSetName");
+ if (string.IsNullOrEmpty(setID))
+ return null;
+
+ // Get the set record
+ DBRecordCollection setRecord = Database.GetRecordFromFile(setID);
+ if (setRecord == null)
+ return null;
- if (itm.prefixInfo != null)
- GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.prefixID));
+ string[] ans = setRecord.GetAllStrings("setMembers");
+ if (ans == null || ans.Length == 0)
+ return null;
- if (itm.suffixInfo != null)
- GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.suffixID));
+ // Added by VillageIdiot to support set Name
+ if (includeName)
+ {
+ string[] setitems = new string[ans.Length + 1];
+ setitems[0] = setRecord.GetString("setName", 0);
+ ans.CopyTo(setitems, 1);
+ return setitems;
+ }
+ else
+ return ans;
+ }
- if (itm.RelicInfo != null)
- GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.relicID));
- if (itm.Relic2Info != null)
- GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(itm.relic2ID));
+ ///
+ /// Encodes an item into the save file format
+ ///
+ /// BinaryWriter instance
+ public void Encode(Item itm, BinaryWriter writer)
+ {
+ int itemCount = itm.StackSize;
+ int cx = itm.PositionX;
+ int cy = itm.PositionY;
+ int cseed = itm.Seed;
- // Add Artifact level requirement to formula
- if (itm.IsFormulae && itm.baseItemInfo != null)
+ if (itm.ContainerType != SackType.Sack && itm.ContainerType != SackType.Player)
+ {
+ // Equipment, Stashes, Vaults
+ if (itm.ContainerType == SackType.Stash)
{
- string artifactID = itm.baseItemInfo.GetString("artifactName");
- GetRequirementsFromRecord(RequirementVariables, Database.GetRecordFromFile(artifactID));
+ TQData.WriteCString(writer, "stackCount");
+ writer.Write(itemCount - 1);
}
- return RequirementVariables;
- }
+ TQData.WriteCString(writer, "begin_block");
+ writer.Write(itm.beginBlockCrap2);
- ///
- /// Gets the character stat bonuses for an item
- ///
- /// Item that needs stat bonuses looked up
- /// Sorted List containing all of the stat bonuses
- public SortedList GetStatBonuses(Item item)
- {
- var statBonuses = new SortedList();
+ TQData.WriteCString(writer, "baseName");
+ TQData.WriteCString(writer, itm.BaseItemId);
- if (item.baseItemInfo != null)
- GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.BaseItemId));
+ TQData.WriteCString(writer, "prefixName");
+ TQData.WriteCString(writer, itm.prefixID);
- if (item.prefixInfo != null)
- GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.prefixID));
+ TQData.WriteCString(writer, "suffixName");
+ TQData.WriteCString(writer, itm.suffixID);
- if (item.suffixInfo != null)
- GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.suffixID));
+ TQData.WriteCString(writer, "relicName");
+ TQData.WriteCString(writer, itm.relicID);
- if (item.RelicInfo != null)
- GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.relicID), item.RelicInfo.CompletedRelicLevel);
+ TQData.WriteCString(writer, "relicBonus");
+ TQData.WriteCString(writer, itm.RelicBonusId);
- if (item.Relic2Info != null)
- GetStatBonusesFromRecord(statBonuses, Database.GetRecordFromFile(item.relic2ID), item.Relic2Info.CompletedRelicLevel);
+ TQData.WriteCString(writer, "seed");
+ writer.Write(cseed);
- return statBonuses;
- }
+ TQData.WriteCString(writer, "var1");
+ writer.Write(itm.Var1);
- ///
- /// Gets the itemID's of all the items in the set.
- ///
- /// Flag to include the set name in the returned array
- /// Returns a string array containing the remaining set items or null if the item is not part of a set.
- public string[] GetSetItems(Item itm, bool includeName)
- {
- if (itm.baseItemInfo == null)
- return null;
+ if (itm.atlantis)
+ {
+ TQData.WriteCString(writer, "relicName2");
+ TQData.WriteCString(writer, itm.relic2ID);
- string setID = itm.baseItemInfo.GetString("itemSetName");
- if (string.IsNullOrEmpty(setID))
- return null;
+ TQData.WriteCString(writer, "relicBonus2");
+ TQData.WriteCString(writer, itm.RelicBonus2Id);
- // Get the set record
- DBRecordCollection setRecord = Database.GetRecordFromFile(setID);
- if (setRecord == null)
- return null;
+ TQData.WriteCString(writer, "var2");
+ writer.Write(itm.Var2);
+ }
- string[] ans = setRecord.GetAllStrings("setMembers");
- if (ans == null || ans.Length == 0)
- return null;
+ TQData.WriteCString(writer, "end_block");
+ writer.Write(itm.endBlockCrap2);
- // Added by VillageIdiot to support set Name
- if (includeName)
+ if (itm.ContainerType == SackType.Stash)
{
- string[] setitems = new string[ans.Length + 1];
- setitems[0] = setRecord.GetString("setName", 0);
- ans.CopyTo(setitems, 1);
- return setitems;
+ TQData.WriteCString(writer, "xOffset");
+ writer.Write(Convert.ToSingle(cx, CultureInfo.InvariantCulture));
+
+ TQData.WriteCString(writer, "yOffset");
+ writer.Write(Convert.ToSingle(cy, CultureInfo.InvariantCulture));
}
- else
- return ans;
}
-
-
- ///
- /// Encodes an item into the save file format
- ///
- /// BinaryWriter instance
- public void Encode(Item itm, BinaryWriter writer)
+ else
{
- int itemCount = itm.StackSize;
- int cx = itm.PositionX;
- int cy = itm.PositionY;
- int cseed = itm.Seed;
-
- if (itm.ContainerType != SackType.Sack && itm.ContainerType != SackType.Player)
+ // itm is a sack
+ // enter a while() loop so we can print out each potion in the stack if it is a potion stack
+ while (true)
{
- // Equipment, Stashes, Vaults
- if (itm.ContainerType == SackType.Stash)
- {
- TQData.WriteCString(writer, "stackCount");
- writer.Write(itemCount - 1);
- }
+ TQData.WriteCString(writer, "begin_block");
+ writer.Write(itm.beginBlockCrap1);
TQData.WriteCString(writer, "begin_block");
writer.Write(itm.beginBlockCrap2);
@@ -471,609 +616,551 @@ public void Encode(Item itm, BinaryWriter writer)
TQData.WriteCString(writer, "end_block");
writer.Write(itm.endBlockCrap2);
- if (itm.ContainerType == SackType.Stash)
- {
- TQData.WriteCString(writer, "xOffset");
- writer.Write(Convert.ToSingle(cx, CultureInfo.InvariantCulture));
-
- TQData.WriteCString(writer, "yOffset");
- writer.Write(Convert.ToSingle(cy, CultureInfo.InvariantCulture));
- }
- }
- else
- {
- // itm is a sack
- // enter a while() loop so we can print out each potion in the stack if it is a potion stack
- while (true)
- {
- TQData.WriteCString(writer, "begin_block");
- writer.Write(itm.beginBlockCrap1);
-
- TQData.WriteCString(writer, "begin_block");
- writer.Write(itm.beginBlockCrap2);
-
- TQData.WriteCString(writer, "baseName");
- TQData.WriteCString(writer, itm.BaseItemId);
-
- TQData.WriteCString(writer, "prefixName");
- TQData.WriteCString(writer, itm.prefixID);
+ TQData.WriteCString(writer, "pointX");
+ writer.Write(cx);
- TQData.WriteCString(writer, "suffixName");
- TQData.WriteCString(writer, itm.suffixID);
+ TQData.WriteCString(writer, "pointY");
+ writer.Write(cy);
- TQData.WriteCString(writer, "relicName");
- TQData.WriteCString(writer, itm.relicID);
-
- TQData.WriteCString(writer, "relicBonus");
- TQData.WriteCString(writer, itm.RelicBonusId);
-
- TQData.WriteCString(writer, "seed");
- writer.Write(cseed);
-
- TQData.WriteCString(writer, "var1");
- writer.Write(itm.Var1);
-
- if (itm.atlantis)
- {
- TQData.WriteCString(writer, "relicName2");
- TQData.WriteCString(writer, itm.relic2ID);
-
- TQData.WriteCString(writer, "relicBonus2");
- TQData.WriteCString(writer, itm.RelicBonus2Id);
-
- TQData.WriteCString(writer, "var2");
- writer.Write(itm.Var2);
- }
-
- TQData.WriteCString(writer, "end_block");
- writer.Write(itm.endBlockCrap2);
-
- TQData.WriteCString(writer, "pointX");
- writer.Write(cx);
-
- TQData.WriteCString(writer, "pointY");
- writer.Write(cy);
-
- TQData.WriteCString(writer, "end_block");
- writer.Write(itm.endBlockCrap1);
+ TQData.WriteCString(writer, "end_block");
+ writer.Write(itm.endBlockCrap1);
- if (!itm.DoesStack)
- return;
+ if (!itm.DoesStack)
+ return;
- if (itemCount <= 1)
- return;
+ if (itemCount <= 1)
+ return;
- // we have more items in the stack to write().
- --itemCount;
- cx = -1;
- cy = -1;
- cseed = Item.GenerateSeed(); // get a new seed for the next potion
- }
+ // we have more items in the stack to write().
+ --itemCount;
+ cx = -1;
+ cy = -1;
+ cseed = Item.GenerateSeed(); // get a new seed for the next potion
}
}
+ }
- ///
- /// Parses an item from the save file format
- ///
- /// BinaryReader instance
- public void Parse(Item itm, BinaryReader reader)
+ ///
+ /// Parses an item from the save file format
+ ///
+ /// BinaryReader instance
+ public void Parse(Item itm, BinaryReader reader)
+ {
+ try
{
- try
+ if (itm.ContainerType == SackType.Stash)
+ {
+ TQData.ValidateNextString("stackCount", reader);
+ itm.beginBlockCrap1 = reader.ReadInt32();
+ }
+ else if (itm.ContainerType == SackType.Sack || itm.ContainerType == SackType.Player)
{
- if (itm.ContainerType == SackType.Stash)
- {
- TQData.ValidateNextString("stackCount", reader);
- itm.beginBlockCrap1 = reader.ReadInt32();
- }
- else if (itm.ContainerType == SackType.Sack || itm.ContainerType == SackType.Player)
- {
- TQData.ValidateNextString("begin_block", reader); // make sure we just read a new block
- itm.beginBlockCrap1 = reader.ReadInt32();
- }
-
TQData.ValidateNextString("begin_block", reader); // make sure we just read a new block
- itm.beginBlockCrap2 = reader.ReadInt32();
-
- TQData.ValidateNextString("baseName", reader);
- itm.BaseItemId = TQData.ReadCString(reader);
-
- TQData.ValidateNextString("prefixName", reader);
- itm.prefixID = TQData.ReadCString(reader);
-
- TQData.ValidateNextString("suffixName", reader);
- itm.suffixID = TQData.ReadCString(reader);
+ itm.beginBlockCrap1 = reader.ReadInt32();
+ }
- TQData.ValidateNextString("relicName", reader);
- itm.relicID = TQData.ReadCString(reader);
+ TQData.ValidateNextString("begin_block", reader); // make sure we just read a new block
+ itm.beginBlockCrap2 = reader.ReadInt32();
- TQData.ValidateNextString("relicBonus", reader);
- itm.RelicBonusId = TQData.ReadCString(reader);
+ TQData.ValidateNextString("baseName", reader);
+ itm.BaseItemId = TQData.ReadCString(reader);
- TQData.ValidateNextString("seed", reader);
- itm.Seed = reader.ReadInt32();
+ TQData.ValidateNextString("prefixName", reader);
+ itm.prefixID = TQData.ReadCString(reader);
- TQData.ValidateNextString("var1", reader);
- itm.Var1 = reader.ReadInt32();
+ TQData.ValidateNextString("suffixName", reader);
+ itm.suffixID = TQData.ReadCString(reader);
- if (TQData.MatchNextString("relicName2", reader))
- {
- TQData.ValidateNextString("relicName2", reader);
- itm.relic2ID = TQData.ReadCString(reader);
- itm.atlantis = true;
- }
+ TQData.ValidateNextString("relicName", reader);
+ itm.relicID = TQData.ReadCString(reader);
- if (itm.atlantis)
- {
- TQData.ValidateNextString("relicBonus2", reader);
- itm.RelicBonus2Id = TQData.ReadCString(reader);
+ TQData.ValidateNextString("relicBonus", reader);
+ itm.RelicBonusId = TQData.ReadCString(reader);
- TQData.ValidateNextString("var2", reader);
- itm.Var2 = reader.ReadInt32();
- }
- else
- {
- itm.relic2ID = string.Empty;
- itm.RelicBonus2Id = string.Empty;
- itm.Var2 = Item.var2Default;
- }
+ TQData.ValidateNextString("seed", reader);
+ itm.Seed = reader.ReadInt32();
- TQData.ValidateNextString("end_block", reader);
- itm.endBlockCrap2 = reader.ReadInt32();
+ TQData.ValidateNextString("var1", reader);
+ itm.Var1 = reader.ReadInt32();
- if (itm.ContainerType == SackType.Stash)
- {
- TQData.ValidateNextString("xOffset", reader);
- itm.PositionX = Convert.ToInt32(reader.ReadSingle(), CultureInfo.InvariantCulture);
+ if (TQData.MatchNextString("relicName2", reader))
+ {
+ TQData.ValidateNextString("relicName2", reader);
+ itm.relic2ID = TQData.ReadCString(reader);
+ itm.atlantis = true;
+ }
- TQData.ValidateNextString("yOffset", reader);
- itm.PositionY = Convert.ToInt32(reader.ReadSingle(), CultureInfo.InvariantCulture);
- }
- else if (itm.ContainerType == SackType.Equipment)
- {
- // Initially set the coordinates to (0, 0)
- itm.PositionX = 0;
- itm.PositionY = 0;
- }
- else
- {
- TQData.ValidateNextString("pointX", reader);
- itm.PositionX = reader.ReadInt32();
+ if (itm.atlantis)
+ {
+ TQData.ValidateNextString("relicBonus2", reader);
+ itm.RelicBonus2Id = TQData.ReadCString(reader);
- TQData.ValidateNextString("pointY", reader);
- itm.PositionY = reader.ReadInt32();
+ TQData.ValidateNextString("var2", reader);
+ itm.Var2 = reader.ReadInt32();
+ }
+ else
+ {
+ itm.relic2ID = string.Empty;
+ itm.RelicBonus2Id = string.Empty;
+ itm.Var2 = Item.var2Default;
+ }
- TQData.ValidateNextString("end_block", reader);
- itm.endBlockCrap1 = reader.ReadInt32();
- }
+ TQData.ValidateNextString("end_block", reader);
+ itm.endBlockCrap2 = reader.ReadInt32();
- GetDBData(itm);
+ if (itm.ContainerType == SackType.Stash)
+ {
+ TQData.ValidateNextString("xOffset", reader);
+ itm.PositionX = Convert.ToInt32(reader.ReadSingle(), CultureInfo.InvariantCulture);
- if (itm.ContainerType == SackType.Stash)
- itm.StackSize = itm.beginBlockCrap1 + 1;
- else
- itm.StackSize = 1;
+ TQData.ValidateNextString("yOffset", reader);
+ itm.PositionY = Convert.ToInt32(reader.ReadSingle(), CultureInfo.InvariantCulture);
}
- catch (ArgumentException ex)
+ else if (itm.ContainerType == SackType.Equipment)
{
- // The ValidateNextString Method can throw an ArgumentException.
- // We just pass it along at itm point.
- Log.LogDebug(ex, "ValidateNextString() fail !");
- throw;
+ // Initially set the coordinates to (0, 0)
+ itm.PositionX = 0;
+ itm.PositionY = 0;
+ }
+ else
+ {
+ TQData.ValidateNextString("pointX", reader);
+ itm.PositionX = reader.ReadInt32();
+
+ TQData.ValidateNextString("pointY", reader);
+ itm.PositionY = reader.ReadInt32();
+
+ TQData.ValidateNextString("end_block", reader);
+ itm.endBlockCrap1 = reader.ReadInt32();
}
- }
- ///
- /// Pulls data out of the TQ item database for this item.
- ///
- public void GetDBData(Item itm)
+ GetDBData(itm);
+
+ if (itm.ContainerType == SackType.Stash)
+ itm.StackSize = itm.beginBlockCrap1 + 1;
+ else
+ itm.StackSize = 1;
+ }
+ catch (ArgumentException ex)
{
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Item.GetDBData () baseItemID = {0}", itm.BaseItemId);
+ // The ValidateNextString Method can throw an ArgumentException.
+ // We just pass it along at itm point.
+ Log.LogDebug(ex, "ValidateNextString() fail !");
+ throw;
+ }
+ }
- itm.BaseItemId = CheckExtension(itm.BaseItemId);
- itm.baseItemInfo = Database.GetInfo(itm.BaseItemId);
+ ///
+ /// Pulls data out of the TQ item database for this item.
+ ///
+ public void GetDBData(Item itm)
+ {
+ if (TQDebug.ItemDebugLevel > 0)
+ Log.LogDebug("Item.GetDBData () baseItemID = {0}", itm.BaseItemId);
- itm.prefixID = CheckExtension(itm.prefixID);
- itm.suffixID = CheckExtension(itm.suffixID);
+ itm.BaseItemId = CheckExtension(itm.BaseItemId);
+ itm.baseItemInfo = Database.GetInfo(itm.BaseItemId);
- if (TQDebug.ItemDebugLevel > 1)
- {
- Log.LogDebug("prefixID = {0}", itm.prefixID);
- Log.LogDebug("suffixID = {0}", itm.suffixID);
- }
+ itm.prefixID = CheckExtension(itm.prefixID);
+ itm.suffixID = CheckExtension(itm.suffixID);
- itm.prefixInfo = Database.GetInfo(itm.prefixID);
- itm.suffixInfo = Database.GetInfo(itm.suffixID);
- itm.relicID = CheckExtension(itm.relicID);
- itm.RelicBonusId = CheckExtension(itm.RelicBonusId);
+ if (TQDebug.ItemDebugLevel > 1)
+ {
+ Log.LogDebug("prefixID = {0}", itm.prefixID);
+ Log.LogDebug("suffixID = {0}", itm.suffixID);
+ }
- if (TQDebug.ItemDebugLevel > 1)
- {
- Log.LogDebug("relicID = {0}", itm.relicID);
- Log.LogDebug("relicBonusID = {0}", itm.RelicBonusId);
- }
+ itm.prefixInfo = Database.GetInfo(itm.prefixID);
+ itm.suffixInfo = Database.GetInfo(itm.suffixID);
+ itm.relicID = CheckExtension(itm.relicID);
+ itm.RelicBonusId = CheckExtension(itm.RelicBonusId);
- itm.RelicInfo = Database.GetInfo(itm.relicID);
- itm.RelicBonusInfo = Database.GetInfo(itm.RelicBonusId);
+ if (TQDebug.ItemDebugLevel > 1)
+ {
+ Log.LogDebug("relicID = {0}", itm.relicID);
+ Log.LogDebug("relicBonusID = {0}", itm.RelicBonusId);
+ }
- itm.Relic2Info = Database.GetInfo(itm.relic2ID);
- itm.RelicBonus2Info = Database.GetInfo(itm.RelicBonus2Id);
+ itm.RelicInfo = Database.GetInfo(itm.relicID);
+ itm.RelicBonusInfo = Database.GetInfo(itm.RelicBonusId);
- if (TQDebug.ItemDebugLevel > 1)
- Log.LogDebug("'{0}' baseItemInfo is {1} null"
- , GetFriendlyNames(itm).FullNameBagTooltip
- , (itm.baseItemInfo == null) ? string.Empty : "NOT"
- );
+ itm.Relic2Info = Database.GetInfo(itm.relic2ID);
+ itm.RelicBonus2Info = Database.GetInfo(itm.RelicBonus2Id);
+
+ if (TQDebug.ItemDebugLevel > 1)
+ Log.LogDebug("'{0}' baseItemInfo is {1} null"
+ , GetFriendlyNames(itm).FullNameBagTooltip
+ , (itm.baseItemInfo == null) ? string.Empty : "NOT"
+ );
- // Extract image raw data
- if (itm.baseItemInfo != null)
+ // Extract image raw data
+ if (itm.baseItemInfo != null)
+ {
+ if (itm.IsRelic && !itm.IsRelicComplete)
{
- if (itm.IsRelic && !itm.IsRelicComplete)
- {
- itm.TexImageResourceId = itm.baseItemInfo.ShardBitmap;
- itm.TexImage = Database.LoadResource(itm.TexImageResourceId);
- if (TQDebug.ItemDebugLevel > 1)
- Log.LogDebug("Loaded shardbitmap ({0})", itm.baseItemInfo.ShardBitmap);
- }
- else
- {
- itm.TexImageResourceId = itm.baseItemInfo.Bitmap;
- itm.TexImage = Database.LoadResource(itm.TexImageResourceId);
- if (TQDebug.ItemDebugLevel > 1)
- Log.LogDebug("Loaded regular bitmap ({0})", itm.baseItemInfo.Bitmap);
- }
+ itm.TexImageResourceId = itm.baseItemInfo.ShardBitmap;
+ itm.TexImage = Database.LoadResource(itm.TexImageResourceId);
+ if (TQDebug.ItemDebugLevel > 1)
+ Log.LogDebug("Loaded shardbitmap ({0})", itm.baseItemInfo.ShardBitmap);
}
else
{
- // Added by VillageIdiot
- // Try showing something so unknown items are not invisible.
- itm.TexImageResourceId = "DefaultBitmap";
+ itm.TexImageResourceId = itm.baseItemInfo.Bitmap;
itm.TexImage = Database.LoadResource(itm.TexImageResourceId);
if (TQDebug.ItemDebugLevel > 1)
- Log.LogDebug("Try loading (DefaultBitmap)");
+ Log.LogDebug("Loaded regular bitmap ({0})", itm.baseItemInfo.Bitmap);
}
-
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Exiting Item.GetDBData ()");
}
-
- #endregion Item Public Methods
-
- #region Item Private Methods
-
- #region Item Private Methods
-
- ///
- /// Holds all of the keys which we are filtering
- ///
- /// key which we are checking whether or not it gets filtered.
- /// true if key is present in this list
- public bool FilterKey(string key)
+ else
{
- string keyUpper = key.ToUpperInvariant();
- return (Array.IndexOf(unwantedTags, keyUpper) != -1
- || keyUpper.EndsWith("SOUND", noCase)
- || keyUpper.EndsWith("MESH", noCase)
- || keyUpper.StartsWith("BODYMASK", noCase)
- );
+ // Added by VillageIdiot
+ // Try showing something so unknown items are not invisible.
+ itm.TexImageResourceId = "DefaultBitmap";
+ itm.TexImage = Database.LoadResource(itm.TexImageResourceId);
+ if (TQDebug.ItemDebugLevel > 1)
+ Log.LogDebug("Try loading (DefaultBitmap)");
}
- ///
- /// Holds all of the requirements which we are filtering
- ///
- /// key which we are checking whether or not it gets filtered.
- /// true if key is present in this list
- public bool FilterRequirements(string key)
- => Array.IndexOf(requirementTags, key.ToUpperInvariant()) != -1;
-
- ///
- /// Indicates whether the key is a character stat boosting attribute
- ///
- /// string containing the key that is being checked
- /// True if the key is a stat boosting attrbute.
- public bool IsStatBonus(string key)
- => Array.IndexOf(statBonusTags, key.ToUpperInvariant()) != -1;
-
-
- internal static ReadOnlyCollection> ItemClassToRequirementEquationPrefixMap = new List>
- {
- new (Item.ICLASS_HEAD, "head"),
- new (Item.ICLASS_FOREARM, "forearm"),
- new (Item.ICLASS_LOWERBODY, "lowerBody"),
- new (Item.ICLASS_UPPERBODY, "upperBody"),
- //new ("ARMORJEWELRY_BRACELET", "bracelet"),// TODO Does it exist ? ARMORJEWELRY_BRACELET
- new (Item.ICLASS_RING, "ring"),
- new (Item.ICLASS_AMULET, "amulet"),
- new (Item.ICLASS_BOW, "bow"),
- new (Item.ICLASS_SPEAR, "spear"),
- new (Item.ICLASS_RANGEDONEHAND, "bow"),
- new (Item.ICLASS_AXE, "axe"),
- new (Item.ICLASS_SWORD, "sword"),
- new (Item.ICLASS_MACE, "mace"),
- new (Item.ICLASS_STAFF, "staff"),
- new (Item.ICLASS_SHIELD, "shield"),
- }.AsReadOnly();
-
- ///
- /// Gets s string containing the prefix of the item class for use in the requirements equation.
- ///
- /// string containing the item class
- /// string containing the prefix of the item class for use in the requirements equation
- private string GetRequirementEquationPrefix(string itemClass)
- {
- var map = ItemClassToRequirementEquationPrefixMap
- .Where(m => m.ItemClass.Equals(itemClass, noCase))
- .Select(m => m.Value);
- return map.Any() ? map.First() : "none";
- }
-
-
- ///
- /// Gets whether or not the variable contains a value which we are filtering.
- ///
- /// Variable which we are checking.
- /// Flag indicating whether or not we are allowing strings to show up
- /// true if the variable contains a value which is filtered.
- public bool FilterValue(Variable variable, bool allowStrings)
- {
- for (int i = 0; i < variable.NumberOfValues; i++)
- {
- switch (variable.DataType)
- {
- case VariableDataType.Integer:
- if (variable.GetInt32(i) != 0)
- return false;
- break;
+ if (TQDebug.ItemDebugLevel > 0)
+ Log.LogDebug("Exiting Item.GetDBData ()");
+ }
- case VariableDataType.Float:
- if (variable.GetSingle(i) != 0.0)
- return false;
- break;
+ #endregion Item Public Methods
- case VariableDataType.StringVar:
- if ((
- allowStrings
- || variable.Name.ToUpperInvariant().Equals("CHARACTERBASEATTACKSPEEDTAG")
- || variable.Name.ToUpperInvariant().Equals("ITEMSKILLNAME") // Added by VillageIdiot for Granted skills
- || variable.Name.ToUpperInvariant().Equals("SKILLNAME") // Added by VillageIdiot for scroll skills
- || variable.Name.ToUpperInvariant().Equals("PETBONUSNAME") // Added by VillageIdiot for pet bonuses
- || ItemAttributeProvider.IsReagent(variable.Name)
- ) && variable.GetString(i).Length > 0
- )
- {
- return false;
- }
- break;
+ #region Item Private Methods
- case VariableDataType.Boolean:
- if (variable.GetInt32(i) != 0)
- return false;
- break;
- }
- }
+ #region Item Private Methods
- return true;
- }
+ ///
+ /// Holds all of the keys which we are filtering
+ ///
+ /// key which we are checking whether or not it gets filtered.
+ /// true if key is present in this list
+ public bool FilterKey(string key)
+ {
+ string keyUpper = key.ToUpperInvariant();
+ return (Array.IndexOf(unwantedTags, keyUpper) != -1
+ || keyUpper.EndsWith("SOUND", noCase)
+ || keyUpper.EndsWith("MESH", noCase)
+ || keyUpper.StartsWith("BODYMASK", noCase)
+ );
+ }
- ///
- /// Gets the stat bonuses for a database record.
- ///
- /// SortedList of stat bonuses
- /// database record
- /// optional level if there can be multiple values
- public void GetStatBonusesFromRecord(SortedList statBonuses, DBRecordCollection record, int statLevel = 0)
- {
- if (record == null || statBonuses == null)
- return;
+ ///
+ /// Holds all of the requirements which we are filtering
+ ///
+ /// key which we are checking whether or not it gets filtered.
+ /// true if key is present in this list
+ public bool FilterRequirements(string key)
+ => Array.IndexOf(requirementTags, key.ToUpperInvariant()) != -1;
- // Some entries can have multiple values, but the value needs to be adjusted for 0 based lookups.
- statLevel = statLevel < 1 ? 0 : statLevel - 1;
+ ///
+ /// Indicates whether the key is a character stat boosting attribute
+ ///
+ /// string containing the key that is being checked
+ /// True if the key is a stat boosting attrbute.
+ public bool IsStatBonus(string key)
+ => Array.IndexOf(statBonusTags, key.ToUpperInvariant()) != -1;
- foreach (Variable variable in record)
- {
- if (FilterValue(variable, false) || !IsStatBonus(variable.Name) || statLevel >= variable.NumberOfValues)
- continue;
+ internal static ReadOnlyCollection> ItemClassToRequirementEquationPrefixMap = new List>
+ {
+ new (Item.ICLASS_HEAD, "head"),
+ new (Item.ICLASS_FOREARM, "forearm"),
+ new (Item.ICLASS_LOWERBODY, "lowerBody"),
+ new (Item.ICLASS_UPPERBODY, "upperBody"),
+ //new ("ARMORJEWELRY_BRACELET", "bracelet"),// TODO Does it exist ? ARMORJEWELRY_BRACELET
+ new (Item.ICLASS_RING, "ring"),
+ new (Item.ICLASS_AMULET, "amulet"),
+ new (Item.ICLASS_BOW, "bow"),
+ new (Item.ICLASS_SPEAR, "spear"),
+ new (Item.ICLASS_RANGEDONEHAND, "bow"),
+ new (Item.ICLASS_AXE, "axe"),
+ new (Item.ICLASS_SWORD, "sword"),
+ new (Item.ICLASS_MACE, "mace"),
+ new (Item.ICLASS_STAFF, "staff"),
+ new (Item.ICLASS_SHIELD, "shield"),
+ }.AsReadOnly();
+
+ ///
+ /// Gets s string containing the prefix of the item class for use in the requirements equation.
+ ///
+ /// string containing the item class
+ /// string containing the prefix of the item class for use in the requirements equation
+ private string GetRequirementEquationPrefix(string itemClass)
+ {
+ var map = ItemClassToRequirementEquationPrefixMap
+ .Where(m => m.ItemClass.Equals(itemClass, noCase))
+ .Select(m => m.Value);
+ return map.Any() ? map.First() : "none";
+ }
- string key = variable.Name.ToUpperInvariant();
- int value = variable.GetInt32(statLevel);
- // Update the value if it already exists.
- if (statBonuses.ContainsKey(key))
- {
- value += statBonuses[key];
- statBonuses.Remove(key);
- }
+ ///
+ /// Gets whether or not the variable contains a value which we are filtering.
+ ///
+ /// Variable which we are checking.
+ /// Flag indicating whether or not we are allowing strings to show up
+ /// true if the variable contains a value which is filtered.
+ public bool FilterValue(Variable variable, bool allowStrings)
+ {
+ for (int i = 0; i < variable.NumberOfValues; i++)
+ {
+ switch (variable.DataType)
+ {
+ case VariableDataType.Integer:
+ if (variable.GetInt32(i) != 0)
+ return false;
+ break;
+
+ case VariableDataType.Float:
+ if (variable.GetSingle(i) != 0.0)
+ return false;
+ break;
+
+ case VariableDataType.StringVar:
+ if ((
+ allowStrings
+ || variable.Name.ToUpperInvariant().Equals("CHARACTERBASEATTACKSPEEDTAG")
+ || variable.Name.ToUpperInvariant().Equals("ITEMSKILLNAME") // Added by VillageIdiot for Granted skills
+ || variable.Name.ToUpperInvariant().Equals("SKILLNAME") // Added by VillageIdiot for scroll skills
+ || variable.Name.ToUpperInvariant().Equals("PETBONUSNAME") // Added by VillageIdiot for pet bonuses
+ || ItemAttributeProvider.IsReagent(variable.Name)
+ ) && variable.GetString(i).Length > 0
+ )
+ {
+ return false;
+ }
+ break;
- statBonuses.Add(key, value);
+ case VariableDataType.Boolean:
+ if (variable.GetInt32(i) != 0)
+ return false;
+ break;
}
}
- ///
- /// Checks to see if the id ends with .dbr and adds it if not.
- /// Sometimes the .dbr extension is not written into the item
- ///
- /// item id to be checked
- /// string containing itemId with a .dbr extension.
- private string CheckExtension(string itemId)
+ return true;
+ }
+
+ ///
+ /// Gets the stat bonuses for a database record.
+ ///
+ /// SortedList of stat bonuses
+ /// database record
+ /// optional level if there can be multiple values
+ public void GetStatBonusesFromRecord(SortedList statBonuses, DBRecordCollection record, int statLevel = 0)
+ {
+ if (record == null || statBonuses == null)
+ return;
+
+ // Some entries can have multiple values, but the value needs to be adjusted for 0 based lookups.
+ statLevel = statLevel < 1 ? 0 : statLevel - 1;
+
+ foreach (Variable variable in record)
{
- if (itemId == null)
- return null;
+ if (FilterValue(variable, false) || !IsStatBonus(variable.Name) || statLevel >= variable.NumberOfValues)
+ continue;
- if (itemId.Length < 4)
- return itemId;
+ string key = variable.Name.ToUpperInvariant();
+ int value = variable.GetInt32(statLevel);
- if (Path.GetExtension(itemId).ToUpperInvariant().Equals(".DBR"))
- return itemId;
- else
- return string.Concat(itemId, ".dbr");
+ // Update the value if it already exists.
+ if (statBonuses.ContainsKey(key))
+ {
+ value += statBonuses[key];
+ statBonuses.Remove(key);
+ }
+
+ statBonuses.Add(key, value);
}
+ }
+
+ ///
+ /// Checks to see if the id ends with .dbr and adds it if not.
+ /// Sometimes the .dbr extension is not written into the item
+ ///
+ /// item id to be checked
+ /// string containing itemId with a .dbr extension.
+ private string CheckExtension(string itemId)
+ {
+ if (itemId == null)
+ return null;
+
+ if (itemId.Length < 4)
+ return itemId;
+
+ if (Path.GetExtension(itemId).ToUpperInvariant().Equals(".DBR"))
+ return itemId;
+ else
+ return string.Concat(itemId, ".dbr");
+ }
+
+ ///
+ /// Gets the item requirements from the database record
+ ///
+ /// SortedList of requirements
+ /// database record
+ private void GetRequirementsFromRecord(SortedList requirements, DBRecordCollection record)
+ {
+ if (TQDebug.ItemDebugLevel > 0)
+ Log.LogDebug("Item.GetDynamicRequirementsFromRecord({0}, {1})", requirements, record);
- ///
- /// Gets the item requirements from the database record
- ///
- /// SortedList of requirements
- /// database record
- private void GetRequirementsFromRecord(SortedList requirements, DBRecordCollection record)
+ if (record == null)
{
if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Item.GetDynamicRequirementsFromRecord({0}, {1})", requirements, record);
+ Log.LogDebug("Error - record was null.");
- if (record == null)
- {
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Error - record was null.");
+ return;
+ }
- return;
- }
+ if (TQDebug.ItemDebugLevel > 1)
+ Log.LogDebug(record.Id);
- if (TQDebug.ItemDebugLevel > 1)
- Log.LogDebug(record.Id);
+ foreach (Variable variable in record)
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug(variable.Name);
- foreach (Variable variable in record)
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug(variable.Name);
+ if (FilterValue(variable, false))
+ continue;
- if (FilterValue(variable, false))
- continue;
+ if (!FilterRequirements(variable.Name))
+ continue;
- if (!FilterRequirements(variable.Name))
- continue;
+ string value = variable.ToStringValue();
+ string key = variable.Name.Replace("Requirement", string.Empty);
- string value = variable.ToStringValue();
- string key = variable.Name.Replace("Requirement", string.Empty);
+ // Upper-case the first char of key
+ key = string.Concat(key.Substring(0, 1).ToUpper(System.Globalization.CultureInfo.InvariantCulture), key.Substring(1));
- // Upper-case the first char of key
- key = string.Concat(key.Substring(0, 1).ToUpper(System.Globalization.CultureInfo.InvariantCulture), key.Substring(1));
+ // Level needs to be LevelRequirement bah
+ if (key.Equals("Level"))
+ key = Variable.KEY_LEVELREQ;
+ ;
+ // Keep Max value per Requirement (LevelRequirement, Strength, Dexterity, Intelligence)
+ if (requirements.ContainsKey(key))
+ {
+ Variable oldVariable = (Variable)requirements[key];
- // Level needs to be LevelRequirement bah
- if (key.Equals("Level"))
- key = Variable.KEY_LEVELREQ;
-;
- // Keep Max value per Requirement (LevelRequirement, Strength, Dexterity, Intelligence)
- if (requirements.ContainsKey(key))
+ // Changed by VillageIdiot
+ // Comparison was failing when level difference was too high
+ // (single digit vs multi-digit)
+ if (value.Contains(",") || oldVariable.Name.Contains(","))
{
- Variable oldVariable = (Variable)requirements[key];
-
- // Changed by VillageIdiot
- // Comparison was failing when level difference was too high
- // (single digit vs multi-digit)
- if (value.Contains(",") || oldVariable.Name.Contains(","))
- {
- // Just in case there is something with multiple values
- // Keep the original code
- if (string.Compare(value, oldVariable.ToStringValue(), noCase) <= 0)
- continue;
-
- requirements.Remove(key);
- }
- else
- {
- if (variable.GetInt32(0) <= oldVariable.GetInt32(0))
- continue;
+ // Just in case there is something with multiple values
+ // Keep the original code
+ if (string.Compare(value, oldVariable.ToStringValue(), noCase) <= 0)
+ continue;
- requirements.Remove(key);
- }
+ requirements.Remove(key);
}
+ else
+ {
+ if (variable.GetInt32(0) <= oldVariable.GetInt32(0))
+ continue;
- if (TQDebug.ItemDebugLevel > 1)
- Log.LogDebug("Added Requirement {0}={1}", key, value);
-
- requirements.Add(key, variable);
+ requirements.Remove(key);
+ }
}
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Exiting Item.GetDynamicRequirementsFromRecord()");
+ if (TQDebug.ItemDebugLevel > 1)
+ Log.LogDebug("Added Requirement {0}={1}", key, value);
+
+ requirements.Add(key, variable);
}
- ///
- /// Gets the dynamic requirements from a database record.
- ///
- /// SortedList of requirements
- /// ItemInfo for the item
- private void GetDynamicRequirementsFromRecord(Item itm, SortedList requirements, Info itemInfo)
- {
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Item.GetDynamicRequirementsFromRecord({0}, {1})", requirements, itemInfo);
+ if (TQDebug.ItemDebugLevel > 0)
+ Log.LogDebug("Exiting Item.GetDynamicRequirementsFromRecord()");
+ }
- DBRecordCollection record = Database.GetRecordFromFile(itemInfo.ItemId);
- if (record == null)
- return;
+ ///
+ /// Gets the dynamic requirements from a database record.
+ ///
+ /// SortedList of requirements
+ /// ItemInfo for the item
+ private void GetDynamicRequirementsFromRecord(Item itm, SortedList requirements, Info itemInfo)
+ {
+ if (TQDebug.ItemDebugLevel > 0)
+ Log.LogDebug("Item.GetDynamicRequirementsFromRecord({0}, {1})", requirements, itemInfo);
- string itemLevelTag = "itemLevel";
- Variable lvl = record[itemLevelTag];
- if (lvl == null)
- return;
+ DBRecordCollection record = Database.GetRecordFromFile(itemInfo.ItemId);
+ if (record == null)
+ return;
- string itemLevel = lvl.ToStringValue();
- string itemCostID = itemInfo.GetString("itemCostName");
+ string itemLevelTag = "itemLevel";
+ Variable lvl = record[itemLevelTag];
+ if (lvl == null)
+ return;
+
+ string itemLevel = lvl.ToStringValue();
+ string itemCostID = itemInfo.GetString("itemCostName");
- record = Database.GetRecordFromFile(itemCostID);
+ record = Database.GetRecordFromFile(itemCostID);
+ if (record == null)
+ {
+ record = Database.GetRecordFromFile("records/game/itemcost.dbr");
if (record == null)
- {
- record = Database.GetRecordFromFile("records/game/itemcost.dbr");
- if (record == null)
- return;
- }
+ return;
+ }
- if (TQDebug.ItemDebugLevel > 1)
- Log.LogDebug(record.Id);
+ if (TQDebug.ItemDebugLevel > 1)
+ Log.LogDebug(record.Id);
- string prefix = GetRequirementEquationPrefix(itemInfo.ItemClass);
- foreach (Variable variable in record)
- {
- if (string.Compare(variable.Name, 0, prefix, 0, prefix.Length, noCase) != 0)
- continue;
+ string prefix = GetRequirementEquationPrefix(itemInfo.ItemClass);
+ foreach (Variable variable in record)
+ {
+ if (string.Compare(variable.Name, 0, prefix, 0, prefix.Length, noCase) != 0)
+ continue;
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug(variable.Name);
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug(variable.Name);
- if (FilterValue(variable, true))
- // our equation is a string, so we want also strings
- return;
+ if (FilterValue(variable, true))
+ // our equation is a string, so we want also strings
+ return;
- string keyRaw = variable.Name;
- string key = variable.Name.Replace(prefix, string.Empty);
- key = key.Replace("Equation", string.Empty);
- key = key.Replace(key[0], char.ToUpperInvariant(key[0]));
+ string keyRaw = variable.Name;
+ string key = variable.Name.Replace(prefix, string.Empty);
+ key = key.Replace("Equation", string.Empty);
+ key = key.Replace(key[0], char.ToUpperInvariant(key[0]));
- // We need to ignore the cost equations.
- // Shields have costs so they will cause an overflow.
- if (key.Equals("Cost"))
- continue;
+ // We need to ignore the cost equations.
+ // Shields have costs so they will cause an overflow.
+ if (key.Equals("Cost"))
+ continue;
- var variableKey = key.ToLowerInvariant();
- if (variableKey == "level" || variableKey == "strength" || variableKey == "dexterity" || variableKey == "intelligence")
- variableKey += "Requirement";
+ var variableKey = key.ToLowerInvariant();
+ if (variableKey == "level" || variableKey == "strength" || variableKey == "dexterity" || variableKey == "intelligence")
+ variableKey += "Requirement";
- // Level needs to be LevelRequirement bah
- if (key.Equals("Level"))
- key = Variable.KEY_LEVELREQ;
+ // Level needs to be LevelRequirement bah
+ if (key.Equals("Level"))
+ key = Variable.KEY_LEVELREQ;
- // Skip over any requirements that have been set by the database record.
- if (requirements.ContainsKey(key))
- continue;
+ // Skip over any requirements that have been set by the database record.
+ if (requirements.ContainsKey(key))
+ continue;
- string valueRaw = variable.ToStringValue();
- string value = variable.ToStringValue().Replace(itemLevelTag, itemLevel);
+ string valueRaw = variable.ToStringValue();
+ string value = variable.ToStringValue().Replace(itemLevelTag, itemLevel);
- // Added by VillageIdiot
- // Changed to reflect Total Attribut count
- value = value.Replace("totalAttCount", Convert.ToString(itm.attributeCount, CultureInfo.InvariantCulture));
+ // Added by VillageIdiot
+ // Changed to reflect Total Attribut count
+ value = value.Replace("totalAttCount", Convert.ToString(itm.attributeCount, CultureInfo.InvariantCulture));
- // Changed by Bman to fix random overflow crashes
- Variable ans = new Variable(variableKey, VariableDataType.Integer, 1);
+ // Changed by Bman to fix random overflow crashes
+ Variable ans = new Variable(variableKey, VariableDataType.Integer, 1);
- // Changed by VillageIdiot to fix random overflow crashes.
- double tempVal = 0;
- try
- {
- tempVal = value.Eval();
- tempVal = Math.Ceiling(tempVal);
- }
- catch (System.Data.EvaluateException)
- {
- var mess = $@"Item Property value computation failed!
+ // Changed by VillageIdiot to fix random overflow crashes.
+ double tempVal = 0;
+ try
+ {
+ tempVal = value.Eval();
+ tempVal = Math.Ceiling(tempVal);
+ }
+ catch (System.Data.EvaluateException)
+ {
+ var mess = $@"Item Property value computation failed!
ItemID : {itemInfo.ItemId}
ItemLevel : {lvl.ToStringValue()}
@@ -1083,2589 +1170,2636 @@ record = Database.GetRecordFromFile("records/game/itemcost.dbr");
VariableValue Raw : {valueRaw}
""{value}"" can't be evaluated!
";
- if (TQDebug.ItemDebugLevel > 0)
- throw new System.Data.EvaluateException(mess);
- else Log.LogError(mess);
- }
-
- int intVal = 0;
- try
- {
- intVal = Convert.ToInt32(tempVal, CultureInfo.InvariantCulture);
- }
- catch (OverflowException)
- {
- intVal = 0;
- }
+ if (TQDebug.ItemDebugLevel > 0)
+ throw new System.Data.EvaluateException(mess);
+ else Log.LogError(mess);
+ }
- ans[0] = intVal;
+ int intVal = 0;
+ try
+ {
+ intVal = Convert.ToInt32(tempVal, CultureInfo.InvariantCulture);
+ }
+ catch (OverflowException)
+ {
+ intVal = 0;
+ }
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Added Requirement {0}={1}", key, ans.ToStringValue());
+ ans[0] = intVal;
- requirements.Add(key, ans);
- }
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Added Requirement {0}={1}", key, ans.ToStringValue());
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Exiting Item.GetDynamicRequirementsFromRecord()");
+ requirements.Add(key, ans);
}
- #endregion Item Private Methods
+ if (TQDebug.ItemDebugLevel > 0)
+ Log.LogDebug("Exiting Item.GetDynamicRequirementsFromRecord()");
+ }
- ///
- /// Gets the level of a triggered skill
- ///
- /// DBRecord for the triggered skill
- /// string containing the record id
- /// variable number which we are looking up since there can be multiple values
- /// int containing the skill level
- public int GetTriggeredSkillLevel(Item itm, DBRecordCollection record, string recordId, int varNum)
- {
- DBRecordCollection baseItem = Database.GetRecordFromFile(itm.baseItemInfo.ItemId);
+ #endregion Item Private Methods
+
+ ///
+ /// Gets the level of a triggered skill
+ ///
+ /// DBRecord for the triggered skill
+ /// string containing the record id
+ /// variable number which we are looking up since there can be multiple values
+ /// int containing the skill level
+ public int GetTriggeredSkillLevel(Item itm, DBRecordCollection record, string recordId, int varNum)
+ {
+ DBRecordCollection baseItem = Database.GetRecordFromFile(itm.baseItemInfo.ItemId);
- // Check to see if it's a Buff Skill
- if (baseItem.GetString("itemSkillAutoController", 0) != null)
+ // Check to see if it's a Buff Skill
+ if (baseItem.GetString("itemSkillAutoController", 0) != null)
+ {
+ int level = baseItem.GetInt32("itemSkillLevel", 0);
+ if (record.GetString("Class", 0).StartsWith("SKILLBUFF", noCase))
{
- int level = baseItem.GetInt32("itemSkillLevel", 0);
- if (record.GetString("Class", 0).StartsWith("SKILLBUFF", noCase))
- {
- DBRecordCollection skill = Database.GetRecordFromFile(itm.baseItemInfo.GetString("itemSkillName"));
- if (skill != null && skill.GetString("buffSkillName", 0) == recordId)
- // Use the level from the Base Item.
- varNum = Math.Max(level, 1) - 1;
- }
- else if (baseItem.GetString("itemSkillName", 0) == recordId)
+ DBRecordCollection skill = Database.GetRecordFromFile(itm.baseItemInfo.GetString("itemSkillName"));
+ if (skill != null && skill.GetString("buffSkillName", 0) == recordId)
+ // Use the level from the Base Item.
varNum = Math.Max(level, 1) - 1;
}
-
- return varNum;
+ else if (baseItem.GetString("itemSkillName", 0) == recordId)
+ varNum = Math.Max(level, 1) - 1;
}
- ///
- /// Pet skills can also have multiple values so we attempt to decode it here
- /// unfortunately the level is not in the skill record so we need to look up
- /// the level from the pet record.
- ///
- /// DBRecord of the skill
- /// string of the record id
- /// Which variable we are using since there can be multiple values.
- /// int containing the pet skill level
- public int GetPetSkillLevel(Item itm, DBRecordCollection record, string recordId, int varNum)
- {
- // Check to see if itm really is a skill
- if (record.GetString("Class", 0).StartsWith("SKILL_ATTACK", noCase))
- {
- // Check to see if itm item creates a pet
- DBRecordCollection petSkill = Database.GetRecordFromFile(itm.baseItemInfo.GetString("skillName"));
- string petID = petSkill.GetString("spawnObjects", 0);
- if (!string.IsNullOrEmpty(petID))
- {
- DBRecordCollection petRecord = Database.GetRecordFromFile(petID);
- int foundSkillOffset = 0;
- for (int skillOffset = 0; skillOffset < 17; skillOffset++)
- {
- // There are upto 17 skills
- // Find the skill in the skill tree so that we can get the level
- if (petRecord.GetString(string.Concat("skillName", skillOffset), 0) == recordId)
- break;
+ return varNum;
+ }
- foundSkillOffset++;
- }
+ ///
+ /// Pet skills can also have multiple values so we attempt to decode it here
+ /// unfortunately the level is not in the skill record so we need to look up
+ /// the level from the pet record.
+ ///
+ /// DBRecord of the skill
+ /// string of the record id
+ /// Which variable we are using since there can be multiple values.
+ /// int containing the pet skill level
+ public int GetPetSkillLevel(Item itm, DBRecordCollection record, string recordId, int varNum)
+ {
+ // Check to see if itm really is a skill
+ if (record.GetString("Class", 0).StartsWith("SKILL_ATTACK", noCase))
+ {
+ // Check to see if itm item creates a pet
+ DBRecordCollection petSkill = Database.GetRecordFromFile(itm.baseItemInfo.GetString("skillName"));
+ string petID = petSkill.GetString("spawnObjects", 0);
+ if (!string.IsNullOrEmpty(petID))
+ {
+ DBRecordCollection petRecord = Database.GetRecordFromFile(petID);
+ int foundSkillOffset = 0;
+ for (int skillOffset = 0; skillOffset < 17; skillOffset++)
+ {
+ // There are upto 17 skills
+ // Find the skill in the skill tree so that we can get the level
+ if (petRecord.GetString(string.Concat("skillName", skillOffset), 0) == recordId)
+ break;
- int level = petRecord.GetInt32(string.Concat("skillLevel", foundSkillOffset), 0);
- varNum = Math.Max(level, 1) - 1;
+ foundSkillOffset++;
}
- }
- return varNum;
+ int level = petRecord.GetInt32(string.Concat("skillLevel", foundSkillOffset), 0);
+ varNum = Math.Max(level, 1) - 1;
+ }
}
+ return varNum;
+ }
+
- #endregion Item Private Methods
+ #endregion Item Private Methods
- ///
- /// Formats a string based on the formatspec
- ///
- /// format specification
- /// first parameter
- /// second parameter
- /// third parameter
- /// formatted string.
- public string Format(string formatSpec, object parameter1, object parameter2 = null, object parameter3 = null)
+ ///
+ /// Formats a string based on the formatspec
+ ///
+ /// format specification
+ /// first parameter
+ /// second parameter
+ /// third parameter
+ /// formatted string.
+ public string Format(string formatSpec, object parameter1, object parameter2 = null, object parameter3 = null)
+ {
+ try
{
- try
- {
- return string.Format(CultureInfo.CurrentCulture, formatSpec, parameter1, parameter2, parameter3);
- }
- catch (ArgumentException)
- {
- string parameters = string.Format(
- CultureInfo.InvariantCulture,
- "\", '{0}', '{1}', '{2}'>",
- parameter1 == null ? "NULL" : parameter1,
- parameter2 == null ? "NULL" : parameter2,
- parameter3 == null ? "NULL" : parameter3);
+ return string.Format(CultureInfo.CurrentCulture, formatSpec, parameter1, parameter2, parameter3);
+ }
+ catch (ArgumentException)
+ {
+ string parameters = string.Format(
+ CultureInfo.InvariantCulture,
+ "\", '{0}', '{1}', '{2}'>",
+ parameter1 == null ? "NULL" : parameter1,
+ parameter2 == null ? "NULL" : parameter2,
+ parameter3 == null ? "NULL" : parameter3);
- string error = string.Concat("FormatErr(\"", formatSpec, parameters);
+ string error = string.Concat("FormatErr(\"", formatSpec, parameters);
- Log.LogDebug(error);
+ Log.LogDebug(error);
- return error;
- }
+ return error;
}
+ }
- ///
- /// Gets the item name and attributes.
- ///
- ///
- /// Extra data scopes as a bitmask
- /// filter extra properties
- /// An object containing the item name and attributes
- public ToFriendlyNameResult GetFriendlyNames(Item itm, FriendlyNamesExtraScopes? scopes = null, bool filterExtra = true)
+ ///
+ /// Gets the item name and attributes.
+ ///
+ ///
+ /// Extra data scopes as a bitmask
+ /// filter extra properties
+ /// An object containing the item name and attributes
+ public ToFriendlyNameResult GetFriendlyNames(Item itm, FriendlyNamesExtraScopes? scopes = null, bool filterExtra = true)
+ {
+ var key = (itm, scopes, filterExtra);
+ return FriendlyNamesCache.GetOrAddAtomic(key, k =>
{
- var key = (itm, scopes, filterExtra);
- return FriendlyNamesCache.GetOrAddAtomic(key, k =>
- {
- var res = new ToFriendlyNameResult(k.Item);
- k.Item.CurrentFriendlyNameResult = res;
+ var res = new ToFriendlyNameResult(k.Item);
+ k.Item.CurrentFriendlyNameResult = res;
- #region Minimal Info (ButtonBag tooltip + Common item properties)
+ #region Minimal Info (ButtonBag tooltip + Common item properties)
- // Item Seed
- res.ItemSeed = string.Format(CultureInfo.CurrentCulture, this.TranslationService.ItemSeed, k.Item.Seed, (k.Item.Seed != 0) ? (k.Item.Seed / (float)Int16.MaxValue) : 0.0f);
- res.ItemQuest = this.TranslationService.ItemQuest;
+ // Item Seed
+ res.ItemSeed = string.Format(CultureInfo.CurrentCulture, this.TranslationService.ItemSeed, k.Item.Seed, (k.Item.Seed != 0) ? (k.Item.Seed / (float)Int16.MaxValue) : 0.0f);
+ res.ItemQuest = this.TranslationService.ItemQuest;
- res.ItemThrown = itm.IsThrownWeapon ? this.TranslationService.TranslateXTag("x2tagThrownWeapon") : null;
+ res.ItemThrown = itm.IsThrownWeapon ? this.TranslationService.TranslateXTag("x2tagThrownWeapon") : null;
- res.ItemOrigin = itm.GameExtension switch {
- GameExtension.Atlantis => this.TranslationService.ItemAtlantis,
- GameExtension.EternalEmbers => this.TranslationService.ItemEmbers,
- GameExtension.Ragnarok => this.TranslationService.ItemRagnarok,
- GameExtension.ImmortalThrone => this.TranslationService.ItemIT,
- _ => null
- };
+ res.ItemOrigin = itm.GameExtension switch
+ {
+ GameExtension.Atlantis => this.TranslationService.ItemAtlantis,
+ GameExtension.EternalEmbers => this.TranslationService.ItemEmbers,
+ GameExtension.Ragnarok => this.TranslationService.ItemRagnarok,
+ GameExtension.ImmortalThrone => this.TranslationService.ItemIT,
+ _ => null
+ };
- #region Prefix translation
+ #region Prefix translation
- if (!k.Item.IsRelic && !string.IsNullOrEmpty(k.Item.prefixID))
+ if (!k.Item.IsRelic && !string.IsNullOrEmpty(k.Item.prefixID))
+ {
+ res.PrefixInfoDescription = k.Item.prefixID;
+ if (k.Item.prefixInfo != null)
{
- res.PrefixInfoDescription = k.Item.prefixID;
- if (k.Item.prefixInfo != null)
- {
- if (TranslationService.TryTranslateXTag(k.Item.prefixInfo.DescriptionTag, out var desc))
- res.PrefixInfoDescription = desc;
- }
+ if (TranslationService.TryTranslateXTag(k.Item.prefixInfo.DescriptionTag, out var desc))
+ res.PrefixInfoDescription = desc;
}
+ }
- #endregion
+ #endregion
- #region Base Item translation
+ #region Base Item translation
- // Load common relic translations if item is relic related by any means
- if (k.Item.IsRelic || k.Item.HasRelicSlot1 || k.Item.HasRelicSlot2 || k.Item.RelicInfo != null || k.Item.Relic2Info != null)
- {
- res.ItemWith = this.TranslationService.ItemWith;
+ // Load common relic translations if item is relic related by any means
+ if (k.Item.IsRelic || k.Item.HasRelicSlot1 || k.Item.HasRelicSlot2 || k.Item.RelicInfo != null || k.Item.Relic2Info != null)
+ {
+ res.ItemWith = this.TranslationService.ItemWith;
- if (k.Item.RelicInfo != null)
- TranslationService.TryTranslateXTag(k.Item.RelicInfo.DescriptionTag, out res.RelicInfo1Description);
+ if (k.Item.RelicInfo != null)
+ TranslationService.TryTranslateXTag(k.Item.RelicInfo.DescriptionTag, out res.RelicInfo1Description);
- if (k.Item.Relic2Info != null)
- TranslationService.TryTranslateXTag(k.Item.Relic2Info.DescriptionTag, out res.RelicInfo2Description);
+ if (k.Item.Relic2Info != null)
+ TranslationService.TryTranslateXTag(k.Item.Relic2Info.DescriptionTag, out res.RelicInfo2Description);
- var labelCompleted = "Completed";
- if (!TranslationService.TryTranslateXTag("tagAnimalPartComplete", out res.AnimalPartComplete))
- res.AnimalPartComplete = labelCompleted;
+ var labelCompleted = "Completed";
+ if (!TranslationService.TryTranslateXTag("tagAnimalPartComplete", out res.AnimalPartComplete))
+ res.AnimalPartComplete = labelCompleted;
- if (!TranslationService.TryTranslateXTag("tagRelicComplete", out res.RelicComplete))
- res.RelicComplete = labelCompleted;
+ if (!TranslationService.TryTranslateXTag("tagRelicComplete", out res.RelicComplete))
+ res.RelicComplete = labelCompleted;
- var labelPartcomplete = "Completion Bonus: ";
- if (!TranslationService.TryTranslateXTag("tagAnimalPartcompleteBonus", out res.AnimalPartCompleteBonus))
- res.AnimalPartCompleteBonus = labelPartcomplete;
+ var labelPartcomplete = "Completion Bonus: ";
+ if (!TranslationService.TryTranslateXTag("tagAnimalPartcompleteBonus", out res.AnimalPartCompleteBonus))
+ res.AnimalPartCompleteBonus = labelPartcomplete;
- if (!TranslationService.TryTranslateXTag("tagRelicBonus", out res.RelicBonus))
- res.RelicBonus = labelPartcomplete;
+ if (!TranslationService.TryTranslateXTag("tagRelicBonus", out res.RelicBonus))
+ res.RelicBonus = labelPartcomplete;
- var labelRelic = "Relic";
- if (!TranslationService.TryTranslateXTag("tagAnimalPart", out res.AnimalPart))
- res.AnimalPart = labelRelic;
+ var labelRelic = "Relic";
+ if (!TranslationService.TryTranslateXTag("tagAnimalPart", out res.AnimalPart))
+ res.AnimalPart = labelRelic;
- if (!TranslationService.TryTranslateXTag("tagRelicShard", out res.RelicShard))
- res.RelicShard = labelRelic;
+ if (!TranslationService.TryTranslateXTag("tagRelicShard", out res.RelicShard))
+ res.RelicShard = labelRelic;
- var labelRelicPattern = "{0} - {1} / {2}";
- if (TranslationService.TryTranslateXTag("tagAnimalPartRatio", out res.AnimalPartRatio))
- res.AnimalPartRatio = ItemAttributeProvider.ConvertFormat(res.AnimalPartRatio);
- else
- res.AnimalPartRatio = labelRelicPattern;
+ var labelRelicPattern = "{0} - {1} / {2}";
+ if (TranslationService.TryTranslateXTag("tagAnimalPartRatio", out res.AnimalPartRatio))
+ res.AnimalPartRatio = ItemAttributeProvider.ConvertFormat(res.AnimalPartRatio);
+ else
+ res.AnimalPartRatio = labelRelicPattern;
- if (TranslationService.TryTranslateXTag("tagRelicRatio", out res.RelicRatio))
- res.RelicRatio = ItemAttributeProvider.ConvertFormat(res.RelicRatio);
- else
- res.RelicRatio = labelRelicPattern;
- }
+ if (TranslationService.TryTranslateXTag("tagRelicRatio", out res.RelicRatio))
+ res.RelicRatio = ItemAttributeProvider.ConvertFormat(res.RelicRatio);
+ else
+ res.RelicRatio = labelRelicPattern;
+ }
- res.BaseItemId = k.Item.BaseItemId;
+ res.BaseItemId = k.Item.BaseItemId;
- // Set Rarity translation
- res.BaseItemRarity = TranslationService.Translate(k.Item.ItemStyle);
+ // Set Rarity translation
+ res.BaseItemRarity = TranslationService.Translate(k.Item.ItemStyle);
- if (k.Item.baseItemInfo != null)
+ if (k.Item.baseItemInfo != null)
+ {
+ // style quality description
+ if (!string.IsNullOrEmpty(k.Item.baseItemInfo.StyleTag))
{
- // style quality description
- if (!string.IsNullOrEmpty(k.Item.baseItemInfo.StyleTag))
+ if (!k.Item.IsPotion && !k.Item.IsRelic && !k.Item.IsScroll && !k.Item.IsParchment && !k.Item.IsQuestItem)
{
- if (!k.Item.IsPotion && !k.Item.IsRelic && !k.Item.IsScroll && !k.Item.IsParchment && !k.Item.IsQuestItem)
- {
- if (!TranslationService.TryTranslateXTag(k.Item.baseItemInfo.StyleTag, out res.BaseItemInfoStyle))
- res.BaseItemInfoStyle = k.Item.baseItemInfo.StyleTag;
- }
+ if (!TranslationService.TryTranslateXTag(k.Item.baseItemInfo.StyleTag, out res.BaseItemInfoStyle))
+ res.BaseItemInfoStyle = k.Item.baseItemInfo.StyleTag;
}
+ }
- if (!string.IsNullOrEmpty(k.Item.baseItemInfo.QualityTag))
- {
- if (!TranslationService.TryTranslateXTag(k.Item.baseItemInfo.QualityTag, out res.BaseItemInfoQuality))
- res.BaseItemInfoQuality = k.Item.baseItemInfo.QualityTag;
- }
+ if (!string.IsNullOrEmpty(k.Item.baseItemInfo.QualityTag))
+ {
+ if (!TranslationService.TryTranslateXTag(k.Item.baseItemInfo.QualityTag, out res.BaseItemInfoQuality))
+ res.BaseItemInfoQuality = k.Item.baseItemInfo.QualityTag;
+ }
- if (!TranslationService.TryTranslateXTag(k.Item.baseItemInfo.DescriptionTag, out res.BaseItemInfoDescription))
- res.BaseItemInfoDescription = k.Item.BaseItemId;
+ if (!TranslationService.TryTranslateXTag(k.Item.baseItemInfo.DescriptionTag, out res.BaseItemInfoDescription))
+ res.BaseItemInfoDescription = k.Item.BaseItemId;
- res.BaseItemInfoClass = TranslationService.TranslateXTag(k.Item.ItemClassTagName);
+ res.BaseItemInfoClass = TranslationService.TranslateXTag(k.Item.ItemClassTagName);
- res.BaseItemInfoRecords = Database.GetRecordFromFile(k.Item.BaseItemId);
+ res.BaseItemInfoRecords = Database.GetRecordFromFile(k.Item.BaseItemId);
- if (k.Item.IsRelic)
+ if (k.Item.IsRelic)
+ {
+ // Add the number of charms in the set acquired.
+ if (k.Item.IsRelicComplete)
{
- // Add the number of charms in the set acquired.
- if (k.Item.IsRelicComplete)
+ if (k.Item.IsCharm)
{
- if (k.Item.IsCharm)
- {
- res.RelicCompletionFormat = res.AnimalPartComplete;
- res.RelicBonusTitle = res.AnimalPartCompleteBonus;
- }
- else
- {
- res.RelicCompletionFormat = res.RelicComplete;
- res.RelicBonusTitle = res.RelicBonus;
- }
-
- if (!string.IsNullOrEmpty(k.Item.RelicBonusId))
- {
- res.RelicBonusFileName = k.Item.RelicBonusId.PrettyFileName();
- res.RelicBonusPattern = "{0} {1}";
- res.RelicBonusFormat = string.Format(CultureInfo.CurrentCulture, res.RelicBonusPattern
- , res.RelicBonusTitle
- , TQColor.Yellow.ColorTag() + res.RelicBonusFileName
- );
- }
- else
- {
- res.RelicBonusPattern = "{0}";
- res.RelicBonusFormat = string.Format(CultureInfo.CurrentCulture, res.RelicBonusPattern, res.RelicBonusTitle);
- }
+ res.RelicCompletionFormat = res.AnimalPartComplete;
+ res.RelicBonusTitle = res.AnimalPartCompleteBonus;
}
else
{
- if (k.Item.IsCharm)
- {
- res.RelicClass = res.AnimalPart;
- res.RelicPattern = res.AnimalPartRatio;
- }
- else
- {
- res.RelicClass = res.RelicShard;
- res.RelicPattern = res.RelicRatio;
- }
-
- res.RelicCompletionFormat = Format(res.RelicPattern, res.RelicClass, k.Item.Number, k.Item.baseItemInfo.CompletedRelicLevel);
- res.RelicBonusFormat = res.RelicCompletionFormat;
+ res.RelicCompletionFormat = res.RelicComplete;
+ res.RelicBonusTitle = res.RelicBonus;
}
- }
- else if (k.Item.IsArtifact)
- {
- // Add Artifact completion bonus
if (!string.IsNullOrEmpty(k.Item.RelicBonusId))
{
- var RelicBonusIdExt = Path.GetFileNameWithoutExtension(TQData.NormalizeRecordPath(k.Item.RelicBonusId));
- res.ArtifactBonus = TranslationService.TranslateXTag("xtagArtifactBonus");
- res.ArtifactBonusFormat = string.Format(CultureInfo.CurrentCulture, "({0} {1})", res.ArtifactBonus, RelicBonusIdExt);
+ res.RelicBonusFileName = k.Item.RelicBonusId.PrettyFileName();
+ res.RelicBonusPattern = "{0} {1}";
+ res.RelicBonusFormat = string.Format(CultureInfo.CurrentCulture, res.RelicBonusPattern
+ , res.RelicBonusTitle
+ , TQColor.Yellow.ColorTag() + res.RelicBonusFileName
+ );
+ }
+ else
+ {
+ res.RelicBonusPattern = "{0}";
+ res.RelicBonusFormat = string.Format(CultureInfo.CurrentCulture, res.RelicBonusPattern, res.RelicBonusTitle);
}
-
- // Show Artifact Class (Lesser / Greater / Divine).
- string artifactClassification = k.Item.baseItemInfo.GetString("artifactClassification").ToUpperInvariant();
- res.ArtifactClass = TranslateArtifactClassification(artifactClassification);
-
}
- else if (k.Item.IsFormulae)
+ else
{
- // Added to show recipe type for Formulae
- if (!TranslationService.TryTranslateXTag("xtagArtifactRecipe", out res.ArtifactRecipe))
- res.ArtifactRecipe = "Recipe";
-
- // Get Reagents format
- if (TranslationService.TryTranslateXTag("xtagArtifactReagents", out res.ArtifactReagents))
- res.ArtifactReagents = ItemAttributeProvider.ConvertFormat(res.ArtifactReagents);
+ if (k.Item.IsCharm)
+ {
+ res.RelicClass = res.AnimalPart;
+ res.RelicPattern = res.AnimalPartRatio;
+ }
else
- res.ArtifactReagents = "Required Reagents ({0}/{1})";
-
-
- // it looks like the formulae reagents is hard coded at 3
- res.FormulaeFormat = Format(res.ArtifactReagents, (object)0, 3);
- res.FormulaeFormat = $"{TQColor.Orange.ColorTag()}{res.FormulaeFormat}";
+ {
+ res.RelicClass = res.RelicShard;
+ res.RelicPattern = res.RelicRatio;
+ }
+ res.RelicCompletionFormat = Format(res.RelicPattern, res.RelicClass, k.Item.Number, k.Item.baseItemInfo.CompletedRelicLevel);
+ res.RelicBonusFormat = res.RelicCompletionFormat;
}
- else if (k.Item.DoesStack)
+
+ }
+ else if (k.Item.IsArtifact)
+ {
+ // Add Artifact completion bonus
+ if (!string.IsNullOrEmpty(k.Item.RelicBonusId))
{
- // display the # potions
- if (k.Item.Number > 1)
- res.NumberFormat = string.Format(CultureInfo.CurrentCulture, "({0:n0})", k.Item.Number);
+ var RelicBonusIdExt = Path.GetFileNameWithoutExtension(TQData.NormalizeRecordPath(k.Item.RelicBonusId));
+ res.ArtifactBonus = TranslationService.TranslateXTag("xtagArtifactBonus");
+ res.ArtifactBonusFormat = string.Format(CultureInfo.CurrentCulture, "({0} {1})", res.ArtifactBonus, RelicBonusIdExt);
}
- }
-
- #endregion
- #region Suffix translation
+ // Show Artifact Class (Lesser / Greater / Divine).
+ string artifactClassification = k.Item.baseItemInfo.GetString("artifactClassification").ToUpperInvariant();
+ res.ArtifactClass = TranslateArtifactClassification(artifactClassification);
- if (!k.Item.IsRelic && !string.IsNullOrWhiteSpace(k.Item.suffixID))
+ }
+ else if (k.Item.IsFormulae)
{
- if (k.Item.suffixInfo != null)
- {
- if (!TranslationService.TryTranslateXTag(k.Item.suffixInfo.DescriptionTag, out res.SuffixInfoDescription))
- res.SuffixInfoDescription = k.Item.suffixID;
- }
+ // Added to show recipe type for Formulae
+ if (!TranslationService.TryTranslateXTag("xtagArtifactRecipe", out res.ArtifactRecipe))
+ res.ArtifactRecipe = "Recipe";
+
+ // Get Reagents format
+ if (TranslationService.TryTranslateXTag("xtagArtifactReagents", out res.ArtifactReagents))
+ res.ArtifactReagents = ItemAttributeProvider.ConvertFormat(res.ArtifactReagents);
else
- res.SuffixInfoDescription = k.Item.suffixID;
- }
+ res.ArtifactReagents = "Required Reagents ({0}/{1})";
- #endregion
- #region flavor text
+ // it looks like the formulae reagents is hard coded at 3
+ res.FormulaeFormat = Format(res.ArtifactReagents, (object)0, 3);
+ res.FormulaeFormat = $"{TQColor.Orange.ColorTag()}{res.FormulaeFormat}";
- // Removed Scroll flavor text since it gets printed by the skill effect code
- if ((k.Item.IsPotion || k.Item.IsRelic || k.Item.IsScroll || k.Item.IsParchment || k.Item.IsQuestItem) && !string.IsNullOrWhiteSpace(k.Item.baseItemInfo?.StyleTag))
+ }
+ else if (k.Item.DoesStack)
{
- if (TranslationService.TryTranslateXTag(k.Item.baseItemInfo.StyleTag, out var flavor))
- {
- var ft = StringHelper.WrapWords(flavor, 40);
- res.FlavorText = ft.ToArray();
- }
+ // display the # potions
+ if (k.Item.Number > 1)
+ res.NumberFormat = string.Format(CultureInfo.CurrentCulture, "({0:n0})", k.Item.Number);
}
+ }
- #endregion
-
- #endregion
+ #endregion
- List results = new List();
+ #region Suffix translation
- if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.PrefixAttributes) ?? false)
+ if (!k.Item.IsRelic && !string.IsNullOrWhiteSpace(k.Item.suffixID))
+ {
+ if (k.Item.suffixInfo != null)
{
- if (k.Item.prefixInfo != null)
- res.PrefixInfoRecords = Database.GetRecordFromFile(k.Item.prefixID);
+ if (!TranslationService.TryTranslateXTag(k.Item.suffixInfo.DescriptionTag, out res.SuffixInfoDescription))
+ res.SuffixInfoDescription = k.Item.suffixID;
+ }
+ else
+ res.SuffixInfoDescription = k.Item.suffixID;
+ }
- if (res.PrefixInfoRecords?.Any() ?? false)
- GetAttributesFromRecord(k.Item, res.PrefixInfoRecords, k.FilterExtra, k.Item.prefixID, results);
+ #endregion
- res.PrefixAttributes = results.ToArray();
- }
+ #region flavor text
- if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.SuffixAttributes) ?? false)
+ // Removed Scroll flavor text since it gets printed by the skill effect code
+ if ((k.Item.IsPotion || k.Item.IsRelic || k.Item.IsScroll || k.Item.IsParchment || k.Item.IsQuestItem) && !string.IsNullOrWhiteSpace(k.Item.baseItemInfo?.StyleTag))
+ {
+ if (TranslationService.TryTranslateXTag(k.Item.baseItemInfo.StyleTag, out var flavor))
{
- results.Clear();
+ var ft = StringHelper.WrapWords(flavor, 40);
+ res.FlavorText = ft.ToArray();
+ }
+ }
- if (k.Item.suffixInfo != null)
- res.SuffixInfoRecords = Database.GetRecordFromFile(k.Item.suffixID);
+ #endregion
- if (res.SuffixInfoRecords?.Any() ?? false)
- GetAttributesFromRecord(k.Item, res.SuffixInfoRecords, k.FilterExtra, k.Item.suffixID, results);
+ #endregion
- res.SuffixAttributes = results.ToArray();
- }
+ List results = new List();
- if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.BaseAttributes) ?? false)
- {
- results.Clear();
-
- // res.baseItemInfoRecords should be already loaded
- if (res.BaseItemInfoRecords?.Any() ?? false)
- GetAttributesFromRecord(k.Item, res.BaseItemInfoRecords, k.FilterExtra, k.Item.BaseItemId, results);
- }
+ if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.PrefixAttributes) ?? false)
+ {
+ if (k.Item.prefixInfo != null)
+ res.PrefixInfoRecords = Database.GetRecordFromFile(k.Item.prefixID);
- res.BaseAttributes = results.ToArray();
+ if (res.PrefixInfoRecords?.Any() ?? false)
+ GetAttributesFromRecord(k.Item, res.PrefixInfoRecords, k.FilterExtra, k.Item.prefixID, results);
- if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.RelicAttributes) ?? false)
- {
- var tmp = new List();
+ res.PrefixAttributes = results.ToArray();
+ }
- if (k.Item.RelicInfo != null)
- res.RelicInfoRecords = Database.GetRecordFromFile(k.Item.relicID);
+ if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.SuffixAttributes) ?? false)
+ {
+ results.Clear();
- if (res.RelicInfoRecords?.Any() ?? false)
- GetAttributesFromRecord(k.Item, res.RelicInfoRecords, k.FilterExtra, k.Item.relicID, tmp);
+ if (k.Item.suffixInfo != null)
+ res.SuffixInfoRecords = Database.GetRecordFromFile(k.Item.suffixID);
- res.Relic1Attributes = tmp.ToArray();
- }
+ if (res.SuffixInfoRecords?.Any() ?? false)
+ GetAttributesFromRecord(k.Item, res.SuffixInfoRecords, k.FilterExtra, k.Item.suffixID, results);
- if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.Relic2Attributes) ?? false)
- {
- var tmp = new List();
+ res.SuffixAttributes = results.ToArray();
+ }
- if (k.Item.Relic2Info != null)
- res.Relic2InfoRecords = Database.GetRecordFromFile(k.Item.relic2ID);
+ if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.BaseAttributes) ?? false)
+ {
+ results.Clear();
- if (res.Relic2InfoRecords?.Any() ?? false)
- GetAttributesFromRecord(k.Item, res.Relic2InfoRecords, k.FilterExtra, k.Item.relic2ID, tmp);
+ // res.baseItemInfoRecords should be already loaded
+ if (res.BaseItemInfoRecords?.Any() ?? false)
+ GetAttributesFromRecord(k.Item, res.BaseItemInfoRecords, k.FilterExtra, k.Item.BaseItemId, results);
+ }
- res.Relic2Attributes = tmp.ToArray();
- }
+ res.BaseAttributes = results.ToArray();
- if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.ItemSet) ?? false)
- res.ItemSet = GetItemSetString(k.Item);
+ if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.RelicAttributes) ?? false)
+ {
+ var tmp = new List();
- if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.Requirements) ?? false)
- {
- var reqs = GetRequirements(k.Item);
- res.Requirements = reqs.Requirements;
- res.RequirementVariables = reqs.RequirementVariables;
- }
+ if (k.Item.RelicInfo != null)
+ res.RelicInfoRecords = Database.GetRecordFromFile(k.Item.relicID);
- #region Extra Attributes for specific types
+ if (res.RelicInfoRecords?.Any() ?? false)
+ GetAttributesFromRecord(k.Item, res.RelicInfoRecords, k.FilterExtra, k.Item.relicID, tmp);
- // Shows Artifact stats for the formula
- if (k.Item.IsFormulae && k.Item.baseItemInfo != null && (k.Scope?.HasFlag(FriendlyNamesExtraScopes.BaseAttributes) ?? false))
- {
- string artifactID = k.Item.baseItemInfo.GetString("artifactName");
+ res.Relic1Attributes = tmp.ToArray();
+ }
- if (!string.IsNullOrWhiteSpace(artifactID))
- {
- List tmp = new List();
- res.FormulaeArtifactRecords = Database.GetRecordFromFile(artifactID);
+ if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.Relic2Attributes) ?? false)
+ {
+ var tmp = new List();
- // Display the name of the Artifact
- if (!TranslationService.TryTranslateXTag(res.FormulaeArtifactRecords.GetString("description", 0), out res.FormulaeArtifactName))
- res.FormulaeArtifactName = "?Unknown Artifact Name?";
+ if (k.Item.Relic2Info != null)
+ res.Relic2InfoRecords = Database.GetRecordFromFile(k.Item.relic2ID);
- // Class
- string artifactClassification = res.FormulaeArtifactRecords.GetString("artifactClassification", 0).ToUpperInvariant();
- res.FormulaeArtifactClass = TranslateArtifactClassification(artifactClassification);
+ if (res.Relic2InfoRecords?.Any() ?? false)
+ GetAttributesFromRecord(k.Item, res.Relic2InfoRecords, k.FilterExtra, k.Item.relic2ID, tmp);
- // Attributes
- GetAttributesFromRecord(k.Item, res.FormulaeArtifactRecords, true, artifactID, tmp);
- res.FormulaeArtifactAttributes = tmp.ToArray();
- }
- }
+ res.Relic2Attributes = tmp.ToArray();
+ }
- // Show the completion bonus. // TODO is it possible to have 2 relics on one artifact ?
- if (k.Item.RelicBonusInfo != null
- && (k.Scope?.HasFlag(FriendlyNamesExtraScopes.RelicAttributes) ?? false)
- && (k.Item.IsArtifact // Artifact completion bonus
- || k.Item.IsRelic // Relic completion bonus
- || k.Item.HasRelicSlot1
- )
- )
- {
- var tmp = new List();
+ if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.ItemSet) ?? false)
+ res.ItemSet = GetItemSetString(k.Item);
- res.RelicBonus1InfoRecords = Database.GetRecordFromFile(k.Item.RelicBonusId);
+ if (k.Scope?.HasFlag(FriendlyNamesExtraScopes.Requirements) ?? false)
+ {
+ var reqs = GetRequirements(k.Item);
+ res.Requirements = reqs.Requirements;
+ res.RequirementVariables = reqs.RequirementVariables;
+ }
- if (res.RelicBonus1InfoRecords?.Any() ?? false)
- GetAttributesFromRecord(k.Item, res.RelicBonus1InfoRecords, k.FilterExtra, k.Item.RelicBonusId, tmp);
+ #region Extra Attributes for specific types
- res.RelicBonus1Attributes = tmp.ToArray();
- }
+ // Shows Artifact stats for the formula
+ if (k.Item.IsFormulae && k.Item.baseItemInfo != null && (k.Scope?.HasFlag(FriendlyNamesExtraScopes.BaseAttributes) ?? false))
+ {
+ string artifactID = k.Item.baseItemInfo.GetString("artifactName");
- // Show the Relic2 completion bonus.
- if (k.Item.HasRelicSlot2 && k.Item.RelicBonus2Info != null && (k.Scope?.HasFlag(FriendlyNamesExtraScopes.Relic2Attributes) ?? false))
+ if (!string.IsNullOrWhiteSpace(artifactID))
{
- var tmp = new List();
- res.RelicBonus2InfoRecords = Database.GetRecordFromFile(k.Item.RelicBonus2Id);
+ List tmp = new List();
+ res.FormulaeArtifactRecords = Database.GetRecordFromFile(artifactID);
- if (res.RelicBonus2InfoRecords?.Any() ?? false)
- GetAttributesFromRecord(k.Item, res.RelicBonus2InfoRecords, k.FilterExtra, k.Item.RelicBonus2Id, tmp);
+ // Display the name of the Artifact
+ if (!TranslationService.TryTranslateXTag(res.FormulaeArtifactRecords.GetString("description", 0), out res.FormulaeArtifactName))
+ res.FormulaeArtifactName = "?Unknown Artifact Name?";
- res.RelicBonus2Attributes = tmp.ToArray();
+ // Class
+ string artifactClassification = res.FormulaeArtifactRecords.GetString("artifactClassification", 0).ToUpperInvariant();
+ res.FormulaeArtifactClass = TranslateArtifactClassification(artifactClassification);
+
+ // Attributes
+ GetAttributesFromRecord(k.Item, res.FormulaeArtifactRecords, true, artifactID, tmp);
+ res.FormulaeArtifactAttributes = tmp.ToArray();
}
+ }
- #endregion
+ // Show the completion bonus. // TODO is it possible to have 2 relics on one artifact ?
+ if (k.Item.RelicBonusInfo != null
+ && (k.Scope?.HasFlag(FriendlyNamesExtraScopes.RelicAttributes) ?? false)
+ && (k.Item.IsArtifact // Artifact completion bonus
+ || k.Item.IsRelic // Relic completion bonus
+ || k.Item.HasRelicSlot1
+ )
+ )
+ {
+ var tmp = new List();
- k.Item.CurrentFriendlyNameResult.TmpAttrib.Clear();
- k.Item.CurrentFriendlyNameResult = null;
- return res;
+ res.RelicBonus1InfoRecords = Database.GetRecordFromFile(k.Item.RelicBonusId);
- });
+ if (res.RelicBonus1InfoRecords?.Any() ?? false)
+ GetAttributesFromRecord(k.Item, res.RelicBonus1InfoRecords, k.FilterExtra, k.Item.RelicBonusId, tmp);
- #region Local Helper
+ res.RelicBonus1Attributes = tmp.ToArray();
+ }
- string TranslateArtifactClassification(string artifactClassificationKey)
+ // Show the Relic2 completion bonus.
+ if (k.Item.HasRelicSlot2 && k.Item.RelicBonus2Info != null && (k.Scope?.HasFlag(FriendlyNamesExtraScopes.Relic2Attributes) ?? false))
{
- string tag = string.Empty;
- string resartifactClass = string.Empty;
- if (artifactClassificationKey == null)
- tag = null;
- else if (artifactClassificationKey == "LESSER")
- tag = "xtagArtifactClass01";
- else if (artifactClassificationKey == "GREATER")
- tag = "xtagArtifactClass02";
- else if (artifactClassificationKey == "DIVINE")
- tag = "xtagArtifactClass03";
- else
- tag = null;
+ var tmp = new List();
+ res.RelicBonus2InfoRecords = Database.GetRecordFromFile(k.Item.RelicBonus2Id);
- if (tag != null)
- resartifactClass = TranslationService.TranslateXTag(tag);
- else
- resartifactClass = "Unknown Artifact Class";
+ if (res.RelicBonus2InfoRecords?.Any() ?? false)
+ GetAttributesFromRecord(k.Item, res.RelicBonus2InfoRecords, k.FilterExtra, k.Item.RelicBonus2Id, tmp);
- return string.IsNullOrWhiteSpace(resartifactClass) ? "Unknown Artifact Class" : resartifactClass;
+ res.RelicBonus2Attributes = tmp.ToArray();
}
#endregion
+
+ k.Item.CurrentFriendlyNameResult.TmpAttrib.Clear();
+ k.Item.CurrentFriendlyNameResult = null;
+ return res;
+
+ });
+
+ #region Local Helper
+
+ string TranslateArtifactClassification(string artifactClassificationKey)
+ {
+ string tag = string.Empty;
+ string resartifactClass = string.Empty;
+ if (artifactClassificationKey == null)
+ tag = null;
+ else if (artifactClassificationKey == "LESSER")
+ tag = "xtagArtifactClass01";
+ else if (artifactClassificationKey == "GREATER")
+ tag = "xtagArtifactClass02";
+ else if (artifactClassificationKey == "DIVINE")
+ tag = "xtagArtifactClass03";
+ else
+ tag = null;
+
+ if (tag != null)
+ resartifactClass = TranslationService.TranslateXTag(tag);
+ else
+ resartifactClass = "Unknown Artifact Class";
+
+ return string.IsNullOrWhiteSpace(resartifactClass) ? "Unknown Artifact Class" : resartifactClass;
}
- ///
- /// Shows the items in a set for the set items
- ///
- /// string containing the set items
- public string[] GetItemSetString(Item itm)
+ #endregion
+ }
+
+ ///
+ /// Shows the items in a set for the set items
+ ///
+ /// string containing the set items
+ public string[] GetItemSetString(Item itm)
+ {
+ List results = new List();
+ string[] setMembers = this.GetSetItems(itm, true);
+ if (setMembers != null)
{
- List results = new List();
- string[] setMembers = this.GetSetItems(itm, true);
- if (setMembers != null)
+ var isfirst = true;
+ foreach (string memb in setMembers)
{
- var isfirst = true;
- foreach (string memb in setMembers)
- {
- string name = string.Empty;
+ string name = string.Empty;
- // Changed by VillageIdiot
- // The first entry is now the set name
- if (isfirst)
- {
- name = TranslationService.TranslateXTag(memb);
- results.Add($"{ItemStyle.Rare.TQColor().ColorTag()}{name}");
- isfirst = false;
- }
- else
- {
- name = "?? Missing database info ??";
- Info info = Database.GetInfo(memb);
+ // Changed by VillageIdiot
+ // The first entry is now the set name
+ if (isfirst)
+ {
+ name = TranslationService.TranslateXTag(memb);
+ results.Add($"{ItemStyle.Rare.TQColor().ColorTag()}{name}");
+ isfirst = false;
+ }
+ else
+ {
+ name = "?? Missing database info ??";
+ Info info = Database.GetInfo(memb);
- if (info != null)
- name = TranslationService.TranslateXTag(info.DescriptionTag);
+ if (info != null)
+ name = TranslationService.TranslateXTag(info.DescriptionTag);
- results.Add($"{ItemStyle.Common.TQColor().ColorTag()} {name}");
- }
+ results.Add($"{ItemStyle.Common.TQColor().ColorTag()} {name}");
}
}
+ }
+
+ return results.ToArray();
+ }
- return results.ToArray();
+ ///
+ /// Gets the item's attributes from the database record.
+ ///
+ ///
+ /// Changed by VillageIdiot
+ /// Added option to NOT translate the attributes to strings
+ ///
+ /// DBRecord for the database record
+ /// whether or not we are filtering strings
+ /// string containing the database record id
+ /// List for the results
+ /// flag on whether we convert attributes to strings.
+ private void GetAttributesFromRecord(Item itm, DBRecordCollection record, bool filtering, string recordId, List results, bool convertStrings = true)
+ {
+ if (TQDebug.ItemDebugLevel > 0)
+ {
+ Log.LogDebug("Item.GetAttributesFromRecord({0}, {1}, {2}, {3}, {4})"
+ , record, filtering, recordId, results, convertStrings
+ );
}
- ///
- /// Gets the item's attributes from the database record.
- ///
- ///
- /// Changed by VillageIdiot
- /// Added option to NOT translate the attributes to strings
- ///
- /// DBRecord for the database record
- /// whether or not we are filtering strings
- /// string containing the database record id
- /// List for the results
- /// flag on whether we convert attributes to strings.
- private void GetAttributesFromRecord(Item itm, DBRecordCollection record, bool filtering, string recordId, List results, bool convertStrings = true)
+ // First get a list of attributes, grouped by effect.
+ Dictionary> attrByEffect = new Dictionary>();
+ if (record == null)
{
if (TQDebug.ItemDebugLevel > 0)
- {
- Log.LogDebug("Item.GetAttributesFromRecord({0}, {1}, {2}, {3}, {4})"
- , record, filtering, recordId, results, convertStrings
- );
- }
-
- // First get a list of attributes, grouped by effect.
- Dictionary> attrByEffect = new Dictionary>();
- if (record == null)
- {
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Error - record was null.");
+ Log.LogDebug("Error - record was null.");
- results.Add("");
- return;
- }
+ results.Add("");
+ return;
+ }
- if (TQDebug.ItemDebugLevel > 1)
- Log.LogDebug(record.Id);
+ if (TQDebug.ItemDebugLevel > 1)
+ Log.LogDebug(record.Id);
- // Added by Village Idiot
- // To keep track of groups so they are not counted twice
- List countedGroups = new List();
+ // Added by Village Idiot
+ // To keep track of groups so they are not counted twice
+ List countedGroups = new List();
- foreach (Variable variable in record)
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug(variable.Name);
+ foreach (Variable variable in record)
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug(variable.Name);
- if (this.FilterValue(variable, !filtering))
- continue;
+ if (this.FilterValue(variable, !filtering))
+ continue;
- if (filtering && this.FilterKey(variable.Name))
- continue;
+ if (filtering && this.FilterKey(variable.Name))
+ continue;
- if (filtering && this.FilterRequirements(variable.Name))
- continue;
+ if (filtering && this.FilterRequirements(variable.Name))
+ continue;
- ItemAttributesData data = ItemAttributeProvider.GetAttributeData(variable.Name);
- if (data == null)
- {
- // unknown attribute
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Unknown Attribute");
+ ItemAttributesData data = ItemAttributeProvider.GetAttributeData(variable.Name);
+ if (data == null)
+ {
+ // unknown attribute
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Unknown Attribute");
- data = new ItemAttributesData(ItemAttributesEffectType.Other, variable.Name, variable.Name, string.Empty, 0);
- }
+ data = new ItemAttributesData(ItemAttributesEffectType.Other, variable.Name, variable.Name, string.Empty, 0);
+ }
- string effectGroup;
+ string effectGroup;
- // Changed by VillageIdiot to group DamageQualifiers together.
- if (data.EffectType == ItemAttributesEffectType.DamageQualifierEffect)
- effectGroup = string.Concat(data.EffectType.ToString(), ":", "DamageQualifier");
- else
- effectGroup = string.Concat(data.EffectType.ToString(), ":", data.Effect);
+ // Changed by VillageIdiot to group DamageQualifiers together.
+ if (data.EffectType == ItemAttributesEffectType.DamageQualifierEffect)
+ effectGroup = string.Concat(data.EffectType.ToString(), ":", "DamageQualifier");
+ else
+ effectGroup = string.Concat(data.EffectType.ToString(), ":", data.Effect);
- // Find or create the attrList for itm effect
- List attrList;
- if (!attrByEffect.TryGetValue(effectGroup, out attrList))
- {
- attrList = new List();
- attrByEffect[effectGroup] = attrList;
- }
+ // Find or create the attrList for itm effect
+ List attrList;
+ if (!attrByEffect.TryGetValue(effectGroup, out attrList))
+ {
+ attrList = new List();
+ attrByEffect[effectGroup] = attrList;
+ }
- // Add itm guy to the attrList
- attrList.Add(variable);
+ // Add itm guy to the attrList
+ attrList.Add(variable);
- // Added by VillageIdiot
- // Set number of attributes parameter for level calculation
- // Filter relics and relic bonuses
- if (recordId != itm.relic2ID && recordId != itm.RelicBonus2Id && recordId != itm.relicID && recordId != itm.RelicBonusId && !itm.isAttributeCounted)
+ // Added by VillageIdiot
+ // Set number of attributes parameter for level calculation
+ // Filter relics and relic bonuses
+ if (recordId != itm.relic2ID && recordId != itm.RelicBonus2Id && recordId != itm.relicID && recordId != itm.RelicBonusId && !itm.isAttributeCounted)
+ {
+ // Added test to see if itm has already been done
+ if (!countedGroups.Contains(effectGroup))
{
- // Added test to see if itm has already been done
- if (!countedGroups.Contains(effectGroup))
+ string normalizedVariableName = variable.Name.ToUpperInvariant();
+ if (!normalizedVariableName.Contains("CHANCE") && !normalizedVariableName.Contains("DURATION"))
{
- string normalizedVariableName = variable.Name.ToUpperInvariant();
- if (!normalizedVariableName.Contains("CHANCE") && !normalizedVariableName.Contains("DURATION"))
+ // Filter Attribute chance and duration tags
+ // Filter base attributes
+ if (normalizedVariableName != "CHARACTERBASEATTACKSPEEDTAG" &&
+ normalizedVariableName != "OFFENSIVEPHYSICALMIN" &&
+ normalizedVariableName != "OFFENSIVEPHYSICALMAX" &&
+ normalizedVariableName != "DEFENSIVEPROTECTION" &&
+ normalizedVariableName != "DEFENSIVEBLOCK" &&
+ normalizedVariableName != "BLOCKRECOVERYTIME" &&
+ normalizedVariableName != "OFFENSIVEGLOBALCHANCE" &&
+ normalizedVariableName != "RETALIATIONGLOBALCHANCE" &&
+ normalizedVariableName != "OFFENSIVEPIERCERATIOMIN")
{
- // Filter Attribute chance and duration tags
- // Filter base attributes
- if (normalizedVariableName != "CHARACTERBASEATTACKSPEEDTAG" &&
- normalizedVariableName != "OFFENSIVEPHYSICALMIN" &&
- normalizedVariableName != "OFFENSIVEPHYSICALMAX" &&
- normalizedVariableName != "DEFENSIVEPROTECTION" &&
- normalizedVariableName != "DEFENSIVEBLOCK" &&
- normalizedVariableName != "BLOCKRECOVERYTIME" &&
- normalizedVariableName != "OFFENSIVEGLOBALCHANCE" &&
- normalizedVariableName != "RETALIATIONGLOBALCHANCE" &&
- normalizedVariableName != "OFFENSIVEPIERCERATIOMIN")
+ // Chance of effects are still messed up.
+ if (normalizedVariableName.StartsWith("AUGMENTSKILLLEVEL", noCase))
{
- // Chance of effects are still messed up.
- if (normalizedVariableName.StartsWith("AUGMENTSKILLLEVEL", noCase))
- {
- // Add value of augment skill level to count instead of incrementing
- itm.attributeCount += variable.GetInt32(0);
- countedGroups.Add(effectGroup);
- }
- else
- {
- ++itm.attributeCount;
- countedGroups.Add(effectGroup);
- }
+ // Add value of augment skill level to count instead of incrementing
+ itm.attributeCount += variable.GetInt32(0);
+ countedGroups.Add(effectGroup);
+ }
+ else
+ {
+ ++itm.attributeCount;
+ countedGroups.Add(effectGroup);
}
}
}
}
}
+ }
- // Added by VillageIdiot
- // Some attributes have been counted so set the flag so we do not count them again
- if (itm.attributeCount != 0)
- itm.isAttributeCounted = true;
+ // Added by VillageIdiot
+ // Some attributes have been counted so set the flag so we do not count them again
+ if (itm.attributeCount != 0)
+ itm.isAttributeCounted = true;
- // Now we have all our attributes grouped by effect. Now lets sort them
- List[] attrArray = new List[attrByEffect.Count];
- attrByEffect.Values.CopyTo(attrArray, 0);
- Array.Sort(attrArray, new ItemAttributeListCompare(itm.IsArmor || itm.IsShield, this.ItemAttributeProvider));
+ // Now we have all our attributes grouped by effect. Now lets sort them
+ List[] attrArray = new List[attrByEffect.Count];
+ attrByEffect.Values.CopyTo(attrArray, 0);
+ Array.Sort(attrArray, new ItemAttributeListCompare(itm.IsArmor || itm.IsShield, this.ItemAttributeProvider));
- // Now for the global params, we need to check to see if they are XOR or all.
- // We do itm by checking the effect just after the global param.
- for (int i = 0; i < attrArray.Length; ++i)
- {
- List attrList = attrArray[i];
+ // Now for the global params, we need to check to see if they are XOR or all.
+ // We do itm by checking the effect just after the global param.
+ for (int i = 0; i < attrArray.Length; ++i)
+ {
+ List attrList = attrArray[i];
- if (ItemAttributeProvider.AttributeGroupIs(new Collection(attrList), "offensiveGlobalChance") ||
- ItemAttributeProvider.AttributeGroupIs(new Collection(attrList), "retaliationGlobalChance"))
+ if (ItemAttributeProvider.AttributeGroupIs(new Collection(attrList), "offensiveGlobalChance") ||
+ ItemAttributeProvider.AttributeGroupIs(new Collection(attrList), "retaliationGlobalChance"))
+ {
+ // check the next effect group
+ int j = i + 1;
+ if (j < attrArray.Length)
{
- // check the next effect group
- int j = i + 1;
- if (j < attrArray.Length)
- {
- List next = attrArray[j];
- if (!ItemAttributeProvider.AttributeGroupHas(new Collection(next), "Global"))
- {
- // itm is a spurious globalChance entry. Let's add 2 null entries to signal it should be ignored
- attrList.Add(null);
- attrList.Add(null);
- }
- else if (ItemAttributeProvider.AttributeGroupHas(new Collection(next), "XOR"))
- {
- // Yes it is global and is also XOR
- // flag our current attribute as XOR
- // We do itm by adding a second NULL entry to the list. Its a hack but it works
- attrList.Add(null);
- }
- }
- else
+ List next = attrArray[j];
+ if (!ItemAttributeProvider.AttributeGroupHas(new Collection(next), "Global"))
{
// itm is a spurious globalChance entry. Let's add 2 null entries to signal it should be ignored
attrList.Add(null);
attrList.Add(null);
}
+ else if (ItemAttributeProvider.AttributeGroupHas(new Collection(next), "XOR"))
+ {
+ // Yes it is global and is also XOR
+ // flag our current attribute as XOR
+ // We do itm by adding a second NULL entry to the list. Its a hack but it works
+ attrList.Add(null);
+ }
+ }
+ else
+ {
+ // itm is a spurious globalChance entry. Let's add 2 null entries to signal it should be ignored
+ attrList.Add(null);
+ attrList.Add(null);
}
}
+ }
- foreach (List attrList in attrArray)
- {
- // Used to sort out the Damage Qualifier effects.
- if (ItemAttributeProvider.AttributeGroupIs(new Collection(attrList), ItemAttributesEffectType.DamageQualifierEffect))
- attrList.Sort(new ItemAttributeSubListCompare(this.ItemAttributeProvider));
+ foreach (List attrList in attrArray)
+ {
+ // Used to sort out the Damage Qualifier effects.
+ if (ItemAttributeProvider.AttributeGroupIs(new Collection(attrList), ItemAttributesEffectType.DamageQualifierEffect))
+ attrList.Sort(new ItemAttributeSubListCompare(this.ItemAttributeProvider));
- if (!convertStrings)
- ConvertBareAttributeListToString(attrList, results);
- else
- ConvertAttributeListToString(itm, record, attrList, recordId, results);
- }
+ if (!convertStrings)
+ ConvertBareAttributeListToString(attrList, results);
+ else
+ ConvertAttributeListToString(itm, record, attrList, recordId, results);
+ }
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Exiting Item.GetAttributesFromRecord()");
+ if (TQDebug.ItemDebugLevel > 0)
+ Log.LogDebug("Exiting Item.GetAttributesFromRecord()");
+ }
+
+ ///
+ /// Converts the item's attribute list to a string
+ ///
+ /// DBRecord for the item
+ /// ArrayList containing the attributes list
+ /// string containing the record id
+ /// List containing the results
+ private void ConvertAttributeListToString(Item itm, DBRecordCollection record, List attributeList, string recordId, List results)
+ {
+ if (TQDebug.ItemDebugLevel > 0)
+ {
+ Log.LogDebug("Item.ConvertAttrListToString ({0}, {1}, {2}, {3})"
+ , record, attributeList, recordId, results
+ );
}
- ///
- /// Converts the item's attribute list to a string
- ///
- /// DBRecord for the item
- /// ArrayList containing the attributes list
- /// string containing the record id
- /// List containing the results
- private void ConvertAttributeListToString(Item itm, DBRecordCollection record, List attributeList, string recordId, List results)
+ // see what kind of effects are in this list
+ Variable variable = (Variable)attributeList[0];
+ ItemAttributesData data = ItemAttributeProvider.GetAttributeData(variable.Name);
+ if (data == null)
{
+ // unknown attribute
if (TQDebug.ItemDebugLevel > 0)
- {
- Log.LogDebug("Item.ConvertAttrListToString ({0}, {1}, {2}, {3})"
- , record, attributeList, recordId, results
- );
- }
+ Log.LogDebug("Error - Unknown Attribute.");
- // see what kind of effects are in this list
- Variable variable = (Variable)attributeList[0];
- ItemAttributesData data = ItemAttributeProvider.GetAttributeData(variable.Name);
- if (data == null)
- {
- // unknown attribute
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Error - Unknown Attribute.");
+ data = new ItemAttributesData(ItemAttributesEffectType.Other, variable.Name, variable.Name, string.Empty, 0);
+ }
- data = new ItemAttributesData(ItemAttributesEffectType.Other, variable.Name, variable.Name, string.Empty, 0);
- }
+ if (TQDebug.ItemDebugLevel > 0)
+ Log.LogDebug("Exiting Item.ConvertAttrListToString ()");
- if (TQDebug.ItemDebugLevel > 0)
- Log.LogDebug("Exiting Item.ConvertAttrListToString ()");
+ ConvertOffenseAttributesToString(itm, record, attributeList, data, recordId, results);
+ return;
+ }
- ConvertOffenseAttributesToString(itm, record, attributeList, data, recordId, results);
- return;
+ ///
+ /// Checks if the Effect type does not has value magnitude dependent on Duration.
+ ///
+ /// ItemAttributesData.Effect value
+ /// True if the effect magnitude does depend on the duration
+ private bool IsDurationReliantValue(string effectName)
+ {
+ return Array.IndexOf(durationIndependentEffects, effectName.ToUpperInvariant()) == -1;
+ }
+
+ ///
+ /// Gets a formatted range amount
+ ///
+ /// ItemAttributesData data
+ /// variable number to look up
+ /// minVar variable
+ /// maxVar variable
+ /// label string
+ /// label color
+ /// formatted range string
+ private string GetAmountRange(Item itm, ItemAttributesData data, int varNum, Variable minVar, Variable maxVar, ref string label, TQColor? labelColor, Variable minDurVar = null)
+ {
+ // Added by VillageIdiot : check to see if min and max are the same
+ TQColor? color = null;
+ string amount = null;
+
+ Variable min = null;
+ Variable max = null;
+
+ if (minVar != null)
+ min = minVar.Clone();
+
+ if (maxVar != null)
+ max = maxVar.Clone();
+
+ // sweet we have a range
+ string tag = "DamageRangeFormat";
+ if (data.Effect.EndsWith("Stun", noCase)
+ || data.Effect.EndsWith("Freeze", noCase)
+ || data.Effect.EndsWith("Petrify", noCase)
+ || data.Effect.EndsWith("Trap", noCase)
+ || data.Effect.EndsWith("Convert", noCase)
+ || data.Effect.EndsWith("Fear", noCase)
+ || data.Effect.EndsWith("Confusion", noCase)
+ || data.Effect.EndsWith("Disruption", noCase)
+ )
+ {
+ tag = "DamageInfluenceRangeFormat";
}
+ else if (data.Effect.Equals("defensiveBlock"))
+ tag = "DefenseBlock";
- ///
- /// Checks if the Effect type does not has value magnitude dependent on Duration.
- ///
- /// ItemAttributesData.Effect value
- /// True if the effect magnitude does depend on the duration
- private bool IsDurationReliantValue(string effectName)
- {
- return Array.IndexOf(durationIndependentEffects, effectName.ToUpperInvariant()) == -1;
- }
-
- ///
- /// Gets a formatted range amount
- ///
- /// ItemAttributesData data
- /// variable number to look up
- /// minVar variable
- /// maxVar variable
- /// label string
- /// label color
- /// formatted range string
- private string GetAmountRange(Item itm, ItemAttributesData data, int varNum, Variable minVar, Variable maxVar, ref string label, TQColor? labelColor, Variable minDurVar = null)
- {
- // Added by VillageIdiot : check to see if min and max are the same
- TQColor? color = null;
- string amount = null;
-
- Variable min = null;
- Variable max = null;
-
- if (minVar != null)
- min = minVar.Clone();
-
- if (maxVar != null)
- max = maxVar.Clone();
-
- // sweet we have a range
- string tag = "DamageRangeFormat";
- if (data.Effect.EndsWith("Stun", noCase)
- || data.Effect.EndsWith("Freeze", noCase)
- || data.Effect.EndsWith("Petrify", noCase)
- || data.Effect.EndsWith("Trap", noCase)
- || data.Effect.EndsWith("Convert", noCase)
- || data.Effect.EndsWith("Fear", noCase)
- || data.Effect.EndsWith("Confusion", noCase)
- || data.Effect.EndsWith("Disruption", noCase)
- )
- {
- tag = "DamageInfluenceRangeFormat";
- }
- else if (data.Effect.Equals("defensiveBlock"))
- tag = "DefenseBlock";
+ if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
+ {
+ formatSpec = "{0}..{1}";
+ color = ItemStyle.Legendary.TQColor();
+ }
+ else
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (range) = " + formatSpec);
- if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
- {
- formatSpec = "{0}..{1}";
- color = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (range) = " + formatSpec);
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ }
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
+ if (label.IndexOf('{') >= 0)
+ {
+ // the label has formatting codes. Use it to format the amount
+ formatSpec = label;
+ label = null;
+ color = labelColor;
+ }
- if (label.IndexOf('{') >= 0)
- {
- // the label has formatting codes. Use it to format the amount
- formatSpec = label;
- label = null;
- color = labelColor;
- }
+ // Added by VillageIdiot
+ // Adjust for itemScalePercent
+ // AMS: Added If the value is reliant on the duration.
+ if ((minDurVar != null) && IsDurationReliantValue(data.Effect))
+ {
+ min[Math.Min(min.NumberOfValues - 1, varNum)] = (float)min[Math.Min(min.NumberOfValues - 1, varNum)] * (float)minDurVar[minDurVar.NumberOfValues - 1] * itm.itemScalePercent;
+ max[Math.Min(max.NumberOfValues - 1, varNum)] = (float)max[Math.Min(max.NumberOfValues - 1, varNum)] * (float)minDurVar[minDurVar.NumberOfValues - 1] * itm.itemScalePercent;
+ }
+ else
+ {
+ min[Math.Min(min.NumberOfValues - 1, varNum)] = (float)min[Math.Min(min.NumberOfValues - 1, varNum)] * itm.itemScalePercent;
+ max[Math.Min(max.NumberOfValues - 1, varNum)] = (float)max[Math.Min(max.NumberOfValues - 1, varNum)] * itm.itemScalePercent;
+ }
- // Added by VillageIdiot
- // Adjust for itemScalePercent
- // AMS: Added If the value is reliant on the duration.
- if ((minDurVar != null) && IsDurationReliantValue(data.Effect))
- {
- min[Math.Min(min.NumberOfValues - 1, varNum)] = (float)min[Math.Min(min.NumberOfValues - 1, varNum)] * (float)minDurVar[minDurVar.NumberOfValues - 1] * itm.itemScalePercent;
- max[Math.Min(max.NumberOfValues - 1, varNum)] = (float)max[Math.Min(max.NumberOfValues - 1, varNum)] * (float)minDurVar[minDurVar.NumberOfValues - 1] * itm.itemScalePercent;
- }
- else
- {
- min[Math.Min(min.NumberOfValues - 1, varNum)] = (float)min[Math.Min(min.NumberOfValues - 1, varNum)] * itm.itemScalePercent;
- max[Math.Min(max.NumberOfValues - 1, varNum)] = (float)max[Math.Min(max.NumberOfValues - 1, varNum)] * itm.itemScalePercent;
- }
-
- amount = this.Format(formatSpec, min[Math.Min(min.NumberOfValues - 1, varNum)], max[Math.Min(max.NumberOfValues - 1, varNum)]);
- return color.HasValue ? $"{color?.ColorTag()}{amount}" : amount;
- }
-
- ///
- /// Gets a formatted single amount
- ///
- /// ItemAttributesData data
- /// variable number to look up
- /// minVar variable
- /// maxVar variable
- /// label string
- /// label color
- /// Duration of Damage
- /// formatted single amount string
- private string GetAmountSingle(Item itm, ItemAttributesData data, int varNum, Variable minVar, Variable maxVar, ref string label, TQColor? labelColor, Variable minDurVar = null)
- {
- TQColor? color = null;
- string amount = null;
-
- string tag = "DamageSingleFormat";
- if (data.Effect.EndsWith("Stun", noCase)
- || data.Effect.EndsWith("Freeze", noCase)
- || data.Effect.EndsWith("Petrify", noCase)
- || data.Effect.EndsWith("Trap", noCase)
- || data.Effect.EndsWith("Convert", noCase)
- || data.Effect.EndsWith("Fear", noCase)
- || data.Effect.EndsWith("Confusion", noCase)
- || data.Effect.EndsWith("Disruption", noCase)
- )
- {
- tag = "DamageInfluenceSingleFormat";
- }
+ amount = this.Format(formatSpec, min[Math.Min(min.NumberOfValues - 1, varNum)], max[Math.Min(max.NumberOfValues - 1, varNum)]);
+ return color.HasValue ? $"{color?.ColorTag()}{amount}" : amount;
+ }
- if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
- {
- formatSpec = "{0}";
- color = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (single) = " + formatSpec);
+ ///
+ /// Gets a formatted single amount
+ ///
+ /// ItemAttributesData data
+ /// variable number to look up
+ /// minVar variable
+ /// maxVar variable
+ /// label string
+ /// label color
+ /// Duration of Damage
+ /// formatted single amount string
+ private string GetAmountSingle(Item itm, ItemAttributesData data, int varNum, Variable minVar, Variable maxVar, ref string label, TQColor? labelColor, Variable minDurVar = null)
+ {
+ TQColor? color = null;
+ string amount = null;
+
+ string tag = "DamageSingleFormat";
+ if (data.Effect.EndsWith("Stun", noCase)
+ || data.Effect.EndsWith("Freeze", noCase)
+ || data.Effect.EndsWith("Petrify", noCase)
+ || data.Effect.EndsWith("Trap", noCase)
+ || data.Effect.EndsWith("Convert", noCase)
+ || data.Effect.EndsWith("Fear", noCase)
+ || data.Effect.EndsWith("Confusion", noCase)
+ || data.Effect.EndsWith("Disruption", noCase)
+ )
+ {
+ tag = "DamageInfluenceSingleFormat";
+ }
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
+ if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
+ {
+ formatSpec = "{0}";
+ color = ItemStyle.Legendary.TQColor();
+ }
+ else
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (single) = " + formatSpec);
- if (label.IndexOf('{') >= 0)
- {
- // the label has formatting codes. Use it to format the amount
- formatSpec = label;
- label = null;
- color = labelColor;
- }
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ }
- Variable currentVariable = null;
+ if (label.IndexOf('{') >= 0)
+ {
+ // the label has formatting codes. Use it to format the amount
+ formatSpec = label;
+ label = null;
+ color = labelColor;
+ }
- if (minVar != null)
- currentVariable = minVar.Clone();
- else if (maxVar != null)
- currentVariable = maxVar.Clone();
+ Variable currentVariable = null;
- if (currentVariable != null)
+ if (minVar != null)
+ currentVariable = minVar.Clone();
+ else if (maxVar != null)
+ currentVariable = maxVar.Clone();
+
+ if (currentVariable != null)
+ {
+ // Adjust for itemScalePercent
+ // only for floats
+ var curvar = currentVariable[Math.Min(currentVariable.NumberOfValues - 1, varNum)];
+ if (currentVariable.DataType == VariableDataType.Float)
{
- // Adjust for itemScalePercent
- // only for floats
- var curvar = currentVariable[Math.Min(currentVariable.NumberOfValues - 1, varNum)];
- if (currentVariable.DataType == VariableDataType.Float)
+ if ((minDurVar != null) && IsDurationReliantValue(data.Effect))
{
- if ((minDurVar != null) && IsDurationReliantValue(data.Effect))
- {
- curvar = (float)curvar * (float)minDurVar[minDurVar.NumberOfValues - 1] * itm.itemScalePercent;
- }
- else
- {
- curvar = (float)curvar * itm.itemScalePercent;
- }
- currentVariable[Math.Min(currentVariable.NumberOfValues - 1, varNum)] = curvar;
-
- // Fix#246, double signed result on negative value Ex : string.Format("{0:+#0} d'intelligence", -10) by removing format sign.
- // Fix "Dotted decimal mask" matching Ex : {0:#0.0} Health Regeneration per second
- formatSpec = Regex.Replace(formatSpec
- , @"(?\{(\d):)(?[+-])(?#([\d\.]+)})"
- , new MatchEvaluator((Match m) =>
- {
- var Prefix = m.Groups["Prefix"].Value;
- var Sign = m.Groups["Sign"].Value;
- var Suffix = m.Groups["Suffix"].Value;
- var val = (float)curvar;
+ curvar = (float)curvar * (float)minDurVar[minDurVar.NumberOfValues - 1] * itm.itemScalePercent;
+ }
+ else
+ {
+ curvar = (float)curvar * itm.itemScalePercent;
+ }
+ currentVariable[Math.Min(currentVariable.NumberOfValues - 1, varNum)] = curvar;
- if ((Sign == "+" && val < 0) || (Sign == "-" && val >= 0))
- return $"{Prefix}{Suffix}";
+ // Fix#246, double signed result on negative value Ex : string.Format("{0:+#0} d'intelligence", -10) by removing format sign.
+ // Fix "Dotted decimal mask" matching Ex : {0:#0.0} Health Regeneration per second
+ formatSpec = Regex.Replace(formatSpec
+ , @"(?\{(\d):)(?[+-])(?#([\d\.]+)})"
+ , new MatchEvaluator((Match m) =>
+ {
+ var Prefix = m.Groups["Prefix"].Value;
+ var Sign = m.Groups["Sign"].Value;
+ var Suffix = m.Groups["Suffix"].Value;
+ var val = (float)curvar;
- return m.Value;
- })
- );
- }
+ if ((Sign == "+" && val < 0) || (Sign == "-" && val >= 0))
+ return $"{Prefix}{Suffix}";
- amount = this.Format(formatSpec, curvar);
+ return m.Value;
+ })
+ );
}
- return color.HasValue ? $"{color?.ColorTag()}{amount}" : amount;
+ amount = this.Format(formatSpec, curvar);
}
- ///
- /// Gets the formatted duration range values
- ///
- /// offset number of the variable value that we are using
- /// minimum duration variable
- /// maximum duration variable
- /// formatted duration string
- private string GetDurationRange(int varNum, Variable minDurVar, Variable maxDurVar)
- {
- string duration = null;
- TQColor? color = null;
-
- if (!TranslationService.TryTranslateXTag("DamageRangeFormatTime", out var formatSpec))
- {
- formatSpec = "for {0}..{1} seconds";
- color = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (time range) = " + formatSpec);
-
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
+ return color.HasValue ? $"{color?.ColorTag()}{amount}" : amount;
+ }
- duration = this.Format(formatSpec, minDurVar[Math.Min(minDurVar.NumberOfValues - 1, varNum)], maxDurVar[Math.Min(maxDurVar.NumberOfValues - 1, varNum)]);
+ ///
+ /// Gets the formatted duration range values
+ ///
+ /// offset number of the variable value that we are using
+ /// minimum duration variable
+ /// maximum duration variable
+ /// formatted duration string
+ private string GetDurationRange(int varNum, Variable minDurVar, Variable maxDurVar)
+ {
+ string duration = null;
+ TQColor? color = null;
- return color.HasValue ? $"{color?.ColorTag()}{duration}" : duration;
+ if (!TranslationService.TryTranslateXTag("DamageRangeFormatTime", out var formatSpec))
+ {
+ formatSpec = "for {0}..{1} seconds";
+ color = ItemStyle.Legendary.TQColor();
}
-
- ///
- /// Gets the formatted duration single value
- ///
- /// offset number of the variable value that we are using
- /// minimum duration variable
- /// maximum duration variable
- /// formatted duration string
- private string GetDurationSingle(int varNum, Variable minDurVar, Variable maxDurVar)
+ else
{
- string duration = null;
- TQColor? color = null;
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (time range) = " + formatSpec);
- if (!TranslationService.TryTranslateXTag("DamageSingleFormatTime", out var formatSpec))
- {
- formatSpec = "{0}";
- color = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (time single) = " + formatSpec);
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ }
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
+ duration = this.Format(formatSpec, minDurVar[Math.Min(minDurVar.NumberOfValues - 1, varNum)], maxDurVar[Math.Min(maxDurVar.NumberOfValues - 1, varNum)]);
- Variable durationVariable = minDurVar;
- if (durationVariable == null)
- durationVariable = maxDurVar;
+ return color.HasValue ? $"{color?.ColorTag()}{duration}" : duration;
+ }
- if (durationVariable != null)
- {
- duration = this.Format(formatSpec, durationVariable[Math.Min(durationVariable.NumberOfValues - 1, varNum)]);
- duration = $"{color?.ColorTag()}{duration}";
- }
+ ///
+ /// Gets the formatted duration single value
+ ///
+ /// offset number of the variable value that we are using
+ /// minimum duration variable
+ /// maximum duration variable
+ /// formatted duration string
+ private string GetDurationSingle(int varNum, Variable minDurVar, Variable maxDurVar)
+ {
+ string duration = null;
+ TQColor? color = null;
- return duration;
+ if (!TranslationService.TryTranslateXTag("DamageSingleFormatTime", out var formatSpec))
+ {
+ formatSpec = "{0}";
+ color = ItemStyle.Legendary.TQColor();
}
-
- ///
- /// Gets the formatted damage ratio string
- ///
- /// offset number of the variable value that we are using
- /// ItemAttributesData for the damage ratio
- /// Damage Ratio variable
- /// formatted damage ratio string
- private string GetDamageRatio(int varNum, ItemAttributesData damageRatioData, Variable damageRatioVar)
+ else
{
- string damageRatio = null;
- TQColor? color = null;
- string formatSpec = null;
-
- string tag = string.Concat("Damage", damageRatioData.FullAttribute.Substring(9, damageRatioData.FullAttribute.Length - 20), "Ratio");
-
- if (!TranslationService.TryTranslateXTag(tag, out formatSpec))
- {
- formatSpec = string.Concat("{0:f1}% ?", damageRatioData.FullAttribute, "?");
- color = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (percent) = " + formatSpec);
-
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
-
- damageRatio = this.Format(formatSpec, damageRatioVar[Math.Min(damageRatioVar.NumberOfValues - 1, varNum)]);
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (time single) = " + formatSpec);
- return $"{color?.ColorTag()}{damageRatio}";
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
}
- ///
- /// Gets formatted chance string
- ///
- /// offset number of the variable value that we are using
- /// chance variable
- /// formatted chance string.
- private string GetChance(int varNum, Variable chanceVar)
+ Variable durationVariable = minDurVar;
+ if (durationVariable == null)
+ durationVariable = maxDurVar;
+
+ if (durationVariable != null)
{
- string chance = null;
- TQColor? color = null;
+ duration = this.Format(formatSpec, durationVariable[Math.Min(durationVariable.NumberOfValues - 1, varNum)]);
+ duration = $"{color?.ColorTag()}{duration}";
+ }
- if (!TranslationService.TryTranslateXTag("ChanceOfTag", out var formatSpec))
- {
- formatSpec = "?{%.1f0}% Chance of?";
- color = ItemStyle.Legendary.TQColor();
- }
+ return duration;
+ }
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (chance) = " + formatSpec);
+ ///
+ /// Gets the formatted damage ratio string
+ ///
+ /// offset number of the variable value that we are using
+ /// ItemAttributesData for the damage ratio
+ /// Damage Ratio variable
+ /// formatted damage ratio string
+ private string GetDamageRatio(int varNum, ItemAttributesData damageRatioData, Variable damageRatioVar)
+ {
+ string damageRatio = null;
+ TQColor? color = null;
+ string formatSpec = null;
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- if (chanceVar != null)
- {
- chance = this.Format(formatSpec, chanceVar[Math.Min(chanceVar.NumberOfValues - 1, varNum)]);
- chance = $"{color?.ColorTag()}{chance}";
- }
+ string tag = string.Concat("Damage", damageRatioData.FullAttribute.Substring(9, damageRatioData.FullAttribute.Length - 20), "Ratio");
- return chance;
+ if (!TranslationService.TryTranslateXTag(tag, out formatSpec))
+ {
+ formatSpec = string.Concat("{0:f1}% ?", damageRatioData.FullAttribute, "?");
+ color = ItemStyle.Legendary.TQColor();
}
-
-
- ///
- /// Gets formatted modifier string
- ///
- /// ItemAttributesData for the attribute
- /// offset number of the variable value that we are using
- /// ItemAttributesData for the modifier
- /// modifier variable
- /// formatted modifier string
- private string GetModifier(ItemAttributesData data, int varNum, ItemAttributesData modifierData, Variable modifierVar)
+ else
{
- string modifier = null;
- TQColor? color = null;
- string formatSpec = null;
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (percent) = " + formatSpec);
- string tag = ItemAttributeProvider.GetAttributeTextTag(data);
- if (string.IsNullOrEmpty(tag))
- {
- formatSpec = string.Concat("{0:f1}% ?", modifierData.FullAttribute, "?");
- color = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (!TranslationService.TryTranslateXTag(tag, out formatSpec))
- {
- formatSpec = string.Concat("{0:f1}% ?", modifierData.FullAttribute, "?");
- color = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (percent) = " + formatSpec);
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ }
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
+ damageRatio = this.Format(formatSpec, damageRatioVar[Math.Min(damageRatioVar.NumberOfValues - 1, varNum)]);
- }
+ return $"{color?.ColorTag()}{damageRatio}";
+ }
- modifier = Format(formatSpec, modifierVar[Math.Min(modifierVar.NumberOfValues - 1, varNum)]);
+ ///
+ /// Gets formatted chance string
+ ///
+ /// offset number of the variable value that we are using
+ /// chance variable
+ /// formatted chance string.
+ private string GetChance(int varNum, Variable chanceVar)
+ {
+ string chance = null;
+ TQColor? color = null;
- return $"{color?.ColorTag()}{modifier}";
+ if (!TranslationService.TryTranslateXTag("ChanceOfTag", out var formatSpec))
+ {
+ formatSpec = "?{%.1f0}% Chance of?";
+ color = ItemStyle.Legendary.TQColor();
}
- ///
- /// Gets formatted duration modifier string
- ///
- /// offset number of the variable value that we are using
- /// duration modifier variable
- /// formatted duration modifier string
- private string GetDurationModifier(int varNum, Variable durationModifierVar)
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (chance) = " + formatSpec);
+
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ if (chanceVar != null)
{
- string durationModifier = null;
- TQColor? color = null;
+ chance = this.Format(formatSpec, chanceVar[Math.Min(chanceVar.NumberOfValues - 1, varNum)]);
+ chance = $"{color?.ColorTag()}{chance}";
+ }
- if (!TranslationService.TryTranslateXTag("ImprovedTimeFormat", out var formatSpec))
- {
- formatSpec = "?with {0:f0}% Improved Duration?";
- color = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (improved time) = " + formatSpec);
+ return chance;
+ }
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
- durationModifier = Format(formatSpec, durationModifierVar[Math.Min(durationModifierVar.NumberOfValues - 1, varNum)]);
+ ///
+ /// Gets formatted modifier string
+ ///
+ /// ItemAttributesData for the attribute
+ /// offset number of the variable value that we are using
+ /// ItemAttributesData for the modifier
+ /// modifier variable
+ /// formatted modifier string
+ private string GetModifier(ItemAttributesData data, int varNum, ItemAttributesData modifierData, Variable modifierVar)
+ {
+ string modifier = null;
+ TQColor? color = null;
+ string formatSpec = null;
- return $"{color?.ColorTag()}{durationModifier}";
+ string tag = ItemAttributeProvider.GetAttributeTextTag(data);
+ if (string.IsNullOrEmpty(tag))
+ {
+ formatSpec = string.Concat("{0:f1}% ?", modifierData.FullAttribute, "?");
+ color = ItemStyle.Legendary.TQColor();
}
-
- ///
- /// Gets a formatted chance modifier string
- ///
- /// offset number of the variable value that we are using
- /// Chance modifier variable
- /// formatted chance modifier string
- private string GetChanceModifier(int varNum, Variable modifierChanceVar)
+ else
{
- string modifierChance = null;
- TQColor? color = null;
-
- if (!TranslationService.TryTranslateXTag("ChanceOfTag", out var formatSpec))
+ if (!TranslationService.TryTranslateXTag(tag, out formatSpec))
{
- formatSpec = "?{%.1f0}% Chance of?";
+ formatSpec = string.Concat("{0:f1}% ?", modifierData.FullAttribute, "?");
color = ItemStyle.Legendary.TQColor();
}
else
{
if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (chance) = " + formatSpec);
+ Log.LogDebug("Item.formatspec (percent) = " + formatSpec);
formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
}
- modifierChance = this.Format(formatSpec, modifierChanceVar[Math.Min(modifierChanceVar.NumberOfValues - 1, varNum)]);
-
- return $"{color?.ColorTag()}{modifierChance}";
}
- ///
- /// Gets the global chance string
- ///
- /// Arraylist containing the attributes
- /// offset number of the variable value that we are using
- /// variable structure
- /// font string
- /// formatted global chance string
- private string GetGlobalChance(List attributeList, int varNum, Variable v, ref TQColor? font)
- {
- string line;
- string tag = "GlobalPercentChanceOfAllTag";
+ modifier = Format(formatSpec, modifierVar[Math.Min(modifierVar.NumberOfValues - 1, varNum)]);
- // use our hack to determine if it was XOR or not.
- if (attributeList.Count > 2)
- {
- // Spurious global chance indicator. Do not use
- line = string.Empty;
- }
- else
- {
- if (attributeList.Count > 1)
- tag = "GlobalPercentChanceOfOneTag";
-
- if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
- {
- formatSpec = string.Format(CultureInfo.CurrentCulture, "{0:f1}% ?{0}?", tag);
- font = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (chance of one) = " + formatSpec);
-
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- font = ItemStyle.Epic.TQColor();
- }
+ return $"{color?.ColorTag()}{modifier}";
+ }
- line = Format(formatSpec, v[System.Math.Min(v.NumberOfValues - 1, varNum)]);
- }
+ ///
+ /// Gets formatted duration modifier string
+ ///
+ /// offset number of the variable value that we are using
+ /// duration modifier variable
+ /// formatted duration modifier string
+ private string GetDurationModifier(int varNum, Variable durationModifierVar)
+ {
+ string durationModifier = null;
+ TQColor? color = null;
- return line;
+ if (!TranslationService.TryTranslateXTag("ImprovedTimeFormat", out var formatSpec))
+ {
+ formatSpec = "?with {0:f0}% Improved Duration?";
+ color = ItemStyle.Legendary.TQColor();
}
-
-
- ///
- /// Gets the formatted racial bonus string(s)
- ///
- /// DBRecord of the databse record
- /// List containing the results
- /// offset number of the variable value that we are using
- /// Flag to signal global parameters
- /// global indent string
- /// variable structure
- /// ItemAttributesData structure
- /// line string
- /// display font string
- /// formatted string of racial bonus(es) adds to the results if there are multiple.
- private string GetRacialBonus(DBRecordCollection record, Item itm, List results, int varNum, bool isGlobal, string globalIndent, Variable v, ItemAttributesData d, string line, ref TQColor? color)
+ else
{
- // Added by VillageIdiot
- // Updated to accept multiple racial bonuses in record
- string[] races = record.GetAllStrings("racialBonusRace");
- if (races != null)
- {
- for (int j = 0; j < races.Length; ++j)
- {
-
- if (!TranslationService.TryTranslateXTag($"racialBonusRace{races[j]}", out var finalRace))
- {
- finalRace = races[j];
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (improved time) = " + formatSpec);
- if (TQDebug.DebugEnabled)
- Log.LogDebug("missing racialBonusRace={0}", finalRace);
- }
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ }
- string formatTag = string.Concat(d.FullAttribute.Substring(0, 1).ToUpperInvariant(), d.FullAttribute.Substring(1));
+ durationModifier = Format(formatSpec, durationModifierVar[Math.Min(durationModifierVar.NumberOfValues - 1, varNum)]);
- if (!TranslationService.TryTranslateXTag(formatTag, out var formatSpec))
- formatSpec = string.Concat(formatTag, " {0} {1}");
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (race bonus) = " + formatSpec);
+ return $"{color?.ColorTag()}{durationModifier}";
+ }
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
+ ///
+ /// Gets a formatted chance modifier string
+ ///
+ /// offset number of the variable value that we are using
+ /// Chance modifier variable
+ /// formatted chance modifier string
+ private string GetChanceModifier(int varNum, Variable modifierChanceVar)
+ {
+ string modifierChance = null;
+ TQColor? color = null;
+ if (!TranslationService.TryTranslateXTag("ChanceOfTag", out var formatSpec))
+ {
+ formatSpec = "?{%.1f0}% Chance of?";
+ color = ItemStyle.Legendary.TQColor();
+ }
+ else
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (chance) = " + formatSpec);
- if (line != null)
- {
- if (d.Variable.Length > 0)
- {
- string s = $"{ItemStyle.Legendary.TQColor().ColorTag()}{d.Variable}";
- line = string.Concat(line, s);
- }
- else
- {
- // There are multiple lines to the attribute so the color tag needs to be added.
- string s = $"{ItemStyle.Epic.TQColor().ColorTag()}";
- line = string.Concat(s, line);
- }
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ }
- if (isGlobal)
- line = string.Concat(globalIndent, line);
+ modifierChance = this.Format(formatSpec, modifierChanceVar[Math.Min(modifierChanceVar.NumberOfValues - 1, varNum)]);
- results.Add(line);
- itm.CurrentFriendlyNameResult.TmpAttrib.Add(line);
- }
+ return $"{color?.ColorTag()}{modifierChance}";
+ }
- line = Format(formatSpec, v[Math.Min(v.NumberOfValues - 1, varNum)], finalRace);
- color = ItemStyle.Epic.TQColor();
- }
- }
+ ///
+ /// Gets the global chance string
+ ///
+ /// Arraylist containing the attributes
+ /// offset number of the variable value that we are using
+ /// variable structure
+ /// font string
+ /// formatted global chance string
+ private string GetGlobalChance(List attributeList, int varNum, Variable v, ref TQColor? font)
+ {
+ string line;
+ string tag = "GlobalPercentChanceOfAllTag";
- return line;
+ // use our hack to determine if it was XOR or not.
+ if (attributeList.Count > 2)
+ {
+ // Spurious global chance indicator. Do not use
+ line = string.Empty;
}
-
-
-
- ///
- /// Gets the + to all skills string
- ///
- /// offset number of the variable value that we are using
- /// variable structure
- /// display font string
- /// formatted string for + to all skills
- private string GetAugmentAllLevel(int variableNumber, Variable variable, ref TQColor? color)
+ else
{
- string tag = "ItemAllSkillIncrement";
+ if (attributeList.Count > 1)
+ tag = "GlobalPercentChanceOfOneTag";
if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
{
- formatSpec = "?+{0} to all skills?";
- color = ItemStyle.Legendary.TQColor();
+ formatSpec = string.Format(CultureInfo.CurrentCulture, "{0:f1}% ?{0}?", tag);
+ font = ItemStyle.Legendary.TQColor();
}
else
{
if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (augment level) = " + formatSpec);
+ Log.LogDebug("Item.formatspec (chance of one) = " + formatSpec);
formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- color = ItemStyle.Epic.TQColor();
+ font = ItemStyle.Epic.TQColor();
}
- return Format(formatSpec, variable[System.Math.Min(variable.NumberOfValues - 1, variableNumber)]);
+ line = Format(formatSpec, v[System.Math.Min(v.NumberOfValues - 1, varNum)]);
}
- ///
- /// Get + to a Mastery string
- ///
- /// DBRecord database record
- /// variable structure
- /// ItemAttributesData structure
- /// display font string
- /// formatted string with the + to mastery
- private string GetAugmentMasteryLevel(DBRecordCollection record, Variable variable, ItemAttributesData attributeData, ref TQColor? font)
- {
- string augmentNumber = attributeData.FullAttribute.Substring(19, 1);
- string skillRecordKey = string.Concat("augmentMasteryName", augmentNumber);
- string skillRecordID = record.GetString(skillRecordKey, 0);
+ return line;
+ }
- if (string.IsNullOrEmpty(skillRecordID))
- skillRecordID = skillRecordKey;
- string skillName = null;
- DBRecordCollection skillRecord = Database.GetRecordFromFile(skillRecordID);
- if (skillRecord != null)
+ ///
+ /// Gets the formatted racial bonus string(s)
+ ///
+ /// DBRecord of the databse record
+ /// List containing the results
+ /// offset number of the variable value that we are using
+ /// Flag to signal global parameters
+ /// global indent string
+ /// variable structure
+ /// ItemAttributesData structure
+ /// line string
+ /// display font string
+ /// formatted string of racial bonus(es) adds to the results if there are multiple.
+ private string GetRacialBonus(DBRecordCollection record, Item itm, List results, int varNum, bool isGlobal, string globalIndent, Variable v, ItemAttributesData d, string line, ref TQColor? color)
+ {
+ // Added by VillageIdiot
+ // Updated to accept multiple racial bonuses in record
+ string[] races = record.GetAllStrings("racialBonusRace");
+ if (races != null)
+ {
+ for (int j = 0; j < races.Length; ++j)
{
- string nameTag = skillRecord.GetString("skillDisplayName", 0);
-
- if (!string.IsNullOrEmpty(nameTag))
- TranslationService.TryTranslateXTag(nameTag, out skillName);
- }
- if (string.IsNullOrEmpty(skillName))
- {
- skillName = Path.GetFileNameWithoutExtension(skillRecordID);
- font = ItemStyle.Legendary.TQColor();
- }
+ if (!TranslationService.TryTranslateXTag($"racialBonusRace{races[j]}", out var finalRace))
+ {
+ finalRace = races[j];
- // now get the formatSpec
- if (!TranslationService.TryTranslateXTag("ItemMasteryIncrement", out var formatSpec))
- {
- formatSpec = "?+{0} to skills in {1}?";
- if (font == null)
- font = ItemStyle.Legendary.TQColor();
- }
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (augment mastery) = " + formatSpec);
+ if (TQDebug.DebugEnabled)
+ Log.LogDebug("missing racialBonusRace={0}", finalRace);
+ }
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- if (!font.HasValue)
- font = ItemStyle.Epic.TQColor();
- }
+ string formatTag = string.Concat(d.FullAttribute.Substring(0, 1).ToUpperInvariant(), d.FullAttribute.Substring(1));
- return Format(formatSpec, variable[0], skillName);
- }
+ if (!TranslationService.TryTranslateXTag(formatTag, out var formatSpec))
+ formatSpec = string.Concat(formatTag, " {0} {1}");
+ else
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (race bonus) = " + formatSpec);
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ }
- ///
- /// Gets a formatted + to skill string
- ///
- /// DBRecord database record
- /// variable structure
- /// ItemAttributesData structure
- /// line of text
- /// display font string
- /// formatted string containing + to skill
- private string GetAugmentSkillLevel(DBRecordCollection record, Variable variable, ItemAttributesData attributeData, string line, ref TQColor? font)
- {
- string augmentSkillNumber = attributeData.FullAttribute.Substring(17, 1);
- string skillRecordKey = string.Concat("augmentSkillName", augmentSkillNumber);
- string skillRecordID = record.GetString(skillRecordKey, 0);
- if (!string.IsNullOrEmpty(skillRecordID))
- {
- string skillName = null;
- string nameTag = null;
- DBRecordCollection skillRecord = Database.GetRecordFromFile(skillRecordID);
- if (skillRecord != null)
+ if (line != null)
{
- // Changed by VillageIdiot
- // for augmenting buff skills
- string buffSkillName = skillRecord.GetString("buffSkillName", 0);
- if (string.IsNullOrEmpty(buffSkillName))
+ if (d.Variable.Length > 0)
{
- // Not a buff so look up the name
- nameTag = skillRecord.GetString("skillDisplayName", 0);
- if (!string.IsNullOrEmpty(nameTag))
- TranslationService.TryTranslateXTag(nameTag, out skillName);
- else
- {
- // Added by VillageIdiot
- // Check to see if this is a pet skill
- nameTag = skillRecord.GetString("Class", 0);
- if (nameTag.Contains("PetModifier"))
- {
- string petSkillID = skillRecord.GetString("petSkillName", 0);
- DBRecordCollection petSkillRecord = Database.GetRecordFromFile(petSkillID);
- if (petSkillRecord != null)
- {
- // Try to get display name
- string petNameTag = petSkillRecord.GetString("skillDisplayName", 0);
- if (!string.IsNullOrEmpty(petNameTag))
- TranslationService.TryTranslateXTag(petNameTag, out skillName);
- else
- { // It may fail because there is another level of redirection (records\xpack\skills\dream\nightmare_petmodifier_mastermind.dbr)
- petNameTag = petSkillRecord.GetString("buffSkillName", 0);
- if (!string.IsNullOrWhiteSpace(petNameTag))
- {
- var petSkillRecordLvl2 = Database.GetRecordFromFile(petNameTag);
- if (petSkillRecordLvl2 is not null)
- {
- petNameTag = petSkillRecordLvl2.GetString("skillDisplayName", 0);
- if (!string.IsNullOrEmpty(petNameTag))
- TranslationService.TryTranslateXTag(petNameTag, out skillName);
-
- }
- }
- }
-
- }
- }
- }
+ string s = $"{ItemStyle.Legendary.TQColor().ColorTag()}{d.Variable}";
+ line = string.Concat(line, s);
}
else
{
- // This is a buff skill
- DBRecordCollection buffSkillRecord = Database.GetRecordFromFile(buffSkillName);
- if (buffSkillRecord != null)
- {
- nameTag = buffSkillRecord.GetString("skillDisplayName", 0);
- if (!string.IsNullOrEmpty(nameTag))
- TranslationService.TryTranslateXTag(nameTag, out skillName);
- }
+ // There are multiple lines to the attribute so the color tag needs to be added.
+ string s = $"{ItemStyle.Epic.TQColor().ColorTag()}";
+ line = string.Concat(s, line);
}
- }
- if (string.IsNullOrEmpty(skillName))
- skillName = Path.GetFileNameWithoutExtension(skillRecordID);
+ if (isGlobal)
+ line = string.Concat(globalIndent, line);
- // now get the formatSpec
- if (!TranslationService.TryTranslateXTag("ItemSkillIncrement", out var formatSpec))
- {
- formatSpec = "?+{0} to skill {1}?";
- font = ItemStyle.Legendary.TQColor();
+ results.Add(line);
+ itm.CurrentFriendlyNameResult.TmpAttrib.Add(line);
}
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (item skill) = " + formatSpec);
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- font = ItemStyle.Epic.TQColor();
- }
-
- line = this.Format(formatSpec, variable[0], skillName);
+ line = Format(formatSpec, v[Math.Min(v.NumberOfValues - 1, varNum)], finalRace);
+ color = ItemStyle.Epic.TQColor();
}
-
- return line;
}
- ///
- /// Gets the formatted formulae string(s)
- ///
- /// results list
- /// variable structure
- /// ItemAttributesData structure
- /// line of text
- /// display font string
- /// formatted formulae string
- private string GetFormulae(List results, Variable variable, ItemAttributesData attributeData, string line, ref TQColor? font)
+ return line;
+ }
+
+
+
+ ///
+ /// Gets the + to all skills string
+ ///
+ /// offset number of the variable value that we are using
+ /// variable structure
+ /// display font string
+ /// formatted string for + to all skills
+ private string GetAugmentAllLevel(int variableNumber, Variable variable, ref TQColor? color)
+ {
+ string tag = "ItemAllSkillIncrement";
+
+ if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
{
- // Special case for formulae reagents
- if (attributeData.FullAttribute.StartsWith("reagent", noCase))
- {
- DBRecordCollection reagentRecord = Database.GetRecordFromFile(variable.GetString(0));
- if (reagentRecord != null)
- {
- string nameTag = reagentRecord.GetString("description", 0);
- if (!string.IsNullOrEmpty(nameTag))
- {
- string reagentName = TranslationService.TranslateXTag(nameTag);
- string formatSpec = "{0}";
- font = ItemStyle.Common.TQColor();
- line = Format(formatSpec, reagentName);
- }
- }
- }
- else if (attributeData.FullAttribute.Equals("artifactCreationCost"))
- {
- if (!TranslationService.TryTranslateXTag("xtagArtifactCost", out var formatSpec))
- formatSpec = "Gold Cost: {0}";
- else
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ formatSpec = "?+{0} to all skills?";
+ color = ItemStyle.Legendary.TQColor();
+ }
+ else
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (augment level) = " + formatSpec);
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (Artifact cost) = " + formatSpec);
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ color = ItemStyle.Epic.TQColor();
+ }
- font = ItemStyle.Rare.TQColor();
- results.Add(string.Empty);
- line = Format(formatSpec, string.Format(CultureInfo.CurrentCulture, "{0:N0}", variable[0]));
- }
+ return Format(formatSpec, variable[System.Math.Min(variable.NumberOfValues - 1, variableNumber)]);
+ }
- return line;
+ ///
+ /// Get + to a Mastery string
+ ///
+ /// DBRecord database record
+ /// variable structure
+ /// ItemAttributesData structure
+ /// display font string
+ /// formatted string with the + to mastery
+ private string GetAugmentMasteryLevel(DBRecordCollection record, Variable variable, ItemAttributesData attributeData, ref TQColor? font)
+ {
+ string augmentNumber = attributeData.FullAttribute.Substring(19, 1);
+ string skillRecordKey = string.Concat("augmentMasteryName", augmentNumber);
+ string skillRecordID = record.GetString(skillRecordKey, 0);
+
+ if (string.IsNullOrEmpty(skillRecordID))
+ skillRecordID = skillRecordKey;
+
+ string skillName = null;
+ DBRecordCollection skillRecord = Database.GetRecordFromFile(skillRecordID);
+ if (skillRecord != null)
+ {
+ string nameTag = skillRecord.GetString("skillDisplayName", 0);
+
+ if (!string.IsNullOrEmpty(nameTag))
+ TranslationService.TryTranslateXTag(nameTag, out skillName);
}
- ///
- /// Gets a formatted string of the granted skill
- ///
- /// DBRecord database record
- /// results list
- /// variable structure
- /// line of text
- /// display font string
- /// formatted granted skill string.
- private string GetGrantedSkill(DBRecordCollection record, Item itm, List results, Variable variable, string line, ref TQColor? font)
+ if (string.IsNullOrEmpty(skillName))
{
- // Added by VillageIdiot
- // Special case for granted skills
- DBRecordCollection skillRecord = Database.GetRecordFromFile(variable.GetString(0));
- if (skillRecord != null)
- {
- // Add a blank line and then the Grants Skill text
- results.Add(string.Empty);
- font = ItemStyle.Mundane.TQColor();
+ skillName = Path.GetFileNameWithoutExtension(skillRecordID);
+ font = ItemStyle.Legendary.TQColor();
+ }
- if (!TranslationService.TryTranslateXTag("tagItemGrantSkill", out var skillTag))
- skillTag = "Grants Skill :";
+ // now get the formatSpec
+ if (!TranslationService.TryTranslateXTag("ItemMasteryIncrement", out var formatSpec))
+ {
+ formatSpec = "?+{0} to skills in {1}?";
+ if (font == null)
+ font = ItemStyle.Legendary.TQColor();
+ }
+ else
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (augment mastery) = " + formatSpec);
- var value = $"{font?.ColorTag()}{skillTag}";
- results.Add(value);
- itm.CurrentFriendlyNameResult.TmpAttrib.Add(value);
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ if (!font.HasValue)
+ font = ItemStyle.Epic.TQColor();
+ }
+
+ return Format(formatSpec, variable[0], skillName);
+ }
- string skillName = null;
- string nameTag = null;
+ ///
+ /// Gets a formatted + to skill string
+ ///
+ /// DBRecord database record
+ /// variable structure
+ /// ItemAttributesData structure
+ /// line of text
+ /// display font string
+ /// formatted string containing + to skill
+ private string GetAugmentSkillLevel(DBRecordCollection record, Variable variable, ItemAttributesData attributeData, string line, ref TQColor? font)
+ {
+ string augmentSkillNumber = attributeData.FullAttribute.Substring(17, 1);
+ string skillRecordKey = string.Concat("augmentSkillName", augmentSkillNumber);
+ string skillRecordID = record.GetString(skillRecordKey, 0);
+
+ if (!string.IsNullOrEmpty(skillRecordID))
+ {
+ string skillName = null;
+ string nameTag = null;
+ DBRecordCollection skillRecord = Database.GetRecordFromFile(skillRecordID);
+ if (skillRecord != null)
+ {
// Changed by VillageIdiot
- // Let's actually test if there is a buff skill
+ // for augmenting buff skills
string buffSkillName = skillRecord.GetString("buffSkillName", 0);
if (string.IsNullOrEmpty(buffSkillName))
{
+ // Not a buff so look up the name
nameTag = skillRecord.GetString("skillDisplayName", 0);
if (!string.IsNullOrEmpty(nameTag))
+ TranslationService.TryTranslateXTag(nameTag, out skillName);
+ else
{
- if (!TranslationService.TryTranslateXTag(nameTag, out skillName))
- skillName = Path.GetFileNameWithoutExtension(variable.GetString(0));
+ // Added by VillageIdiot
+ // Check to see if this is a pet skill
+ nameTag = skillRecord.GetString("Class", 0);
+ if (nameTag.Contains("PetModifier"))
+ {
+ string petSkillID = skillRecord.GetString("petSkillName", 0);
+ DBRecordCollection petSkillRecord = Database.GetRecordFromFile(petSkillID);
+ if (petSkillRecord != null)
+ {
+ // Try to get display name
+ string petNameTag = petSkillRecord.GetString("skillDisplayName", 0);
+ if (!string.IsNullOrEmpty(petNameTag))
+ TranslationService.TryTranslateXTag(petNameTag, out skillName);
+ else
+ { // It may fail because there is another level of redirection (records\xpack\skills\dream\nightmare_petmodifier_mastermind.dbr)
+ petNameTag = petSkillRecord.GetString("buffSkillName", 0);
+ if (!string.IsNullOrWhiteSpace(petNameTag))
+ {
+ var petSkillRecordLvl2 = Database.GetRecordFromFile(petNameTag);
+ if (petSkillRecordLvl2 is not null)
+ {
+ petNameTag = petSkillRecordLvl2.GetString("skillDisplayName", 0);
+ if (!string.IsNullOrEmpty(petNameTag))
+ TranslationService.TryTranslateXTag(petNameTag, out skillName);
+
+ }
+ }
+ }
+
+ }
+ }
}
}
else
{
// This is a buff skill
DBRecordCollection buffSkillRecord = Database.GetRecordFromFile(buffSkillName);
- if (buffSkillRecord != null)
- {
- nameTag = buffSkillRecord.GetString("skillDisplayName", 0);
- if (!string.IsNullOrEmpty(nameTag))
- {
- if (!TranslationService.TryTranslateXTag(nameTag, out skillName))
- skillName = Path.GetFileNameWithoutExtension(variable.GetString(0));
- }
- }
- }
-
- // Added by VillageIdiot to support skill activation text
- string triggerType = null;
- string activationTag = null;
- string activationText = null;
- string autoController = record.GetString("itemSkillAutoController", 0);
- if (!string.IsNullOrEmpty(autoController))
- {
- DBRecordCollection autoControllerRecord = Database.GetRecordFromFile(autoController);
- if (autoControllerRecord != null)
- triggerType = autoControllerRecord.GetString("triggerType", 0);
- }
-
- // Convert TriggerType into text tag
- if (!string.IsNullOrEmpty(triggerType))
- {
- switch (triggerType.ToUpperInvariant())
+ if (buffSkillRecord != null)
{
- case "LOWHEALTH":
- // Activated on low health
- activationTag = "xtagAutoSkillCondition01";
- break;
-
- case "LOWMANA":
- // Activated on low energy
- activationTag = "xtagAutoSkillCondition02";
- break;
-
- case "HITBYENEMY":
- // Activated upon taking damage
- activationTag = "xtagAutoSkillCondition03";
- break;
-
- case "HITBYMELEE":
- // Activated upon taking melee damage
- activationTag = "xtagAutoSkillCondition04";
- break;
-
- case "HITBYPROJECTILE":
- // Activated upon taking ranged damage
- activationTag = "xtagAutoSkillCondition05";
- break;
-
- case "CASTBUFF":
- // Activated upon casting a buff
- activationTag = "xtagAutoSkillCondition06";
- break;
-
- case "ATTACKENEMY":
- // Activated on attack
- activationTag = "xtagAutoSkillCondition07";
- break;
-
- case "ONEQUIP":
- // Activated when equipped
- activationTag = "xtagAutoSkillCondition08";
- break;
-
- default:
- activationTag = string.Empty;
- break;
+ nameTag = buffSkillRecord.GetString("skillDisplayName", 0);
+ if (!string.IsNullOrEmpty(nameTag))
+ TranslationService.TryTranslateXTag(nameTag, out skillName);
}
}
-
- if (!string.IsNullOrEmpty(activationTag))
- TranslationService.TryTranslateXTag(activationTag, out activationText);
- else
- activationText = string.Empty;
-
- if (string.IsNullOrEmpty(activationText))
- font = ItemStyle.Epic.TQColor();
- else
- font = ItemStyle.Mundane.TQColor();
-
- line = Format("{0} {1}", skillName, activationText);
}
- return line;
- }
-
+ if (string.IsNullOrEmpty(skillName))
+ skillName = Path.GetFileNameWithoutExtension(skillRecordID);
- ///
- /// Gets the pet bonus string
- ///
- /// display font string
- /// formatted pet bonus name
- private string GetPetBonusName(ref TQColor? color)
- {
- string tag = "xtagPetBonusNameAllPets";
- if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
+ // now get the formatSpec
+ if (!TranslationService.TryTranslateXTag("ItemSkillIncrement", out var formatSpec))
{
- formatSpec = "?Bonus to All Pets:?";
- color = ItemStyle.Legendary.TQColor();
+ formatSpec = "?+{0} to skill {1}?";
+ font = ItemStyle.Legendary.TQColor();
}
else
{
if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (pet bonus) = " + formatSpec);
+ Log.LogDebug("Item.formatspec (item skill) = " + formatSpec);
formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- color = ItemStyle.Relic.TQColor();
+ font = ItemStyle.Epic.TQColor();
}
- return formatSpec;
+ line = this.Format(formatSpec, variable[0], skillName);
}
+ return line;
+ }
- ///
- /// Gets the skill effects string
- ///
- /// ItemAttributesData structure of the base attribute
- /// offset number of the variable value that we are using
- /// variable structure
- /// ItemAttributesData structure of the current attribute
- /// line of text
- /// display font string
- /// formatted skill effect string
- private string GetSkillEffect(ItemAttributesData baseAttributeData, int variableNumber, Variable variable, ItemAttributesData currentAttributeData, string line, ref TQColor? color)
+ ///
+ /// Gets the formatted formulae string(s)
+ ///
+ /// results list
+ /// variable structure
+ /// ItemAttributesData structure
+ /// line of text
+ /// display font string
+ /// formatted formulae string
+ private string GetFormulae(List results, Variable variable, ItemAttributesData attributeData, string line, ref TQColor? font)
+ {
+ // Special case for formulae reagents
+ if (attributeData.FullAttribute.StartsWith("reagent", noCase))
{
- string labelTag = ItemAttributeProvider.GetAttributeTextTag(baseAttributeData);
- if (string.IsNullOrEmpty(labelTag))
- {
- labelTag = string.Concat("?", baseAttributeData.FullAttribute, "?");
- color = ItemStyle.Legendary.TQColor();
- }
-
- if (!TranslationService.TryTranslateXTag(labelTag, out var label))
+ DBRecordCollection reagentRecord = Database.GetRecordFromFile(variable.GetString(0));
+ if (reagentRecord != null)
{
- label = string.Concat("?", labelTag, "?");
- color = ItemStyle.Legendary.TQColor();
+ string nameTag = reagentRecord.GetString("description", 0);
+ if (!string.IsNullOrEmpty(nameTag))
+ {
+ string reagentName = TranslationService.TranslateXTag(nameTag);
+ string formatSpec = "{0}";
+ font = ItemStyle.Common.TQColor();
+ line = Format(formatSpec, reagentName);
+ }
}
+ }
+ else if (attributeData.FullAttribute.Equals("artifactCreationCost"))
+ {
+ if (!TranslationService.TryTranslateXTag("xtagArtifactCost", out var formatSpec))
+ formatSpec = "Gold Cost: {0}";
+ else
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.label (scroll) = " + label);
+ Log.LogDebug("Item.formatspec (Artifact cost) = " + formatSpec);
+
+ font = ItemStyle.Rare.TQColor();
+ results.Add(string.Empty);
+ line = Format(formatSpec, string.Format(CultureInfo.CurrentCulture, "{0:N0}", variable[0]));
+ }
+
+ return line;
+ }
+
+ ///
+ /// Gets a formatted string of the granted skill
+ ///
+ /// DBRecord database record
+ /// results list
+ /// variable structure
+ /// line of text
+ /// display font string
+ /// formatted granted skill string.
+ private string GetGrantedSkill(DBRecordCollection record, Item itm, List results, Variable variable, string line, ref TQColor? font)
+ {
+ // Added by VillageIdiot
+ // Special case for granted skills
+ DBRecordCollection skillRecord = Database.GetRecordFromFile(variable.GetString(0));
+ if (skillRecord != null)
+ {
+ // Add a blank line and then the Grants Skill text
+ results.Add(string.Empty);
+ font = ItemStyle.Mundane.TQColor();
+
+ if (!TranslationService.TryTranslateXTag("tagItemGrantSkill", out var skillTag))
+ skillTag = "Grants Skill :";
- label = ItemAttributeProvider.ConvertFormat(label);
+ var value = $"{font?.ColorTag()}{skillTag}";
+ results.Add(value);
+ itm.CurrentFriendlyNameResult.TmpAttrib.Add(value);
- // Find the extra format tag for those that take 2 parameters.
- string formatSpecTag = null;
- string formatSpec = null;
- if (currentAttributeData.FullAttribute.EndsWith("Cost", noCase))
- formatSpecTag = "SkillIntFormat";
- else if (currentAttributeData.FullAttribute.EndsWith("Level", noCase))
- formatSpecTag = "SkillIntFormat";
- else if (currentAttributeData.FullAttribute.EndsWith("Duration", noCase))
- formatSpecTag = "SkillSecondFormat";
- else if (currentAttributeData.FullAttribute.EndsWith("Radius", noCase))
- formatSpecTag = "SkillDistanceFormat";
+ string skillName = null;
+ string nameTag = null;
- if (!string.IsNullOrEmpty(formatSpecTag))
+ // Changed by VillageIdiot
+ // Let's actually test if there is a buff skill
+ string buffSkillName = skillRecord.GetString("buffSkillName", 0);
+ if (string.IsNullOrEmpty(buffSkillName))
{
- if (!TranslationService.TryTranslateXTag(formatSpecTag, out formatSpec))
+ nameTag = skillRecord.GetString("skillDisplayName", 0);
+ if (!string.IsNullOrEmpty(nameTag))
{
- formatSpec = "?{0} {1}?";
- color = ItemStyle.Legendary.TQColor();
+ if (!TranslationService.TryTranslateXTag(nameTag, out skillName))
+ skillName = Path.GetFileNameWithoutExtension(variable.GetString(0));
}
- else
+ }
+ else
+ {
+ // This is a buff skill
+ DBRecordCollection buffSkillRecord = Database.GetRecordFromFile(buffSkillName);
+ if (buffSkillRecord != null)
{
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (2 parameter) = " + formatSpec);
-
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- color = ItemStyle.Epic.TQColor();
+ nameTag = buffSkillRecord.GetString("skillDisplayName", 0);
+ if (!string.IsNullOrEmpty(nameTag))
+ {
+ if (!TranslationService.TryTranslateXTag(nameTag, out skillName))
+ skillName = Path.GetFileNameWithoutExtension(variable.GetString(0));
+ }
}
}
- if (string.IsNullOrEmpty(formatSpecTag))
+ // Added by VillageIdiot to support skill activation text
+ string triggerType = null;
+ string activationTag = null;
+ string activationText = null;
+ string autoController = record.GetString("itemSkillAutoController", 0);
+ if (!string.IsNullOrEmpty(autoController))
{
- color = ItemStyle.Epic.TQColor();
- line = Format(label, variable[Math.Min(variable.NumberOfValues - 1, variableNumber)]);
+ DBRecordCollection autoControllerRecord = Database.GetRecordFromFile(autoController);
+ if (autoControllerRecord != null)
+ triggerType = autoControllerRecord.GetString("triggerType", 0);
}
- else
+
+ // Convert TriggerType into text tag
+ if (!string.IsNullOrEmpty(triggerType))
{
- line = Format(formatSpec, variable[Math.Min(variable.NumberOfValues - 1, variableNumber)], label);
+ switch (triggerType.ToUpperInvariant())
+ {
+ case "LOWHEALTH":
+ // Activated on low health
+ activationTag = "xtagAutoSkillCondition01";
+ break;
+
+ case "LOWMANA":
+ // Activated on low energy
+ activationTag = "xtagAutoSkillCondition02";
+ break;
+
+ case "HITBYENEMY":
+ // Activated upon taking damage
+ activationTag = "xtagAutoSkillCondition03";
+ break;
+
+ case "HITBYMELEE":
+ // Activated upon taking melee damage
+ activationTag = "xtagAutoSkillCondition04";
+ break;
+
+ case "HITBYPROJECTILE":
+ // Activated upon taking ranged damage
+ activationTag = "xtagAutoSkillCondition05";
+ break;
+
+ case "CASTBUFF":
+ // Activated upon casting a buff
+ activationTag = "xtagAutoSkillCondition06";
+ break;
+
+ case "ATTACKENEMY":
+ // Activated on attack
+ activationTag = "xtagAutoSkillCondition07";
+ break;
+
+ case "ONEQUIP":
+ // Activated when equipped
+ activationTag = "xtagAutoSkillCondition08";
+ break;
+
+ default:
+ activationTag = string.Empty;
+ break;
+ }
}
- return line;
+ if (!string.IsNullOrEmpty(activationTag))
+ TranslationService.TryTranslateXTag(activationTag, out activationText);
+ else
+ activationText = string.Empty;
+
+ if (string.IsNullOrEmpty(activationText))
+ font = ItemStyle.Epic.TQColor();
+ else
+ font = ItemStyle.Mundane.TQColor();
+
+ line = Format("{0} {1}", skillName, activationText);
}
- ///
- /// Gets a raw attribute string
- ///
- /// ItemAttributesData structure
- /// offset number of the variable value that we are using
- /// variable structure
- /// display font string
- /// formatted raw attribute string
- private string GetRawAttribute(ItemAttributesData attributeData, int variableNumber, Variable variable, ref TQColor? color)
+ return line;
+ }
+
+
+ ///
+ /// Gets the pet bonus string
+ ///
+ /// display font string
+ /// formatted pet bonus name
+ private string GetPetBonusName(ref TQColor? color)
+ {
+ string tag = "xtagPetBonusNameAllPets";
+ if (!TranslationService.TryTranslateXTag(tag, out var formatSpec))
{
- string line = null;
+ formatSpec = "?Bonus to All Pets:?";
+ color = ItemStyle.Legendary.TQColor();
+ }
+ else
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (pet bonus) = " + formatSpec);
- string labelTag = ItemAttributeProvider.GetAttributeTextTag(attributeData);
- if (string.IsNullOrWhiteSpace(labelTag))
- {
- labelTag = string.Concat("?", attributeData.FullAttribute, "?");
- color = ItemStyle.Legendary.TQColor();
- }
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ color = ItemStyle.Relic.TQColor();
+ }
- if (!TranslationService.TryTranslateXTag(labelTag, out var label))
- {
- label = string.Concat("?", labelTag, "?");
- color = ItemStyle.Legendary.TQColor();
- }
+ return formatSpec;
+ }
+
+
+ ///
+ /// Gets the skill effects string
+ ///
+ /// ItemAttributesData structure of the base attribute
+ /// offset number of the variable value that we are using
+ /// variable structure
+ /// ItemAttributesData structure of the current attribute
+ /// line of text
+ /// display font string
+ /// formatted skill effect string
+ private string GetSkillEffect(ItemAttributesData baseAttributeData, int variableNumber, Variable variable, ItemAttributesData currentAttributeData, string line, ref TQColor? color)
+ {
+ string labelTag = ItemAttributeProvider.GetAttributeTextTag(baseAttributeData);
+ if (string.IsNullOrEmpty(labelTag))
+ {
+ labelTag = string.Concat("?", baseAttributeData.FullAttribute, "?");
+ color = ItemStyle.Legendary.TQColor();
+ }
+
+ if (!TranslationService.TryTranslateXTag(labelTag, out var label))
+ {
+ label = string.Concat("?", labelTag, "?");
+ color = ItemStyle.Legendary.TQColor();
+ }
+
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.label (scroll) = " + label);
+
+ label = ItemAttributeProvider.ConvertFormat(label);
- label = ItemAttributeProvider.ConvertFormat(label);
- if (label.IndexOf('{') >= 0)
+ // Find the extra format tag for those that take 2 parameters.
+ string formatSpecTag = null;
+ string formatSpec = null;
+ if (currentAttributeData.FullAttribute.EndsWith("Cost", noCase))
+ formatSpecTag = "SkillIntFormat";
+ else if (currentAttributeData.FullAttribute.EndsWith("Level", noCase))
+ formatSpecTag = "SkillIntFormat";
+ else if (currentAttributeData.FullAttribute.EndsWith("Duration", noCase))
+ formatSpecTag = "SkillSecondFormat";
+ else if (currentAttributeData.FullAttribute.EndsWith("Radius", noCase))
+ formatSpecTag = "SkillDistanceFormat";
+
+ if (!string.IsNullOrEmpty(formatSpecTag))
+ {
+ if (!TranslationService.TryTranslateXTag(formatSpecTag, out formatSpec))
{
- // we have a format string. try using it.
- line = Format(label, variable[Math.Min(variable.NumberOfValues - 1, variableNumber)]);
- if (!color.HasValue)
- color = ItemStyle.Epic.TQColor();
+ formatSpec = "?{0} {1}?";
+ color = ItemStyle.Legendary.TQColor();
}
else
{
- // no format string.
- line = Database.VariableToStringNice(variable);
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (2 parameter) = " + formatSpec);
+
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ color = ItemStyle.Epic.TQColor();
}
+ }
- if (!color.HasValue)
- color = ItemStyle.Legendary.TQColor(); // make these unknowns stand out
+ if (string.IsNullOrEmpty(formatSpecTag))
+ {
+ color = ItemStyle.Epic.TQColor();
+ line = Format(label, variable[Math.Min(variable.NumberOfValues - 1, variableNumber)]);
+ }
+ else
+ {
+ line = Format(formatSpec, variable[Math.Min(variable.NumberOfValues - 1, variableNumber)], label);
+ }
+
+ return line;
+ }
+
+ ///
+ /// Gets a raw attribute string
+ ///
+ /// ItemAttributesData structure
+ /// offset number of the variable value that we are using
+ /// variable structure
+ /// display font string
+ /// formatted raw attribute string
+ private string GetRawAttribute(ItemAttributesData attributeData, int variableNumber, Variable variable, ref TQColor? color)
+ {
+ string line = null;
- return line;
+ string labelTag = ItemAttributeProvider.GetAttributeTextTag(attributeData);
+ if (string.IsNullOrWhiteSpace(labelTag))
+ {
+ labelTag = string.Concat("?", attributeData.FullAttribute, "?");
+ color = ItemStyle.Legendary.TQColor();
}
- ///
- /// Converts the item's offensice attributes to a string
- ///
- /// DBRecord of the database record
- /// ArrayList containing the attribute list
- /// ItemAttributesData for the item
- /// string containing the record id
- /// List containing the results
- private void ConvertOffenseAttributesToString(Item itm, DBRecordCollection record, List attributeList, ItemAttributesData data, string recordId, List results)
+ if (!TranslationService.TryTranslateXTag(labelTag, out var label))
{
- if (TQDebug.ItemDebugLevel > 0)
- {
- Log.LogDebug("Item.ConvertOffenseAttrToString({0}, {1}, {2}, {3}, {4})"
- , record, attributeList, data, recordId, results
- );
- }
+ label = string.Concat("?", labelTag, "?");
+ color = ItemStyle.Legendary.TQColor();
+ }
- // If we are a relic, then sometimes there are multiple values per variable depending on how many pieces we have.
- // Let's determine which variable we want in these cases.
- int variableNumber = 0;
- if (itm.IsRelic && recordId == itm.BaseItemId)
- variableNumber = itm.Number - 1;
- else if (itm.HasRelicSlot1 && recordId == itm.relicID)
- variableNumber = Math.Max(itm.Var1, 1) - 1;
- else if (itm.HasRelicSlot2 && recordId == itm.relic2ID)
- variableNumber = Math.Max(itm.Var2, 1) - 1;
-
- // Pet skills can also have multiple values so we attempt to decode it here
- if (itm.IsScroll || itm.IsRelic)
- variableNumber = GetPetSkillLevel(itm, record, recordId, variableNumber);
-
- // Triggered skills can have also multiple values so we need to decode it here
- if (record.GetString("Class", 0).StartsWith("SKILL", noCase))
- variableNumber = GetTriggeredSkillLevel(itm, record, recordId, variableNumber);
-
- // See what variables we have
- ItemAttributesData minData = null;
- ItemAttributesData maxData = null;
- ItemAttributesData minDurData = null;
- ItemAttributesData maxDurData = null;
- ItemAttributesData chanceData = null;
- ItemAttributesData modifierData = null;
- ItemAttributesData durationModifierData = null;
- ItemAttributesData modifierChanceData = null;
- ItemAttributesData damageRatioData = null; // Added by VillageIdiot
-
- Variable minVar = null;
- Variable maxVar = null;
- Variable minDurVar = null;
- Variable maxDurVar = null;
- Variable chanceVar = null;
- Variable modifierVar = null;
- Variable durationModifierVar = null;
- Variable modifierChanceVar = null;
- Variable damageRatioVar = null; // Added by VillageIdiot
-
- bool isGlobal = ItemAttributeProvider.AttributeGroupHas(new Collection(attributeList), "Global");
- string globalIndent = new string(' ', 4);
-
- foreach (Variable variable in attributeList)
- {
- if (variable == null)
- continue;
+ label = ItemAttributeProvider.ConvertFormat(label);
+ if (label.IndexOf('{') >= 0)
+ {
+ // we have a format string. try using it.
+ line = Format(label, variable[Math.Min(variable.NumberOfValues - 1, variableNumber)]);
+ if (!color.HasValue)
+ color = ItemStyle.Epic.TQColor();
+ }
+ else
+ {
+ // no format string.
+ line = Database.VariableToStringNice(variable);
+ }
- ItemAttributesData attributeData = ItemAttributeProvider.GetAttributeData(variable.Name);
- if (attributeData == null)
- {
- // unknown attribute
- attributeData = new ItemAttributesData(ItemAttributesEffectType.Other, variable.Name, variable.Name, string.Empty, 0);
- }
+ if (!color.HasValue)
+ color = ItemStyle.Legendary.TQColor(); // make these unknowns stand out
- switch (attributeData.Variable.ToUpperInvariant())
- {
- case "MIN":
- minData = attributeData;
- minVar = variable;
- break;
+ return line;
+ }
+ ///
+ /// Converts the item's offensice attributes to a string
+ ///
+ /// DBRecord of the database record
+ /// ArrayList containing the attribute list
+ /// ItemAttributesData for the item
+ /// string containing the record id
+ /// List containing the results
+ private void ConvertOffenseAttributesToString(Item itm, DBRecordCollection record, List attributeList, ItemAttributesData data, string recordId, List results)
+ {
+ if (TQDebug.ItemDebugLevel > 0)
+ {
+ Log.LogDebug("Item.ConvertOffenseAttrToString({0}, {1}, {2}, {3}, {4})"
+ , record, attributeList, data, recordId, results
+ );
+ }
- case "MAX":
- maxData = attributeData;
- maxVar = variable;
- break;
+ // If we are a relic, then sometimes there are multiple values per variable depending on how many pieces we have.
+ // Let's determine which variable we want in these cases.
+ int variableNumber = 0;
+ if (itm.IsRelic && recordId == itm.BaseItemId)
+ variableNumber = itm.Number - 1;
+ else if (itm.HasRelicSlot1 && recordId == itm.relicID)
+ variableNumber = Math.Max(itm.Var1, 1) - 1;
+ else if (itm.HasRelicSlot2 && recordId == itm.relic2ID)
+ variableNumber = Math.Max(itm.Var2, 1) - 1;
+
+ // Pet skills can also have multiple values so we attempt to decode it here
+ if (itm.IsScroll || itm.IsRelic)
+ variableNumber = GetPetSkillLevel(itm, record, recordId, variableNumber);
+
+ // Triggered skills can have also multiple values so we need to decode it here
+ if (record.GetString("Class", 0).StartsWith("SKILL", noCase))
+ variableNumber = GetTriggeredSkillLevel(itm, record, recordId, variableNumber);
+
+ // See what variables we have
+ ItemAttributesData minData = null;
+ ItemAttributesData maxData = null;
+ ItemAttributesData minDurData = null;
+ ItemAttributesData maxDurData = null;
+ ItemAttributesData chanceData = null;
+ ItemAttributesData modifierData = null;
+ ItemAttributesData durationModifierData = null;
+ ItemAttributesData modifierChanceData = null;
+ ItemAttributesData damageRatioData = null; // Added by VillageIdiot
+
+ Variable minVar = null;
+ Variable maxVar = null;
+ Variable minDurVar = null;
+ Variable maxDurVar = null;
+ Variable chanceVar = null;
+ Variable modifierVar = null;
+ Variable durationModifierVar = null;
+ Variable modifierChanceVar = null;
+ Variable damageRatioVar = null; // Added by VillageIdiot
+
+ bool isGlobal = ItemAttributeProvider.AttributeGroupHas(new Collection(attributeList), "Global");
+ string globalIndent = new string(' ', 4);
+
+ foreach (Variable variable in attributeList)
+ {
+ if (variable == null)
+ continue;
+ ItemAttributesData attributeData = ItemAttributeProvider.GetAttributeData(variable.Name);
+ if (attributeData == null)
+ {
+ // unknown attribute
+ attributeData = new ItemAttributesData(ItemAttributesEffectType.Other, variable.Name, variable.Name, string.Empty, 0);
+ }
- case "DURATIONMIN":
- minDurData = attributeData;
- minDurVar = variable;
- break;
+ switch (attributeData.Variable.ToUpperInvariant())
+ {
+ case "MIN":
+ minData = attributeData;
+ minVar = variable;
+ break;
- case "DURATIONMAX":
- maxDurData = attributeData;
- maxDurVar = variable;
- break;
+ case "MAX":
+ maxData = attributeData;
+ maxVar = variable;
+ break;
- case "CHANCE":
- chanceData = attributeData;
- chanceVar = variable;
- break;
+ case "DURATIONMIN":
+ minDurData = attributeData;
+ minDurVar = variable;
+ break;
- case "MODIFIER":
- modifierData = attributeData;
- modifierVar = variable;
- break;
+ case "DURATIONMAX":
+ maxDurData = attributeData;
+ maxDurVar = variable;
+ break;
- case "MODIFIERCHANCE":
- modifierChanceData = attributeData;
- modifierChanceVar = variable;
- break;
+ case "CHANCE":
+ chanceData = attributeData;
+ chanceVar = variable;
+ break;
- case "DURATIONMODIFIER":
- durationModifierData = attributeData;
- durationModifierVar = variable;
- break;
+ case "MODIFIER":
+ modifierData = attributeData;
+ modifierVar = variable;
+ break;
- case "DRAINMIN":
- // Added by VillageIdiot
- minData = attributeData;
- minVar = variable;
- break;
+ case "MODIFIERCHANCE":
+ modifierChanceData = attributeData;
+ modifierChanceVar = variable;
+ break;
- case "DRAINMAX":
- // Added by VillageIdiot
- maxData = attributeData;
- maxVar = variable;
- break;
+ case "DURATIONMODIFIER":
+ durationModifierData = attributeData;
+ durationModifierVar = variable;
+ break;
- case "DAMAGERATIO":
- // Added by VillageIdiot
- damageRatioData = attributeData;
- damageRatioVar = variable;
- break;
+ case "DRAINMIN":
+ // Added by VillageIdiot
+ minData = attributeData;
+ minVar = variable;
+ break;
- }
- }
- // Figure out the label string
- string labelTag = null;
- TQColor? labelColor = null;
- string label = GetLabelAndColorFromTag(itm, data, recordId, ref labelTag, ref labelColor);
+ case "DRAINMAX":
+ // Added by VillageIdiot
+ maxData = attributeData;
+ maxVar = variable;
+ break;
- if (TQDebug.ItemDebugLevel > 1)
- {
- Log.LogDebug("Full attribute = " + data.FullAttribute);
- Log.LogDebug("Item.label = " + label);
- }
- label = ItemAttributeProvider.ConvertFormat(label);
+ case "DAMAGERATIO":
+ // Added by VillageIdiot
+ damageRatioData = attributeData;
+ damageRatioVar = variable;
+ break;
- // Figure out the Amount string
- string amount = null;
- if (minData != null
- && maxData != null
- && minVar.GetSingle(Math.Min(minVar.NumberOfValues - 1, variableNumber)) != maxVar.GetSingle(Math.Min(maxVar.NumberOfValues - 1, variableNumber))
- )
- {
- if (minDurVar != null)
- amount = GetAmountRange(itm, data, variableNumber, minVar, maxVar, ref label, labelColor, minDurVar);
- else
- amount = GetAmountRange(itm, data, variableNumber, minVar, maxVar, ref label, labelColor);
- }
- else
- {
- if (minDurVar != null)
- amount = GetAmountSingle(itm, data, variableNumber, minVar, maxVar, ref label, labelColor, minDurVar);
- else
- amount = GetAmountSingle(itm, data, variableNumber, minVar, maxVar, ref label, labelColor);
}
+ }
- // Figure out the duration string
- string duration = null;
- //If we have both minDurData and maxDurData we also need to check if the actual Values of minDurVar and maxDurVar are actually different
- float minDurVarValue = -1;
- float maxDurVarValue = -1;
-
- if (minDurData != null)
- minDurVarValue = (float)minDurVar[minDurVar.NumberOfValues - 1];
+ // Figure out the label string
+ string labelTag = null;
+ TQColor? labelColor = null;
+ string label = GetLabelAndColorFromTag(itm, data, recordId, ref labelTag, ref labelColor);
- if (maxDurData != null)
- maxDurVarValue = (float)maxDurVar[maxDurVar.NumberOfValues - 1];
- if (minDurData != null && maxDurData != null && minDurVarValue != maxDurVarValue)
- duration = GetDurationRange(variableNumber, minDurVar, maxDurVar);
- else
- duration = GetDurationSingle(variableNumber, minDurVar, maxDurVar);
+ if (TQDebug.ItemDebugLevel > 1)
+ {
+ Log.LogDebug("Full attribute = " + data.FullAttribute);
+ Log.LogDebug("Item.label = " + label);
+ }
- // Figure out the Damage Ratio string
- string damageRatio = null;
- if (damageRatioData != null)
- damageRatio = GetDamageRatio(variableNumber, damageRatioData, damageRatioVar);
+ label = ItemAttributeProvider.ConvertFormat(label);
- // Figure out the chance string
- string chance = null;
- if (chanceData != null)
- chance = GetChance(variableNumber, chanceVar);
+ // Figure out the Amount string
+ string amount = null;
+ if (minData != null
+ && maxData != null
+ && minVar.GetSingle(Math.Min(minVar.NumberOfValues - 1, variableNumber)) != maxVar.GetSingle(Math.Min(maxVar.NumberOfValues - 1, variableNumber))
+ )
+ {
+ if (minDurVar != null)
+ amount = GetAmountRange(itm, data, variableNumber, minVar, maxVar, ref label, labelColor, minDurVar);
+ else
+ amount = GetAmountRange(itm, data, variableNumber, minVar, maxVar, ref label, labelColor);
+ }
+ else
+ {
+ if (minDurVar != null)
+ amount = GetAmountSingle(itm, data, variableNumber, minVar, maxVar, ref label, labelColor, minDurVar);
+ else
+ amount = GetAmountSingle(itm, data, variableNumber, minVar, maxVar, ref label, labelColor);
+ }
- // Display the chance + label + Amount + Duration + DamageRatio
- string[] strarray = new string[5];
- int numberOfStrings = 0;
- if (!string.IsNullOrEmpty(label))
- {
- if (!label.HasColorPrefix())
- label = $"{labelColor?.ColorTag()}{label}";
- }
+ // Figure out the duration string
+ string duration = null;
+ //If we have both minDurData and maxDurData we also need to check if the actual Values of minDurVar and maxDurVar are actually different
+ float minDurVarValue = -1;
+ float maxDurVarValue = -1;
+
+ if (minDurData != null)
+ minDurVarValue = (float)minDurVar[minDurVar.NumberOfValues - 1];
+
+ if (maxDurData != null)
+ maxDurVarValue = (float)maxDurVar[maxDurVar.NumberOfValues - 1];
+ if (minDurData != null && maxDurData != null && minDurVarValue != maxDurVarValue)
+ duration = GetDurationRange(variableNumber, minDurVar, maxDurVar);
+ else
+ duration = GetDurationSingle(variableNumber, minDurVar, maxDurVar);
+
+ // Figure out the Damage Ratio string
+ string damageRatio = null;
+ if (damageRatioData != null)
+ damageRatio = GetDamageRatio(variableNumber, damageRatioData, damageRatioVar);
+
+ // Figure out the chance string
+ string chance = null;
+ if (chanceData != null)
+ chance = GetChance(variableNumber, chanceVar);
+
+ // Display the chance + label + Amount + Duration + DamageRatio
+ string[] strarray = new string[5];
+ int numberOfStrings = 0;
+ if (!string.IsNullOrEmpty(label))
+ {
+ if (!label.HasColorPrefix())
+ label = $"{labelColor?.ColorTag()}{label}";
+ }
- if (!string.IsNullOrEmpty(chance))
- strarray[numberOfStrings++] = chance;
+ if (!string.IsNullOrEmpty(chance))
+ strarray[numberOfStrings++] = chance;
- if (!string.IsNullOrEmpty(amount))
- strarray[numberOfStrings++] = amount;
+ if (!string.IsNullOrEmpty(amount))
+ strarray[numberOfStrings++] = amount;
- if (!string.IsNullOrEmpty(label))
- strarray[numberOfStrings++] = label;
+ if (!string.IsNullOrEmpty(label))
+ strarray[numberOfStrings++] = label;
- if (!string.IsNullOrEmpty(duration))
- strarray[numberOfStrings++] = duration;
+ if (!string.IsNullOrEmpty(duration))
+ strarray[numberOfStrings++] = duration;
- if (!string.IsNullOrEmpty(damageRatio))
- // Added by VillageIdiot
- strarray[numberOfStrings++] = damageRatio;
+ if (!string.IsNullOrEmpty(damageRatio))
+ // Added by VillageIdiot
+ strarray[numberOfStrings++] = damageRatio;
- if (!string.IsNullOrEmpty(amount) || !string.IsNullOrEmpty(duration))
+ if (!string.IsNullOrEmpty(amount) || !string.IsNullOrEmpty(duration))
+ {
+ string amountOrDurationText = string.Join(" ", strarray, 0, numberOfStrings);
+
+ // Figure out what color to use
+ TQColor? fontColor = null;
+ if (!isGlobal
+ && (string.IsNullOrEmpty(chance) || data.Effect.Equals("defensiveBlock"))
+ && recordId == itm.BaseItemId
+ && string.IsNullOrEmpty(duration)
+ && !string.IsNullOrEmpty(amount)
+ )
{
- string amountOrDurationText = string.Join(" ", strarray, 0, numberOfStrings);
-
- // Figure out what color to use
- TQColor? fontColor = null;
- if (!isGlobal
- && (string.IsNullOrEmpty(chance) || data.Effect.Equals("defensiveBlock"))
- && recordId == itm.BaseItemId
- && string.IsNullOrEmpty(duration)
- && !string.IsNullOrEmpty(amount)
- )
+ if (itm.IsWeapon)
{
- if (itm.IsWeapon)
+ if (data.Effect.Equals("offensivePierceRatio")
+ || data.Effect.Equals("offensivePhysical")
+ || data.Effect.Equals("offensiveBaseFire")
+ || data.Effect.Equals("offensiveBaseCold")
+ || data.Effect.Equals("offensiveBaseLightning")
+ || data.Effect.Equals("offensiveBaseLife")
+ )
{
- if (data.Effect.Equals("offensivePierceRatio")
- || data.Effect.Equals("offensivePhysical")
- || data.Effect.Equals("offensiveBaseFire")
- || data.Effect.Equals("offensiveBaseCold")
- || data.Effect.Equals("offensiveBaseLightning")
- || data.Effect.Equals("offensiveBaseLife")
- )
- {
- // mundane effect
- fontColor = ItemStyle.Mundane.TQColor();
- }
+ // mundane effect
+ fontColor = ItemStyle.Mundane.TQColor();
}
+ }
- if (itm.IsShield)
+ if (itm.IsShield)
+ {
+ if (data.Effect.Equals("defensiveBlock")
+ || data.Effect.Equals("blockRecoveryTime")
+ || data.Effect.Equals("offensivePhysical")
+ )
{
- if (data.Effect.Equals("defensiveBlock")
- || data.Effect.Equals("blockRecoveryTime")
- || data.Effect.Equals("offensivePhysical")
- )
- {
- fontColor = ItemStyle.Mundane.TQColor();
- }
+ fontColor = ItemStyle.Mundane.TQColor();
}
}
+ }
- // magical effect
- if (!fontColor.HasValue)
- fontColor = ItemStyle.Epic.TQColor();
+ // magical effect
+ if (!fontColor.HasValue)
+ fontColor = ItemStyle.Epic.TQColor();
- if (!amountOrDurationText.HasColorPrefix())
- amountOrDurationText = $"{fontColor?.ColorTag()}{amountOrDurationText}";
+ if (!amountOrDurationText.HasColorPrefix())
+ amountOrDurationText = $"{fontColor?.ColorTag()}{amountOrDurationText}";
- if (isGlobal)
- amountOrDurationText = amountOrDurationText.InsertAfterColorPrefix(globalIndent);
+ if (isGlobal)
+ amountOrDurationText = amountOrDurationText.InsertAfterColorPrefix(globalIndent);
- results.Add(amountOrDurationText);
- itm.CurrentFriendlyNameResult.TmpAttrib.Add(amountOrDurationText);
- }
- else
- {
- // null these out to indicate they did not get used
- amount = null;
- duration = null;
- chance = null;
- }
+ results.Add(amountOrDurationText);
+ itm.CurrentFriendlyNameResult.TmpAttrib.Add(amountOrDurationText);
+ }
+ else
+ {
+ // null these out to indicate they did not get used
+ amount = null;
+ duration = null;
+ chance = null;
+ }
- // now see if we have a modifier
- string modifier = null;
- if (modifierData != null)
- modifier = GetModifier(data, variableNumber, modifierData, modifierVar);
+ // now see if we have a modifier
+ string modifier = null;
+ if (modifierData != null)
+ modifier = GetModifier(data, variableNumber, modifierData, modifierVar);
- string durationModifier = null;
- if (durationModifierData != null)
- durationModifier = GetDurationModifier(variableNumber, durationModifierVar);
+ string durationModifier = null;
+ if (durationModifierData != null)
+ durationModifier = GetDurationModifier(variableNumber, durationModifierVar);
- string modifierChance = null;
- if (modifierChanceData != null)
- modifierChance = GetChanceModifier(variableNumber, modifierChanceVar);
+ string modifierChance = null;
+ if (modifierChanceData != null)
+ modifierChance = GetChanceModifier(variableNumber, modifierChanceVar);
- numberOfStrings = 0;
- if (!string.IsNullOrEmpty(modifierChance))
- strarray[numberOfStrings++] = modifierChance;
+ numberOfStrings = 0;
+ if (!string.IsNullOrEmpty(modifierChance))
+ strarray[numberOfStrings++] = modifierChance;
- if (!string.IsNullOrEmpty(modifier))
- strarray[numberOfStrings++] = modifier;
+ if (!string.IsNullOrEmpty(modifier))
+ strarray[numberOfStrings++] = modifier;
- if (!string.IsNullOrEmpty(durationModifier))
- strarray[numberOfStrings++] = durationModifier;
+ if (!string.IsNullOrEmpty(durationModifier))
+ strarray[numberOfStrings++] = durationModifier;
- if (!string.IsNullOrEmpty(modifier))
- {
- string modifierText = string.Join(" ", strarray, 0, numberOfStrings);
+ if (!string.IsNullOrEmpty(modifier))
+ {
+ string modifierText = string.Join(" ", strarray, 0, numberOfStrings);
- if (isGlobal)
- modifierText = string.Concat(globalIndent, modifierText);
+ if (isGlobal)
+ modifierText = string.Concat(globalIndent, modifierText);
- if (!modifierText.HasColorPrefix())
- modifierText = $"{ItemStyle.Epic.TQColor().ColorTag()}{modifierText}";
+ if (!modifierText.HasColorPrefix())
+ modifierText = $"{ItemStyle.Epic.TQColor().ColorTag()}{modifierText}";
- results.Add(modifierText);
- itm.CurrentFriendlyNameResult.TmpAttrib.Add(modifierText);
- }
- else
- {
- modifier = null;
- modifierChance = null;
- durationModifier = null;
- }
+ results.Add(modifierText);
+ itm.CurrentFriendlyNameResult.TmpAttrib.Add(modifierText);
+ }
+ else
+ {
+ modifier = null;
+ modifierChance = null;
+ durationModifier = null;
+ }
- // Added so we only show the title once for the group.
- bool displayDamageQualifierTitle = true;
+ // Added so we only show the title once for the group.
+ bool displayDamageQualifierTitle = true;
- // Now display any other variables we did not see here.
- foreach (Variable variable in attributeList)
- {
- if (variable == null)
- continue;
+ // Now display any other variables we did not see here.
+ foreach (Variable variable in attributeList)
+ {
+ if (variable == null)
+ continue;
- ItemAttributesData attributeData = ItemAttributeProvider.GetAttributeData(variable.Name);
-
- if (attributeData == null)
- // unknown attribute
- attributeData = new ItemAttributesData(ItemAttributesEffectType.Other, variable.Name, variable.Name, string.Empty, 0);
-
- string normalizedAttributeVariable = attributeData.Variable.ToUpperInvariant();
- if (
- !(
- amount != null
- && (normalizedAttributeVariable == "MIN"
- || normalizedAttributeVariable == "MAX"
- || normalizedAttributeVariable == "DRAINMIN"
- || normalizedAttributeVariable == "DRAINMAX"
- )
+ ItemAttributesData attributeData = ItemAttributeProvider.GetAttributeData(variable.Name);
+
+ if (attributeData == null)
+ // unknown attribute
+ attributeData = new ItemAttributesData(ItemAttributesEffectType.Other, variable.Name, variable.Name, string.Empty, 0);
+
+ string normalizedAttributeVariable = attributeData.Variable.ToUpperInvariant();
+ if (
+ !(
+ amount != null
+ && (normalizedAttributeVariable == "MIN"
+ || normalizedAttributeVariable == "MAX"
+ || normalizedAttributeVariable == "DRAINMIN"
+ || normalizedAttributeVariable == "DRAINMAX"
)
- && !(duration != null && (normalizedAttributeVariable == "DURATIONMIN" || normalizedAttributeVariable == "DURATIONMAX"))
- && !(chance != null && normalizedAttributeVariable == "CHANCE")
- && !(modifier != null && normalizedAttributeVariable == "MODIFIER")
- && !(durationModifier != null && normalizedAttributeVariable == "DURATIONMODIFIER")
- && !(modifierChance != null && normalizedAttributeVariable == "MODIFIERCHANCE")
- && !(damageRatio != null && normalizedAttributeVariable == "DAMAGERATIO")
- && normalizedAttributeVariable != "GLOBAL"
- && !(normalizedAttributeVariable == "XOR" && isGlobal)
)
+ && !(duration != null && (normalizedAttributeVariable == "DURATIONMIN" || normalizedAttributeVariable == "DURATIONMAX"))
+ && !(chance != null && normalizedAttributeVariable == "CHANCE")
+ && !(modifier != null && normalizedAttributeVariable == "MODIFIER")
+ && !(durationModifier != null && normalizedAttributeVariable == "DURATIONMODIFIER")
+ && !(modifierChance != null && normalizedAttributeVariable == "MODIFIERCHANCE")
+ && !(damageRatio != null && normalizedAttributeVariable == "DAMAGERATIO")
+ && normalizedAttributeVariable != "GLOBAL"
+ && !(normalizedAttributeVariable == "XOR" && isGlobal)
+ )
+ {
+ string line = null;
+ TQColor? color = null;
+ string normalizedFullAttribute = attributeData.FullAttribute.ToUpperInvariant();
+ if (normalizedFullAttribute == "CHARACTERBASEATTACKSPEEDTAG")
+ {
+ // only display itm tag if we are a basic weapon
+ if (itm.IsWeapon && recordId == itm.BaseItemId)
+ {
+ color = ItemStyle.Mundane.TQColor();
+ line = TranslationService.TranslateXTag(variable.GetString(0));
+ }
+ else
+ line = string.Empty;
+ }
+ else if (normalizedFullAttribute.EndsWith("GLOBALCHANCE", noCase))
+ line = GetGlobalChance(attributeList, variableNumber, variable, ref color);
+ else if (normalizedFullAttribute.StartsWith("RACIALBONUS", noCase))
+ line = GetRacialBonus(record, itm, results, variableNumber, isGlobal, globalIndent, variable, attributeData, line, ref color);
+ else if (normalizedFullAttribute == "AUGMENTALLLEVEL")
+ line = GetAugmentAllLevel(variableNumber, variable, ref color);
+ else if (normalizedFullAttribute.StartsWith("AUGMENTMASTERYLEVEL", noCase))
+ line = GetAugmentMasteryLevel(record, variable, attributeData, ref color);
+ else if (normalizedFullAttribute.StartsWith("AUGMENTSKILLLEVEL", noCase))
+ line = GetAugmentSkillLevel(record, variable, attributeData, line, ref color);
+ else if (itm.IsFormulae && recordId == itm.BaseItemId)
+ line = GetFormulae(results, variable, attributeData, line, ref color);
+ else if (normalizedFullAttribute == "ITEMSKILLNAME")
+ line = GetGrantedSkill(record, itm, results, variable, line, ref color);
+
+ // Added by VillageIdiot
+ // Shows the header text for the pet bonus
+ if (normalizedFullAttribute == "PETBONUSNAME")
+ line = StringHelper.TQNewLineTag + GetPetBonusName(ref color);
+
+ // Added by VillageIdiot
+ // Set the scale percent here
+ if (recordId == itm.BaseItemId && normalizedFullAttribute == "ATTRIBUTESCALEPERCENT" && itm.itemScalePercent == 1.00)
{
- string line = null;
- TQColor? color = null;
- string normalizedFullAttribute = attributeData.FullAttribute.ToUpperInvariant();
- if (normalizedFullAttribute == "CHARACTERBASEATTACKSPEEDTAG")
- {
- // only display itm tag if we are a basic weapon
- if (itm.IsWeapon && recordId == itm.BaseItemId)
- {
- color = ItemStyle.Mundane.TQColor();
- line = TranslationService.TranslateXTag(variable.GetString(0));
- }
- else
- line = string.Empty;
- }
- else if (normalizedFullAttribute.EndsWith("GLOBALCHANCE", noCase))
- line = GetGlobalChance(attributeList, variableNumber, variable, ref color);
- else if (normalizedFullAttribute.StartsWith("RACIALBONUS", noCase))
- line = GetRacialBonus(record, itm, results, variableNumber, isGlobal, globalIndent, variable, attributeData, line, ref color);
- else if (normalizedFullAttribute == "AUGMENTALLLEVEL")
- line = GetAugmentAllLevel(variableNumber, variable, ref color);
- else if (normalizedFullAttribute.StartsWith("AUGMENTMASTERYLEVEL", noCase))
- line = GetAugmentMasteryLevel(record, variable, attributeData, ref color);
- else if (normalizedFullAttribute.StartsWith("AUGMENTSKILLLEVEL", noCase))
- line = GetAugmentSkillLevel(record, variable, attributeData, line, ref color);
- else if (itm.IsFormulae && recordId == itm.BaseItemId)
- line = GetFormulae(results, variable, attributeData, line, ref color);
- else if (normalizedFullAttribute == "ITEMSKILLNAME")
- line = GetGrantedSkill(record, itm, results, variable, line, ref color);
+ itm.itemScalePercent += variable.GetSingle(0) / 100;
+ // Set line to nothing so we do not see the tag text.
+ line = string.Empty;
+ }
+ else if (normalizedFullAttribute == "SKILLNAME")
+ {
// Added by VillageIdiot
- // Shows the header text for the pet bonus
- if (normalizedFullAttribute == "PETBONUSNAME")
- line = StringHelper.TQNewLineTag + GetPetBonusName(ref color);
-
+ // itm is for Scroll effects which get decoded in the skill code below
+ // Set line to nothing so we do not see the tag text.
+ line = string.Empty;
+ }
+ else if (attributeData.EffectType == ItemAttributesEffectType.SkillEffect)
+ {
+ line = GetSkillEffect(data, variableNumber, variable, attributeData, line, ref color);
+ }
+ else if (normalizedFullAttribute.EndsWith("DAMAGEQUALIFIER", noCase))
+ {
// Added by VillageIdiot
- // Set the scale percent here
- if (recordId == itm.BaseItemId && normalizedFullAttribute == "ATTRIBUTESCALEPERCENT" && itm.itemScalePercent == 1.00)
- {
- itm.itemScalePercent += variable.GetSingle(0) / 100;
+ // for Damage Absorption
- // Set line to nothing so we do not see the tag text.
- line = string.Empty;
- }
- else if (normalizedFullAttribute == "SKILLNAME")
- {
- // Added by VillageIdiot
- // itm is for Scroll effects which get decoded in the skill code below
- // Set line to nothing so we do not see the tag text.
- line = string.Empty;
- }
- else if (attributeData.EffectType == ItemAttributesEffectType.SkillEffect)
+ // Get the qualifier title
+ if (!TranslationService.TryTranslateXTag("tagDamageAbsorptionTitle", out var title))
+ title = "Protects Against :";
+
+ // We really only want to show the title once for the group.
+ if (displayDamageQualifierTitle)
{
- line = GetSkillEffect(data, variableNumber, variable, attributeData, line, ref color);
+ results.Add(title);
+ itm.CurrentFriendlyNameResult.TmpAttrib.Add(title);
+ displayDamageQualifierTitle = false;
}
- else if (normalizedFullAttribute.EndsWith("DAMAGEQUALIFIER", noCase))
- {
- // Added by VillageIdiot
- // for Damage Absorption
-
- // Get the qualifier title
- if (!TranslationService.TryTranslateXTag("tagDamageAbsorptionTitle", out var title))
- title = "Protects Against :";
- // We really only want to show the title once for the group.
- if (displayDamageQualifierTitle)
- {
- results.Add(title);
- itm.CurrentFriendlyNameResult.TmpAttrib.Add(title);
- displayDamageQualifierTitle = false;
- }
+ // Show the damage type
+ string damageTag = attributeData.FullAttribute.Remove(attributeData.FullAttribute.Length - 15);
+ damageTag = string.Concat(damageTag.Substring(0, 1).ToUpperInvariant(), damageTag.Substring(1));
+ TranslationService.TryTranslateXTag(string.Concat("tagQualifyingDamage", damageTag), out var damageType);
- // Show the damage type
- string damageTag = attributeData.FullAttribute.Remove(attributeData.FullAttribute.Length - 15);
- damageTag = string.Concat(damageTag.Substring(0, 1).ToUpperInvariant(), damageTag.Substring(1));
- TranslationService.TryTranslateXTag(string.Concat("tagQualifyingDamage", damageTag), out var damageType);
+ if (!TranslationService.TryTranslateXTag("formatQualifyingDamage", out var formatSpec))
+ formatSpec = "{0}";
+ else
+ {
+ if (TQDebug.ItemDebugLevel > 2)
+ Log.LogDebug("Item.formatspec (Damage type) = " + formatSpec);
- if (!TranslationService.TryTranslateXTag("formatQualifyingDamage", out var formatSpec))
- formatSpec = "{0}";
- else
- {
- if (TQDebug.ItemDebugLevel > 2)
- Log.LogDebug("Item.formatspec (Damage type) = " + formatSpec);
+ formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
+ }
- formatSpec = ItemAttributeProvider.ConvertFormat(formatSpec);
- }
+ color = ItemStyle.Mundane.TQColor();
+ line = Format(formatSpec, damageType);
+ }
- color = ItemStyle.Mundane.TQColor();
- line = Format(formatSpec, damageType);
- }
+ // We have no line so just show the raw attribute
+ if (line == null)
+ line = GetRawAttribute(data, variableNumber, variable, ref color);
- // We have no line so just show the raw attribute
- if (line == null)
- line = GetRawAttribute(data, variableNumber, variable, ref color);
+ // Start finalizing the line of text
+ string itemSkillAutoController = null;
+ if (line.Length > 0)
+ {
+ if (attributeData.Variable.Length > 0)
+ line = string.Concat(
+ line
+ , ' '
+ , $"{ItemStyle.Legendary.TQColor().ColorTag()}{attributeData.Variable}"
+ );
- // Start finalizing the line of text
- string itemSkillAutoController = null;
- if (line.Length > 0)
+ // Add another special case for skill name formatting
+ // if it's an activated skill
+ if (normalizedFullAttribute == "ITEMSKILLNAME")
{
- if (attributeData.Variable.Length > 0)
- line = string.Concat(
- line
- , ' '
- , $"{ItemStyle.Legendary.TQColor().ColorTag()}{attributeData.Variable}"
- );
-
- // Add another special case for skill name formatting
- // if it's an activated skill
- if (normalizedFullAttribute == "ITEMSKILLNAME")
+ itemSkillAutoController = record.GetString("itemSkillAutoController", 0);
+ if (!string.IsNullOrEmpty(itemSkillAutoController))
{
- itemSkillAutoController = record.GetString("itemSkillAutoController", 0);
- if (!string.IsNullOrEmpty(itemSkillAutoController))
- {
- // Granted Skill name BOLD. TODO must implement extended ColorTag {^(?.)(?