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)