From 2559133d33a250bf9dffdb3c7d6af4798bf41891 Mon Sep 17 00:00:00 2001 From: Doriel Rivalet <100863878+DorielRivalet@users.noreply.github.com> Date: Fri, 2 Feb 2024 02:13:22 -0300 Subject: [PATCH] feat: update gear section --- MHFZ_Overlay/MHFZ_Overlay.csproj | 2 +- .../Models/Addresses/AddressModelHGE.cs | 2 +- .../Models/Addresses/AddressModelNotHGE.cs | 2 +- MHFZ_Overlay/Models/QuestsDiva.cs | 2 +- MHFZ_Overlay/Models/QuestsHalk.cs | 6 +- MHFZ_Overlay/Models/QuestsOverlayHash.cs | 17 + MHFZ_Overlay/Models/Structures/Bitfields.cs | 19 + MHFZ_Overlay/Services/DatabaseService.cs | 806 +++++++++++++++++- .../ViewModels/Windows/AddressModel.cs | 403 ++++++++- MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs | 14 +- 10 files changed, 1208 insertions(+), 65 deletions(-) create mode 100644 MHFZ_Overlay/Models/QuestsOverlayHash.cs diff --git a/MHFZ_Overlay/MHFZ_Overlay.csproj b/MHFZ_Overlay/MHFZ_Overlay.csproj index 4b3207f6..b41398d1 100644 --- a/MHFZ_Overlay/MHFZ_Overlay.csproj +++ b/MHFZ_Overlay/MHFZ_Overlay.csproj @@ -1859,7 +1859,7 @@ - + diff --git a/MHFZ_Overlay/Models/Addresses/AddressModelHGE.cs b/MHFZ_Overlay/Models/Addresses/AddressModelHGE.cs index eaaa18a8..61f2b532 100644 --- a/MHFZ_Overlay/Models/Addresses/AddressModelHGE.cs +++ b/MHFZ_Overlay/Models/Addresses/AddressModelHGE.cs @@ -546,7 +546,7 @@ public AddressModelHGE(Mem m) public override int HalkDefense() => this.M.ReadByte("mhfo-hd.dll+ED3C128"); /// - public override int HalkIntelligence() => this.M.ReadByte("mhfo-hd.dll+ED3C129"); + public override int HalkIntellect() => this.M.ReadByte("mhfo-hd.dll+ED3C129"); /// public override int HalkSkill1() => this.M.ReadByte("mhfo-hd.dll+ED3C12A"); diff --git a/MHFZ_Overlay/Models/Addresses/AddressModelNotHGE.cs b/MHFZ_Overlay/Models/Addresses/AddressModelNotHGE.cs index cb0472b1..9b0b6708 100644 --- a/MHFZ_Overlay/Models/Addresses/AddressModelNotHGE.cs +++ b/MHFZ_Overlay/Models/Addresses/AddressModelNotHGE.cs @@ -461,7 +461,7 @@ public AddressModelNotHGE(Mem m) public override int HalkDefense() => this.M.ReadByte("mhfo.dll+6101988"); /// - public override int HalkIntelligence() => this.M.ReadByte("mhfo.dll+6101989"); + public override int HalkIntellect() => this.M.ReadByte("mhfo.dll+6101989"); /// public override int HalkSkill1() => this.M.ReadByte("mhfo.dll+610198A"); diff --git a/MHFZ_Overlay/Models/QuestsDiva.cs b/MHFZ_Overlay/Models/QuestsDiva.cs index 7e8fed87..0792c017 100644 --- a/MHFZ_Overlay/Models/QuestsDiva.cs +++ b/MHFZ_Overlay/Models/QuestsDiva.cs @@ -10,7 +10,7 @@ namespace MHFZ_Overlay.Models; public sealed class QuestsDiva { public long? QuestsDivaID { get; set; } - public bool? DivaSongBuffOn { get; set; } + public long? DivaSongBuffOn { get; set; } public long? DivaPrayerGemRedSkill { get; set; } public long? DivaPrayerGemRedLevel { get; set; } public long? DivaPrayerGemYellowSkill { get; set; } diff --git a/MHFZ_Overlay/Models/QuestsHalk.cs b/MHFZ_Overlay/Models/QuestsHalk.cs index 1b8e7032..1dc4f67d 100644 --- a/MHFZ_Overlay/Models/QuestsHalk.cs +++ b/MHFZ_Overlay/Models/QuestsHalk.cs @@ -11,9 +11,9 @@ public sealed class QuestsHalk { public long? QuestsHalkID { get; set; } - public bool? HalkOn { get; set; } + public long? HalkOn { get; set; } - public bool? HalkPotEffectOn { get; set; } + public long? HalkPotEffectOn { get; set; } public long? HalkFullness { get; set; } @@ -27,7 +27,7 @@ public sealed class QuestsHalk public long? HalkDefense { get; set; } - public long? HalkIntelligence { get; set; } + public long? HalkIntellect { get; set; } public long? HalkSkill1 { get; set; } diff --git a/MHFZ_Overlay/Models/QuestsOverlayHash.cs b/MHFZ_Overlay/Models/QuestsOverlayHash.cs new file mode 100644 index 00000000..86788f7f --- /dev/null +++ b/MHFZ_Overlay/Models/QuestsOverlayHash.cs @@ -0,0 +1,17 @@ +// © 2023 The mhfz-overlay developers. +// Use of this source code is governed by a MIT license that can be +// found in the LICENSE file. + +namespace MHFZ_Overlay.Models; + +using System; + +// TODO: ORM +public sealed class QuestsOverlayHash +{ + public long? QuestsOverlayHashID { get; set; } + + public string? OverlayHash { get; set; } + + public long? RunID { get; set; } +} diff --git a/MHFZ_Overlay/Models/Structures/Bitfields.cs b/MHFZ_Overlay/Models/Structures/Bitfields.cs index 1cc7a570..77b30873 100644 --- a/MHFZ_Overlay/Models/Structures/Bitfields.cs +++ b/MHFZ_Overlay/Models/Structures/Bitfields.cs @@ -415,6 +415,25 @@ public enum CourseRightsFirstByte : uint All = Assist | N | Hiden | Support | NBoost, } +/// +/// Course Rights second byte. +/// +[Flags] +[JsonConverter(typeof(JsonStringEnumConverter))] +public enum CourseRightsSecondByte : uint +{ + [DefaultValue(None)] + None = 0, + UNK1 = 1, + Trial = 2, + HunterLife = 4, + Extra = 8, + UNK2 = 16, + UNK3 = 32, + Premium = 64, + All = UNK1 | Trial | HunterLife | Extra | UNK2 | UNK3 | Premium, +} + /// /// TODO Run filters by buff. /// diff --git a/MHFZ_Overlay/Services/DatabaseService.cs b/MHFZ_Overlay/Services/DatabaseService.cs index d75b651a..8d15a51f 100644 --- a/MHFZ_Overlay/Services/DatabaseService.cs +++ b/MHFZ_Overlay/Services/DatabaseService.cs @@ -88,6 +88,15 @@ public sealed class DatabaseService public HashSet AllQuestsToggleMode { get; set; } + public HashSet AllQuestsActiveFeature { get; set; } + + public HashSet AllQuestsHalk { get; set; } + + public HashSet AllQuestsDiva { get; set; } + + public HashSet AllQuestsGuildPoogie { get; set; } + + public TimeSpan SnackbarTimeOut { get; set; } = TimeSpan.FromSeconds(5); private string? connectionString { get; set; } @@ -1863,7 +1872,7 @@ FinalTimeValue ASC using (var cmd = new SQLiteCommand(sql, conn)) { - var activeFeature = GetActiveFeature(model); + var activeFeature = dataLoader.Model.GetActiveFeature(); cmd.Parameters.AddWithValue("@ActiveFeature", activeFeature); cmd.Parameters.AddWithValue("@RunID", runID); @@ -1904,7 +1913,7 @@ FinalTimeValue ASC HalkHealth, HalkAttack, HalkDefense, - HalkIntelligence, + HalkIntellect, HalkSkill1, HalkSkill2, HalkSkill3, @@ -1927,7 +1936,7 @@ FinalTimeValue ASC @HalkHealth, @HalkAttack, @HalkDefense, - @HalkIntelligence, + @HalkIntellect, @HalkSkill1, @HalkSkill2, @HalkSkill3, @@ -1953,7 +1962,7 @@ FinalTimeValue ASC cmd.Parameters.AddWithValue("@HalkHealth", model.HalkHealth()); cmd.Parameters.AddWithValue("@HalkAttack", model.HalkAttack()); cmd.Parameters.AddWithValue("@HalkDefense", model.HalkDefense()); - cmd.Parameters.AddWithValue("@HalkIntelligence", model.HalkIntelligence()); + cmd.Parameters.AddWithValue("@HalkIntellect", model.HalkIntellect()); cmd.Parameters.AddWithValue("@HalkSkill1", model.HalkSkill1()); cmd.Parameters.AddWithValue("@HalkSkill2", model.HalkSkill2()); cmd.Parameters.AddWithValue("@HalkSkill3", model.HalkSkill3()); @@ -1999,7 +2008,8 @@ FinalTimeValue ASC using (var cmd = new SQLiteCommand(sql, conn)) { - cmd.Parameters.AddWithValue("@DivaSongBuffOn", !model.DivaSongEnded); + // TODO test + cmd.Parameters.AddWithValue("@DivaSongBuffOn", model.DivaSongActive); cmd.Parameters.AddWithValue("@DivaPrayerGemRedSkill", model.DivaPrayerGemRedSkill()); cmd.Parameters.AddWithValue("@DivaPrayerGemRedLevel", model.DivaPrayerGemRedLevel()); cmd.Parameters.AddWithValue("@DivaPrayerGemYellowSkill", model.DivaPrayerGemYellowSkill()); @@ -2060,7 +2070,7 @@ FinalTimeValue ASC var cuffSlot2 = model.Cuff2ID(); var styleID = model.WeaponStyle(); var weaponIconID = weaponTypeID; - var divaSkillID = model.DivaSkill(); + var divaSkillID = model.DivaSkillUsesLeft() > 0 ? model.DivaSkill() : 0; var guildFoodID = model.GuildFoodSkill(); var poogieItemID = model.PoogieItemUseID(); @@ -2465,6 +2475,10 @@ private void UpdateHashSets(SQLiteConnection conn) var lastGachaCard = this.GetLastGachaCard(conn); var lastPlayerInventory = this.GetLastPlayerInventory(conn); var lastQuestsToggleMode = this.GetLastQuestsToggleMode(conn); + var lastQuestsActiveFeature = this.GetLastQuestsActiveFeature(conn); + var lastQuestsDiva = this.GetLastQuestsDiva(conn); + var lastQuestsHalk = this.GetLastQuestsHalk(conn); + var lastQuestsGuildPoogie = this.GetLastQuestsGuildPoogie(conn); if (lastQuest.RunID != 0) { @@ -2600,6 +2614,42 @@ private void UpdateHashSets(SQLiteConnection conn) Logger.Warn(CultureInfo.InvariantCulture, "Last quests toggle mode already found in hash set"); } } + + if (lastQuestsHalk.QuestsHalkID != 0) + { + var questsHalkAdded = this.AllQuestsHalk.Add(lastQuestsHalk); + if (!questsHalkAdded) + { + Logger.Warn(CultureInfo.InvariantCulture, "Last quests halk already found in hash set"); + } + } + + if (lastQuestsDiva.QuestsDivaID != 0) + { + var questsDivaAdded = this.AllQuestsDiva.Add(lastQuestsDiva); + if (!questsDivaAdded) + { + Logger.Warn(CultureInfo.InvariantCulture, "Last quests diva already found in hash set"); + } + } + + if (lastQuestsActiveFeature.QuestsActiveFeatureID != 0) + { + var questsActiveFeatureAdded = this.AllQuestsActiveFeature.Add(lastQuestsActiveFeature); + if (!questsActiveFeatureAdded) + { + Logger.Warn(CultureInfo.InvariantCulture, "Last quests active feature already found in hash set"); + } + } + + if (lastQuestsGuildPoogie.QuestsGuildPoogieID != 0) + { + var questsGuildPoogieAdded = this.AllQuestsGuildPoogie.Add(lastQuestsGuildPoogie); + if (!questsGuildPoogieAdded) + { + Logger.Warn(CultureInfo.InvariantCulture, "Last quests guild poogie already found in hash set"); + } + } } private void CreateDatabaseTriggers(SQLiteConnection conn) @@ -2623,6 +2673,7 @@ private void CreateDatabaseTriggers(SQLiteConnection conn) // bingo // mezfesminigames // mezfes + // run buffs tables: prayer gem, guild poogie, halk, active feature, etc. using (var cmd = new SQLiteCommand(conn)) { cmd.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_audit_deletion @@ -3338,27 +3389,6 @@ public string GetOverlayHash() return overlayHash; } - /// - /// TODO needs real testing - /// - /// - /// - public int GetActiveFeature(AddressModel model) - { - var activeFeatures = new[] { model.ActiveFeature1(), model.ActiveFeature2(), model.ActiveFeature3() }; - - foreach (var activeFeature in activeFeatures) - { - if (model.IsValidBitfield((uint)activeFeature, (uint)ActiveFeature.All)) - { - return activeFeature; - } - } - - Logger.Warn("Active feature not found: {0} {1} {2}", activeFeatures[0], activeFeatures[1], activeFeatures[2]); - return 0; - } - /// /// Stores the overlay hash. /// @@ -5655,7 +5685,7 @@ FOREIGN KEY(RunID) REFERENCES Quests(RunID) HalkHealth INTEGER NOT NULL DEFAULT 0, HalkAttack INTEGER NOT NULL DEFAULT 0, HalkDefense INTEGER NOT NULL DEFAULT 0, - HalkIntelligence INTEGER NOT NULL DEFAULT 0, + HalkIntellect INTEGER NOT NULL DEFAULT 0, HalkSkill1 INTEGER NOT NULL DEFAULT 0, HalkSkill2 INTEGER NOT NULL DEFAULT 0, HalkSkill3 INTEGER NOT NULL DEFAULT 0, @@ -7218,7 +7248,366 @@ public Quest GetQuest(long runID) } } - return quest; + return quest; + } + + public QuestsDiva GetDiva(long runID) + { + QuestsDiva questsDiva = new(); + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot get diva. dataSource: {0}", this.dataSource); + return questsDiva; + } + + // Use a SQL query to retrieve the Quest for the specific RunID from the database + using (var conn = new SQLiteConnection(this.dataSource)) + { + conn.Open(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsDiva WHERE RunID = @runID", conn)) + { + cmd.Parameters.AddWithValue("@runID", runID); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + questsDiva = new QuestsDiva + { + QuestsDivaID = long.Parse(reader["QuestsDivaID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaSongBuffOn = long.Parse(reader["DivaSongBuffOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemRedSkill = long.Parse(reader["DivaPrayerGemRedSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemRedLevel = long.Parse(reader["DivaPrayerGemRedLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemYellowSkill = long.Parse(reader["DivaPrayerGemYellowSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemYellowLevel = long.Parse(reader["DivaPrayerGemYellowLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemGreenSkill = long.Parse(reader["DivaPrayerGemGreenSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemGreenLevel = long.Parse(reader["DivaPrayerGemGreenLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemBlueSkill = long.Parse(reader["DivaPrayerGemBlueSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemBlueLevel = long.Parse(reader["DivaPrayerGemBlueLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + } + + return questsDiva; + } + + public QuestsActiveFeature GetActiveFeature(long runID) + { + QuestsActiveFeature data = new(); + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot get active feature. dataSource: {0}", this.dataSource); + return data; + } + + // Use a SQL query to retrieve the Quest for the specific RunID from the database + using (var conn = new SQLiteConnection(this.dataSource)) + { + conn.Open(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsActiveFeature WHERE RunID = @runID", conn)) + { + cmd.Parameters.AddWithValue("@runID", runID); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + data = new QuestsActiveFeature + { + QuestsActiveFeatureID = long.Parse(reader["QuestsActiveFeatureID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + ActiveFeature = long.Parse(reader["ActiveFeature"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + } + + return data; + } + + public QuestsCourse GetCourses(long runID) + { + QuestsCourse data = new(); + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot get courses. dataSource: {0}", this.dataSource); + return data; + } + + // Use a SQL query to retrieve the Quest for the specific RunID from the database + using (var conn = new SQLiteConnection(this.dataSource)) + { + conn.Open(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsCourse WHERE RunID = @runID", conn)) + { + cmd.Parameters.AddWithValue("@runID", runID); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + data = new QuestsCourse + { + QuestsCourseID = long.Parse(reader["QuestsCourseID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + Rights = long.Parse(reader["Rights"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + } + + return data; + } + + public QuestsGuildPoogie GetGuildPoogie(long runID) + { + QuestsGuildPoogie data = new(); + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot get guild poogie. dataSource: {0}", this.dataSource); + return data; + } + + // Use a SQL query to retrieve the Quest for the specific RunID from the database + using (var conn = new SQLiteConnection(this.dataSource)) + { + conn.Open(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsGuildPoogie WHERE RunID = @runID", conn)) + { + cmd.Parameters.AddWithValue("@runID", runID); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + data = new QuestsGuildPoogie + { + QuestsGuildPoogieID = long.Parse(reader["QuestsGuildPoogieID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie1Skill = long.Parse(reader["GuildPoogie1Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie2Skill = long.Parse(reader["GuildPoogie2Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie3Skill = long.Parse(reader["GuildPoogie3Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + } + + return data; + } + + public QuestsHalk GetHalk(long runID) + { + QuestsHalk data = new(); + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot get halk. dataSource: {0}", this.dataSource); + return data; + } + + // Use a SQL query to retrieve the Quest for the specific RunID from the database + using (var conn = new SQLiteConnection(this.dataSource)) + { + conn.Open(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsHalk WHERE RunID = @runID", conn)) + { + cmd.Parameters.AddWithValue("@runID", runID); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + data = new QuestsHalk + { + QuestsHalkID = long.Parse(reader["QuestsHalkID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkOn = long.Parse(reader["HalkOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkPotEffectOn = long.Parse(reader["HalkPotEffectOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkFullness = long.Parse(reader["HalkFullness"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkLevel = long.Parse(reader["HalkLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIntimacy = long.Parse(reader["HalkIntimacy"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkHealth = long.Parse(reader["HalkHealth"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkAttack = long.Parse(reader["HalkAttack"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkDefense = long.Parse(reader["HalkDefense"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIntellect = long.Parse(reader["HalkIntellect"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill1 = long.Parse(reader["HalkSkill1"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill2 = long.Parse(reader["HalkSkill2"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill3 = long.Parse(reader["HalkSkill3"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkElementNone = long.Parse(reader["HalkElementNone"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkFire = long.Parse(reader["HalkFire"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkThunder = long.Parse(reader["HalkThunder"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkWater = long.Parse(reader["HalkWater"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIce = long.Parse(reader["HalkIce"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkDragon = long.Parse(reader["HalkDragon"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSleep = long.Parse(reader["HalkSleep"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkParalysis = long.Parse(reader["HalkParalysis"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkPoison = long.Parse(reader["HalkPoison"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + } + + return data; + } + + public QuestsToggleMode GetQuestToggleMode(long runID) + { + QuestsToggleMode data = new(); + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot get quest toggle mode. dataSource: {0}", this.dataSource); + return data; + } + + // Use a SQL query to retrieve the Quest for the specific RunID from the database + using (var conn = new SQLiteConnection(this.dataSource)) + { + conn.Open(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsToggleMode WHERE RunID = @runID", conn)) + { + cmd.Parameters.AddWithValue("@runID", runID); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + data = new QuestsToggleMode + { + QuestsToggleModeID = long.Parse(reader["QuestsToggleModeID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + QuestToggleMode = long.Parse(reader["QuestToggleMode"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + } + + return data; + } + + public QuestsOverlayHash GetOverlayHash(long runID) + { + QuestsOverlayHash data = new(); + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot get overlay hash. dataSource: {0}", this.dataSource); + return data; + } + + // Use a SQL query to retrieve the Quest for the specific RunID from the database + using (var conn = new SQLiteConnection(this.dataSource)) + { + conn.Open(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsOverlayHash WHERE RunID = @runID", conn)) + { + cmd.Parameters.AddWithValue("@runID", runID); + + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + data = new QuestsOverlayHash + { + QuestsOverlayHashID = long.Parse(reader["QuestsOverlayHashID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + OverlayHash = reader["OverlayHash"]?.ToString() ?? "0", + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + } + + return data; } private Quest GetLastQuest(SQLiteConnection conn) @@ -8035,6 +8424,172 @@ private QuestsToggleMode GetLastQuestsToggleMode(SQLiteConnection conn) return last; } + private QuestsActiveFeature GetLastQuestsActiveFeature(SQLiteConnection conn) + { + QuestsActiveFeature last = new(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsActiveFeature ORDER BY QuestsActiveFeatureID DESC LIMIT 1", conn)) + { + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + last = new QuestsActiveFeature + { + QuestsActiveFeatureID = long.Parse(reader["QuestsActiveFeatureID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + ActiveFeature = long.Parse(reader["ActiveFeature"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + return last; + } + + private QuestsGuildPoogie GetLastQuestsGuildPoogie(SQLiteConnection conn) + { + QuestsGuildPoogie last = new(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsGuildPoogie ORDER BY QuestsGuildPoogieID DESC LIMIT 1", conn)) + { + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + last = new QuestsGuildPoogie + { + QuestsGuildPoogieID = long.Parse(reader["QuestsGuildPoogieID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie1Skill = long.Parse(reader["GuildPoogie1Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie2Skill = long.Parse(reader["GuildPoogie2Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie3Skill = long.Parse(reader["GuildPoogie3Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + return last; + } + + private QuestsDiva GetLastQuestsDiva(SQLiteConnection conn) + { + QuestsDiva last = new(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsDiva ORDER BY QuestsDivaID DESC LIMIT 1", conn)) + { + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + last = new QuestsDiva + { + QuestsDivaID = long.Parse(reader["QuestsDivaID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaSongBuffOn = long.Parse(reader["DivaSongBuffOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemRedSkill = long.Parse(reader["DivaPrayerGemRedSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemRedLevel = long.Parse(reader["DivaPrayerGemRedLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemYellowSkill = long.Parse(reader["DivaPrayerGemYellowSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemYellowLevel = long.Parse(reader["DivaPrayerGemYellowLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemGreenSkill = long.Parse(reader["DivaPrayerGemGreenSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemGreenLevel = long.Parse(reader["DivaPrayerGemGreenLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemBlueSkill = long.Parse(reader["DivaPrayerGemBlueSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemBlueLevel = long.Parse(reader["DivaPrayerGemBlueLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + return last; + } + + private QuestsHalk GetLastQuestsHalk(SQLiteConnection conn) + { + QuestsHalk last = new(); + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand("SELECT * FROM QuestsHalk ORDER BY QuestsHalkID DESC LIMIT 1", conn)) + { + using (var reader = cmd.ExecuteReader()) + { + if (reader.Read()) + { + last = new QuestsHalk + { + QuestsHalkID = long.Parse(reader["QuestsHalkID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkOn = long.Parse(reader["HalkOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkPotEffectOn = long.Parse(reader["HalkPotEffectOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkFullness = long.Parse(reader["HalkFullness"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkLevel = long.Parse(reader["HalkLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIntimacy = long.Parse(reader["HalkIntimacy"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkHealth = long.Parse(reader["HalkHealth"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkAttack = long.Parse(reader["HalkAttack"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkDefense = long.Parse(reader["HalkDefense"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIntellect = long.Parse(reader["HalkIntellect"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill1 = long.Parse(reader["HalkSkill1"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill2 = long.Parse(reader["HalkSkill2"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill3 = long.Parse(reader["HalkSkill3"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkElementNone = long.Parse(reader["HalkElementNone"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkFire = long.Parse(reader["HalkFire"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkThunder = long.Parse(reader["HalkThunder"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkWater = long.Parse(reader["HalkWater"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIce = long.Parse(reader["HalkIce"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkDragon = long.Parse(reader["HalkDragon"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSleep = long.Parse(reader["HalkSleep"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkParalysis = long.Parse(reader["HalkParalysis"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkPoison = long.Parse(reader["HalkPoison"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + return last; + } + /// /// Loads the database data into hash sets. This is used to avoid querying the database when checking for achievement unlocks. /// When inserting into these hashsets, the database must also be updated, and viceversa. @@ -8070,6 +8625,11 @@ public void LoadDatabaseDataIntoHashSets(Grid saveIconGrid, DataLoader dataLoade this.AllGachaCards = this.GetAllGachaCards(conn); this.AllPlayerInventories = this.GetAllPlayerInventories(conn); this.AllQuestsToggleMode = this.GetAllQuestsToggleMode(conn); + this.AllQuestsActiveFeature = this.GetAllQuestsActiveFeature(conn); + this.AllQuestsGuildPoogie = this.GetAllQuestsGuildPoogie(conn); + this.AllQuestsDiva = this.GetAllQuestsDiva(conn); + this.AllQuestsHalk = this.GetAllQuestsHalk(conn); + } } catch (Exception ex) @@ -8080,6 +8640,8 @@ public void LoadDatabaseDataIntoHashSets(Grid saveIconGrid, DataLoader dataLoade dataLoader.Model.ShowSaveIcon = false; } + + public RoadDureSkills GetRoadDureSkills(long runID) { var roadDureSkills = new RoadDureSkills(); @@ -8244,6 +8806,185 @@ private HashSet GetAllQuestsToggleMode(SQLiteConnection conn) return hashSet; } + private HashSet GetAllQuestsActiveFeature(SQLiteConnection conn) + { + HashSet hashSet = new HashSet(); + + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand(@"SELECT * FROM QuestsActiveFeature", conn)) + { + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + QuestsActiveFeature data = new QuestsActiveFeature + { + QuestsActiveFeatureID = long.Parse(reader["QuestsActiveFeatureID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + ActiveFeature = long.Parse(reader["ActiveFeature"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + + hashSet.Add(data); + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + return hashSet; + } + + private HashSet GetAllQuestsGuildPoogie(SQLiteConnection conn) + { + HashSet hashSet = new HashSet(); + + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand(@"SELECT * FROM QuestsGuildPoogie", conn)) + { + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + QuestsGuildPoogie data = new QuestsGuildPoogie + { + QuestsGuildPoogieID = long.Parse(reader["QuestsGuildPoogieID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie1Skill = long.Parse(reader["GuildPoogie1Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie2Skill = long.Parse(reader["GuildPoogie2Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + GuildPoogie3Skill = long.Parse(reader["GuildPoogie3Skill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + + hashSet.Add(data); + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + return hashSet; + } + + private HashSet GetAllQuestsDiva(SQLiteConnection conn) + { + HashSet hashSet = new HashSet(); + + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand(@"SELECT * FROM QuestsDiva", conn)) + { + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + QuestsDiva data = new QuestsDiva + { + QuestsDivaID = long.Parse(reader["QuestsDivaID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaSongBuffOn = long.Parse(reader["DivaSongBuffOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemRedSkill = long.Parse(reader["DivaPrayerGemRedSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemRedLevel = long.Parse(reader["DivaPrayerGemRedLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemYellowSkill = long.Parse(reader["DivaPrayerGemYellowSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemYellowLevel = long.Parse(reader["DivaPrayerGemYellowLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemGreenSkill = long.Parse(reader["DivaPrayerGemGreenSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemGreenLevel = long.Parse(reader["DivaPrayerGemGreenLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemBlueSkill = long.Parse(reader["DivaPrayerGemBlueSkill"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + DivaPrayerGemBlueLevel = long.Parse(reader["DivaPrayerGemBlueLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + + hashSet.Add(data); + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + return hashSet; + } + + private HashSet GetAllQuestsHalk(SQLiteConnection conn) + { + HashSet hashSet = new HashSet(); + + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand(@"SELECT * FROM QuestsHalk", conn)) + { + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + QuestsHalk data = new QuestsHalk + { + QuestsHalkID = long.Parse(reader["QuestsHalkID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkOn = long.Parse(reader["HalkOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkPotEffectOn = long.Parse(reader["HalkPotEffectOn"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkFullness = long.Parse(reader["HalkFullness"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkLevel = long.Parse(reader["HalkLevel"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIntimacy = long.Parse(reader["HalkIntimacy"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkHealth = long.Parse(reader["HalkHealth"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkAttack = long.Parse(reader["HalkAttack"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkDefense = long.Parse(reader["HalkDefense"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIntellect = long.Parse(reader["HalkIntellect"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill1 = long.Parse(reader["HalkSkill1"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill2 = long.Parse(reader["HalkSkill2"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSkill3 = long.Parse(reader["HalkSkill3"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkElementNone = long.Parse(reader["HalkElementNone"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkFire = long.Parse(reader["HalkFire"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkThunder = long.Parse(reader["HalkThunder"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkWater = long.Parse(reader["HalkWater"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkIce = long.Parse(reader["HalkIce"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkDragon = long.Parse(reader["HalkDragon"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkSleep = long.Parse(reader["HalkSleep"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkParalysis = long.Parse(reader["HalkParalysis"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + HalkPoison = long.Parse(reader["HalkPoison"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + }; + + hashSet.Add(data); + } + } + } + + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + return hashSet; + } + + private HashSet GetAllGachaCards(SQLiteConnection conn) { HashSet hashSet = new (); @@ -15459,8 +16200,7 @@ FROM PersonalBests /// /// /// - /// true if succeeded - private static bool AlterTableData(SQLiteConnection connection, string newSchema, string updateQuery, string tableName) + private static void AlterTableData(SQLiteConnection connection, string newSchema, string updateQuery, string tableName) { Logger.Info(CultureInfo.InvariantCulture, $"Altering {tableName} table"); @@ -15660,10 +16400,8 @@ v0.24 to v0.25 (fixing the refreshrate check is above, but the fix is implemente { // Roll back the transaction if any errors occur Logger.Error(ex, "Could not alter table {0}", tableName); - return false; + LoggingService.WriteCrashLog(ex, string.Format(CultureInfo.InvariantCulture, "Could not alter table {0}", tableName)); } - - return true; } private static void AlterTableGameFolder(SQLiteConnection connection, string newSchema) diff --git a/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs b/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs index 8cce32bc..2c0be1ec 100644 --- a/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs +++ b/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs @@ -9,6 +9,7 @@ namespace MHFZ_Overlay.ViewModels.Windows; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; +using System.Drawing.Imaging; using System.Globalization; using System.IO; using System.Linq; @@ -28,6 +29,7 @@ namespace MHFZ_Overlay.ViewModels.Windows; using MHFZ_Overlay.Models.Structures; using MHFZ_Overlay.Services; using MHFZ_Overlay.Services.Converter; +using NLog; using RESTCountries.NET.Models; using RESTCountries.NET.Services; using SkiaSharp; @@ -342,7 +344,7 @@ 21747 or public abstract int HalkDefense(); - public abstract int HalkIntelligence(); + public abstract int HalkIntellect(); public abstract int HalkSkill1(); @@ -1783,8 +1785,10 @@ public OverlayMode GetOverlayMode() } else if (s.TimerInfoShown && s.EnableInputLogging && s.EnableQuestLogging && s.OverlayModeWatermarkShown) { - // TODO diva prayer gem - if (!HasBitfieldFlag((uint)this.Rights(), CourseRightsFirstByte.Support) && this.DivaSkillUsesLeft() == 0 && this.StyleRank1() != 15 && this.StyleRank2() != 15) + var gems = new List { DivaPrayerGemRedSkill(), DivaPrayerGemRedLevel(), DivaPrayerGemYellowSkill(), DivaPrayerGemYellowLevel(), DivaPrayerGemGreenSkill(), DivaPrayerGemGreenLevel(), DivaPrayerGemBlueSkill(), DivaPrayerGemBlueLevel() }; + var guildPoogies = new List { GuildPoogie1Skill(), GuildPoogie2Skill(), GuildPoogie3Skill() }; + // TODO test + if (!HalkPotEffectOn() && GetGuildPoogieEffect(guildPoogies) == "No Poogie" && this.GuildFoodSkill() == 0 && !HalkOn() && GetDivaPrayerGems(gems) == "None" && !IsActiveFeatureOn(GetActiveFeature(), this.WeaponType()) && !HasBitfieldFlag((uint)this.Rights(), CourseRightsFirstByte.Support) && this.DivaSkillUsesLeft() == 0 && this.StyleRank1() != 15 && this.StyleRank2() != 15) { return OverlayMode.TimeAttack; } @@ -1803,6 +1807,27 @@ public OverlayMode GetOverlayMode() } } + /// + /// TODO needs real testing + /// + /// + /// + public int GetActiveFeature() + { + var activeFeatures = new[] { this.ActiveFeature1(), this.ActiveFeature2(), this.ActiveFeature3() }; + + foreach (var activeFeature in activeFeatures) + { + if (IsValidBitfield((uint)activeFeature, (uint)ActiveFeature.All)) + { + return activeFeature; + } + } + + LoggerInstance.Warn("Active feature not found: {0} {1} {2}", activeFeatures[0], activeFeatures[1], activeFeatures[2]); + return 0; + } + public bool HasBitfieldFlag(uint value, CourseRightsFirstByte flag) { if (value < 0x0100) @@ -1826,6 +1851,24 @@ public bool HasBitfieldFlag(uint value, CourseRightsFirstByte flag) return rights.HasFlag(flag); } + public bool HasBitfieldFlag(uint value, CourseRightsSecondByte flag) + { + // Extract the byte + byte secondByte = (byte)(value & 0xFF); + + // Validate + if ((secondByte & (uint)CourseRightsSecondByte.All) != secondByte) + { + return false; + } + + // Convert the first byte to CourseRightsFirstByte + CourseRightsSecondByte rights = (CourseRightsSecondByte)secondByte; + + // Check if the flag is set + return rights.HasFlag(flag); + } + public bool HasBitfieldFlag(uint value, T flag, uint all) where T : Enum { // Validate @@ -1835,7 +1878,7 @@ public bool HasBitfieldFlag(uint value, T flag, uint all) where T : Enum } // Convert - Enum convertedValue = (Enum)(object)value; + T convertedValue = (T)Enum.ToObject(typeof(T), value); // Check if the flag is set return convertedValue.HasFlag(flag); @@ -2610,10 +2653,15 @@ public bool DivaSongEnded var expiry = DivaSongStart() + (60 * 90); double secondsLeft = expiry - ServerHeartbeat(); - return (QuestID() <= 0 && secondsLeft <= 0); + return secondsLeft <= 0; } } + /// + /// Whether the buff is still active even if it expired inside quest but after quest start. + /// + public bool DivaSongActive { get; set; } + public bool GuildFoodEnding { get @@ -2642,7 +2690,7 @@ public bool GuildFoodEnded var expiry = GuildFoodStart() + (60 * 90); double secondsLeft = expiry - ServerHeartbeat(); - return (QuestID() <= 0 && secondsLeft <= 0); + return secondsLeft <= 0; } } @@ -7788,6 +7836,7 @@ public static string GetGRWeaponLevel(int level) /// public string GenerateGearStats(long? runID = null) { + // TODO: update if (runID == null) { // save gear to variable @@ -7822,6 +7871,13 @@ public string GenerateGearStats(long? runID = null) var styleRankSkills = DatabaseManagerInstance.GetStyleRankSkills((long)runID); var zenithSkills = DatabaseManagerInstance.GetZenithSkills((long)runID); var quest = DatabaseManagerInstance.GetQuest((long)runID); + var diva = DatabaseManagerInstance.GetDiva((long)runID); + var activeFeature = DatabaseManagerInstance.GetActiveFeature((long)runID); + var courses = DatabaseManagerInstance.GetCourses((long)runID); + var guildPoogie = DatabaseManagerInstance.GetGuildPoogie((long)runID); + var halk = DatabaseManagerInstance.GetHalk((long)runID); + var toggleMode = DatabaseManagerInstance.GetQuestToggleMode((long)runID); + var overlayHash = DatabaseManagerInstance.GetOverlayHash((long)runID); var createdBy = playerGear.CreatedBy; var weaponClass = this.GetWeaponClass((int?)playerGear.WeaponClassID); @@ -7850,7 +7906,7 @@ public string GenerateGearStats(long? runID = null) var armorSkills = GetArmorSkillsForRunID((int)activeSkills.ActiveSkill1ID, (int)activeSkills.ActiveSkill2ID, (int)activeSkills.ActiveSkill3ID, (int)activeSkills.ActiveSkill4ID, (int)activeSkills.ActiveSkill5ID, (int)activeSkills.ActiveSkill6ID, (int)activeSkills.ActiveSkill7ID, (int)activeSkills.ActiveSkill8ID, (int)activeSkills.ActiveSkill9ID, (int)activeSkills.ActiveSkill10ID, (int)activeSkills.ActiveSkill11ID, (int)activeSkills.ActiveSkill12ID, (int)activeSkills.ActiveSkill13ID, (int)activeSkills.ActiveSkill14ID, (int)activeSkills.ActiveSkill15ID, (int)activeSkills.ActiveSkill16ID, (int)activeSkills.ActiveSkill17ID, (int)activeSkills.ActiveSkill18ID, (int)activeSkills.ActiveSkill19ID); var caravanSkillsList = GetCaravanSkillsForRunID((int)caravanSkills.CaravanSkill1ID, (int)caravanSkills.CaravanSkill2ID, (int)caravanSkills.CaravanSkill3ID); var divaSkill = GetDivaSkillNameFromID((int)playerGear.DivaSkillID); - var guildFood = GetArmorSkill((int)playerGear.GuildFoodID); + var guildFood = GetArmorSkill((int)playerGear.GuildFoodID) == "None" ? "No Food" : GetArmorSkill((int)playerGear.GuildFoodID); var styleRankSkillsList = GetGSRSkillsForRunID((int)styleRankSkills.StyleRankSkill1ID, (int)styleRankSkills.StyleRankSkill2ID); var inventory = GetItemsForRunID(new int[] { (int)playerInventory.Item1ID, (int)playerInventory.Item2ID, (int)playerInventory.Item3ID, (int)playerInventory.Item4ID, (int)playerInventory.Item5ID, (int)playerInventory.Item6ID, (int)playerInventory.Item7ID, (int)playerInventory.Item8ID, (int)playerInventory.Item9ID, (int)playerInventory.Item10ID, (int)playerInventory.Item11ID, (int)playerInventory.Item12ID, (int)playerInventory.Item13ID, (int)playerInventory.Item14ID, (int)playerInventory.Item15ID, (int)playerInventory.Item16ID, (int)playerInventory.Item17ID, (int)playerInventory.Item18ID, (int)playerInventory.Item19ID, (int)playerInventory.Item20ID }); var ammo = GetItemsForRunID(new int[] { (int)ammoPouch.Item1ID, (int)ammoPouch.Item2ID, (int)ammoPouch.Item3ID, (int)ammoPouch.Item4ID, (int)ammoPouch.Item5ID, (int)ammoPouch.Item6ID, (int)ammoPouch.Item7ID, (int)ammoPouch.Item8ID, (int)ammoPouch.Item9ID, (int)ammoPouch.Item10ID }); @@ -7863,6 +7919,12 @@ public string GenerateGearStats(long? runID = null) var questCategory = quest.ActualOverlayMode; var partySize = quest.PartySize; + var toggleModeName = toggleMode.QuestToggleMode == null ? "Normal" : EZlion.Mapper.QuestToggleMode.IDName[(int)toggleMode.QuestToggleMode]; + var activeFeatureState = activeFeature.ActiveFeature == null ? false : IsActiveFeatureOn((long)activeFeature.ActiveFeature, playerGear.WeaponTypeID); + var halkSkill1 = halk.HalkSkill1 == null ? "None" : EZlion.Mapper.SkillHalk.IDName[(int)halk.HalkSkill1]; + var halkSkill2 = halk.HalkSkill2 == null ? "None" : EZlion.Mapper.SkillHalk.IDName[(int)halk.HalkSkill2]; + var halkSkill3 = halk.HalkSkill3 == null ? "None" : EZlion.Mapper.SkillHalk.IDName[(int)halk.HalkSkill3]; + // TODO: fix // var partnyaBagItems = GetItemsForRunID(new int[] { (int)partnyaBag.Item1ID, (int)partnyaBag.Item2ID, (int)partnyaBag.Item3ID, (int)partnyaBag.Item4ID, (int)partnyaBag.Item5ID, (int)partnyaBag.Item6ID, (int)partnyaBag.Item7ID, (int)partnyaBag.Item8ID, (int)partnyaBag.Item9ID, (int)partnyaBag.Item10ID }); return string.Format( @@ -7892,31 +7954,57 @@ public string GenerateGearStats(long? runID = null) Caravan Skills: {19} -Diva Skill: +Diva: {20} +Song {21} + +Diva Prayer Gems: +{22} -Guild Food: -{21} +Guild: +{23} +{24} Style Rank: -{22} +{25} Items: -{23} +{26} Ammo: -{24} +{27} Poogie Item: -{25} +{28} Road/Duremudira Skills: -{26} - -Quest: {27} -{28} {29} {30} -Category: {31} -Party Size: {32}", +{29} + +Quest: {30} +{31} {32} {33} +Category: {34} +Party Size: {35} +Mode: {36} +Active Feature {37} + +Courses: +{38} + +Halk: +{39} +Halk Pot {40} +LV{41} +Element Type {42} +Status Type {43} +Intimacy {44} +Health {45} +Attack {46} +Defense {47} +Intellect {48} +{49} | {50} | {51} + +Overlay Hash: {52} +", createdBy, weaponClass, gender, @@ -7938,21 +8026,292 @@ public string GenerateGearStats(long? runID = null) armorSkills, caravanSkillsList, divaSkill, + diva.DivaSongBuffOn > 0 ? "ON" : "OFF", + GetDivaPrayerGems(diva), guildFood, + GetGuildPoogieEffect(guildPoogie), styleRankSkillsList, inventory, ammo, poogieItem, roadDureSkillsList, - // partnyaBagItems + // TODO partnyaBagItems questName, questObjectiveType, questObjectiveQuantity, questObjectiveName, questCategory, - partySize); + partySize, + toggleModeName, + activeFeatureState == true ? "ON" : "OFF", + $"Main: {GetMainCourses(courses.Rights)}\nAdditional: {GetAdditionalCourses(courses.Rights)}", + halk.HalkOn > 0 ? "Active" : "Inactive", + halk.HalkPotEffectOn > 0 ? "ON" : "OFF", + halk.HalkLevel, + GetHalkElement(halk), + GetHalkStatus(halk), + halk.HalkIntimacy, + halk.HalkHealth, + halk.HalkAttack, + halk.HalkDefense, + halk.HalkIntellect, + halkSkill1, + halkSkill2, + halkSkill3, + overlayHash.OverlayHash + ); + } + } + + public string GetMainCourses(long? rights) + { + if (rights == null || rights <= 0 || rights > 0xFFFF) + { + return "None"; + } + + // Map the first and second bytes to course rights names + var courseNames = MapCourseRightsToNames((long)rights, 0, typeof(CourseRightsSecondByte)); + // Join the names with commas + return string.Join(", ", courseNames).Trim(); + } + + public string GetAdditionalCourses(long? rights) + { + if (rights == null || rights <= 0 || rights > 0xFFFF) + { + return "None"; + } + + // Map the first and second bytes to course rights names + var courseNames = MapCourseRightsToNames((long)rights, 1, typeof(CourseRightsFirstByte)); + // Join the names with commas + return string.Join(", ", courseNames).Trim(); + } + + private IEnumerable MapCourseRightsToNames(long rights, int bytePosition, Type enumType) + { + if ((rights < 0x0100 && bytePosition == 1) || rights == 0) + { + yield return "None"; + yield break; + } + + // Extract the required byte + byte value = (byte)(((ulong)rights >> (bytePosition * 8)) & 0xFF); + + foreach (var name in Enum.GetNames(enumType)) + { + if (name == "None") + continue; + + if (enumType == typeof(CourseRightsFirstByte)) + { + if (HasBitfieldFlag((uint)Enum.Parse(enumType, name), (CourseRightsFirstByte)value)) + { + yield return name; + } + } + else if (enumType == typeof(CourseRightsSecondByte)) + { + if (HasBitfieldFlag((uint)Enum.Parse(enumType, name), (CourseRightsSecondByte)value)) + { + yield return name; + } + } + } + } + + public bool IsActiveFeatureOn(long activeFeature, long weaponTypeID) + { + uint value = (uint)Math.Pow(2, weaponTypeID); + return HasBitfieldFlag(value, (ActiveFeature)(uint)activeFeature, (uint)ActiveFeature.All); + } + + public string GetHalkElement(QuestsHalk halk) + { + var element = "None"; + + if (halk.HalkFire >= 100) + { + return "Fire"; + } + if (halk.HalkWater >= 100) + { + return "Water"; + } + if (halk.HalkThunder >= 100) + { + return "Thunder"; + } + if (halk.HalkIce >= 100) + { + return "Ice"; + } + if (halk.HalkDragon >= 100) + { + return "Dragon"; + } + + return element; + } + + public string GetHalkStatus(QuestsHalk halk) + { + var status = "None"; + + if (halk.HalkPoison >= 100) + { + return "Poison"; + } + if (halk.HalkSleep >= 100) + { + return "Sleep"; + } + if (halk.HalkParalysis >= 100) + { + return "Paralysis"; + } + + return status; + } + + public string GetGuildPoogieEffect(QuestsGuildPoogie poogie) + { + var effect = "No Poogie"; + + if (poogie.GuildPoogie1Skill >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[(int)poogie.GuildPoogie1Skill]; + } + + if (poogie.GuildPoogie2Skill >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[(int)poogie.GuildPoogie2Skill]; + } + + if (poogie.GuildPoogie3Skill >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[(int)poogie.GuildPoogie3Skill]; + } + + return effect; + } + + public string GetGuildPoogieEffect(List poogie) + { + var effect = "No Poogie"; + + if (poogie[0] >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[(int)poogie[0]]; + } + + if (poogie[1] >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[(int)poogie[1]]; + } + + if (poogie[2] >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[(int)poogie[2]]; + } + + return effect; + } + + public string GetDivaPrayerGems(QuestsDiva diva) + { + var gems = string.Empty; + var gemTypes = new long?[] { diva.DivaPrayerGemRedSkill, diva.DivaPrayerGemYellowSkill, diva.DivaPrayerGemGreenSkill, diva.DivaPrayerGemBlueSkill }; + var gemLevels = new long?[] { diva.DivaPrayerGemRedLevel, diva.DivaPrayerGemYellowLevel, diva.DivaPrayerGemGreenLevel, diva.DivaPrayerGemBlueLevel }; + + for (var i = 0; i < gemTypes.Length; i++) + { + var skillId = gemTypes[i]; + + if (skillId == null) + { + continue; + } + + if (SkillDivaPrayerGem.IDName.TryGetValue((int)skillId, out var skillName) + && skillName != "None" && skillName != string.Empty) + { + var gemColor = string.Empty; + + switch (i){ + case 0: + gemColor = "Red"; + break; + case 1: + gemColor = "Yellow"; + break; + case 2: + gemColor = "Green"; + break; + case 3: + gemColor = "Blue"; + break; + } + + gems += $"{gemColor} 💎 {skillName} LV{gemLevels[i]}"; + if (i != gemTypes.Length - 1) + { + gems += "\n"; + } + } } + + return string.IsNullOrEmpty(gems) ? "None" : gems; + } + + /// + /// red yellow green blue. type level. + /// + /// + /// + public string GetDivaPrayerGems(List diva) + { + var gems = string.Empty; + var gemTypes = new int[] { diva[0], diva[2], diva[4], diva[6] }; + var gemLevels = new int[] { diva[1], diva[3], diva[4], diva[5] }; + + for (var i = 0; i < gemTypes.Length; i++) + { + var skillId = gemTypes[i]; + + if (SkillDivaPrayerGem.IDName.TryGetValue((int)skillId, out var skillName) + && skillName != "None" && skillName != string.Empty) + { + var gemColor = string.Empty; + + switch (i) + { + case 0: + gemColor = "Red"; + break; + case 1: + gemColor = "Yellow"; + break; + case 2: + gemColor = "Green"; + break; + case 3: + gemColor = "Blue"; + break; + } + + gems += $"{gemColor} 💎 {skillName} LV{gemLevels[i]}"; + if (i != gemTypes.Length - 1) + { + gems += "\n"; + } + } + } + + return string.IsNullOrEmpty(gems) ? "None" : gems; } public int CalculateTotalLargeMonstersHunted() => this.RoadFatalisSlain() + diff --git a/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs b/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs index b6450814..517eb585 100644 --- a/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs +++ b/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs @@ -1307,8 +1307,8 @@ private void SetPlayerStatsVisibility(bool v, Settings s) this.DataLoader.Model.ShowSharpness = v && s.EnableSharpness; this.DataLoader.Model.ShowSessionTimeInfo = v && s.SessionTimeShown; this.DataLoader.Model.ShowPlayerPositionInfo = v && s.PlayerPositionShown; - this.DataLoader.Model.ShowDivaSongTimer = v && s.DivaSongTimerShown && !this.DataLoader.Model.DivaSongEnded; - this.DataLoader.Model.ShowGuildFoodTimer = v && s.GuildFoodTimerShown && !this.DataLoader.Model.GuildFoodEnded; + this.DataLoader.Model.ShowDivaSongTimer = v && s.DivaSongTimerShown && this.DataLoader.Model.DivaSongActive; + this.DataLoader.Model.ShowGuildFoodTimer = v && s.GuildFoodTimerShown && this.DataLoader.Model.GuildFoodSkill() > 0; this.DataLoader.Model.ShowMap = v && s.EnableMap; this.DataLoader.Model.ShowFrameCounter = v && s.FrameCounterShown; @@ -1907,6 +1907,11 @@ private void CheckMezFesScore() private bool CalculatedQuestDataForDisplay { get; set; } + private bool DivaSongActive { get; set; } + + private bool GuildFoodActive { get; set; } + + // TODO: optimization private Task CheckQuestStateForDatabaseLogging() { @@ -1940,6 +1945,8 @@ private Task CheckQuestStateForDatabaseLogging() { this.CalculatedQuestDataForDisplay = true; this.UpdateQuestDataForDisplay(); + this.DataLoader.Model.DivaSongActive = this.DataLoader.Model.DivaSongEnded ? false : true; + //this.DataLoader.Model.GuildFoodActive = this.DataLoader.Model.DivaSongEnded ? false : true; } } @@ -1953,6 +1960,9 @@ private Task CheckQuestStateForDatabaseLogging() this.DataLoader.Model.PreviousRoadFloor = 0; this.personalBestTextBlock.Text = Messages.TimerNotLoaded; this.CalculatedQuestDataForDisplay = false; + // TODO test + this.DataLoader.Model.DivaSongActive = this.DataLoader.Model.DivaSongEnded ? false : true; + //this.DataLoader.Model.GuildFoodActive = this.DataLoader.Model.DivaSongEnded ? false : true; return Task.CompletedTask; } else if (!this.DataLoader.Model.LoadedItemsAtQuestStart && this.DataLoader.Model.QuestState() == 0 && this.DataLoader.Model.QuestID() != 0)