diff --git a/CHANGELOG.md b/CHANGELOG.md index ac6e9ca6..db686686 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,43 @@ +## [0.35.0](https://github.com/DorielRivalet/MHFZ_Overlay/compare/v0.34.0...v0.35.0) (2024-02-09) + + +### Features + +* add area images ([31e42b6](https://github.com/DorielRivalet/MHFZ_Overlay/commit/31e42b668f6eb3f72a128394fc7bedbc4a418bd2)) +* add more achievements ([6fb7771](https://github.com/DorielRivalet/MHFZ_Overlay/commit/6fb77715685381b9a50b1f19832682cba484f874)) +* add more achievements ([f0ddef3](https://github.com/DorielRivalet/MHFZ_Overlay/commit/f0ddef367f7cb34f6259ac5e232c15536092ab20)) +* add player input opacity options ([ae72aef](https://github.com/DorielRivalet/MHFZ_Overlay/commit/ae72aef9f67ab5764dbf5689c1a43df391fad0b5)), closes [DorielRivalet/mhfz-overlay#279](https://github.com/DorielRivalet/mhfz-overlay/issues/279) +* add quest variants filter ([4a1d029](https://github.com/DorielRivalet/MHFZ_Overlay/commit/4a1d029824c3a6ebf64ee5ae31f44a5be572bc34)), closes [DorielRivalet/mhfz-overlay#277](https://github.com/DorielRivalet/mhfz-overlay/issues/277) +* add run buffs ([296546e](https://github.com/DorielRivalet/MHFZ_Overlay/commit/296546e5480539beee46c456cb7891f2d77f4eda)), closes [DorielRivalet/mhfz-overlay#261](https://github.com/DorielRivalet/mhfz-overlay/issues/261) +* add run buffs filters ([49fbddc](https://github.com/DorielRivalet/MHFZ_Overlay/commit/49fbddc580129b328ea8708dd2dafa07c89d812e)), closes [DorielRivalet/mhfz-overlay#263](https://github.com/DorielRivalet/mhfz-overlay/issues/263) +* add run buffs in watermark ([1426697](https://github.com/DorielRivalet/MHFZ_Overlay/commit/1426697a251cc1ae4c7ecca46bd49ffefb760a90)), closes [DorielRivalet/mhfz-overlay#262](https://github.com/DorielRivalet/mhfz-overlay/issues/262) +* add run buffs tags ([d9242d2](https://github.com/DorielRivalet/MHFZ_Overlay/commit/d9242d2a1c39640aad47c70796eea9ef3de410a2)) +* update achievements ([71be1b6](https://github.com/DorielRivalet/MHFZ_Overlay/commit/71be1b6c40b0c486c75a2635047f01fa7e208825)) +* update attempts display to include run buffs ([48bbd18](https://github.com/DorielRivalet/MHFZ_Overlay/commit/48bbd18e17b04154a4722bc8a398904a7b64f6b7)) +* update compendium section ([6c2fba7](https://github.com/DorielRivalet/MHFZ_Overlay/commit/6c2fba7a426c35d27c132412365cdc6d6dc0cc6e)), closes [DorielRivalet/mhfz-overlay#274](https://github.com/DorielRivalet/mhfz-overlay/issues/274) +* update gear stats text ([5cf3adc](https://github.com/DorielRivalet/MHFZ_Overlay/commit/5cf3adc0a72ade7c959142527698b30eb180cb0d)), closes [DorielRivalet/mhfz-overlay#278](https://github.com/DorielRivalet/mhfz-overlay/issues/278) +* update run buffs ([1f37698](https://github.com/DorielRivalet/MHFZ_Overlay/commit/1f376984abc412b3d490641ba62648179dbefc4e)) + + +### Bug Fixes + +* buff timers ([1289ddb](https://github.com/DorielRivalet/MHFZ_Overlay/commit/1289ddb84b2c3308071d36ebcaec24157a9e75e3)) +* diva song in guild hall ([ff1651b](https://github.com/DorielRivalet/MHFZ_Overlay/commit/ff1651bfed13850b2e7292b92722601774cc8f14)), closes [DorielRivalet/mhfz-overlay#276](https://github.com/DorielRivalet/mhfz-overlay/issues/276) +* guild card formatting ([39dd150](https://github.com/DorielRivalet/MHFZ_Overlay/commit/39dd150ffa7a86422ba8d9bae4657d5b8394c087)) +* run buffs ([a3a2c2d](https://github.com/DorielRivalet/MHFZ_Overlay/commit/a3a2c2d648281b3bab14fa3152b7436d6b696d34)) +* run buffs insert ([df16966](https://github.com/DorielRivalet/MHFZ_Overlay/commit/df16966b39d7b504db673264ab653ccf3563e8be)) +* run buffs tags ([35cd5eb](https://github.com/DorielRivalet/MHFZ_Overlay/commit/35cd5eb70252a3ec4a49bf4c8d3172c01570529d)) +* **sqlite:** missing comma ([a837884](https://github.com/DorielRivalet/MHFZ_Overlay/commit/a8378843b946e0b26571a5a62b310b9258919abe)) + + +### For Developers + +* bump version ([6ac2af7](https://github.com/DorielRivalet/MHFZ_Overlay/commit/6ac2af783fe312563f7ef0918984bf5ebc084859)) +* **FAQ:** add run buffs tags ([400fcfc](https://github.com/DorielRivalet/MHFZ_Overlay/commit/400fcfcd06813fdd5a17921f2e49fdb1f6af8d26)) +* update FAQ.md ([7e35d71](https://github.com/DorielRivalet/MHFZ_Overlay/commit/7e35d719ab9a7ac123624b68122b74e811ffb045)) + ## [0.34.0](https://github.com/DorielRivalet/MHFZ_Overlay/compare/v0.33.0...v0.34.0) (2024-02-02) diff --git a/FAQ.md b/FAQ.md index 0b80429a..5921a16a 100644 --- a/FAQ.md +++ b/FAQ.md @@ -3,6 +3,7 @@ - [Frequently Asked Questions](#frequently-asked-questions) - [How to Enable Discord Rich Presence?](#how-to-enable-discord-rich-presence) - [How to Enable Speedrun Categories \& Zen Mode?](#how-to-enable-speedrun-categories--zen-mode) + - [What are Run Buffs in the Quest Logs section?](#what-are-run-buffs-in-the-quest-logs-section) - [How to Record Videos with the Overlay?](#how-to-record-videos-with-the-overlay) - [My game slows down when recording with the Overlay, what should I do?](#my-game-slows-down-when-recording-with-the-overlay-what-should-i-do) - [How to Enable Quest Logging?](#how-to-enable-quest-logging) @@ -54,9 +55,6 @@ Use the preset option found in the General tab. Keep reading if you want to know - Speedrun Mode Categories: Enable the required settings in the Quest Logs section, disable **everything** else, including Quest Pace Color (Monster Icon, Quest Timer + Percentage, KBM Layout, Personal Best and Discord Rich Presence optional) -- Time Attack: Do not use halk, guild poogie, active feature, guild food, diva skill and diva prayer gem. -- Freestyle: Use any of the above or everything else with/without Secret Technique Style Rank Skill. - **Important**: It is recommended to make a backup of the `MHFZ_Overlay.sqlite` file periodically. The file is located inside the database folder, which is inside your game folder. Don't lose your speedrun records! ![Discord Rich Presence](./demo/discord8.png) @@ -65,7 +63,44 @@ Use the preset option found in the General tab. Keep reading if you want to know ![Discord Rich Presence](./demo/discord11.png) -The current speedrun categories are pending an overhaul. Zen mode is not counted as a speedrun mode. +## What are Run Buffs in the Quest Logs section? + +Run Buffs are the buffs that you can filter by when searching for quests: + +| Name | Value | +|---------------------------|-------| +| Halk | 1 | +| Poogie Item | 2 | +| Diva Song | 4 | +| Halk Pot Effect | 8 | +| Bento | 16 | +| Guild Poogie | 32 | +| Active Feature | 64 | +| Guild Food | 128 | +| Diva Skill | 256 | +| Secret Technique | 512 | +| Diva Prayer Gem | 1024 | +| Course Attack Boost | 2048 | +| All | 4095 | +| Time Attack | 183 | +| Freestyle No Secret Tech | 1527 | +| Freestyle With Secret Tech | 2039 | + +If you had the old categories in your runs, these are their run buffs equivalents: + +- Time Attack: Halk + Poogie Item + Diva Song + Bento + Guild Poogie + Guild Food. +- Freestyle No Secret Tech: Time Attack buffs + Active Feature + Diva Skill + Diva Prayer Gem. +- Freestyle With Secret Tech: Freestyle No Secret Tech buffs + Secret Technique. + +When you set the overlay mode to Speedrun, the run buffs value or tag will be displayed on watermark in parentheses. Tags that are submitted to leaderboard will be: + +|Name|Tag|Value|Buffs| +|-|-|-|-| +|Time Attack|TA|183|Halk + Poogie Item + Diva Song + Bento + Guild Poogie + Guild Food| +|Freestyle Diva Skill|FDS|503|TA + Diva Skill + Active Feature| +|Freestyle Diva Prayer Gem|FDP|1527|FDS + Diva Prayer Gem| +|Freestyle Secret Tech|FST|2039|FDP + Secret Technique| +|Freestyle Course Attack Boost|FCA|4095|FST + Course Attack Boost + Halk Pot Effect| ## How to Record Videos with the Overlay? diff --git a/MHFZ_Overlay/App.config b/MHFZ_Overlay/App.config index 442d32ca..4f5de082 100644 --- a/MHFZ_Overlay/App.config +++ b/MHFZ_Overlay/App.config @@ -1023,6 +1023,12 @@ 60 + + 0.2 + + + 0.5 + diff --git a/MHFZ_Overlay/Assets/Icons/png/area/balloon.png b/MHFZ_Overlay/Assets/Icons/png/area/balloon.png new file mode 100644 index 00000000..1fb255ed Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/balloon.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/blacksmith.png b/MHFZ_Overlay/Assets/Icons/png/area/blacksmith.png new file mode 100644 index 00000000..4d2ed92d Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/blacksmith.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/cattleya.png b/MHFZ_Overlay/Assets/Icons/png/area/cattleya.png new file mode 100644 index 00000000..7af9946d Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/cattleya.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/desert.png b/MHFZ_Overlay/Assets/Icons/png/area/desert.png new file mode 100644 index 00000000..8bf750fc Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/desert.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/diva_fountain.png b/MHFZ_Overlay/Assets/Icons/png/area/diva_fountain.png new file mode 100644 index 00000000..d7fd9ec1 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/diva_fountain.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/dure.gif b/MHFZ_Overlay/Assets/Icons/png/area/dure.gif new file mode 100644 index 00000000..cf949d75 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/dure.gif differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/entrance.png b/MHFZ_Overlay/Assets/Icons/png/area/entrance.png new file mode 100644 index 00000000..60bc7e01 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/entrance.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/flower_fields.png b/MHFZ_Overlay/Assets/Icons/png/area/flower_fields.png new file mode 100644 index 00000000..0561d167 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/flower_fields.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/forest_and_hills.png b/MHFZ_Overlay/Assets/Icons/png/area/forest_and_hills.png new file mode 100644 index 00000000..857942c3 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/forest_and_hills.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/gorge.png b/MHFZ_Overlay/Assets/Icons/png/area/gorge.png new file mode 100644 index 00000000..2c86bbbb Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/gorge.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/great_forest.png b/MHFZ_Overlay/Assets/Icons/png/area/great_forest.png new file mode 100644 index 00000000..70f5adb9 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/great_forest.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/guild_hall.png b/MHFZ_Overlay/Assets/Icons/png/area/guild_hall.png new file mode 100644 index 00000000..d0fca085 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/guild_hall.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/highlands.png b/MHFZ_Overlay/Assets/Icons/png/area/highlands.png new file mode 100644 index 00000000..2e87b8d4 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/highlands.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/jungle.png b/MHFZ_Overlay/Assets/Icons/png/area/jungle.png new file mode 100644 index 00000000..c93f3b52 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/jungle.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/map.png b/MHFZ_Overlay/Assets/Icons/png/area/map.png new file mode 100644 index 00000000..2fcc12ab Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/map.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/mezfes.png b/MHFZ_Overlay/Assets/Icons/png/area/mezfes.png new file mode 100644 index 00000000..c5e86802 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/mezfes.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/my_gallery.png b/MHFZ_Overlay/Assets/Icons/png/area/my_gallery.png new file mode 100644 index 00000000..2076b7d6 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/my_gallery.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/my_garden.png b/MHFZ_Overlay/Assets/Icons/png/area/my_garden.png new file mode 100644 index 00000000..f377bce3 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/my_garden.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/my_house.png b/MHFZ_Overlay/Assets/Icons/png/area/my_house.png new file mode 100644 index 00000000..0e5eaec0 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/my_house.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/my_missions.png b/MHFZ_Overlay/Assets/Icons/png/area/my_missions.png new file mode 100644 index 00000000..6a1ea402 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/my_missions.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/my_support.png b/MHFZ_Overlay/Assets/Icons/png/area/my_support.png new file mode 100644 index 00000000..e686d5b0 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/my_support.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/my_tore.png b/MHFZ_Overlay/Assets/Icons/png/area/my_tore.png new file mode 100644 index 00000000..6b688a39 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/my_tore.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/painted_falls.png b/MHFZ_Overlay/Assets/Icons/png/area/painted_falls.png new file mode 100644 index 00000000..d2d219f4 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/painted_falls.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/pallone_caravan.png b/MHFZ_Overlay/Assets/Icons/png/area/pallone_caravan.png new file mode 100644 index 00000000..c5c19e9a Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/pallone_caravan.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/polar_sea.png b/MHFZ_Overlay/Assets/Icons/png/area/polar_sea.png new file mode 100644 index 00000000..27510eab Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/polar_sea.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/pvp.png b/MHFZ_Overlay/Assets/Icons/png/area/pvp.png new file mode 100644 index 00000000..0e0cb8cd Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/pvp.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/rasta_bar.png b/MHFZ_Overlay/Assets/Icons/png/area/rasta_bar.png new file mode 100644 index 00000000..7c88f742 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/rasta_bar.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/rengoku.png b/MHFZ_Overlay/Assets/Icons/png/area/rengoku.png new file mode 100644 index 00000000..f68b6625 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/rengoku.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/snowy_mountains.png b/MHFZ_Overlay/Assets/Icons/png/area/snowy_mountains.png new file mode 100644 index 00000000..7ea78c21 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/snowy_mountains.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/swamp.png b/MHFZ_Overlay/Assets/Icons/png/area/swamp.png new file mode 100644 index 00000000..aa7d0900 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/swamp.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/tent.png b/MHFZ_Overlay/Assets/Icons/png/area/tent.png new file mode 100644 index 00000000..124d92d4 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/tent.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/tidal_island.png b/MHFZ_Overlay/Assets/Icons/png/area/tidal_island.png new file mode 100644 index 00000000..66faa519 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/tidal_island.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/tower.png b/MHFZ_Overlay/Assets/Icons/png/area/tower.png new file mode 100644 index 00000000..305ccf18 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/tower.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/volcano.png b/MHFZ_Overlay/Assets/Icons/png/area/volcano.png new file mode 100644 index 00000000..8a142fdc Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/volcano.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/area/white_lake.png b/MHFZ_Overlay/Assets/Icons/png/area/white_lake.png new file mode 100644 index 00000000..4661473e Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/area/white_lake.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/key_6.png b/MHFZ_Overlay/Assets/Icons/png/key_6.png new file mode 100644 index 00000000..f8523fa5 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/key_6.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/key_alt.png b/MHFZ_Overlay/Assets/Icons/png/key_alt.png new file mode 100644 index 00000000..c7000319 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/key_alt.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/key_b.png b/MHFZ_Overlay/Assets/Icons/png/key_b.png new file mode 100644 index 00000000..90b190b1 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/key_b.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/key_y.png b/MHFZ_Overlay/Assets/Icons/png/key_y.png new file mode 100644 index 00000000..3a97de8e Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/key_y.png differ diff --git a/MHFZ_Overlay/Assets/Icons/png/rengoku.png b/MHFZ_Overlay/Assets/Icons/png/rengoku.png new file mode 100644 index 00000000..f68b6625 Binary files /dev/null and b/MHFZ_Overlay/Assets/Icons/png/rengoku.png differ diff --git a/MHFZ_Overlay/MHFZ_Overlay.csproj b/MHFZ_Overlay/MHFZ_Overlay.csproj index 2cdd2777..b89c69db 100644 --- a/MHFZ_Overlay/MHFZ_Overlay.csproj +++ b/MHFZ_Overlay/MHFZ_Overlay.csproj @@ -20,7 +20,7 @@ mhfz-overlay Doriel Rivalet Doriel Rivalet - 0.34.0 + 0.35.0 https://github.com/DorielRivalet/mhfz-overlay https://github.com/DorielRivalet/mhfz-overlay.git git @@ -159,6 +159,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -267,7 +302,10 @@ + + + @@ -284,6 +322,7 @@ + @@ -717,6 +756,7 @@ + @@ -1183,6 +1223,41 @@ MSBuild:Compile + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1291,7 +1366,10 @@ + + + @@ -1308,6 +1386,7 @@ + @@ -1741,6 +1820,7 @@ + diff --git a/MHFZ_Overlay/Models/Addresses/AddressModelHGE.cs b/MHFZ_Overlay/Models/Addresses/AddressModelHGE.cs index 61f2b532..3fef6ee0 100644 --- a/MHFZ_Overlay/Models/Addresses/AddressModelHGE.cs +++ b/MHFZ_Overlay/Models/Addresses/AddressModelHGE.cs @@ -1837,7 +1837,13 @@ public AddressModelHGE(Mem m) public override int ActiveFeature3() => this.M.Read2Byte("mhfo-hd.dll+E41A2A8"); /// - public override int ServerHeartbeat() => this.M.ReadInt("mhfo-hd.dll+EABD4F0"); + public override int ServerHeartbeatLandOdd() => this.M.ReadInt("mhfo-hd.dll+EABD4F0"); + + /// + public override int ServerHeartbeatLandEven() => this.M.ReadInt("mhfo-hd.dll+E9D1EB0"); + + /// + public override int LandSlot() => this.M.ReadInt("mhfo-hd.dll+EDFB940"); /// public override int GuildFoodStart() => this.M.ReadInt("mhfo-hd.dll+E7FED08"); @@ -1887,4 +1893,19 @@ public AddressModelHGE(Mem m) /// public override bool HalkPotEffectOn() => this.M.ReadByte("mhfo-hd.dll+DC6C524") > 0 ? true : false; + /// + public override int DivaSongFromGuildStart() => this.M.ReadInt("mhfo-hd.dll+ED3EB24"); + + /// + public override int QuestVariant1() => this.M.ReadByte("mhfo-hd.dll+2AFA897"); + + /// + public override int QuestVariant2() => this.M.ReadByte("mhfo-hd.dll+2AFA898"); + + /// + public override int QuestVariant3() => this.M.ReadByte("mhfo-hd.dll+2AFA899"); + + /// + public override int QuestVariant4() => this.M.ReadByte("mhfo-hd.dll+2AFA89A"); + } diff --git a/MHFZ_Overlay/Models/Addresses/AddressModelNotHGE.cs b/MHFZ_Overlay/Models/Addresses/AddressModelNotHGE.cs index 9b0b6708..3b67aa78 100644 --- a/MHFZ_Overlay/Models/Addresses/AddressModelNotHGE.cs +++ b/MHFZ_Overlay/Models/Addresses/AddressModelNotHGE.cs @@ -1756,7 +1756,13 @@ public AddressModelNotHGE(Mem m) public override int ActiveFeature3() => this.M.Read2Byte("mhfo.dll+57E26E8"); /// - public override int ServerHeartbeat() => this.M.ReadInt("mhfo.dll+5E83A00"); + public override int ServerHeartbeatLandOdd() => this.M.ReadInt("mhfo.dll+5E83A00"); + + /// + public override int ServerHeartbeatLandEven() => this.M.ReadInt("mhfo.dll+5D983C0"); + + /// + public override int LandSlot() => this.M.ReadInt("mhfo.dll+61C11A0"); /// public override int GuildFoodStart() => this.M.ReadInt("mhfo.dll+5BC70E0"); @@ -1805,4 +1811,20 @@ public AddressModelNotHGE(Mem m) /// public override bool HalkPotEffectOn() => this.M.ReadByte("mhfo.dll+5034964") > 0 ? true : false; + + /// + public override int DivaSongFromGuildStart() => this.M.ReadInt("mhfo.dll+6104384"); + + /// + public override int QuestVariant1() => this.M.ReadByte("mhfo.dll+28C2CE7"); + + /// + public override int QuestVariant2() => this.M.ReadByte("mhfo.dll+28C2CE8"); + + /// + public override int QuestVariant3() => this.M.ReadByte("mhfo.dll+28C2CE9"); + + /// + public override int QuestVariant4() => this.M.ReadByte("mhfo.dll+28C2CEA"); + } diff --git a/MHFZ_Overlay/Models/Addresses/README.md b/MHFZ_Overlay/Models/Addresses/README.md index 2719273e..069cd7c6 100644 --- a/MHFZ_Overlay/Models/Addresses/README.md +++ b/MHFZ_Overlay/Models/Addresses/README.md @@ -7,7 +7,7 @@ For the addresses, check the respective files. ## IDs -- [Mappers](../Mappers) +- [Mappers](https://github.com/DorielRivalet/ezlion/tree/main/src/packages/csharp/EZlion/EZlion/Mapper) - [Bitfields and Enumerations](../Structures) ### Sigil Skills diff --git a/MHFZ_Overlay/Models/Collections/Achievements.cs b/MHFZ_Overlay/Models/Collections/Achievements.cs index 1ebeb2c1..2ac43a4c 100644 --- a/MHFZ_Overlay/Models/Collections/Achievements.cs +++ b/MHFZ_Overlay/Models/Collections/Achievements.cs @@ -5883,6 +5883,45 @@ [] [U] [] [] [] IsSecret = false, Hint = string.Empty, } + }, + { + 447, new Achievement() + { + CompletionDate = DateTime.UnixEpoch, + Title = "The Long and Winding Road", + Description = string.Empty, + Rank = AchievementRank.Platinum, + Image = @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/rengoku.png", + Objective = "Reach a total of 10,000 road floors completed.", + IsSecret = false, + Hint = string.Empty, + } + }, + { + 448, new Achievement() + { + CompletionDate = DateTime.UnixEpoch, + Title = "Over the Hills and Far Away", + Description = string.Empty, + Rank = AchievementRank.Gold, + Image = @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/flame_ul.png", + Objective = "Complete 1 UL Azure Rathalos quest solo (Speedrun/Zen) in Forest and Hills under 5 minutes.", + IsSecret = false, + Hint = string.Empty, + } + }, + { + 449, new Achievement() + { + CompletionDate = DateTime.UnixEpoch, + Title = "PLUS ULTRA", + Description = string.Empty, + Rank = AchievementRank.Bronze, + Image = @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/achievement/hunter.jpg", + Objective = "Attempt a quest with all run buffs active at once.", + IsSecret = false, + Hint = string.Empty, + } } }); } diff --git a/MHFZ_Overlay/Models/Collections/AreaIcons.cs b/MHFZ_Overlay/Models/Collections/AreaIcons.cs index 967730cc..7de3ab5d 100644 --- a/MHFZ_Overlay/Models/Collections/AreaIcons.cs +++ b/MHFZ_Overlay/Models/Collections/AreaIcons.cs @@ -15,102 +15,102 @@ public static class AreaIcons public static ReadOnlyDictionary, string> AreaIconID { get; } = new (new Dictionary, string> { // Loading - { new List { 0 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/entrance.png" }, + { new List { 0 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/entrance.png" }, // Jungle areas - { new List { 1, 2, 3, 4, 5, 18, 19, 22, 23, 26, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 212, 213 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/jungle.png" }, + { new List { 1, 2, 3, 4, 5, 18, 19, 22, 23, 26, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 212, 213 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/jungle.png" }, // Snowy mountain areas - { new List { 6, 15, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 218, 219 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/snowy_mountains.png" }, + { new List { 6, 15, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 218, 219 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/snowy_mountains.png" }, // Desert areas - { new List { 7, 24, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 214, 215 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/desert.png" }, + { new List { 7, 24, 45, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 214, 215 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/desert.png" }, // Volcano areas - { new List { 8, 27, 58, 59, 60, 61, 62, 63, 64, 65, 74, 161, 162, 163, 164, 165, 166, 167, 169, 216, 217, 220, 221, 222, 223 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/volcano.png" }, + { new List { 8, 27, 58, 59, 60, 61, 62, 63, 64, 65, 74, 161, 162, 163, 164, 165, 166, 167, 169, 216, 217, 220, 221, 222, 223 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/volcano.png" }, // Swamp areas - { new List { 9, 16, 29, 44, 67, 68, 69, 70, 71, 72, 73, 75, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/swamp.png" }, + { new List { 9, 16, 29, 44, 67, 68, 69, 70, 71, 72, 73, 75, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/swamp.png" }, // Forest and Hills areas - { new List { 21, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/forest_and_hills.png" }, + { new List { 21, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/forest_and_hills.png" }, // Great Forest areas - { new List { 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/great_forest.png" }, + { new List { 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/great_forest.png" }, // Highlands areas - { new List { 247, 248, 249, 250, 251, 252, 253, 254, 255, 302, 303, 304, 305, 306, 307, 308 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/highlands.png" }, + { new List { 247, 248, 249, 250, 251, 252, 253, 254, 255, 302, 303, 304, 305, 306, 307, 308 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/highlands.png" }, // Tidal Island areas - { new List { 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/tidal_island.png" }, + { new List { 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338, 339 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/tidal_island.png" }, // Polar Sea areas - { new List { 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/polar_sea.png" }, + { new List { 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/polar_sea.png" }, // Flower Field areas - { new List { 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/flower_fields.png" }, + { new List { 361, 362, 363, 364, 365, 366, 367, 368, 369, 370, 371, 372 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/flower_fields.png" }, // Sky Corridor / Tower - { new List { 390, 391, 392, 393, 394, 415, 416 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/tower.png" }, + { new List { 390, 391, 392, 393, 394, 415, 416 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/tower.png" }, // Duremudira Areas - { new List { 399, 414 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/dure.gif" }, + { new List { 399, 414 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/dure.gif" }, // White Lake - { new List { 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/white_lake.png" }, + { new List { 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/white_lake.png" }, // Painted Falls areas - { new List { 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/painted_falls.png" }, + { new List { 423, 424, 425, 426, 427, 428, 429, 430, 431, 432, 433, 434, 435, 436 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/painted_falls.png" }, // road - { new List { 459 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/rengoku.png" }, + { new List { 459 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/rengoku.png" }, // Gorge areas - { new List { 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/gorge.png" }, + { new List { 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 301 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/gorge.png" }, // Mezeporta - { new List { 200, 397 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/cattleya.png" }, + { new List { 200, 397 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/cattleya.png" }, // my houses - { new List { 173, 174, 175 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/my_house.png" }, + { new List { 173, 174, 175 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/my_house.png" }, // hairdresser - { new List { 201 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/tent.png" }, + { new List { 201 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/tent.png" }, // guild halls - { new List { 202, 203, 204 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/guild_hall.png" }, + { new List { 202, 203, 204 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/guild_hall.png" }, // my tore / poogie farm - { new List { 205 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/my_tore.png" }, + { new List { 205 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/my_tore.png" }, // bars - { new List { 210, 211 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/rasta_bar.png" }, + { new List { 210, 211 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/rasta_bar.png" }, // caravan / pallone - { new List { 256, 260, 261, 262, 263 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/pallone_caravan.png" }, + { new List { 256, 260, 261, 262, 263 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/pallone_caravan.png" }, // blacksmith - { new List { 257 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/blacksmith.png" }, + { new List { 257 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/blacksmith.png" }, // gallery - { new List { 264 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/my_gallery.png" }, + { new List { 264 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/my_gallery.png" }, // guuku farm/garden - { new List { 265 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/my_garden.png" }, + { new List { 265 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/my_garden.png" }, // halk area - { new List { 283 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/my_support.png" }, + { new List { 283 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/my_support.png" }, // PvP room - { new List { 286 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/pvp.png" }, + { new List { 286 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/pvp.png" }, // sr rooms - { new List { 340, 341 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/my_missions.png" }, + { new List { 340, 341 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/my_missions.png" }, // diva halls/fountain - { new List { 379, 445 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/diva_fountain.png" }, + { new List { 379, 445 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/diva_fountain.png" }, // MezFes areas - { new List { 462, 463, 464, 465, 466, 467, 468, 469 }, "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/mezfes.png" }, + { new List { 462, 463, 464, 465, 466, 467, 468, 469 }, @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/mezfes.png" }, }); } diff --git a/MHFZ_Overlay/Models/Constant/Messages.cs b/MHFZ_Overlay/Models/Constant/Messages.cs index ec9c8f0f..34ed2b72 100644 --- a/MHFZ_Overlay/Models/Constant/Messages.cs +++ b/MHFZ_Overlay/Models/Constant/Messages.cs @@ -4,6 +4,8 @@ namespace MHFZ_Overlay.Models.Constant; +using System.Windows.Forms; + /// /// Static messages and placeholder strings. /// @@ -46,4 +48,17 @@ public static class Messages public const string EmptyImage = "https://i.imgur.com/aAcPJGb.png"; public const string CustomQuestName = "Custom Quest"; + + public const string OverlayModeTimeAttack = "Time Attack"; + + public const string OverlayModeStandard = "Standard"; + + public const string OverlayModeFreestyleNoSecretTech = "Freestyle No Secret Tech"; + + public const string OverlayModeFreestyleWithSecretTech = "Freestyle w/ Secret Tech"; + + public const string OverlayModeConfiguring = "Configuring"; + + public const string OverlayModeSpeedrun = "Speedrun"; + } diff --git a/MHFZ_Overlay/Models/Constant/Numbers.cs b/MHFZ_Overlay/Models/Constant/Numbers.cs index 75c35092..9672c879 100644 --- a/MHFZ_Overlay/Models/Constant/Numbers.cs +++ b/MHFZ_Overlay/Models/Constant/Numbers.cs @@ -154,36 +154,72 @@ TODO replace the numbers in source code as necessary public const int QuestIDUpperShitenDisufiroa = 23603; + public const int QuestIDLowerShitenUnknown = 23604; + + public const int QuestIDLowerShitenDisufiroa = 23602; + public const int QuestIDThirstyPariapuria = 55532; public const int QuestIDRulingGuanzorumu = 55529; + public const int QuestIDRulingGuanzorumu5m = 56126; + public const int QuestIDShiftingMiRu = 55531; public const int QuestIDBlinkingNargacugaForest = 55534; public const int QuestIDBlinkingNargacugaHistoric = 55922; + public const int QuestIDBlinkingNargacugaHistoric20m = 55921; + + public const int QuestIDBlinkingNargacugaHistoric5m = 56130; + public const int QuestIDHowlingZinogreForest = 55535; public const int QuestIDHowlingZinogreHistoric = 55919; + public const int QuestIDHowlingZinogreHistoricRepel = 55918; + + public const int QuestIDHowlingZinogreHistoric5m = 56131; + public const int QuestIDSparklingZerureusu = 55951; + public const int QuestIDSparklingZerureusuRepel = 55950; + public const int QuestIDSparklingZerureusuEvent = 56106; + public const int QuestIDSparklingZerureusu5m = 56127; + public const int QuestIDArrogantDuremudira = 23649; + public const int QuestIDArrogantDuremudiraRepel = 23648; + public const int QuestIDStarvingDeviljhoArena = 55530; public const int QuestIDStarvingDeviljhoHistoric = 55917; + public const int QuestIDStarvingDeviljhoHistoric20m = 55916; + public const int QuestIDBlitzkriegBogabadorumu = 55949; + public const int QuestIDBlitzkriegBogabadorumuRepel = 55948; + + public const int QuestIDBlitzkriegBogabadorumu5m = 56128; + + public const int QuestIDBlitzkriegBogabadorumu3m = 56152; + public const int QuestIDBurningFreezingElzelionTower = 55714; public const int QuestIDBurningFreezingElzelionHistoric = 55936; + public const int QuestIDBurningFreezingElzelionHistoricRepel = 55935; + + public const int QuestIDBurningFreezingElzelionHistoric5m = 56133; + + public const int QuestIDBurningFreezingElzelionTower3m = 56153; + + public const int QuestIDBurningFreezingElzelionTowerUltimate = 56158; + public const int QuestIDVeggieElderLove = 53189; public const int QuestIDProducerGogomoaLR = 50748; diff --git a/MHFZ_Overlay/Models/FastestRun.cs b/MHFZ_Overlay/Models/FastestRun.cs index 7bf7f3df..3c3a6131 100644 --- a/MHFZ_Overlay/Models/FastestRun.cs +++ b/MHFZ_Overlay/Models/FastestRun.cs @@ -22,4 +22,6 @@ public sealed class FastestRun public string FinalTimeDisplay { get; set; } = Messages.MaximumTimerPlaceholder; public DateTime Date { get; set; } + + public long RunBuffs { get; set; } } diff --git a/MHFZ_Overlay/Models/PersonalBestAttempts.cs b/MHFZ_Overlay/Models/PersonalBestAttempts.cs index 8de56dff..89998be4 100644 --- a/MHFZ_Overlay/Models/PersonalBestAttempts.cs +++ b/MHFZ_Overlay/Models/PersonalBestAttempts.cs @@ -15,4 +15,6 @@ public sealed class PersonalBestAttempts public string ActualOverlayMode { get; set; } = string.Empty; public long Attempts { get; set; } + + public long RunBuffs { get; set; } } diff --git a/MHFZ_Overlay/Models/PersonalBests.cs b/MHFZ_Overlay/Models/PersonalBests.cs index 83366291..dff21bdb 100644 --- a/MHFZ_Overlay/Models/PersonalBests.cs +++ b/MHFZ_Overlay/Models/PersonalBests.cs @@ -8,7 +8,7 @@ namespace MHFZ_Overlay.Models; public sealed class PersonalBests { - public PersonalBests(string weaponType, long attempts, DateTime createdAt, string actualOverlayMode, long runID, long timeLeft) + public PersonalBests(string weaponType, long attempts, DateTime createdAt, string actualOverlayMode, long runID, long timeLeft, long runBuffs) { this.WeaponType = weaponType; this.Attempts = attempts; @@ -16,6 +16,7 @@ public PersonalBests(string weaponType, long attempts, DateTime createdAt, strin this.ActualOverlayMode = actualOverlayMode; this.RunID = runID; this.TimeLeft = timeLeft; + this.RunBuffs = runBuffs; } public string WeaponType { get; set; } @@ -29,4 +30,7 @@ public PersonalBests(string weaponType, long attempts, DateTime createdAt, strin public long RunID { get; set; } public long TimeLeft { get; set; } + + public long RunBuffs { get; set; } + } diff --git a/MHFZ_Overlay/Models/Quest.cs b/MHFZ_Overlay/Models/Quest.cs index 47a18595..5cca939f 100644 --- a/MHFZ_Overlay/Models/Quest.cs +++ b/MHFZ_Overlay/Models/Quest.cs @@ -85,4 +85,5 @@ public sealed class Quest public string? ActualOverlayMode { get; set; } = string.Empty; public long? PartySize { get; set; } = 0; + } diff --git a/MHFZ_Overlay/Models/QuestAttempts.cs b/MHFZ_Overlay/Models/QuestAttempts.cs index 509ff4b6..70831442 100644 --- a/MHFZ_Overlay/Models/QuestAttempts.cs +++ b/MHFZ_Overlay/Models/QuestAttempts.cs @@ -15,4 +15,7 @@ public sealed class QuestAttempts public string ActualOverlayMode { get; set; } = string.Empty; public long Attempts { get; set; } + + public long RunBuffs { get; set; } + } diff --git a/MHFZ_Overlay/Models/QuestCompendium.cs b/MHFZ_Overlay/Models/QuestCompendium.cs index f27d9251..8e3b24aa 100644 --- a/MHFZ_Overlay/Models/QuestCompendium.cs +++ b/MHFZ_Overlay/Models/QuestCompendium.cs @@ -57,6 +57,22 @@ public sealed class QuestCompendium public double PercentOfSkillFruit { get; set; } + public double PercentOfActiveFeature { get; set; } + + public double PercentOfDivaSong { get; set; } + + public double PercentOfDivaPrayerGem { get; set; } + + public double PercentOfHalkOn { get; set; } + + public double PercentOfHalkPotEffectOn { get; set; } + + public double PercentOfCourseAttackBoost { get; set; } + + public double PercentOfGuildPoogie { get; set; } + + public long MostCommonGuildPoogie { get; set; } + public long MostCommonDivaSkill { get; set; } public long MostCommonGuildFood { get; set; } diff --git a/MHFZ_Overlay/Models/RecentRuns.cs b/MHFZ_Overlay/Models/RecentRuns.cs index 3fa340b7..e822e33a 100644 --- a/MHFZ_Overlay/Models/RecentRuns.cs +++ b/MHFZ_Overlay/Models/RecentRuns.cs @@ -26,4 +26,7 @@ public sealed class RecentRuns public string ActualOverlayMode { get; set; } = Messages.OverlayModePlaceholder; public long PartySize { get; set; } + + public long RunBuffs { get; set; } + } diff --git a/MHFZ_Overlay/Models/Structures/Bitfields.cs b/MHFZ_Overlay/Models/Structures/Bitfields.cs index bc4dcc45..c7a38c4b 100644 --- a/MHFZ_Overlay/Models/Structures/Bitfields.cs +++ b/MHFZ_Overlay/Models/Structures/Bitfields.cs @@ -245,7 +245,7 @@ public enum QuestWeaponTypesDisabled : uint Bow = 1024, Tonfa = 2048, SwitchAxeF = 4096, - // TODO MS Flag 64 + MagnetSpike = 8192, } /// @@ -257,6 +257,9 @@ public enum QuestVariant1 : uint { [DefaultValue(HR)] HR = 0, + /// + /// SR + /// Hiden = 1, HardcoreFixed = 2, HardcoreUnlimitedToggle = 4, @@ -265,6 +268,7 @@ public enum QuestVariant1 : uint Diva = 32, HarcoreNormalToggle = 64, UnlimitedFixed = 128, + All = 255, } /// @@ -277,13 +281,20 @@ public enum QuestVariant2 : uint [DefaultValue(None)] None = 0, Level1 = 1, - DisableHalkPotion = 2, - DisableHalkPoogie = 4, + DisableHalkPotionCourseAttack = 2, + DisableHalkPoogieCuff = 4, Timer = 8, DisableActiveFeature = 16, FixedDifficulty = 32, + /// + /// no secret tech, transcend, halk pot, course atk, prayer gem + /// Level9999 = 64, + /// + /// no rasta, partnya, halk, soul revival or similar, halk pot, diva skill, diva prayer gem + /// Road = 128, + All = 255, } /// @@ -297,12 +308,19 @@ public enum QuestVariant3 : uint None = 0, DisableRewardBonus = 1, RequireGRank = 2, - UNK1 = 4, - UNK2 = 8, + NoSimpleMode = 4, + /// + /// no transcend? no diva skills + /// + NoGPSkills = 8, Zenith = 16, + /// + /// Interception + /// DivaDefense = 32, UNK3Course = 64, DisabledSigil = 128, + All = 255, } /// @@ -322,6 +340,7 @@ public enum QuestVariant4 : uint UNK5 = 32, UNK6 = 64, UNK7 = 128, + All = 255, } /// @@ -435,7 +454,7 @@ public enum CourseRightsSecondByte : uint } /// -/// TODO Run filters by buff. +/// The run buffs. /// [Flags] [JsonConverter(typeof(JsonStringEnumConverter))] @@ -459,10 +478,24 @@ public enum RunBuff : uint /// CourseAttackBoost = 2048, - // old categories - TimeAttack = PoogieItem | DivaSong | Bento, - FreestyleNoSecretTech = Halk | PoogieItem | DivaSong | Bento | GuildPoogie | ActiveFeature | GuildFood | DivaSkill | DivaPrayerGem, + // old overlay categories + TimeAttack = Halk | PoogieItem | DivaSong | Bento | GuildPoogie | GuildFood, + FreestyleNoSecretTech = TimeAttack | ActiveFeature | DivaSkill | DivaPrayerGem, FreestyleWithSecretTech = FreestyleNoSecretTech | SecretTechnique, + + // leaderboard in website + // TA + LeaderboardTimeAttack = TimeAttack, + // FDS + LeaderboardFreestyleDivaSkill = LeaderboardTimeAttack | ActiveFeature | DivaSkill, + // FDP (FreestyleNoSecretTech in old category) + LeaderboardFreestyleDivaPrayerGem = LeaderboardFreestyleDivaSkill | DivaPrayerGem, + // FST (FreestyleWithSecretTech in old category) + LeaderboardFreestyleSecretTechnique = LeaderboardFreestyleDivaPrayerGem | SecretTechnique, + // FCA + LeaderboardFreestyleCourseAttackBoost = LeaderboardFreestyleSecretTechnique | CourseAttackBoost | HalkPotEffect, + + All = Halk | PoogieItem | DivaSong | HalkPotEffect | Bento | GuildPoogie | ActiveFeature | GuildFood | DivaSkill | SecretTechnique | DivaPrayerGem | CourseAttackBoost, } /// diff --git a/MHFZ_Overlay/Models/Structures/Enums.cs b/MHFZ_Overlay/Models/Structures/Enums.cs index 28417a4b..1d251be7 100644 --- a/MHFZ_Overlay/Models/Structures/Enums.cs +++ b/MHFZ_Overlay/Models/Structures/Enums.cs @@ -471,9 +471,7 @@ public enum OverlayMode NoGame, MainMenu, WorldSelect, - TimeAttack, - FreestyleSecretTech, - Freestyle, + Speedrun, Zen, } diff --git a/MHFZ_Overlay/Services/AchievementService.cs b/MHFZ_Overlay/Services/AchievementService.cs index f22af6ec..7d12bf97 100644 --- a/MHFZ_Overlay/Services/AchievementService.cs +++ b/MHFZ_Overlay/Services/AchievementService.cs @@ -253,7 +253,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 4: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4AkuraVashimu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4AkuraVashimu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 5: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Anorupatisu); case 6: @@ -287,7 +287,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 9: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Anorupatisu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Anorupatisu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 10: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Blangonga); case 11: @@ -321,7 +321,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 14: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Blangonga && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Blangonga && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 15: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4DaimyoHermitaur); case 16: @@ -355,7 +355,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 19: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4DaimyoHermitaur && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4DaimyoHermitaur && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 20: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Doragyurosu); case 21: @@ -389,7 +389,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 24: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Doragyurosu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Doragyurosu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 25: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Espinas); case 26: @@ -423,7 +423,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 29: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Espinas && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Espinas && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 30: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Gasurabazura); case 31: @@ -457,7 +457,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 34: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Gasurabazura && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Gasurabazura && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 35: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Giaorugu); case 36: @@ -491,7 +491,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 39: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Giaorugu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Giaorugu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 40: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Hypnocatrice); case 41: @@ -525,7 +525,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 44: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Hypnocatrice && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Hypnocatrice && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 45: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Hyujikiki); case 46: @@ -559,7 +559,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 49: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Hyujikiki && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Hyujikiki && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 50: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Inagami); case 51: @@ -593,7 +593,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 54: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Inagami && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Inagami && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 55: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Khezu); case 56: @@ -627,7 +627,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 59: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Khezu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Khezu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 60: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Midogaron); case 61: @@ -661,7 +661,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 64: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Midogaron && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Midogaron && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 65: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDHugePlesioth); case 66: @@ -695,7 +695,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 69: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDHugePlesioth && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDHugePlesioth && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 70: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Rathalos); case 71: @@ -729,7 +729,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 74: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Rathalos && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Rathalos && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 75: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Rukodiora); case 76: @@ -763,7 +763,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 79: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Rukodiora && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Rukodiora && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 80: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Tigrex); case 81: @@ -797,7 +797,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 84: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Tigrex && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Tigrex && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 85: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Toridcless); case 86: @@ -831,7 +831,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 89: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Toridcless && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Toridcless && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 90: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Baruragaru); case 91: @@ -865,7 +865,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 94: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Baruragaru && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Baruragaru && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 95: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Bogabadorumu); case 96: @@ -899,7 +899,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 99: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Bogabadorumu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Bogabadorumu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 100: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Gravios); case 101: @@ -933,7 +933,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 104: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Gravios && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Gravios && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 105: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Harudomerugu); case 106: @@ -967,7 +967,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 109: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Harudomerugu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4Harudomerugu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 110: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4TaikunZamuza); case 111: @@ -1001,7 +1001,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 114: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4TaikunZamuza && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDZ4TaikunZamuza && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 115: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Fatalis); case 116: @@ -1035,7 +1035,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 119: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Fatalis && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Fatalis && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 120: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999CrimsonFatalis); case 121: @@ -1069,7 +1069,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 124: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999CrimsonFatalis && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999CrimsonFatalis && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 125: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Shantien); case 126: @@ -1103,7 +1103,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 129: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Shantien && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Shantien && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 130: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Disufiroa); case 131: @@ -1137,7 +1137,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 134: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Disufiroa && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDLV9999Disufiroa && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 135: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDUpperShitenUnknown); case 136: @@ -1171,7 +1171,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 139: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDUpperShitenUnknown && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDUpperShitenUnknown && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 140: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDUpperShitenDisufiroa); case 141: @@ -1205,7 +1205,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 144: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDUpperShitenDisufiroa && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDUpperShitenDisufiroa && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 145: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDThirstyPariapuria); case 146: @@ -1239,7 +1239,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 149: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDThirstyPariapuria && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDThirstyPariapuria && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 150: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDRulingGuanzorumu); case 151: @@ -1273,7 +1273,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 154: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDRulingGuanzorumu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDRulingGuanzorumu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 155: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDShiftingMiRu); case 156: @@ -1307,7 +1307,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 159: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDShiftingMiRu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDShiftingMiRu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 160: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID is Numbers.QuestIDBlinkingNargacugaForest or Numbers.QuestIDBlinkingNargacugaHistoric); case 161: @@ -1341,7 +1341,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 164: - return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDBlinkingNargacugaForest || quest.QuestID == Numbers.QuestIDBlinkingNargacugaHistoric) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDBlinkingNargacugaForest || quest.QuestID == Numbers.QuestIDBlinkingNargacugaHistoric) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 165: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID is Numbers.QuestIDHowlingZinogreForest or Numbers.QuestIDHowlingZinogreHistoric); case 166: @@ -1375,7 +1375,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 169: - return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDHowlingZinogreForest || quest.QuestID == Numbers.QuestIDHowlingZinogreHistoric) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDHowlingZinogreForest || quest.QuestID == Numbers.QuestIDHowlingZinogreHistoric) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 170: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID is Numbers.QuestIDStarvingDeviljhoArena or Numbers.QuestIDStarvingDeviljhoHistoric); case 171: @@ -1409,7 +1409,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 174: - return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDStarvingDeviljhoArena || quest.QuestID == Numbers.QuestIDStarvingDeviljhoHistoric) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDStarvingDeviljhoArena || quest.QuestID == Numbers.QuestIDStarvingDeviljhoHistoric) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 175: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID is Numbers.QuestIDSparklingZerureusu or Numbers.QuestIDSparklingZerureusuEvent); case 176: @@ -1443,7 +1443,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 179: - return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDSparklingZerureusu || quest.QuestID == Numbers.QuestIDSparklingZerureusuEvent) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDSparklingZerureusu || quest.QuestID == Numbers.QuestIDSparklingZerureusuEvent) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 180: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDArrogantDuremudira); case 181: @@ -1477,7 +1477,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 184: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDArrogantDuremudira && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDArrogantDuremudira && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 185: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDBlitzkriegBogabadorumu); case 186: @@ -1511,7 +1511,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 189: - return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDBlitzkriegBogabadorumu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID == Numbers.QuestIDBlitzkriegBogabadorumu && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 190: return databaseManagerInstance.AllQuests.Any(quest => quest.QuestID is Numbers.QuestIDBurningFreezingElzelionTower or Numbers.QuestIDBurningFreezingElzelionHistoric); case 191: @@ -1545,7 +1545,7 @@ private static bool CheckConditionsForAchievement(int achievementID, DataLoader } case 194: - return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDBurningFreezingElzelionTower || quest.QuestID == Numbers.QuestIDBurningFreezingElzelionHistoric) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Time Attack" || quest.ActualOverlayMode.Contains("Freestyle"))); + return databaseManagerInstance.AllQuests.Any(quest => (quest.QuestID == Numbers.QuestIDBurningFreezingElzelionTower || quest.QuestID == Numbers.QuestIDBurningFreezingElzelionHistoric) && quest.PartySize == 1 && quest.ActualOverlayMode != null && (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun")); case 195: // Join quests and player inventories based on RunID var completedQuests = from quest in databaseManagerInstance.AllQuests @@ -2249,7 +2249,7 @@ join playerGear in databaseManagerInstance.AllPlayerGear on quest.RunID equals p } case 342: - if (dataLoader.Model.GetOverlayMode() is OverlayMode.Freestyle or OverlayMode.FreestyleSecretTech or OverlayMode.TimeAttack) + if (dataLoader.Model.GetOverlayMode() is OverlayMode.Speedrun) { return true; } @@ -2705,7 +2705,7 @@ join styleRankSkills in databaseManagerInstance.AllStyleRankSkills on quest.RunI } return weaponUsageArray.All(n => n == 1); - case 446: // TODO test + case 446: var maxTrueRaw = 8_000; var foundQuestData = from quest in databaseManagerInstance.AllQuests @@ -2730,6 +2730,30 @@ join styleRankSkills in databaseManagerInstance.AllStyleRankSkills on quest.RunI { return false; } + case 447: + return dataLoader.Model.RoadTotalStagesMultiplayer() >= 10_000; + case 448: // TODO test + var foundQuest = from quest in databaseManagerInstance.AllQuests + where (quest.PartySize == 1 && + quest.QuestID == 23_349 && + (quest.ActualOverlayMode == "Zen" || quest.ActualOverlayMode == "Speedrun") && quest.FinalTimeValue < Numbers.Frames1Minute * 5) + select quest; + + if (foundQuest.Count() == 0) + { + return false; + } + + if (databaseManagerInstance.AllQuestsToggleMode.Any(q => q.RunID == foundQuest.First().RunID && q.QuestToggleMode == 3)) + { + return true; + } + else + { + return false; + } + case 449: + return databaseManagerInstance.AllQuestAttempts.Any(q => q.RunBuffs >= (long)RunBuff.All); } } diff --git a/MHFZ_Overlay/Services/DatabaseService.cs b/MHFZ_Overlay/Services/DatabaseService.cs index 8d15a51f..03780206 100644 --- a/MHFZ_Overlay/Services/DatabaseService.cs +++ b/MHFZ_Overlay/Services/DatabaseService.cs @@ -2,6 +2,11 @@ // Use of this source code is governed by a MIT license that can be // found in the LICENSE file. +using NLog; +using System.Data.SQLite; +using System.Transactions; +using System; + namespace MHFZ_Overlay.Services; using System; @@ -208,7 +213,7 @@ public TimeSpan CalculateTotalTimeSpent() private static string previousVersion = string.Empty; - private readonly List validTableNames = new () + private readonly List validTableNames = new() { "RankName", "ObjectiveType", @@ -463,6 +468,7 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest, var runID = 0; var questID = dataLoader.Model.QuestID(); var actualOverlayMode = string.Empty; + long runBuffs = (long)dataLoader.Model.GetRunBuffs(); dataLoader.Model.ShowSaveIcon = true; var timeLeft = dataLoader.Model.TimeInt(); @@ -659,7 +665,7 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest, } // Raviente - else if (dataLoader.Model.AreaID() is 309 or(>= 311 and <= 321) or(>= 417 and <= 422) or 437 or(>= 440 and <= 444)) + else if (dataLoader.Model.AreaID() is 309 or (>= 311 and <= 321) or (>= 417 and <= 422) or 437 or (>= 440 and <= 444)) { objectiveImage = dataLoader.Model.GetMonsterIcon(dataLoader.Model.LargeMonster1ID()); } @@ -825,18 +831,22 @@ public void InsertPersonalBest(DataLoader dataLoader, long currentPersonalBest, TimeLeft, FinalTimeValue, FinalTimeDisplay, - ActualOverlayMode, - PartySize, - pg.WeaponTypeID + q.ActualOverlayMode, + q.PartySize, + pg.WeaponTypeID, + qrb.RunBuffs FROM Quests q JOIN PlayerGear pg ON q.RunID = pg.RunID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.QuestID = @questID AND pg.WeaponTypeID = @weaponTypeID AND q.ActualOverlayMode = @category AND q.PartySize = @partySize + AND qrb.RunBuffs = @runBuffs ORDER BY FinalTimeValue ASC LIMIT 1", conn)) @@ -845,6 +855,7 @@ FinalTimeValue ASC cmd.Parameters.AddWithValue("@weaponTypeID", weaponType); cmd.Parameters.AddWithValue("@category", actualOverlayMode); cmd.Parameters.AddWithValue("@partySize", partySize); + cmd.Parameters.AddWithValue("@runBuffs", runBuffs); var reader = cmd.ExecuteReader(); if (reader.Read()) @@ -858,11 +869,13 @@ FinalTimeValue ASC sql = @"INSERT INTO PersonalBests( RunID, Attempts, - PartySize + PartySize, + RunBuffs ) VALUES ( @RunID, @Attempts, - @PartySize)"; + @PartySize, + @RunBuffs)"; using (var cmd = new SQLiteCommand(sql, conn)) { if (finalTimeValue < personalBest || personalBest == 0) @@ -871,6 +884,7 @@ FinalTimeValue ASC cmd.Parameters.AddWithValue("@RunID", runID); cmd.Parameters.AddWithValue("@Attempts", attempts); cmd.Parameters.AddWithValue("@PartySize", partySize); + cmd.Parameters.AddWithValue("@RunBuffs", runBuffs); // Execute the stored procedure cmd.ExecuteNonQuery(); @@ -884,13 +898,14 @@ FinalTimeValue ASC SET Attempts = 0 WHERE - (QuestID, WeaponTypeID, ActualOverlayMode, PartySize) = (@QuestID, @WeaponTypeID, @ActualOverlayMode, @PartySize)"; + (QuestID, WeaponTypeID, ActualOverlayMode, PartySize, RunBuffs) = (@QuestID, @WeaponTypeID, @ActualOverlayMode, @PartySize, @RunBuffs)"; using (var cmd = new SQLiteCommand(sql, conn)) { cmd.Parameters.AddWithValue("@QuestID", questID); cmd.Parameters.AddWithValue("@WeaponTypeID", weaponType); cmd.Parameters.AddWithValue("@ActualOverlayMode", actualOverlayMode); cmd.Parameters.AddWithValue("@PartySize", partySize); + cmd.Parameters.AddWithValue("@RunBuffs", runBuffs); // Execute the stored procedure cmd.ExecuteNonQuery(); @@ -1815,7 +1830,7 @@ FinalTimeValue ASC using (var cmd = new SQLiteCommand(sql, conn)) { - var questToggleMode = model.QuestToggleMonsterMode(); + var questToggleMode = model.QuestToggleMonsterMode(); cmd.Parameters.AddWithValue("@QuestToggleMode", questToggleMode); cmd.Parameters.AddWithValue("@RunID", runID); @@ -1955,7 +1970,7 @@ FinalTimeValue ASC using (var cmd = new SQLiteCommand(sql, conn)) { cmd.Parameters.AddWithValue("@HalkOn", model.HalkOn()); - cmd.Parameters.AddWithValue("@HalkPotEffectOn", model.HalkPotEffectOn()); + cmd.Parameters.AddWithValue("@HalkPotEffectOn", model.HalkPotEffectOn() || model.IsHalkPotEquipped()); cmd.Parameters.AddWithValue("@HalkFullness", model.HalkFullness()); cmd.Parameters.AddWithValue("@HalkLevel", model.HalkLevel()); cmd.Parameters.AddWithValue("@HalkIntimacy", model.HalkIntimacy()); @@ -2024,9 +2039,52 @@ FinalTimeValue ASC Logger.Debug("Inserted into QuestsDiva table"); + sql = @"INSERT INTO QuestsRunBuffs ( + RunBuffs, + RunBuffsTag, + RunID + ) VALUES ( + @RunBuffs, + @RunBuffsTag, + @RunID + )"; + using (var cmd = new SQLiteCommand(sql, conn)) + { + // TODO test + cmd.Parameters.AddWithValue("@RunBuffs", runBuffs); + cmd.Parameters.AddWithValue("@RunBuffsTag", dataLoader.Model.GetRunBuffsTag((RunBuff)runBuffs)); + cmd.Parameters.AddWithValue("@RunID", runID); + cmd.ExecuteNonQuery(); + } + Logger.Debug("Inserted into QuestsRunBuffs table"); + sql = @"INSERT INTO QuestsQuestVariant ( + QuestVariant1, + QuestVariant2, + QuestVariant3, + QuestVariant4, + RunID + ) VALUES ( + @QuestVariant1, + @QuestVariant2, + @QuestVariant3, + @QuestVariant4, + @RunID + )"; + + using (var cmd = new SQLiteCommand(sql, conn)) + { + cmd.Parameters.AddWithValue("@QuestVariant1", model.QuestVariant1()); + cmd.Parameters.AddWithValue("@QuestVariant2", model.QuestVariant2()); + cmd.Parameters.AddWithValue("@QuestVariant3", model.QuestVariant3()); + cmd.Parameters.AddWithValue("@QuestVariant4", model.QuestVariant4()); + cmd.Parameters.AddWithValue("@RunID", runID); + cmd.ExecuteNonQuery(); + } + + Logger.Debug("Inserted into QuestsQuestVariant table"); @@ -3054,7 +3112,45 @@ AFTER DELETE ON QuestsGuildPoogie cmd.ExecuteNonQuery(); } - // TODO run buffs + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quests_run_buffs_updates + AFTER UPDATE ON QuestsRunBuffs + BEGIN + SELECT RAISE(ROLLBACK, 'Updating rows is not allowed. Keep in mind that all attempted modifications are logged into the central database.'); + END;"; + cmd.ExecuteNonQuery(); + } + + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quests_run_buffs_deletion + AFTER DELETE ON QuestsRunBuffs + BEGIN + SELECT RAISE(ROLLBACK, 'Updating rows is not allowed. Keep in mind that all attempted modifications are logged into the central database.'); + END;"; + cmd.ExecuteNonQuery(); + } + + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quests_quest_variant_updates + AFTER UPDATE ON QuestsQuestVariant + BEGIN + SELECT RAISE(ROLLBACK, 'Updating rows is not allowed. Keep in mind that all attempted modifications are logged into the central database.'); + END;"; + cmd.ExecuteNonQuery(); + } + + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quests_quest_variant_deletion + AFTER DELETE ON QuestsQuestVariant + BEGIN + SELECT RAISE(ROLLBACK, 'Updating rows is not allowed. Keep in mind that all attempted modifications are logged into the central database.'); + END;"; + cmd.ExecuteNonQuery(); + } using (var cmd = new SQLiteCommand(conn)) { @@ -3346,6 +3442,176 @@ private static void HandleError(SQLiteTransaction? transaction, Exception ex) LoggingService.WriteCrashLog(ex, $"SQLite error (version: {serverVersion})"); } + public void FillRunBuffs(SQLiteConnection conn, DataLoader dataLoader) + { + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot update run buffs. dataSource: {0}", this.dataSource); + return; + } + + // Start a transaction + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = "SELECT * FROM Quests"; + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var actualOverlayMode = reader["ActualOverlayMode"].ToString(); + var runID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture); + + if (actualOverlayMode == null || runID == 0) + { + continue; + } + + // Separate command for the insert operation + using (var cmd2 = new SQLiteCommand(conn)) + { + cmd2.CommandText = "INSERT INTO QuestsRunBuffs(RunBuffs, RunBuffsTag, RunID) VALUES (@RunBuffs, @RunBuffsTag, @RunID)"; + cmd2.Parameters.AddWithValue("@RunBuffs", dataLoader.Model.GetRunBuffs(actualOverlayMode)); + cmd2.Parameters.AddWithValue("@RunBuffsTag", dataLoader.Model.GetRunBuffsTag(dataLoader.Model.GetRunBuffs(actualOverlayMode))); + cmd2.Parameters.AddWithValue("@RunID", runID); + + cmd2.ExecuteNonQuery(); + } + } + } + } + + // Commit the transaction + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + Logger.Debug("Updated run buffs table"); + } + + /// + /// TODO test + /// + /// + /// + public void UpdatePersonalBestsRunBuffs(SQLiteConnection conn, DataLoader dataLoader) + { + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot update run buffs for personal bests. dataSource: {0}", this.dataSource); + return; + } + + // Start a transaction + using (var transaction = conn.BeginTransaction()) + { + try + { + string sql = @" + SELECT pb.*, q.ActualOverlayMode + FROM PersonalBests pb + LEFT JOIN Quests q ON pb.RunID = q.RunID"; + + using (var cmd = new SQLiteCommand(sql, conn)) + { + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var runID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture); + var actualOverlayMode = reader["ActualOverlayMode"].ToString(); + + if (runID == 0 || actualOverlayMode == null) + { + continue; + } + + // Separate command for the insert operation + using (var cmd2 = new SQLiteCommand(conn)) + { + cmd2.CommandText = "UPDATE PersonalBests SET RunBuffs = @RunBuffs WHERE RunID = @RunID"; + cmd2.Parameters.AddWithValue("@RunBuffs", dataLoader.Model.GetRunBuffs(actualOverlayMode)); + cmd2.Parameters.AddWithValue("@RunID", runID); + + cmd2.ExecuteNonQuery(); + } + } + } + } + + // Commit the transaction + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + Logger.Debug("Updated run buffs for PersonalBests table"); + } + + public void UpdateTableRunBuffs(string tableName, SQLiteConnection conn, DataLoader dataLoader) + { + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot update run buffs for {0} table. dataSource: {1}", tableName, this.dataSource); + return; + } + + // Start a transaction + using (var transaction = conn.BeginTransaction()) + { + try + { + string sql = $"SELECT * FROM {tableName}"; + + using (var cmd = new SQLiteCommand(sql, conn)) + { + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var actualOverlayMode = reader["ActualOverlayMode"].ToString(); + var rowID = long.Parse(reader[$"{tableName}ID"]?.ToString() ?? "0", CultureInfo.InvariantCulture); + + if (actualOverlayMode == null || rowID == 0) + { + continue; + } + + using (var cmd2 = new SQLiteCommand(conn)) + { + cmd2.CommandText = $"UPDATE {tableName} SET RunBuffs = @RunBuffs WHERE {tableName}ID = @rowID"; + cmd2.Parameters.AddWithValue("@RunBuffs", dataLoader.Model.GetRunBuffs(actualOverlayMode)); + cmd2.Parameters.AddWithValue("@rowID", rowID); + + cmd2.ExecuteNonQuery(); + } + } + } + } + + // Commit the transaction + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + Logger.Debug($"Updated run buffs for {tableName} table"); + } + public string GetOverlayHash() { var overlayHash = string.Empty; @@ -3823,7 +4089,7 @@ private Dictionary> CreateReferenceSchemaJSON // Initialize the schema entry for the table if it doesn't exist if (tableName != null && !schema.ContainsKey(tableName)) { - schema[tableName] = new (); + schema[tableName] = new(); } if (tableName != null) @@ -3847,7 +4113,7 @@ private Dictionary> CreateReferenceSchemaJSON // Initialize the schema entry for the table if it doesn't exist if (tableName != null && !schema.ContainsKey(tableName)) { - schema[tableName] = new (); + schema[tableName] = new(); } if (tableName != null) @@ -3873,7 +4139,7 @@ private Dictionary> CreateReferenceSchemaJSON // Initialize the schema entry for the table if it doesn't exist if (tableName != null && !schema.ContainsKey(tableName)) { - schema[tableName] = new (); + schema[tableName] = new(); } if (tableName != null) @@ -5355,8 +5621,9 @@ QuestID INTEGER NOT NULL CHECK (QuestID >= 0) DEFAULT 0, ActualOverlayMode TEXT NOT NULL DEFAULT 'Standard', Attempts INTEGER NOT NULL DEFAULT 1, PartySize INTEGER NOT NULL DEFAULT 1, + RunBuffs INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(WeaponTypeID) REFERENCES WeaponType(WeaponTypeID), - UNIQUE (QuestID, WeaponTypeID, ActualOverlayMode, PartySize) + UNIQUE (QuestID, WeaponTypeID, ActualOverlayMode, PartySize, RunBuffs) ) "; using (var cmd = new SQLiteCommand(sql, conn)) @@ -5369,6 +5636,7 @@ FOREIGN KEY(WeaponTypeID) REFERENCES WeaponType(WeaponTypeID), RunID INTEGER NOT NULL DEFAULT 0, Attempts INTEGER NOT NULL DEFAULT 1, PartySize INTEGER NOT NULL DEFAULT 1, + RunBuffs INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(RunID) REFERENCES Quests(RunID) ) "; @@ -5442,8 +5710,9 @@ QuestID INTEGER NOT NULL CHECK (QuestID >= 0) DEFAULT 0, ActualOverlayMode TEXT NOT NULL DEFAULT 'Standard', Attempts INTEGER NOT NULL DEFAULT 0, PartySize INTEGER NOT NULL DEFAULT 1, + RunBuffs INTEGER NOT NULL DEFAULT 0, FOREIGN KEY(WeaponTypeID) REFERENCES WeaponType(WeaponTypeID), - UNIQUE (QuestID, WeaponTypeID, ActualOverlayMode, PartySize) + UNIQUE (QuestID, WeaponTypeID, ActualOverlayMode, PartySize, RunBuffs) )"; using (var cmd = new SQLiteCommand(sql, conn)) { @@ -5726,6 +5995,31 @@ FOREIGN KEY(RunID) REFERENCES Quests(RunID) } // TODO extra tables + sql = @"CREATE TABLE IF NOT EXISTS QuestsRunBuffs( + QuestsRunBuffsID INTEGER PRIMARY KEY AUTOINCREMENT, + RunBuffs INTEGER NOT NULL DEFAULT 0, + RunBuffsTag TEXT NOT NULL DEFAULT '', + RunID INTEGER NOT NULL, + FOREIGN KEY(RunID) REFERENCES Quests(RunID) + )"; + using (var cmd = new SQLiteCommand(sql, conn)) + { + cmd.ExecuteNonQuery(); + } + + sql = @"CREATE TABLE IF NOT EXISTS QuestsQuestVariant( + QuestsQuestVariantID INTEGER PRIMARY KEY AUTOINCREMENT, + QuestVariant1 INTEGER NOT NULL DEFAULT 0, + QuestVariant2 INTEGER NOT NULL DEFAULT 0, + QuestVariant3 INTEGER NOT NULL DEFAULT 0, + QuestVariant4 INTEGER NOT NULL DEFAULT 0, + RunID INTEGER NOT NULL, + FOREIGN KEY(RunID) REFERENCES Quests(RunID) + )"; + using (var cmd = new SQLiteCommand(sql, conn)) + { + cmd.ExecuteNonQuery(); + } // a mh game but like a MUD. hunt in-game to get many kinds of points for this game. hunt and tame monsters. challenge other CPU players/monsters. sql = @"CREATE TABLE IF NOT EXISTS GachaMaterial( @@ -6276,7 +6570,7 @@ public bool UpdateYoutubeLink(object sender, RoutedEventArgs e, long runID, stri return success; } - public long GetPersonalBestElapsedTimeValue(long questID, int weaponTypeID, string category) + public long GetPersonalBestElapsedTimeValue(long questID, int weaponTypeID, string category, uint runBuffs) { if (string.IsNullOrEmpty(this.dataSource)) { @@ -6338,7 +6632,7 @@ FinalTimeValue ASC return personalBest; } - public string GetPersonalBest(long questID, int weaponTypeID, string category, string timerMode, DataLoader dataLoader, long partySize) + public string GetPersonalBest(long questID, int weaponTypeID, string category, string timerMode, DataLoader dataLoader, long partySize, long runBuffs) { var personalBest = Messages.TimerNotLoaded; if (string.IsNullOrEmpty(this.dataSource)) @@ -6359,17 +6653,20 @@ public string GetPersonalBest(long questID, int weaponTypeID, string category, s TimeLeft, FinalTimeValue, FinalTimeDisplay, - ActualOverlayMode, + q.ActualOverlayMode, pg.WeaponTypeID FROM Quests q JOIN PlayerGear pg ON q.RunID = pg.RunID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE QuestID = @questID AND pg.WeaponTypeID = @weaponTypeID AND q.ActualOverlayMode = @category AND q.PartySize = @partySize + AND qrb.RunBuffs = @runBuffs ORDER BY FinalTimeValue ASC LIMIT 1", conn)) @@ -6378,6 +6675,7 @@ FinalTimeValue ASC cmd.Parameters.AddWithValue("@weaponTypeID", weaponTypeID); cmd.Parameters.AddWithValue("@category", category); cmd.Parameters.AddWithValue("@partySize", partySize); + cmd.Parameters.AddWithValue("@runBuffs", runBuffs); var reader = cmd.ExecuteReader(); if (reader.Read()) @@ -6412,7 +6710,7 @@ FinalTimeValue ASC return personalBest; } - public async Task GetPersonalBestAsync(long questID, int weaponTypeID, string category, string timerMode, DataLoader dataLoader) + public async Task GetPersonalBestAsync(long questID, int weaponTypeID, string category, string timerMode, DataLoader dataLoader, uint runBuffs) { var personalBest = Messages.TimerNotLoaded; if (string.IsNullOrEmpty(this.dataSource)) @@ -6503,9 +6801,9 @@ FinalTimeValue ASC return personalBest; } - public Dictionary GetPersonalBestsByDate(long questID, int weaponTypeID, string category) + public Dictionary GetPersonalBestsByDate(long questID, int weaponTypeID, string category, uint runBuffs) { - Dictionary personalBests = new (); + Dictionary personalBests = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get personal bests by date. dataSource: {0}", this.dataSource); @@ -6525,16 +6823,20 @@ public Dictionary GetPersonalBestsByDate(long questID, int weapo q.ActualOverlayMode, pg.WeaponTypeID, q.CreatedAt, - q.RunID + q.RunID, + qrb.RunBuffs FROM Quests q JOIN PlayerGear pg ON q.RunID = pg.RunID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.QuestID = @questID AND pg.WeaponTypeID = @weaponTypeID AND q.ActualOverlayMode = @category AND q.PartySize = 1 + AND qrb.RunBuffs = @runBuffs ORDER BY q.CreatedAt ASC", conn)) @@ -6542,9 +6844,10 @@ ORDER BY cmd.Parameters.AddWithValue("@questID", questID); cmd.Parameters.AddWithValue("@weaponTypeID", weaponTypeID); cmd.Parameters.AddWithValue("@category", category); + cmd.Parameters.AddWithValue("@runBuffs", runBuffs); var reader = cmd.ExecuteReader(); - Dictionary personalBestTimes = new (); + Dictionary personalBestTimes = new(); while (reader.Read()) { @@ -6604,9 +6907,9 @@ ORDER BY } // Get personal best times by attempts - public Dictionary GetPersonalBestsByAttempts(long questID, int weaponTypeID, string category) + public Dictionary GetPersonalBestsByAttempts(long questID, int weaponTypeID, string category, uint runBuffs) { - Dictionary personalBests = new (); + Dictionary personalBests = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get personal bests by attempts. dataSource: {0}", this.dataSource); @@ -6623,7 +6926,8 @@ public Dictionary GetPersonalBestsByAttempts(long questID, int weapo using (var cmd = new SQLiteCommand( @"SELECT pb.Attempts, - q.FinalTimeValue + q.FinalTimeValue, + pb.RunBuffs FROM PersonalBests pb JOIN @@ -6634,6 +6938,7 @@ PersonalBests pb q.QuestID = @questID AND pg.WeaponTypeID = @weaponTypeID AND q.ActualOverlayMode = @category + AND pb.RunBuffs = @runBuffs AND q.PartySize = 1 ORDER BY pb.Attempts ASC", @@ -6642,6 +6947,7 @@ ORDER BY cmd.Parameters.AddWithValue("@questID", questID); cmd.Parameters.AddWithValue("@weaponTypeID", weaponTypeID); cmd.Parameters.AddWithValue("@category", category); + cmd.Parameters.AddWithValue("@runBuffs", runBuffs); var reader = cmd.ExecuteReader(); @@ -6691,7 +6997,7 @@ ORDER BY return personalBests; } - public int UpsertQuestAttempts(long questID, int weaponTypeID, string category, long partySize) + public int UpsertQuestAttempts(long questID, int weaponTypeID, string category, long partySize, long runBuffs) { var attempts = 0; if (string.IsNullOrEmpty(this.dataSource)) @@ -6715,11 +7021,11 @@ public int UpsertQuestAttempts(long questID, int weaponTypeID, string category, { command.CommandText = @"INSERT INTO - QuestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize) + QuestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize, RunBuffs) VALUES - (@QuestID, @WeaponTypeID, @ActualOverlayMode, 1, @PartySize) + (@QuestID, @WeaponTypeID, @ActualOverlayMode, 1, @PartySize, @RunBuffs) ON CONFLICT - (QuestID, WeaponTypeID, ActualOverlayMode, PartySize) + (QuestID, WeaponTypeID, ActualOverlayMode, PartySize, RunBuffs) DO UPDATE SET Attempts = Attempts + 1 @@ -6730,6 +7036,7 @@ DO UPDATE command.Parameters.AddWithValue("@WeaponTypeID", weaponTypeID); command.Parameters.AddWithValue("@ActualOverlayMode", category); command.Parameters.AddWithValue("@PartySize", partySize); + command.Parameters.AddWithValue("@RunBuffs", runBuffs); attempts = Convert.ToInt32(command.ExecuteScalar(), CultureInfo.InvariantCulture); } @@ -6760,7 +7067,7 @@ DO UPDATE return attempts; } - public int UpsertPersonalBestAttempts(long questID, int weaponTypeID, string category, long partySize) + public int UpsertPersonalBestAttempts(long questID, int weaponTypeID, string category, long partySize, long runBuffs) { var attempts = 0; if (string.IsNullOrEmpty(this.dataSource)) @@ -6784,11 +7091,11 @@ public int UpsertPersonalBestAttempts(long questID, int weaponTypeID, string cat { command.CommandText = @"INSERT INTO - PersonalBestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize) + PersonalBestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize, RunBuffs) VALUES - (@QuestID, @WeaponTypeID, @ActualOverlayMode, 1, @PartySize) + (@QuestID, @WeaponTypeID, @ActualOverlayMode, 1, @PartySize, @RunBuffs) ON CONFLICT - (QuestID, WeaponTypeID, ActualOverlayMode, PartySize) + (QuestID, WeaponTypeID, ActualOverlayMode, PartySize, RunBuffs) DO UPDATE SET Attempts = Attempts + 1 @@ -6799,6 +7106,7 @@ DO UPDATE command.Parameters.AddWithValue("@WeaponTypeID", weaponTypeID); command.Parameters.AddWithValue("@ActualOverlayMode", category); command.Parameters.AddWithValue("@PartySize", partySize); + command.Parameters.AddWithValue("@RunBuffs", runBuffs); attempts = Convert.ToInt32(command.ExecuteScalar(), CultureInfo.InvariantCulture); } @@ -6829,7 +7137,7 @@ DO UPDATE return attempts; } - public async Task UpsertQuestAttemptsAsync(long questID, int weaponTypeID, string category) + public async Task UpsertQuestAttemptsAsync(long questID, int weaponTypeID, string category, uint runBuffs) { var attempts = 0; if (string.IsNullOrEmpty(this.dataSource)) @@ -6897,7 +7205,7 @@ DO UPDATE return attempts; } - public async Task UpsertPersonalBestAttemptsAsync(long questID, int weaponTypeID, string category) + public async Task UpsertPersonalBestAttemptsAsync(long questID, int weaponTypeID, string category, uint runBuffs) { var attempts = 0; if (string.IsNullOrEmpty(this.dataSource)) @@ -6966,7 +7274,7 @@ DO UPDATE } // TODO test - public long GetQuestAttempts(long questID, int weaponTypeID, string category) + public long GetQuestAttempts(long questID, int weaponTypeID, string category, uint runBuffs) { long attempts = 0; if (string.IsNullOrEmpty(this.dataSource)) @@ -6991,11 +7299,13 @@ public long GetQuestAttempts(long questID, int weaponTypeID, string category) WHERE QuestID = @questID AND WeaponTypeID = @weaponTypeID - AND ActualOverlayMode = @category", conn)) + AND ActualOverlayMode = @category + AND RunBuffs = @runBuffs", conn)) { cmd.Parameters.Add("@questID", DbType.Int64).Value = questID; cmd.Parameters.Add("@weaponTypeID", DbType.Int32).Value = weaponTypeID; cmd.Parameters.Add("@category", DbType.String).Value = category; + cmd.Parameters.Add("@runBuffs", DbType.Int32).Value = runBuffs; var result = cmd.ExecuteScalar(); if (result != null) @@ -7171,7 +7481,7 @@ public PlayerInventory GetPlayerInventory(long runID) public Quest GetQuest(long runID) { - Quest quest = new (); + Quest quest = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get quest. dataSource: {0}", this.dataSource); @@ -7612,7 +7922,7 @@ public QuestsOverlayHash GetOverlayHash(long runID) private Quest GetLastQuest(SQLiteConnection conn) { - Quest quest = new (); + Quest quest = new(); using (var transaction = conn.BeginTransaction()) { try @@ -7681,7 +7991,7 @@ private Quest GetLastQuest(SQLiteConnection conn) private MezFes GetLastMezFes(SQLiteConnection conn) { - MezFes last = new (); + MezFes last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -7717,7 +8027,7 @@ private MezFes GetLastMezFes(SQLiteConnection conn) private Bingo GetLastBingo(SQLiteConnection conn) { - Bingo last = new (); + Bingo last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -7848,7 +8158,7 @@ public void SetPlayerBingoPoints(long points) private ZenithGauntlet GetLastZenithGauntlet(SQLiteConnection conn) { - ZenithGauntlet last = new (); + ZenithGauntlet last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -7907,7 +8217,7 @@ private ZenithGauntlet GetLastZenithGauntlet(SQLiteConnection conn) private SolsticeGauntlet GetLastSolsticeGauntlet(SQLiteConnection conn) { - SolsticeGauntlet last = new (); + SolsticeGauntlet last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -7949,7 +8259,7 @@ private SolsticeGauntlet GetLastSolsticeGauntlet(SQLiteConnection conn) private MusouGauntlet GetLastMusouGauntlet(SQLiteConnection conn) { - MusouGauntlet last = new (); + MusouGauntlet last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -7995,7 +8305,7 @@ private MusouGauntlet GetLastMusouGauntlet(SQLiteConnection conn) private PersonalBestAttempts GetLastPersonalBestAttempt(SQLiteConnection conn) { - PersonalBestAttempts last = new (); + PersonalBestAttempts last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8013,6 +8323,7 @@ private PersonalBestAttempts GetLastPersonalBestAttempt(SQLiteConnection conn) WeaponTypeID = long.Parse(reader["WeaponTypeID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), ActualOverlayMode = reader["ActualOverlayMode"]?.ToString() ?? "0", Attempts = long.Parse(reader["Attempts"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunBuffs = long.Parse(reader["RunBuffs"]?.ToString() ?? "0", CultureInfo.InvariantCulture), }; } } @@ -8031,7 +8342,7 @@ private PersonalBestAttempts GetLastPersonalBestAttempt(SQLiteConnection conn) private QuestAttempts GetLastQuestAttempt(SQLiteConnection conn) { - QuestAttempts last = new (); + QuestAttempts last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8049,6 +8360,7 @@ private QuestAttempts GetLastQuestAttempt(SQLiteConnection conn) WeaponTypeID = long.Parse(reader["WeaponTypeID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), ActualOverlayMode = reader["ActualOverlayMode"]?.ToString() ?? "0", Attempts = long.Parse(reader["Attempts"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunBuffs = long.Parse(reader["RunBuffs"]?.ToString() ?? "0", CultureInfo.InvariantCulture), }; } } @@ -8067,7 +8379,7 @@ private QuestAttempts GetLastQuestAttempt(SQLiteConnection conn) private PlayerGear GetLastPlayerGear(SQLiteConnection conn) { - PlayerGear last = new (); + PlayerGear last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8151,7 +8463,7 @@ private PlayerGear GetLastPlayerGear(SQLiteConnection conn) private ActiveSkills GetLastActiveSkills(SQLiteConnection conn) { - ActiveSkills last = new (); + ActiveSkills last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8247,7 +8559,7 @@ private ZenithSkills GetLastZenithSkills(SQLiteConnection conn) private StyleRankSkills GetLastStyleRankSkills(SQLiteConnection conn) { - StyleRankSkills last = new (); + StyleRankSkills last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8284,7 +8596,7 @@ private StyleRankSkills GetLastStyleRankSkills(SQLiteConnection conn) private GachaCardInventory GetLastGachaCard(SQLiteConnection conn) { - GachaCardInventory last = new (); + GachaCardInventory last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8317,7 +8629,7 @@ private GachaCardInventory GetLastGachaCard(SQLiteConnection conn) private PlayerInventory GetLastPlayerInventory(SQLiteConnection conn) { - PlayerInventory last = new (); + PlayerInventory last = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8695,7 +9007,7 @@ public RoadDureSkills GetRoadDureSkills(long runID) private HashSet GetAllPlayerInventories(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8706,7 +9018,7 @@ private HashSet GetAllPlayerInventories(SQLiteConnection conn) { while (reader.Read()) { - PlayerInventory data = new () + PlayerInventory data = new() { PlayerInventoryID = long.Parse(reader["PlayerInventoryID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), CreatedAt = DateTime.Parse(reader["CreatedAt"]?.ToString() ?? DateTime.UnixEpoch.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture), @@ -8987,7 +9299,7 @@ private HashSet GetAllQuestsHalk(SQLiteConnection conn) private HashSet GetAllGachaCards(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -8998,7 +9310,7 @@ private HashSet GetAllGachaCards(SQLiteConnection conn) { while (reader.Read()) { - GachaCardInventory data = new () + GachaCardInventory data = new() { GachaCardInventoryID = long.Parse(reader["GachaCardInventoryID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), GachaCardID = long.Parse(reader["GachaCardID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), @@ -9022,7 +9334,7 @@ private HashSet GetAllGachaCards(SQLiteConnection conn) private HashSet GetAllQuestAttempts(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9033,13 +9345,14 @@ private HashSet GetAllQuestAttempts(SQLiteConnection conn) { while (reader.Read()) { - QuestAttempts data = new () + QuestAttempts data = new() { QuestAttemptsID = long.Parse(reader["QuestAttemptsID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), QuestID = long.Parse(reader["QuestID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), WeaponTypeID = long.Parse(reader["WeaponTypeID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), ActualOverlayMode = reader["ActualOverlayMode"]?.ToString() ?? "0", Attempts = long.Parse(reader["Attempts"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunBuffs = long.Parse(reader["RunBuffs"]?.ToString() ?? "0", CultureInfo.InvariantCulture), }; hashSet.Add(data); @@ -9060,7 +9373,7 @@ private HashSet GetAllQuestAttempts(SQLiteConnection conn) private HashSet GetAllPlayerGear(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9071,7 +9384,7 @@ private HashSet GetAllPlayerGear(SQLiteConnection conn) { while (reader.Read()) { - PlayerGear data = new () + PlayerGear data = new() { PlayerGearHash = reader["PlayerGearHash"]?.ToString() ?? "0", CreatedAt = DateTime.Parse(reader["CreatedAt"]?.ToString() ?? DateTime.UnixEpoch.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture), @@ -9152,7 +9465,7 @@ private HashSet GetAllPlayerGear(SQLiteConnection conn) private HashSet GetAllActiveSkills(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9163,7 +9476,7 @@ private HashSet GetAllActiveSkills(SQLiteConnection conn) { while (reader.Read()) { - ActiveSkills data = new () + ActiveSkills data = new() { ActiveSkillsID = long.Parse(reader["ActiveSkillsID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), CreatedAt = DateTime.Parse(reader["CreatedAt"]?.ToString() ?? DateTime.UnixEpoch.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture), @@ -9252,7 +9565,7 @@ private HashSet GetAllZenithSkills(SQLiteConnection conn) private HashSet GetAllStyleRankSkills(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9263,7 +9576,7 @@ private HashSet GetAllStyleRankSkills(SQLiteConnection conn) { while (reader.Read()) { - StyleRankSkills data = new () + StyleRankSkills data = new() { StyleRankSkillsID = long.Parse(reader["StyleRankSkillsID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), CreatedAt = DateTime.Parse(reader["CreatedAt"]?.ToString() ?? DateTime.UnixEpoch.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture), @@ -9291,7 +9604,7 @@ private HashSet GetAllStyleRankSkills(SQLiteConnection conn) private HashSet GetAllPersonalBestAttempts(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9302,13 +9615,14 @@ private HashSet GetAllPersonalBestAttempts(SQLiteConnectio { while (reader.Read()) { - PersonalBestAttempts data = new () + PersonalBestAttempts data = new() { PersonalBestAttemptsID = long.Parse(reader["PersonalBestAttemptsID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), QuestID = long.Parse(reader["QuestID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), WeaponTypeID = long.Parse(reader["WeaponTypeID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), ActualOverlayMode = reader["ActualOverlayMode"]?.ToString() ?? "0", Attempts = long.Parse(reader["Attempts"]?.ToString() ?? "0", CultureInfo.InvariantCulture), + RunBuffs = long.Parse(reader["RunBuffs"]?.ToString() ?? "0", CultureInfo.InvariantCulture), }; hashSet.Add(data); @@ -9329,7 +9643,7 @@ private HashSet GetAllPersonalBestAttempts(SQLiteConnectio private HashSet GetAllMusouGauntlets(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9340,7 +9654,7 @@ private HashSet GetAllMusouGauntlets(SQLiteConnection conn) { while (reader.Read()) { - MusouGauntlet data = new () + MusouGauntlet data = new() { MusouGauntletID = long.Parse(reader["MusouGauntletID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), WeaponType = reader["WeaponType"]?.ToString() ?? "0", @@ -9377,7 +9691,7 @@ private HashSet GetAllMusouGauntlets(SQLiteConnection conn) private HashSet GetAllSolsticeGauntlets(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9388,7 +9702,7 @@ private HashSet GetAllSolsticeGauntlets(SQLiteConnection conn) { while (reader.Read()) { - SolsticeGauntlet data = new () + SolsticeGauntlet data = new() { SolsticeGauntletID = long.Parse(reader["SolsticeGauntletID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), WeaponType = reader["WeaponType"]?.ToString() ?? "0", @@ -9421,7 +9735,7 @@ private HashSet GetAllSolsticeGauntlets(SQLiteConnection conn) private HashSet GetAllZenithGauntlets(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9432,7 +9746,7 @@ private HashSet GetAllZenithGauntlets(SQLiteConnection conn) { while (reader.Read()) { - ZenithGauntlet data = new () + ZenithGauntlet data = new() { ZenithGauntletID = long.Parse(reader["ZenithGauntletID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), WeaponType = reader["WeaponType"]?.ToString() ?? "0", @@ -9482,7 +9796,7 @@ private HashSet GetAllZenithGauntlets(SQLiteConnection conn) private HashSet GetAllBingo(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9493,7 +9807,7 @@ private HashSet GetAllBingo(SQLiteConnection conn) { while (reader.Read()) { - Bingo data = new () + Bingo data = new() { BingoID = long.Parse(reader["BingoID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), CreatedAt = DateTime.Parse(reader["CreatedAt"]?.ToString() ?? DateTime.UnixEpoch.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture), @@ -9525,7 +9839,7 @@ private HashSet GetAllBingo(SQLiteConnection conn) private HashSet GetAllMezFes(SQLiteConnection conn) { - HashSet hashSet = new (); + HashSet hashSet = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9536,7 +9850,7 @@ private HashSet GetAllMezFes(SQLiteConnection conn) { while (reader.Read()) { - MezFes data = new () + MezFes data = new() { MezFesID = long.Parse(reader["MezFesID"]?.ToString() ?? "0", CultureInfo.InvariantCulture), CreatedAt = DateTime.Parse(reader["CreatedAt"]?.ToString() ?? DateTime.UnixEpoch.ToString(CultureInfo.InvariantCulture), CultureInfo.InvariantCulture), @@ -9563,7 +9877,7 @@ private HashSet GetAllMezFes(SQLiteConnection conn) private HashSet GetAllQuests(SQLiteConnection conn) { - HashSet quests = new (); + HashSet quests = new(); using (var transaction = conn.BeginTransaction()) { try @@ -9834,7 +10148,7 @@ public CaravanSkills GetCaravanSkills(long runID) public Dictionary GetAttackBuffDictionary(long runID) { - Dictionary attackBuffDictionary = new (); + Dictionary attackBuffDictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get attack buff dictionary. dataSource: {0}", this.dataSource); @@ -9880,7 +10194,7 @@ public Dictionary GetAttackBuffDictionary(long runID) public Dictionary GetHitCountDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get hit count dictionary. dataSource: {0}", this.dataSource); @@ -9926,7 +10240,7 @@ public Dictionary GetHitCountDictionary(long runID) public Dictionary GetHitsPerSecondDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get hits per second dictionary. dataSource: {0}", this.dataSource); @@ -9972,7 +10286,7 @@ public Dictionary GetHitsPerSecondDictionary(long runID) public Dictionary GetDamageDealtDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get damage dealt dictionary. dataSource: {0}", this.dataSource); @@ -10018,7 +10332,7 @@ public Dictionary GetDamageDealtDictionary(long runID) public Dictionary GetDamagePerSecondDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get damage per second dictionary. dataSource: {0}", this.dataSource); @@ -10064,7 +10378,7 @@ public Dictionary GetDamagePerSecondDictionary(long runID) public Dictionary GetAreaChangesDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get area changes dictionary. dataSource: {0}", this.dataSource); @@ -10110,7 +10424,7 @@ public Dictionary GetAreaChangesDictionary(long runID) public Dictionary GetCartsDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get carts dictionary. dataSource: {0}", this.dataSource); @@ -10156,7 +10470,7 @@ public Dictionary GetCartsDictionary(long runID) public Dictionary> GetMonster1HPDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 1 HP dictionary. dataSource: {0}", this.dataSource); @@ -10202,7 +10516,7 @@ public Dictionary> GetMonster1HPDictionary(long runID) public Dictionary> GetMonster2HPDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 2 HP dictionary. dataSource: {0}", this.dataSource); @@ -10248,7 +10562,7 @@ public Dictionary> GetMonster2HPDictionary(long runID) public Dictionary> GetMonster3HPDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 3 HP dictionary. dataSource: {0}", this.dataSource); @@ -10294,7 +10608,7 @@ public Dictionary> GetMonster3HPDictionary(long runID) public Dictionary> GetMonster4HPDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 4 HP dictionary. dataSource: {0}", this.dataSource); @@ -10340,7 +10654,7 @@ public Dictionary> GetMonster4HPDictionary(long runID) public Dictionary> GetMonster1AttackMultiplierDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 1 attack multiplier dictionary. dataSource: {0}", this.dataSource); @@ -10386,7 +10700,7 @@ public Dictionary> GetMonster1AttackMultiplierDicti public Dictionary> GetMonster1DefenseRateDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 1 defense rate dictionary. dataSource: {0}", this.dataSource); @@ -10478,7 +10792,7 @@ public Dictionary> GetMonster1PoisonThresholdDictionar public Dictionary> GetMonster1SleepThresholdDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 1 sleep threshold dictionary. dataSource: {0}", this.dataSource); @@ -10524,7 +10838,7 @@ public Dictionary> GetMonster1SleepThresholdDictionary public Dictionary> GetMonster1ParalysisThresholdDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 1 paralysis threshold dictionary. dataSource: {0}", this.dataSource); @@ -10570,7 +10884,7 @@ public Dictionary> GetMonster1ParalysisThresholdDictio public Dictionary> GetMonster1BlastThresholdDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 1 blast threshold dictionary. dataSource: {0}", this.dataSource); @@ -10616,7 +10930,7 @@ public Dictionary> GetMonster1BlastThresholdDictionary public Dictionary> GetMonster1StunThresholdDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get monster 1 stun threshold dictionary. dataSource: {0}", this.dataSource); @@ -10662,7 +10976,7 @@ public Dictionary> GetMonster1StunThresholdDictionary( public Dictionary>> GetPlayerInventoryDictionary(long runID) { - Dictionary>> dictionary = new (); + Dictionary>> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get player inventory dictionary. dataSource: {0}", this.dataSource); @@ -10708,7 +11022,7 @@ public Dictionary>> GetPlayerInventoryDictionary( public Dictionary>> GetAmmoDictionary(long runID) { - Dictionary>> dictionary = new (); + Dictionary>> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get ammo dictionary. dataSource: {0}", this.dataSource); @@ -10754,7 +11068,7 @@ public Dictionary>> GetAmmoDictionary(long runID) public Dictionary>> GetPartnyaBagDictionary(long runID) { - Dictionary>> dictionary = new (); + Dictionary>> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get partnya bag dictionary. dataSource: {0}", this.dataSource); @@ -10800,7 +11114,7 @@ public Dictionary>> GetPartnyaBagDictionary(long public Dictionary> GetHitsTakenBlockedDictionary(long runID) { - Dictionary> dictionary = new (); + Dictionary> dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get hits taken/blocked dictionary. dataSource: {0}", this.dataSource); @@ -10846,7 +11160,7 @@ public Dictionary> GetHitsTakenBlockedDictionary(long public Dictionary GetHitsTakenBlockedPerSecondDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get hits taken/blocked per second dictionary. dataSource: {0}", this.dataSource); @@ -10892,7 +11206,7 @@ public Dictionary GetHitsTakenBlockedPerSecondDictionary(long runID public Dictionary GetPlayerHPDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get player HP dictionary. dataSource: {0}", this.dataSource); @@ -10938,7 +11252,7 @@ public Dictionary GetPlayerHPDictionary(long runID) public Dictionary GetPlayerStaminaDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get player stamina dictionary. dataSource: {0}", this.dataSource); @@ -10984,7 +11298,7 @@ public Dictionary GetPlayerStaminaDictionary(long runID) public Dictionary GetKeystrokesDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get keystrokes dictionary. dataSource: {0}", this.dataSource); @@ -11030,7 +11344,7 @@ public Dictionary GetKeystrokesDictionary(long runID) public Dictionary GetMouseInputDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get mouse input dictionary. dataSource: {0}", this.dataSource); @@ -11076,7 +11390,7 @@ public Dictionary GetMouseInputDictionary(long runID) public Dictionary GetGamepadInputDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get gamepad input dictionary. dataSource: {0}", this.dataSource); @@ -11122,7 +11436,7 @@ public Dictionary GetGamepadInputDictionary(long runID) public Dictionary GetActionsPerMinuteDictionary(long runID) { - Dictionary dictionary = new (); + Dictionary dictionary = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get actions per minute dictionary. dataSource: {0}", this.dataSource); @@ -11168,7 +11482,7 @@ public Dictionary GetActionsPerMinuteDictionary(long runID) public Dictionary GetMostCommonCategory() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common category. dataSource: {0}", this.dataSource); @@ -11375,7 +11689,7 @@ public PlayerGear GetPlayerGear(long runID) } // TODO add check if there are runs for the quest id? - public List GetFastestRuns(ConfigWindow configWindow, string weaponName = "All Weapons") + public List GetFastestRuns(ConfigWindow configWindow, uint selectedRunBuffs, string weaponName = "All Weapons") { var fastestRuns = new List(); if (string.IsNullOrEmpty(this.dataSource)) @@ -11407,15 +11721,19 @@ public List GetFastestRuns(ConfigWindow configWindow, string weaponN FinalTimeDisplay, Date, ActualOverlayMode, - PartySize + PartySize, + qrb.RunBuffs FROM Quests q JOIN QuestName qn ON q.QuestID = qn.QuestNameID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.QuestID = @questID AND q.PartySize = 1 AND q.ActualOverlayMode = @SelectedOverlayMode + AND qrb.RunBuffs = @SelectedRunBuffs ORDER BY FinalTimeValue ASC LIMIT 20"; @@ -11432,18 +11750,22 @@ FinalTimeValue ASC Date, ActualOverlayMode, PartySize, - pg.WeaponTypeID + pg.WeaponTypeID, + qrb.RunBuffs FROM Quests q JOIN QuestName qn ON q.QuestID = qn.QuestNameID JOIN PlayerGear pg ON q.RunID = pg.RunID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.QuestID = @questID AND q.PartySize = 1 AND q.ActualOverlayMode = @SelectedOverlayMode AND pg.WeaponTypeID = @SelectedWeaponTypeID + AND qrb.RunBuffs = @SelectedRunBuffs ORDER BY FinalTimeValue ASC LIMIT 20"; @@ -11453,7 +11775,6 @@ FinalTimeValue ASC using (var cmd = new SQLiteCommand(sql, conn)) { var selectedOverlayMode = ((ComboBoxItem)configWindow.OverlayModeComboBox.SelectedItem).Content.ToString(); - // idk if this is needed if (string.IsNullOrEmpty(selectedOverlayMode)) { @@ -11462,6 +11783,7 @@ FinalTimeValue ASC cmd.Parameters.AddWithValue("@questID", questID); cmd.Parameters.AddWithValue("@SelectedOverlayMode", selectedOverlayMode); + cmd.Parameters.AddWithValue("@SelectedRunBuffs", selectedRunBuffs); if (weaponName != "All Weapons") { @@ -11488,6 +11810,7 @@ FinalTimeValue ASC YouTubeID = (string)reader["YouTubeID"], FinalTimeDisplay = (string)reader["FinalTimeDisplay"], Date = DateTime.Parse((string)reader["Date"], CultureInfo.InvariantCulture), + RunBuffs = long.Parse(reader["RunBuffs"]?.ToString() ?? "0", CultureInfo.InvariantCulture), }); } } @@ -11538,18 +11861,21 @@ public List GetUneditedYouTubeLinkRuns() FinalTimeDisplay, Date, ActualOverlayMode, - PartySize + PartySize, + qrb.RunBuffs FROM Quests q JOIN QuestName qn ON q.QuestID = qn.QuestNameID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.PartySize = 1 AND q.YouTubeID = 'dQw4w9WgXcQ' AND q.ActualOverlayMode != 'Standard' ORDER BY q.RunID DESC"; - + using (var cmd = new SQLiteCommand(sql, conn)) { using (var reader = cmd.ExecuteReader()) @@ -11572,6 +11898,7 @@ ORDER BY YouTubeID = (string)reader["YouTubeID"], FinalTimeDisplay = (string)reader["FinalTimeDisplay"], Date = DateTime.Parse((string)reader["Date"], CultureInfo.InvariantCulture), + RunBuffs = long.Parse(reader["RunBuffs"]?.ToString() ?? "0", CultureInfo.InvariantCulture), }); } } @@ -11747,17 +12074,20 @@ public ObservableCollection GetRecentRuns() @"SELECT ObjectiveImage, qn.QuestNameName, - RunID, + q.RunID, QuestID, YouTubeID, FinalTimeDisplay, Date, ActualOverlayMode, - PartySize + PartySize, + qrb.RunBuffs FROM Quests q JOIN QuestName qn ON q.QuestID = qn.QuestNameID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID ORDER BY Date DESC LIMIT 10", conn)) @@ -11784,6 +12114,7 @@ Date DESC Date = DateTime.Parse((string)reader["Date"], CultureInfo.InvariantCulture), ActualOverlayMode = (string)reader["ActualOverlayMode"], PartySize = (long)reader["PartySize"], + RunBuffs = long.Parse(reader["RunBuffs"]?.ToString() ?? "0", CultureInfo.InvariantCulture), }; recentRuns.Add(recentRun); } @@ -11828,21 +12159,24 @@ public List GetCalendarRuns(DateTime? selectedDate) @"SELECT ObjectiveImage, qn.QuestNameName, - RunID, + q.RunID, QuestID, YouTubeID, FinalTimeDisplay, Date, ActualOverlayMode, - PartySize + PartySize, + qrb.RunBuffs FROM Quests q JOIN QuestName qn ON q.QuestID = qn.QuestNameID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE DATE(Date) = DATE(@SelectedDate) ORDER BY - RunID ASC", conn)) + q.RunID ASC", conn)) { cmd.Parameters.AddWithValue("@SelectedDate", selectedDate.Value.Date); using (var reader = cmd.ExecuteReader()) @@ -11867,6 +12201,7 @@ ORDER BY Date = DateTime.Parse((string)reader["Date"], CultureInfo.InvariantCulture), ActualOverlayMode = (string)reader["ActualOverlayMode"], PartySize = (long)reader["PartySize"], + RunBuffs = long.Parse(reader["RunBuffs"]?.ToString() ?? "0", CultureInfo.InvariantCulture), }; recentRuns.Add(recentRun); } @@ -11986,7 +12321,7 @@ GROUP BY return weaponUsageData; } - public void QuestIDButtonClick(object sender, RoutedEventArgs e, ConfigWindow configWindow) + public void QuestIDButtonClick(object sender, RoutedEventArgs e, ConfigWindow configWindow, uint selectedRunBuffs) { if (string.IsNullOrEmpty(this.dataSource)) { @@ -12013,7 +12348,7 @@ public void QuestIDButtonClick(object sender, RoutedEventArgs e, ConfigWindow co try { using (var cmd = new SQLiteCommand( - @"SELECT + @"SELECT q.ObjectiveImage, q.ObjectiveTypeID, q.ObjectiveQuantity, @@ -12035,7 +12370,7 @@ INNER JOIN { if (!reader.HasRows) { - var message = string.Format(CultureInfo.InvariantCulture, "Quest ID not found. Please use the Quest ID option in Settings and go into a quest in order to view the ID needed to search. You may also not have completed any runs for the selected Quest ID or for the selected category.\n\nQuest ID: {0}\nOverlay Mode: {1}\n{2}", questID, selectedOverlayMode, reader.ToString()); + var message = string.Format(CultureInfo.InvariantCulture, "Quest ID not found. Please use the Quest ID option in Settings and go into a quest in order to view the ID needed to search. You may also not have completed any runs for the selected Quest ID or for the selected category.\n\nQuest ID: {0}\nOverlay Mode: {1}\nRun Buffs: {2}\n{3}", questID, selectedOverlayMode, selectedRunBuffs, reader.ToString()); var snackbar = new Snackbar(configWindow.ConfigWindowSnackBarPresenter) { Style = (Style)configWindow.FindResource("CatppuccinMochaSnackBar"), @@ -12064,27 +12399,32 @@ INNER JOIN @"SELECT pg.WeaponTypeID, MIN(q.FinalTimeValue) as BestTime, - q.RunID + q.RunID, + qrb.RunBuffs FROM Quests q JOIN - PlayerGear pg ON q.RunID = pg.RunID + PlayerGear pg ON q.RunID = pg.RunID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.QuestID = @QuestID AND q.PartySize = 1 AND q.ActualOverlayMode = @SelectedOverlayMode + AND qrb.RunBuffs = @SelectedRunBuffs GROUP BY pg.WeaponTypeID ", conn)) { cmd.Parameters.AddWithValue("@QuestID", questID); cmd.Parameters.AddWithValue("@SelectedOverlayMode", selectedOverlayMode); + cmd.Parameters.AddWithValue("@SelectedRunBuffs", selectedRunBuffs); using (var reader = cmd.ExecuteReader()) { if (!reader.HasRows) { - var message = string.Format(CultureInfo.InvariantCulture, "Quest ID not found. Please use the Quest ID option in Settings and go into a quest in order to view the ID needed to search. You may also not have completed any runs for the selected Quest ID or for the selected category.\n\nQuest ID: {0}\nOverlay Mode: {1}\n{2}", questID, selectedOverlayMode, reader.ToString()); + var message = string.Format(CultureInfo.InvariantCulture, "Quest ID not found. Please use the Quest ID option in Settings and go into a quest in order to view the ID needed to search. You may also not have completed any runs for the selected Quest ID or for the selected category.\n\nQuest ID: {0}\nOverlay Mode: {1}\nRun Buffs: {2}\n{3}", questID, selectedOverlayMode, selectedRunBuffs, reader.ToString()); var snackbar = new Snackbar(configWindow.ConfigWindowSnackBarPresenter) { Style = (Style)configWindow.FindResource("CatppuccinMochaSnackBar"), @@ -12202,7 +12542,7 @@ GROUP BY public Dictionary GetMostQuestCompletions() { - Dictionary questCompletions = new (); + Dictionary questCompletions = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most quest completions. dataSource: {0}", this.dataSource); @@ -12250,7 +12590,7 @@ GROUP BY return questCompletions; } - public string GetQuestCompletions(long questID, string actualOverlayMode, int weaponTypeID, long partySize) + public string GetQuestCompletions(long questID, string actualOverlayMode, int weaponTypeID, long partySize, long runBuffs) { var questCompletions = "0"; if (string.IsNullOrEmpty(this.dataSource)) @@ -12273,17 +12613,21 @@ public string GetQuestCompletions(long questID, string actualOverlayMode, int we Quests q JOIN PlayerGear pg ON q.RunID = pg.RunID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.QuestID = @QuestID AND q.ActualOverlayMode = @ActualOverlayMode AND pg.WeaponTypeID = @WeaponTypeID - AND q.PartySize = @PartySize"; + AND q.PartySize = @PartySize + AND qrb.RunBuffs = @RunBuffs"; using (var cmd = new SQLiteCommand(sql, conn)) { cmd.Parameters.AddWithValue("@QuestID", questID); cmd.Parameters.AddWithValue("@ActualOverlayMode", actualOverlayMode); cmd.Parameters.AddWithValue("@WeaponTypeID", weaponTypeID); cmd.Parameters.AddWithValue("@PartySize", partySize); + cmd.Parameters.AddWithValue("@RunBuffs", runBuffs); using (var reader = cmd.ExecuteReader()) { @@ -12360,7 +12704,7 @@ Quests q return questCompletions; } - public async Task GetQuestAttemptsAsync(long questID, string actualOverlayMode, int weaponTypeID) + public async Task GetQuestAttemptsAsync(long questID, string actualOverlayMode, int weaponTypeID, uint runBuffs) { var questAttempts = "0"; if (string.IsNullOrEmpty(this.dataSource)) @@ -12412,7 +12756,7 @@ QuestAttempts qa return questAttempts; } - public async Task GetQuestAttemptsPerPersonalBestAsync(long questID, int weaponTypeID, string actualOverlayMode) + public async Task GetQuestAttemptsPerPersonalBestAsync(long questID, int weaponTypeID, string actualOverlayMode, uint runBuffs) { var attemptsPerPersonalBest = 0.0; if (string.IsNullOrEmpty(this.dataSource)) @@ -12421,8 +12765,8 @@ public async Task GetQuestAttemptsPerPersonalBestAsync(long questID, int return attemptsPerPersonalBest; } - var questAttempts = await GetQuestAttemptsAsync(questID, actualOverlayMode, weaponTypeID); - var personalBestCount = await GetPersonalBestsCountAsync(questID, weaponTypeID, actualOverlayMode); + var questAttempts = await GetQuestAttemptsAsync(questID, actualOverlayMode, weaponTypeID, runBuffs); + var personalBestCount = await GetPersonalBestsCountAsync(questID, weaponTypeID, actualOverlayMode, runBuffs); if (personalBestCount > 0) { attemptsPerPersonalBest = double.Parse(questAttempts, CultureInfo.InvariantCulture) / personalBestCount; @@ -12431,7 +12775,7 @@ public async Task GetQuestAttemptsPerPersonalBestAsync(long questID, int return attemptsPerPersonalBest; } - public double GetQuestAttemptsPerPersonalBest(long questID, int weaponTypeID, string actualOverlayMode, string questAttempts, long partySize) + public double GetQuestAttemptsPerPersonalBest(long questID, int weaponTypeID, string actualOverlayMode, string questAttempts, long partySize, long runBuffs) { var attemptsPerPersonalBest = 0.0; if (string.IsNullOrEmpty(this.dataSource)) @@ -12440,7 +12784,7 @@ public double GetQuestAttemptsPerPersonalBest(long questID, int weaponTypeID, st return attemptsPerPersonalBest; } - var personalBestCount = GetPersonalBestsCount(questID, weaponTypeID, actualOverlayMode, partySize); + var personalBestCount = GetPersonalBestsCount(questID, weaponTypeID, actualOverlayMode, partySize, runBuffs); if (personalBestCount > 0) { attemptsPerPersonalBest = double.Parse(questAttempts, CultureInfo.InvariantCulture) / personalBestCount; @@ -12449,7 +12793,7 @@ public double GetQuestAttemptsPerPersonalBest(long questID, int weaponTypeID, st return attemptsPerPersonalBest; } - public async Task GetPersonalBestsCountAsync(long questID, int weaponTypeID, string category) + public async Task GetPersonalBestsCountAsync(long questID, int weaponTypeID, string category, uint runBuffs) { int personalBestCount = 0; long? previousBestTime = null; @@ -12511,7 +12855,7 @@ Quests q return personalBestCount; } - public int GetPersonalBestsCount(long questID, int weaponTypeID, string category, long partySize) + public int GetPersonalBestsCount(long questID, int weaponTypeID, string category, long partySize, long runBuffs) { int personalBestCount = 0; long? previousBestTime = null; @@ -12535,17 +12879,21 @@ public int GetPersonalBestsCount(long questID, int weaponTypeID, string category Quests q JOIN PlayerGear pg ON q.RunID = pg.RunID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.QuestID = @questID AND q.ActualOverlayMode = @category AND pg.WeaponTypeID = @weaponTypeID AND - q.PartySize = @partySize + q.PartySize = @partySize AND + qrb.RunBuffs = @runBuffs ORDER BY q.RunID ASC", conn)) { cmd.Parameters.AddWithValue("@questID", questID); cmd.Parameters.AddWithValue("@weaponTypeID", weaponTypeID); cmd.Parameters.AddWithValue("@category", category); cmd.Parameters.AddWithValue("@partySize", partySize); + cmd.Parameters.AddWithValue("@runBuffs", runBuffs); using (var reader = cmd.ExecuteReader()) { @@ -12575,7 +12923,7 @@ Quests q return personalBestCount; } - public List GetQuests(long questID, string weaponName, string actualOverlayMode) + public List GetQuests(long questID, string weaponName, string actualOverlayMode, uint runBuffs) { List quests = new(); if (string.IsNullOrEmpty(this.dataSource)) @@ -12600,16 +12948,20 @@ public List GetQuests(long questID, string weaponName, string actualOverl Quests q JOIN PlayerGear pg ON q.RunID = pg.RunID + JOIN + QuestsRunBuffs qrb ON q.RunID = qrb.RunID WHERE q.QuestID = @QuestID AND q.ActualOverlayMode = @ActualOverlayMode AND pg.WeaponTypeID = @WeaponTypeID + AND qrb.RunBuffs = @RunBuffs ORDER BY RunID ASC"; using (var cmd = new SQLiteCommand(sql, conn)) { cmd.Parameters.AddWithValue("@QuestID", questID); cmd.Parameters.AddWithValue("@ActualOverlayMode", actualOverlayMode); cmd.Parameters.AddWithValue("@WeaponTypeID", weaponTypeID); + cmd.Parameters.AddWithValue("@RunBuffs", runBuffs); using (var reader = cmd.ExecuteReader()) { @@ -12676,7 +13028,7 @@ Quests q public Dictionary GetMostCommonObjectiveTypes() { - Dictionary objectiveCounts = new (); + Dictionary objectiveCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common objective types. dataSource: {0}", this.dataSource); @@ -12727,7 +13079,7 @@ GROUP BY public Dictionary GetMostCommonStarGrades() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common star grades. dataSource: {0}", this.dataSource); @@ -12777,7 +13129,7 @@ GROUP BY public Dictionary GetMostCommonHeadPieces() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common head pieces. dataSource: {0}", this.dataSource); @@ -12828,7 +13180,7 @@ GROUP BY public Dictionary GetMostCommonChestPieces() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common chest pieces. dataSource: {0}", this.dataSource); @@ -12881,7 +13233,7 @@ GROUP BY public Dictionary GetMostCommonArmsPieces() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common arms pieces. dataSource: {0}", this.dataSource); @@ -12932,7 +13284,7 @@ GROUP BY public Dictionary GetMostCommonWaistPieces() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common waist pieces. dataSource: {0}", this.dataSource); @@ -12983,7 +13335,7 @@ GROUP BY public Dictionary GetMostCommonLegsPieces() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common legs pieces. dataSource: {0}", this.dataSource); @@ -13034,7 +13386,7 @@ GROUP BY public Dictionary GetMostCommonDivaSkill() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common diva skill. dataSource: {0}", this.dataSource); @@ -13085,7 +13437,7 @@ GROUP BY public Dictionary GetMostCommonGuildFood() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common guild food. dataSource: {0}", this.dataSource); @@ -13136,7 +13488,7 @@ GROUP BY public Dictionary GetMostCommonRankBands() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common rank bands. dataSource: {0}", this.dataSource); @@ -13186,7 +13538,7 @@ GROUP BY public Dictionary GetMostCommonObjectives() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common objectives. dataSource: {0}", this.dataSource); @@ -13236,7 +13588,7 @@ GROUP BY public Dictionary GetMostCommonSetNames() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common set names. dataSource: {0}", this.dataSource); @@ -13286,7 +13638,7 @@ GROUP BY public Dictionary GetQuestsCompletedByDate() { - Dictionary questsCompletedByDate = new (); + Dictionary questsCompletedByDate = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get quests completed by date. dataSource: {0}", this.dataSource); @@ -13336,7 +13688,7 @@ GROUP BY public Dictionary GetMostCommonWeaponNames() { - Dictionary weaponCounts = new (); + Dictionary weaponCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common weapon names. dataSource: {0}", this.dataSource); @@ -13401,7 +13753,7 @@ GROUP BY public Dictionary GetMostCommonStyleRankSkills() { - Dictionary skillCounts = new (); + Dictionary skillCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common style rank skills. dataSource: {0}", this.dataSource); @@ -13467,7 +13819,7 @@ GROUP BY public Dictionary GetMostCommonCaravanSkills() { - Dictionary skillCounts = new (); + Dictionary skillCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common caravan skills. dataSource: {0}", this.dataSource); @@ -13541,7 +13893,7 @@ GROUP BY public Dictionary GetMostCommonPartySize() { - Dictionary fieldCounts = new (); + Dictionary fieldCounts = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get most common party size. dataSource: {0}", this.dataSource); @@ -13595,7 +13947,7 @@ GROUP BY /// public Dictionary GetTotalTimeSpentInQuests() { - Dictionary questTimeSpent = new (); + Dictionary questTimeSpent = new(); if (string.IsNullOrEmpty(this.dataSource)) { Logger.Warn(CultureInfo.InvariantCulture, "Cannot get total time spent in quests. dataSource: {0}", this.dataSource); @@ -13836,7 +14188,7 @@ FROM Quests questCompendium.TotalCartsInQuest = finalCartValues.Sum(); // Initialize dictionary to hold the total carts for each quest ID - Dictionary questTotalCarts = new (); + Dictionary questTotalCarts = new(); // Query to get carts dictionary for all quests with non-empty carts dictionary query = @"SELECT QuestId, CartsDictionary FROM Quests WHERE CartsDictionary IS NOT NULL AND CartsDictionary != '{}'"; @@ -13968,6 +14320,68 @@ FROM Quests questCompendium.PercentOfSkillFruit = skillFruitUsagePercentage; + query = @" + SELECT + RunBuffs + FROM QuestsRunBuffs"; + + var totalQuests = 0; + List runBuffsList = new(); + + using (var cmd = new SQLiteCommand(query, conn)) + { + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var runBuffs = (long)reader["RunBuffs"]; + runBuffsList.Add((RunBuff)runBuffs); + totalQuests++; + } + } + } + + var runBuffCount = new Dictionary() + { + { RunBuff.Halk, 0 }, + { RunBuff.PoogieItem, 0 }, + { RunBuff.DivaSong, 0 }, + { RunBuff.HalkPotEffect, 0 }, + { RunBuff.Bento, 0 }, + { RunBuff.GuildPoogie, 0 }, + { RunBuff.ActiveFeature, 0 }, + { RunBuff.GuildFood, 0 }, + { RunBuff.DivaSkill, 0 }, + { RunBuff.SecretTechnique, 0 }, + { RunBuff.DivaPrayerGem, 0 }, + { RunBuff.CourseAttackBoost, 0 }, + }; + + foreach (var runBuff in runBuffsList) + { + foreach (var kvp in runBuffCount) + { + if (runBuff.HasFlag(kvp.Key)) + { + runBuffCount[kvp.Key]++; + break; + } + } + } + + if (totalQuests > 0) + { + questCompendium.PercentOfActiveFeature = runBuffCount[RunBuff.ActiveFeature] * 100.0 / totalQuests; + questCompendium.PercentOfDivaSong = runBuffCount[RunBuff.DivaSong] * 100.0 / totalQuests; + questCompendium.PercentOfDivaPrayerGem = runBuffCount[RunBuff.DivaPrayerGem] * 100.0 / totalQuests; + questCompendium.PercentOfGuildPoogie = runBuffCount[RunBuff.GuildPoogie] * 100.0 / totalQuests; + questCompendium.PercentOfHalkOn = runBuffCount[RunBuff.Halk] * 100.0 / totalQuests; + questCompendium.PercentOfHalkPotEffectOn = runBuffCount[RunBuff.HalkPotEffect] * 100.0 / totalQuests; + questCompendium.PercentOfCourseAttackBoost = runBuffCount[RunBuff.CourseAttackBoost] * 100.0 / totalQuests; + } + + questCompendium.MostCommonGuildPoogie = GetMostCommonGuildPoogie(conn); + transaction.Commit(); } catch (Exception ex) @@ -14597,6 +15011,52 @@ private static long GetModeValue(string field, string table, SQLiteConnection co } } + private static long GetMostCommonGuildPoogie(SQLiteConnection conn) + { + var guildPoogies = new List(); + var query = @"SELECT + GuildPoogie1Skill, GuildPoogie2Skill, GuildPoogie3Skill + FROM + QuestsGuildPoogie"; + using (var cmd = new SQLiteCommand(query, conn)) + { + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var skill1 = (long)reader["GuildPoogie1Skill"]; + var skill2 = (long)reader["GuildPoogie2Skill"]; + var skill3 = (long)reader["GuildPoogie3Skill"]; + + if (skill1 > 0) + { + guildPoogies.Add(skill1); + continue; + } + + if (skill2 > 0) + { + guildPoogies.Add(skill2); + continue; + } + + if (skill3 > 0) + { + guildPoogies.Add(skill3); + continue; + } + } + } + } + + var mostCommonGuildPoogie = guildPoogies + .GroupBy(n => n) // Group the numbers + .OrderByDescending(g => g.Count()) // Order the groups by their count + .FirstOrDefault()?.Key; // Get the key of the first group (most common number) + + return (long)(mostCommonGuildPoogie == null ? 0 : mostCommonGuildPoogie); + } + /// /// Gets the maximum value with WHERE clause. /// @@ -14730,7 +15190,7 @@ FROM PlayerGear /// private static long GetMostCommonDecorationID(SQLiteConnection conn) { - Dictionary decorationCounts = new (); + Dictionary decorationCounts = new(); var query = @" SELECT HeadSlot1ID, HeadSlot2ID, HeadSlot3ID, @@ -14800,7 +15260,7 @@ private static long GetLeastUsedArmorSkillID(SQLiteConnection conn) FROM ActiveSkills "; - Dictionary skillCounts = new (); + Dictionary skillCounts = new(); using (var cmd = new SQLiteCommand(query, conn)) { @@ -15590,7 +16050,7 @@ 11. Commit the transaction started in step 2. 12. If foreign keys constraints were originally enabled, re-enable them now. */ - private void MigrateToSchemaFromVersion(SQLiteConnection conn, int fromVersion) + private void MigrateToSchemaFromVersion(SQLiteConnection conn, int fromVersion, DataLoader dataLoader) { // Keep in mind if you manually change the user_version to 0 and then perform the updates to for example v0.25.0, you // will lose the data for the fields that got updated to v0.25.0, because the program assumes that you are in @@ -15639,11 +16099,11 @@ private void MigrateToSchemaFromVersion(SQLiteConnection conn, int fromVersion) MessageBoxImage.Information); break; case 0: // v0.22.0 or older (TODO: does this work with older or just v0.22.0?) - // change pin type to mode 'pin' for keyboard handling changes - // removing types from previous schema - // sqlite3_exec(db, "DELETE FROM types;", NULL, NULL, NULL); - // NSLog(@"installing current types"); - // [self loadInitialData]; + // change pin type to mode 'pin' for keyboard handling changes + // removing types from previous schema + // sqlite3_exec(db, "DELETE FROM types;", NULL, NULL, NULL); + // NSLog(@"installing current types"); + // [self loadInitialData]; { this.PerformUpdateToVersion_0_23_0(conn); newVersion++; @@ -15652,8 +16112,8 @@ private void MigrateToSchemaFromVersion(SQLiteConnection conn, int fromVersion) } case 1: // v0.25.0 - // adds support for recent view tracking - // sqlite3_exec(db, "ALTER TABLE entries ADD COLUMN touched_at TEXT;", NULL, NULL, NULL); + // adds support for recent view tracking + // sqlite3_exec(db, "ALTER TABLE entries ADD COLUMN touched_at TEXT;", NULL, NULL, NULL); { this.PerformUpdateToVersion_0_25_0(conn); this.EnforceForeignKeys(conn); @@ -15667,20 +16127,28 @@ private void MigrateToSchemaFromVersion(SQLiteConnection conn, int fromVersion) this.EnforceForeignKeys(conn); newVersion++; Logger.Info(CultureInfo.InvariantCulture, "Updated schema to version v0.34.0. newVersion {0}", newVersion); + goto case 3; + case 3: // 0.35.0 + { + this.PerformUpdateToVersion_0_35_0(conn, dataLoader); + this.EnforceForeignKeys(conn); + newVersion++; + Logger.Info(CultureInfo.InvariantCulture, "Updated schema to version v0.35.0. newVersion {0}", newVersion); break; - // case 2://v0.24.0 - // sqlite3_exec(db, "ALTER TABLE categories ADD COLUMN image TEXT;", NULL, NULL, NULL); - // sqlite3_exec(db, "ALTER TABLE categories ADD COLUMN entry_count INTEGER;", NULL, NULL, NULL); - // sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS categories_id_idx ON categories(id);", NULL, NULL, NULL); - // sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS categories_name_id ON categories(name);", NULL, NULL, NULL); - // sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS entries_id_idx ON entries(id);", NULL, NULL, NULL); + } + // case 2://v0.24.0 + // sqlite3_exec(db, "ALTER TABLE categories ADD COLUMN image TEXT;", NULL, NULL, NULL); + // sqlite3_exec(db, "ALTER TABLE categories ADD COLUMN entry_count INTEGER;", NULL, NULL, NULL); + // sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS categories_id_idx ON categories(id);", NULL, NULL, NULL); + // sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS categories_name_id ON categories(name);", NULL, NULL, NULL); + // sqlite3_exec(db, "CREATE INDEX IF NOT EXISTS entries_id_idx ON entries(id);", NULL, NULL, NULL); - // etc... - // { - // PerformUpdateToVersion_0_25_0(conn); - // newVersion++; - // break; - // } + // etc... + // { + // PerformUpdateToVersion_0_25_0(conn); + // newVersion++; + // break; + // } } // [self setSchemaVersion]; @@ -15925,7 +16393,7 @@ private void UpdateDatabaseSchema(SQLiteConnection connection, DataLoader dataLo ApplicationService.HandleShutdown(); } - this.MigrateToSchemaFromVersion(connection, currentUserVersion); + this.MigrateToSchemaFromVersion(connection, currentUserVersion, dataLoader); var referenceSchemaFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "MHFZ_Overlay\\reference_schema.json"); FileService.DeleteFile(referenceSchemaFilePath); @@ -15977,7 +16445,7 @@ FOREIGN KEY(RunID) REFERENCES Quests(RunID) // without having to recreate the table and manually transfer all the data. } - private static void AlterTablePersonalBestAttempts(SQLiteConnection connection, string newSchema) + private static void AlterTablePersonalBestAttempts(SQLiteConnection connection, string newSchema, string transferDataSql) { Logger.Info(CultureInfo.InvariantCulture, "Altering PersonalBestAttempts table"); @@ -15998,8 +16466,6 @@ private static void AlterTablePersonalBestAttempts(SQLiteConnection connection, // Transfer content from X into new_X using a statement like: INSERT INTO new_X SELECT ... FROM X // Transfer data from the old table "PersonalBestAttempts" to the new table "new_PersonalBestAttempts". - var transferDataSql = @"INSERT INTO new_PersonalBestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize) - SELECT QuestID, WeaponTypeID, ActualOverlayMode, Attempts, 1 FROM PersonalBestAttempts;"; using (var transferDataCmd = new SQLiteCommand(transferDataSql, connection)) { transferDataCmd.ExecuteNonQuery(); @@ -16048,7 +16514,7 @@ private static void AlterTablePersonalBestAttempts(SQLiteConnection connection, } } - private static void AlterTableQuestAttempts(SQLiteConnection connection, string newSchema) + private static void AlterTableQuestAttempts(SQLiteConnection connection, string newSchema, string transferDataSql) { Logger.Info(CultureInfo.InvariantCulture, "Altering QuestAttempts table"); @@ -16069,8 +16535,6 @@ private static void AlterTableQuestAttempts(SQLiteConnection connection, string // Transfer content from X into new_X using a statement like: INSERT INTO new_X SELECT ... FROM X // Transfer data from the old table "QuestAttempts" to the new table "new_QuestAttempts". - var transferDataSql = @"INSERT INTO new_QuestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize) - SELECT QuestID, WeaponTypeID, ActualOverlayMode, Attempts, 1 FROM QuestAttempts;"; using (var transferDataCmd = new SQLiteCommand(transferDataSql, connection)) { transferDataCmd.ExecuteNonQuery(); @@ -16119,7 +16583,7 @@ private static void AlterTableQuestAttempts(SQLiteConnection connection, string } } - private static void AlterTablePersonalBests(SQLiteConnection connection, string newSchema) + private static void AlterTablePersonalBests(SQLiteConnection connection, string newSchema, string transferDataSql) { Logger.Info(CultureInfo.InvariantCulture, "Altering PersonalBests table"); @@ -16140,10 +16604,6 @@ private static void AlterTablePersonalBests(SQLiteConnection connection, string // Transfer content from X into new_X using a statement like: INSERT INTO new_X SELECT ... FROM X // Transfer data from the old table "QuestAttempts" to the new table "new_QuestAttempts". - var transferDataSql = @"INSERT INTO new_PersonalBests (RunID, Attempts, PartySize) - SELECT PersonalBests.RunID, PersonalBests.Attempts, Quests.PartySize - FROM PersonalBests - INNER JOIN Quests ON PersonalBests.RunID = Quests.RunID"; using (var transferDataCmd = new SQLiteCommand(transferDataSql, connection)) { transferDataCmd.ExecuteNonQuery(); @@ -16607,9 +17067,9 @@ private static void AlterTableSchema(SQLiteConnection connection, string tableNa var rememberFormat = new SQLiteCommand("SELECT type, sql FROM sqlite_schema WHERE tbl_name=@tableName;", connection); rememberFormat.Parameters.AddWithValue("@tableName", tableName); var reader = rememberFormat.ExecuteReader(); - List indexSqls = new (); - List triggerSqls = new (); - List viewSqls = new (); + List indexSqls = new(); + List triggerSqls = new(); + List viewSqls = new(); while (reader.Read()) { var type = reader.GetString(0); @@ -16701,8 +17161,8 @@ private static void AlterTableSchema(SQLiteConnection connection, string tableNa // Check if any views refer to table X in a way that is affected by the schema change var findViews = new SQLiteCommand("SELECT name, sql FROM sqlite_master WHERE type='view' AND sql LIKE '% " + tableName + " %';", connection); var viewReader = findViews.ExecuteReader(); - List viewNames = new (); - List viewSqlsModified = new (); + List viewNames = new(); + List viewSqlsModified = new(); while (viewReader.Read()) { viewNames.Add(viewReader.GetString(0)); @@ -16985,7 +17445,10 @@ FOREIGN KEY(WeaponTypeID) REFERENCES WeaponType(WeaponTypeID), cmd.ExecuteNonQuery(); } - AlterTablePersonalBestAttempts(connection, sql); + var transferDataSql = @"INSERT INTO new_PersonalBestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize) + SELECT QuestID, WeaponTypeID, ActualOverlayMode, Attempts, 1 FROM PersonalBestAttempts;"; + + AlterTablePersonalBestAttempts(connection, sql, transferDataSql); sql = @"CREATE TABLE IF NOT EXISTS new_QuestAttempts( QuestAttemptsID INTEGER PRIMARY KEY AUTOINCREMENT, @@ -17003,7 +17466,10 @@ FOREIGN KEY(WeaponTypeID) REFERENCES WeaponType(WeaponTypeID), cmd.ExecuteNonQuery(); } - AlterTableQuestAttempts(connection, sql); + transferDataSql = @"INSERT INTO new_QuestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize) + SELECT QuestID, WeaponTypeID, ActualOverlayMode, Attempts, 1 FROM QuestAttempts;"; + + AlterTableQuestAttempts(connection, sql, transferDataSql); sql = @"CREATE TABLE IF NOT EXISTS new_PersonalBests( PersonalBestsID INTEGER PRIMARY KEY AUTOINCREMENT, @@ -17018,7 +17484,265 @@ FOREIGN KEY(RunID) REFERENCES Quests(RunID) cmd.ExecuteNonQuery(); } - AlterTablePersonalBests(connection, sql); + transferDataSql = @"INSERT INTO new_PersonalBests (RunID, Attempts, PartySize) + SELECT PersonalBests.RunID, PersonalBests.Attempts, Quests.PartySize + FROM PersonalBests + INNER JOIN Quests ON PersonalBests.RunID = Quests.RunID"; + + AlterTablePersonalBests(connection, sql, transferDataSql); + } + + private void PerformUpdateToVersion_0_35_0(SQLiteConnection connection, DataLoader dataLoader) + { + var sql = @"CREATE TABLE IF NOT EXISTS new_PersonalBestAttempts + ( + PersonalBestAttemptsID INTEGER PRIMARY KEY AUTOINCREMENT, + QuestID INTEGER NOT NULL CHECK (QuestID >= 0) DEFAULT 0, + WeaponTypeID INTEGER NOT NULL DEFAULT 0, + ActualOverlayMode TEXT NOT NULL DEFAULT 'Standard', + Attempts INTEGER NOT NULL DEFAULT 0, + PartySize INTEGER NOT NULL DEFAULT 1, + RunBuffs INTEGER NOT NULL DEFAULT 0, + FOREIGN KEY(WeaponTypeID) REFERENCES WeaponType(WeaponTypeID), + UNIQUE (QuestID, WeaponTypeID, ActualOverlayMode, PartySize, RunBuffs) + )"; + using (var cmd = new SQLiteCommand(sql, connection)) + { + cmd.ExecuteNonQuery(); + } + + var transferDataSql = @"INSERT INTO new_PersonalBestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize, RunBuffs) + SELECT QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize, 0 FROM PersonalBestAttempts;"; + + AlterTablePersonalBestAttempts(connection, sql, transferDataSql); + + sql = @"CREATE TABLE IF NOT EXISTS new_QuestAttempts( + QuestAttemptsID INTEGER PRIMARY KEY AUTOINCREMENT, + QuestID INTEGER NOT NULL CHECK (QuestID >= 0) DEFAULT 0, + WeaponTypeID INTEGER NOT NULL DEFAULT 0, + ActualOverlayMode TEXT NOT NULL DEFAULT 'Standard', + Attempts INTEGER NOT NULL DEFAULT 1, + PartySize INTEGER NOT NULL DEFAULT 1, + RunBuffs INTEGER NOT NULL DEFAULT 0, + FOREIGN KEY(WeaponTypeID) REFERENCES WeaponType(WeaponTypeID), + UNIQUE (QuestID, WeaponTypeID, ActualOverlayMode, PartySize, RunBuffs) + ) + "; + using (var cmd = new SQLiteCommand(sql, connection)) + { + cmd.ExecuteNonQuery(); + } + + transferDataSql = @"INSERT INTO new_QuestAttempts (QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize, RunBuffs) + SELECT QuestID, WeaponTypeID, ActualOverlayMode, Attempts, PartySize, 0 FROM QuestAttempts;"; + + AlterTableQuestAttempts(connection, sql, transferDataSql); + + sql = @"CREATE TABLE IF NOT EXISTS new_PersonalBests( + PersonalBestsID INTEGER PRIMARY KEY AUTOINCREMENT, + RunID INTEGER NOT NULL DEFAULT 0, + Attempts INTEGER NOT NULL DEFAULT 1, + PartySize INTEGER NOT NULL DEFAULT 1, + RunBuffs INTEGER NOT NULL DEFAULT 0, + FOREIGN KEY(RunID) REFERENCES Quests(RunID) + ) + "; + using (var cmd = new SQLiteCommand(sql, connection)) + { + cmd.ExecuteNonQuery(); + } + + transferDataSql = @"INSERT INTO new_PersonalBests (RunID, Attempts, PartySize, RunBuffs) + SELECT PersonalBests.RunID, PersonalBests.Attempts, Quests.PartySize, 0 + FROM PersonalBests + INNER JOIN Quests ON PersonalBests.RunID = Quests.RunID"; + + AlterTablePersonalBests(connection, sql, transferDataSql); + + // TODO replace actualoverlaymode speedruns and runbuffs at 0. first do the runbuffs. + UpdateRunBuffs(connection, dataLoader); + UpdateQuestsActualOverlayMode(connection); + UpdateTableActualOverlayMode("PersonalBestAttempts", connection); + UpdateTableActualOverlayMode("QuestAttempts", connection); + } + + private void UpdateQuestsActualOverlayMode(SQLiteConnection conn) + { + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot update speedrun modes for quests table. dataSource: {0}", this.dataSource); + return; + } + + // Start a transaction + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd0 = new SQLiteCommand(conn)) + { + cmd0.CommandText = @"DROP TRIGGER IF EXISTS prevent_quest_updates"; + cmd0.ExecuteNonQuery(); + } + + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = "SELECT * FROM Quests"; + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var actualOverlayMode = reader["ActualOverlayMode"].ToString(); + var runID = long.Parse(reader["RunID"]?.ToString() ?? "0", CultureInfo.InvariantCulture); + + if (actualOverlayMode == null || runID == 0) + { + continue; + } + + var newActualOverlayMode = actualOverlayMode == Messages.OverlayModeTimeAttack || actualOverlayMode == Messages.OverlayModeFreestyleNoSecretTech || actualOverlayMode == Messages.OverlayModeFreestyleWithSecretTech ? Messages.OverlayModeSpeedrun : actualOverlayMode; + + using (var cmd2 = new SQLiteCommand(conn)) + { + cmd2.CommandText = "UPDATE Quests SET ActualOverlayMode = @new_ActualOverlayMode WHERE RunID = @RunID"; + cmd2.Parameters.AddWithValue("@RunID", runID); + cmd2.Parameters.AddWithValue("@new_ActualOverlayMode", newActualOverlayMode); + + cmd2.ExecuteNonQuery(); + } + } + } + } + + using (var cmd1 = new SQLiteCommand(conn)) + { + cmd1.CommandText = @"CREATE TRIGGER IF NOT EXISTS prevent_quest_updates + AFTER UPDATE ON Quests + FOR EACH ROW + WHEN NEW.YouTubeID = OLD.YouTubeID + BEGIN + SELECT RAISE(ABORT, 'Cannot update quest fields'); + END;"; + cmd1.ExecuteNonQuery(); + } + + // Commit the transaction + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + Logger.Debug("Updated speedrun modes in quests table"); + } + + private void UpdateTableActualOverlayMode(string tableName, SQLiteConnection conn) + { + if (string.IsNullOrEmpty(this.dataSource)) + { + Logger.Warn(CultureInfo.InvariantCulture, "Cannot update speedrun modes for {0} table. dataSource: {1}", tableName, this.dataSource); + return; + } + + // Start a transaction + using (var transaction = conn.BeginTransaction()) + { + try + { + using (var cmd = new SQLiteCommand(conn)) + { + cmd.CommandText = $"SELECT * FROM {tableName}"; + + using (var reader = cmd.ExecuteReader()) + { + while (reader.Read()) + { + var actualOverlayMode = reader["ActualOverlayMode"].ToString(); + var rowID = long.Parse(reader[$"{tableName}ID"]?.ToString() ?? "0", CultureInfo.InvariantCulture); + + if (actualOverlayMode == null || rowID == 0) + { + continue; + } + + var newActualOverlayMode = actualOverlayMode == Messages.OverlayModeTimeAttack || actualOverlayMode == Messages.OverlayModeFreestyleNoSecretTech || actualOverlayMode == Messages.OverlayModeFreestyleWithSecretTech ? Messages.OverlayModeSpeedrun : actualOverlayMode; + + using (var cmd2 = new SQLiteCommand(conn)) + { + cmd2.CommandText = $"UPDATE {tableName} SET ActualOverlayMode = @new_ActualOverlayMode WHERE {tableName}ID = @RowID"; + cmd2.Parameters.AddWithValue("@RowID", rowID); + cmd2.Parameters.AddWithValue("@new_ActualOverlayMode", newActualOverlayMode); + + cmd2.ExecuteNonQuery(); + } + } + } + } + + // Commit the transaction + transaction.Commit(); + } + catch (Exception ex) + { + HandleError(transaction, ex); + } + } + + Logger.Debug($"Updated speedrun modes in {tableName} table"); + } + + /// + /// Fills run buffs table and updates runbuffs fields with new values. + /// + /// + private void UpdateRunBuffs(SQLiteConnection connection, DataLoader dataLoader) + { + // 1. recreate runbuffs table + var sql = @"DROP TABLE IF EXISTS QuestsRunBuffs"; + using (var cmd = new SQLiteCommand(sql, connection)) + { + cmd.ExecuteNonQuery(); + } + + sql = @"CREATE TABLE IF NOT EXISTS QuestsRunBuffs( + QuestsRunBuffsID INTEGER PRIMARY KEY AUTOINCREMENT, + RunBuffs INTEGER NOT NULL DEFAULT 0, + RunBuffsTag TEXT NOT NULL DEFAULT '', + RunID INTEGER NOT NULL, + FOREIGN KEY(RunID) REFERENCES Quests(RunID) + )"; + using (var cmd = new SQLiteCommand(sql, connection)) + { + cmd.ExecuteNonQuery(); + } + + // 2. for every row in quests table, add a row to runbuffs table: + // runid taken from quests table + // runbuffs from GetRunBuffs(string actualoverlaymode from quests table) + FillRunBuffs(connection, dataLoader); + + // 3. for every row in personalbests, update personalbests.runbuffs: + // get actualoverlaymode by doing personalbests.RunID = quests.RunID, then quests.ActualOverlayMode. + // if quests.ActualOverlayMode = "Freestyle No Secret Tech" then update personalbests.runbuffs to (Enum) RunBuff.FreestyleNoSecretTech. + // else if quests.ActualOverlayMode = "Freestyle w/ Secret Tech" then update personalbests.runbuffs to (Enum) RunBuff.FreestyleWithSecretTech. + // else if quests.ActualOverlayMode = "TimeAttack" then update personalbests.runbuffs to (Enum) RunBuff.TimeAttack. + UpdatePersonalBestsRunBuffs(connection, dataLoader); + + // 4. for every row in personalbestattempts, update personalbestattempts.runbuffs: + // if personalbestattempts.ActualOverlayMode = "Freestyle No Secret Tech" then update personalbestattempts.runbuffs to (Enum) RunBuff.FreestyleNoSecretTech. + // else if personalbestattempts.ActualOverlayMode = "Freestyle w/ Secret Tech" then update personalbestattempts.runbuffs to (Enum) RunBuff.FreestyleWithSecretTech. + // else if personalbestattempts.ActualOverlayMode = "TimeAttack" then update personalbestattempts.runbuffs to (Enum) RunBuff.TimeAttack. + UpdateTableRunBuffs("PersonalBestAttempts", connection, dataLoader); + + // 5. for every row in questattempts, update questattempts.runbuffs: + // if questattempts.ActualOverlayMode = "Freestyle No Secret Tech" then update questattempts.runbuffs to (Enum) RunBuff.FreestyleNoSecretTech. + // else if questattempts.ActualOverlayMode = "Freestyle w/ Secret Tech" then update questattempts.runbuffs to (Enum) RunBuff.FreestyleWithSecretTech. + // else if questattempts.ActualOverlayMode = "TimeAttack" then update questattempts.runbuffs to (Enum) RunBuff.TimeAttack. + + UpdateTableRunBuffs("QuestAttempts", connection, dataLoader); } // TODO: should i put this in FileManager? diff --git a/MHFZ_Overlay/Services/DiscordService.cs b/MHFZ_Overlay/Services/DiscordService.cs index d0f6c145..b1c739a4 100644 --- a/MHFZ_Overlay/Services/DiscordService.cs +++ b/MHFZ_Overlay/Services/DiscordService.cs @@ -303,7 +303,7 @@ public void UpdateDiscordRPC(DataLoader dataLoader) if ((dataLoader.Model.ObjectiveType() == 0x0 || dataLoader.Model.ObjectiveType() == 0x02 || dataLoader.Model.ObjectiveType() == 0x1002) && dataLoader.Model.QuestID() != 23527 && dataLoader.Model.QuestID() != 23628 && dataLoader.Model.QuestID() != 21731 && dataLoader.Model.QuestID() != 21749 && dataLoader.Model.QuestID() != 21746 && dataLoader.Model.QuestID() != 21750) { largeImageTextString = string.Format(CultureInfo.InvariantCulture, "{0}{1}", GetQuestInformation(dataLoader), dataLoader.Model.GetAreaName(dataLoader.Model.AreaID())); - PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID()); + PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID(), true); PresenceTemplate.Assets.LargeImageText = largeImageTextString.Length <= MaxDiscordRPCStringLength ? largeImageTextString : largeImageTextString[.. (MaxDiscordRPCStringLength - 3)] + "..."; } @@ -311,14 +311,14 @@ public void UpdateDiscordRPC(DataLoader dataLoader) else if (dataLoader.Model.AreaID() is 391 or 392 or 394 or 415 or 416) { largeImageTextString = string.Format(CultureInfo.InvariantCulture, "{0}{1}", GetQuestInformation(dataLoader), dataLoader.Model.GetAreaName(dataLoader.Model.AreaID())); - PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID()); + PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID(), true); PresenceTemplate.Assets.LargeImageText = largeImageTextString.Length <= MaxDiscordRPCStringLength ? largeImageTextString : largeImageTextString[.. (MaxDiscordRPCStringLength - 3)] + "..."; } // Duremudira Doors else if (dataLoader.Model.AreaID() is 399 or 414) { - PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID()); + PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID(), true); largeImageTextString = string.Format(CultureInfo.InvariantCulture, "{0}{1}", GetQuestInformation(dataLoader), dataLoader.Model.GetAreaName(dataLoader.Model.AreaID())); PresenceTemplate.Assets.LargeImageText = largeImageTextString.Length <= MaxDiscordRPCStringLength ? largeImageTextString : largeImageTextString[.. (MaxDiscordRPCStringLength - 3)] + "..."; } @@ -334,7 +334,7 @@ public void UpdateDiscordRPC(DataLoader dataLoader) // Hunter's Road Base Camp else if (dataLoader.Model.AreaID() == 459) { - PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID()); + PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID(), true); largeImageTextString = string.Format(CultureInfo.InvariantCulture, "{0}{1} | Faints: {2}/{3}", GetQuestInformation(dataLoader), dataLoader.Model.GetAreaName(dataLoader.Model.AreaID()), dataLoader.Model.CurrentFaints(), dataLoader.Model.GetMaxFaints()); PresenceTemplate.Assets.LargeImageText = largeImageTextString.Length <= MaxDiscordRPCStringLength ? largeImageTextString : largeImageTextString[.. (MaxDiscordRPCStringLength - 3)] + "..."; } @@ -461,7 +461,7 @@ public void UpdateDiscordRPC(DataLoader dataLoader) break; } - PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID()); + PresenceTemplate.Assets.LargeImageKey = ViewModels.Windows.AddressModel.GetAreaIconFromID(dataLoader.Model.AreaID(), true); largeImageTextString = dataLoader.Model.GetAreaName(dataLoader.Model.AreaID()); PresenceTemplate.Assets.LargeImageText = largeImageTextString.Length <= MaxDiscordRPCStringLength ? largeImageTextString : string.Concat(largeImageTextString.AsSpan(0, MaxDiscordRPCStringLength - 3), "..."); } diff --git a/MHFZ_Overlay/Settings.Designer.cs b/MHFZ_Overlay/Settings.Designer.cs index 33bcda60..47a60405 100644 --- a/MHFZ_Overlay/Settings.Designer.cs +++ b/MHFZ_Overlay/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace MHFZ_Overlay { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.7.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.8.0.0")] public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -4078,5 +4078,29 @@ public double GuildFoodTimerY { this["GuildFoodTimerY"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0.2")] + public double PlayerInputUnpressedOpacity { + get { + return ((double)(this["PlayerInputUnpressedOpacity"])); + } + set { + this["PlayerInputUnpressedOpacity"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0.5")] + public double PlayerInputPressedOpacity { + get { + return ((double)(this["PlayerInputPressedOpacity"])); + } + set { + this["PlayerInputPressedOpacity"] = value; + } + } } } diff --git a/MHFZ_Overlay/Settings.settings b/MHFZ_Overlay/Settings.settings index 77ffc685..5a8eafc6 100644 --- a/MHFZ_Overlay/Settings.settings +++ b/MHFZ_Overlay/Settings.settings @@ -1016,5 +1016,11 @@ 60 + + 0.2 + + + 0.5 + \ No newline at end of file diff --git a/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs b/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs index 51e3d2f8..415f7ffa 100644 --- a/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs +++ b/MHFZ_Overlay/ViewModels/Windows/AddressModel.cs @@ -8,6 +8,7 @@ namespace MHFZ_Overlay.ViewModels.Windows; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; +using System.Data.SQLite; using System.Diagnostics; using System.Drawing.Imaging; using System.Globalization; @@ -1340,11 +1341,11 @@ 21747 or /// public abstract int ActiveFeature3(); - /// - /// Updates every 11 seconds - /// - /// - public abstract int ServerHeartbeat(); + public abstract int ServerHeartbeatLandEven(); + + public abstract int ServerHeartbeatLandOdd(); + + public abstract int LandSlot(); public abstract int GuildFoodStart(); @@ -1376,6 +1377,25 @@ 21747 or public abstract bool HalkPotEffectOn(); + public abstract int DivaSongFromGuildStart(); + + public abstract int QuestVariant1(); + + public abstract int QuestVariant2(); + + public abstract int QuestVariant3(); + + /// + /// unused? + /// + /// + public abstract int QuestVariant4(); + + /// + /// Updates every 11 seconds + /// + /// + public int ServerHeartbeat => LandSlot() % 2 == 0 ? ServerHeartbeatLandEven() : ServerHeartbeatLandOdd(); /// /// [] Not Done @@ -1635,9 +1655,7 @@ public string GetOverlayModeForStorage() OverlayMode.NoGame => "No Game", OverlayMode.MainMenu => "Main Menu", OverlayMode.WorldSelect => "World Select", - OverlayMode.TimeAttack => "Time Attack", - OverlayMode.FreestyleSecretTech => "Freestyle w/ Secret Tech", - OverlayMode.Freestyle => "Freestyle No Secret Tech", + OverlayMode.Speedrun => "Speedrun", OverlayMode.Zen => "Zen", _ => "Not Found", }; @@ -1660,10 +1678,20 @@ public string GetFinalOverlayModeForDisplay() // TODO: test if (OverlayModeDictionary.Count == 2 && OverlayModeDictionary.First().Value == "Standard") { + if (OverlayModeDictionary.Last().Value == "Speedrun") + { + return "Speedrun+" + $" ({GetRunBuffsTag(GetRunBuffs())})"; + } + return OverlayModeDictionary.Last().Value + "+"; } else { + if (OverlayModeDictionary.First().Value == "Speedrun") + { + return "Speedrun+" + $" ({GetRunBuffsTag(GetRunBuffs())})"; + } + return OverlayModeDictionary.First().Value + "+"; } } @@ -1689,9 +1717,7 @@ public string GetOverlayModeForRPC() OverlayMode.NoGame => "Game not found | ", OverlayMode.MainMenu => "Main menu | ", OverlayMode.WorldSelect => "World Select | ", - OverlayMode.TimeAttack => "Time Attack | ", - OverlayMode.FreestyleSecretTech => "Freestyle Secret Tech | ", - OverlayMode.Freestyle => "Freestyle | ", // TODO rename? + OverlayMode.Speedrun => "Speedrun | ", OverlayMode.Zen => "Zen | ", _ => string.Empty, @@ -1785,21 +1811,7 @@ public OverlayMode GetOverlayMode() } else if (s.TimerInfoShown && s.EnableInputLogging && s.EnableQuestLogging && s.OverlayModeWatermarkShown) { - 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()) && !IsBitfieldContainingFlag((uint)this.Rights(), CourseRightsFirstByte.Support, (uint)CourseRightsFirstByte.All, true, 1) && this.DivaSkillUsesLeft() == 0 && this.StyleRank1() != 15 && this.StyleRank2() != 15) - { - return OverlayMode.TimeAttack; - } - else if (this.StyleRank1() == 15 || this.StyleRank2() == 15) - { - return OverlayMode.FreestyleSecretTech; - } - else - { - return OverlayMode.Freestyle; - } + return OverlayMode.Speedrun; } else { @@ -1828,6 +1840,16 @@ public int GetActiveFeature() return 0; } + /// + /// This only works for bitfield argument values 255 and below, if you don't intend to extract bytes. Consider using HasFlag directly if so. + /// + /// + /// + /// + /// + /// + /// + /// public bool IsBitfieldContainingFlag(uint bitfield, T flag, uint all, bool extractByte = false, int bytePosition = 0) where T : Enum { byte value = extractByte ? (byte)(((uint)bitfield >> (bytePosition * 8)) & 0xFF) : (byte)bitfield; @@ -2590,13 +2612,15 @@ public bool DivaSongEnding { get { - if (DivaSongStart() <= 0) + var divaSongStart = Math.Max(DivaSongStart(), DivaSongFromGuildStart()); + + if (divaSongStart <= 0) { return true; } - var expiry = DivaSongStart() + (60 * 90); - double secondsLeft = expiry - ServerHeartbeat(); + var expiry = divaSongStart + (60 * 90); + double secondsLeft = expiry - ServerHeartbeat; return secondsLeft <= 60*10; } @@ -2606,13 +2630,15 @@ public bool DivaSongEnded { get { - if (DivaSongStart() <= 0) + var divaSongStart = Math.Max(DivaSongStart(), DivaSongFromGuildStart()); + + if (divaSongStart <= 0) { return true; } - var expiry = DivaSongStart() + (60 * 90); - double secondsLeft = expiry - ServerHeartbeat(); + var expiry = divaSongStart + (60 * 90); + double secondsLeft = expiry - ServerHeartbeat; return secondsLeft <= 0; } @@ -2638,7 +2664,7 @@ public bool GuildFoodEnding } var expiry = GuildFoodStart() + (60 * 90); - double secondsLeft = expiry - ServerHeartbeat(); + double secondsLeft = expiry - ServerHeartbeat; return secondsLeft <= 60 * 10; } @@ -2654,7 +2680,7 @@ public bool GuildFoodEnded } var expiry = GuildFoodStart() + (60 * 90); - double secondsLeft = expiry - ServerHeartbeat(); + double secondsLeft = expiry - ServerHeartbeat; return secondsLeft <= 0; } @@ -2724,6 +2750,169 @@ public string IsOnPace } } + public bool isShitenQuest(int questID) + { + return questID switch + { + Numbers.QuestIDUpperShitenDisufiroa => true, + Numbers.QuestIDLowerShitenDisufiroa => true, + Numbers.QuestIDUpperShitenUnknown => true, + Numbers.QuestIDLowerShitenUnknown => true, + _ => false + }; + } + + public bool IsHalkPotEquipped() + { + return (PouchItem1ID() == 4952 || PouchItem2ID() == 4952 || PouchItem3ID() == 4952 || PouchItem4ID() == 4952 || PouchItem5ID() == 4952 || PouchItem6ID() == 4952 || PouchItem7ID() == 4952 || PouchItem8ID() == 4952 || PouchItem9ID() == 4952 || PouchItem10ID() == 4952 || PouchItem11ID() == 4952 || PouchItem12ID() == 4952 || PouchItem13ID() == 4952 || PouchItem14ID() == 4952 || PouchItem15ID() == 4952 || PouchItem16ID() == 4952 || PouchItem17ID() == 4952 || PouchItem18ID() == 4952 || PouchItem19ID() == 4952 || PouchItem20ID() == 4952 || PartnyaBagItem1ID() == 4952 || PartnyaBagItem2ID() == 4952 || PartnyaBagItem3ID() == 4952 || PartnyaBagItem4ID() == 4952 || PartnyaBagItem5ID() == 4952 || PartnyaBagItem6ID() == 4952 || PartnyaBagItem7ID() == 4952 || PartnyaBagItem8ID() == 4952 || PartnyaBagItem9ID() == 4952 || PartnyaBagItem10ID() == 4952); + } + + public string GetRunBuffsTag(RunBuff runBuff) + { + return runBuff switch + { + RunBuff.None => "None", + RunBuff.LeaderboardTimeAttack => "TA", + RunBuff.LeaderboardFreestyleDivaSkill => "FDS", + RunBuff.LeaderboardFreestyleDivaPrayerGem => "FDP", + RunBuff.LeaderboardFreestyleSecretTechnique => "FST", + RunBuff.LeaderboardFreestyleCourseAttackBoost => "FCA", + _ => CalculateRunBuffsTag(runBuff), + }; + } + + /// + /// TODO test + /// + /// + /// + public string CalculateRunBuffsTag(RunBuff runBuffs) + { + var value = (uint)runBuffs; + + if (runBuffs.HasFlag(RunBuff.CourseAttackBoost)) + { + return "FCA"; + } + + if (runBuffs.HasFlag(RunBuff.SecretTechnique) && !runBuffs.HasFlag(RunBuff.HalkPotEffect)) + { + return "FST"; + } + + if (runBuffs.HasFlag(RunBuff.DivaPrayerGem) && !runBuffs.HasFlag(RunBuff.HalkPotEffect)) + { + return "FDP"; + } + + if (runBuffs.HasFlag(RunBuff.DivaSkill) && !runBuffs.HasFlag(RunBuff.HalkPotEffect)) + { + return "FDS"; + } + + if (!runBuffs.HasFlag(RunBuff.HalkPotEffect) && !runBuffs.HasFlag(RunBuff.ActiveFeature)) + { + return "TA"; + } + + return value.ToString(); + } + + /// + /// Gets the run buffs + /// + /// + /// + public RunBuff GetRunBuffs(string overlayMode = "") + { + if (overlayMode != string.Empty) + { + switch (overlayMode) + { + case Messages.OverlayModeFreestyleNoSecretTech: + return RunBuff.FreestyleNoSecretTech; + case Messages.OverlayModeFreestyleWithSecretTech: + return RunBuff.FreestyleWithSecretTech; + case Messages.OverlayModeTimeAttack: + return RunBuff.TimeAttack; + default: + // we do not know the quest variants in 0.34, so we set as none. + // if we do not take into account quest variants, calculating the run buffs + // may be wrong because, for example, if we detect that halk was on we increase by 1 but + // in quests where halk is disabled the value in db is still positive, although in-game + // halk is off. + return RunBuff.None; + } + } + + var runBuffs = RunBuff.None; + var questVariant2 = (QuestVariant2)QuestVariant2(); + var questVariant3 = (QuestVariant3)QuestVariant3(); + + if (HalkOn() && !(questVariant2.HasFlag(Models.Structures.QuestVariant2.DisableHalkPoogieCuff)) || questVariant2.HasFlag(Models.Structures.QuestVariant2.Road)) + { + runBuffs |= RunBuff.Halk; + } + + if (PoogieItemUseID() > 0) + { + runBuffs |= RunBuff.PoogieItem; + } + + if (DivaSongActive) + { + runBuffs |= RunBuff.DivaSong; + } + + if ((HalkPotEffectOn() || IsHalkPotEquipped()) && !(questVariant2.HasFlag(Models.Structures.QuestVariant2.DisableHalkPotionCourseAttack) || questVariant2.HasFlag(Models.Structures.QuestVariant2.Level9999) || questVariant2.HasFlag(Models.Structures.QuestVariant2.Road))) + { + runBuffs |= RunBuff.HalkPotEffect; + } + + // TODO bento + if (true == true) + { + runBuffs |= RunBuff.Bento; + } + + if (GuildPoogie1Skill() > 0 || GuildPoogie2Skill() > 0 || GuildPoogie3Skill() > 0) + { + runBuffs |= RunBuff.GuildPoogie; + } + + if (IsActiveFeatureOn(GetActiveFeature(), WeaponType()) && !questVariant2.HasFlag(Models.Structures.QuestVariant2.DisableActiveFeature)) + { + runBuffs |= RunBuff.ActiveFeature; + } + + if (GuildFoodSkill() > 0) + { + runBuffs |= RunBuff.GuildFood; + } + + if ((DivaSkill() > 0 && DivaSkillUsesLeft() > 0) && !(questVariant2.HasFlag(Models.Structures.QuestVariant2.Road) || questVariant3.HasFlag(Models.Structures.QuestVariant3.NoGPSkills))) + { + runBuffs |= RunBuff.DivaSkill; + } + + if ((StyleRank1() == 15 || StyleRank2() == 15) && !questVariant2.HasFlag(Models.Structures.QuestVariant2.Level9999)) + { + runBuffs |= RunBuff.SecretTechnique; + } + + if ((DivaPrayerGemRedSkill() != 0 || DivaPrayerGemYellowSkill() != 0 || DivaPrayerGemGreenSkill() != 0 || DivaPrayerGemBlueSkill() != 0) && !(questVariant2.HasFlag(Models.Structures.QuestVariant2.Road) || questVariant2.HasFlag(Models.Structures.QuestVariant2.Level9999))) + { + runBuffs |= RunBuff.DivaPrayerGem; + } + + if (GetAdditionalCourses(Rights()).Contains("Support") && !(questVariant2.HasFlag(Models.Structures.QuestVariant2.DisableHalkPotionCourseAttack) || questVariant2.HasFlag(Models.Structures.QuestVariant2.Level9999))) + { + runBuffs |= RunBuff.CourseAttackBoost; + } + + return runBuffs; + } + public static double GetAverageHitsPerSecond(int weaponTypeID) { var weaponFound = WeaponCanUseReflect.WeaponTypeID.ContainsKey(weaponTypeID); @@ -7815,9 +8004,157 @@ public string GenerateGearStats(long? runID = null) // zp in bold for markdown // fruits and speedrunner items also in bold - this.SavedGearStats = string.Format(CultureInfo.InvariantCulture, "【MHF-Z】Overlay {0} {1}({2}){3}\n\n{4}{5}: {6}\nHead: {7}\nChest: {8}\nArms: {9}\nWaist: {10}\nLegs: {11}\nCuffs: {12}\n\nWeapon Attack: {13} | Total Defense: {14}\n\nZenith Skills:\n{15}\n\nAutomatic Skills:\n{16}\n\nActive Skills{17}:\n{18}\n\nCaravan Skills:\n{19}\n\nDiva Skill:\n{20}\n\nGuild Food:\n{21}\n\nStyle Rank:\n{22}\n\nItems:\n{23}\n\nAmmo:\n{24}\n\nPoogie Item:\n{25}\n\nRoad/Duremudira Skills:\n{26}\n", App.CurrentProgramVersion, this.GetWeaponClass(), GetGender(), GetMetadata, GetGearDescription, this.CurrentWeaponName, this.GetRealWeaponName, this.GetArmorHeadName, this.GetArmorChestName, this.GetArmorArmName, this.GetArmorWaistName, this.GetArmorLegName, this.GetCuffs, this.BloatedWeaponAttack().ToString(CultureInfo.InvariantCulture), this.TotalDefense().ToString(CultureInfo.InvariantCulture), this.GetZenithSkills, this.GetAutomaticSkills, showGouBoost, this.GetArmorSkills, this.GetCaravanSkills, GetDivaSkillNameFromID(this.DivaSkill()), GetArmorSkill(this.GuildFoodSkill()), this.GetGSRSkills, this.GetItemPouch, this.GetAmmoPouch, GetItemName(this.PoogieItemUseID()), this.GetRoadDureSkills); - this.MarkdownSavedGearStats = string.Format(CultureInfo.InvariantCulture, "__【MHF-Z】Overlay {0}__ *{1}({2})*{3}\n\n{4}**{5}**: {6}\n**Head:** {7}\n**Chest:** {8}\n**Arms:** {9}\n**Waist:** {10}\n**Legs:** {11}\n**Cuffs:** {12}\n\n**Weapon Attack:** {13} | **Total Defense:** {14}\n\n**Zenith Skills:**\n{15}\n\n**Automatic Skills:**\n{16}\n\n**Active Skills{17}:**\n{18}\n\n**Caravan Skills:**\n{19}\n\n**Diva Skill:**\n{20}\n\n**Guild Food:**\n{21}\n\n**Style Rank:**\n{22}\n\n**Items:**\n{23}\n\n**Ammo:**\n{24}\n\n**Poogie Item:**\n{25}\n\n**Road/Duremudira Skills:**\n{26}\n", App.CurrentProgramVersion, this.GetWeaponClass(), GetGender(), GetMetadata, GetGearDescription, this.CurrentWeaponName, this.GetRealWeaponName, this.GetArmorHeadName, this.GetArmorChestName, this.GetArmorArmName, this.GetArmorWaistName, this.GetArmorLegName, this.GetCuffs, this.BloatedWeaponAttack().ToString(CultureInfo.InvariantCulture), this.TotalDefense().ToString(CultureInfo.InvariantCulture), this.GetZenithSkills, this.GetAutomaticSkills, showGouBoost, this.GetArmorSkills, this.GetCaravanSkills, GetDivaSkillNameFromID(this.DivaSkill()), GetArmorSkill(this.GuildFoodSkill()), this.GetGSRSkills, this.GetItemPouch, this.GetAmmoPouch, GetItemName(this.PoogieItemUseID()), this.GetRoadDureSkills); - return string.Format(CultureInfo.InvariantCulture, "【MHF-Z】Overlay {0} {1}({2}){3}\n\n{4}{5}: {6}\nHead: {7}\nChest: {8}\nArms: {9}\nWaist: {10}\nLegs: {11}\nCuffs: {12}\n\nWeapon Attack: {13} | Total Defense: {14}\n\nZenith Skills:\n{15}\n\nAutomatic Skills:\n{16}\n\nActive Skills{17}:\n{18}\n\nCaravan Skills:\n{19}\n\nDiva Skill:\n{20}\n\nGuild Food:\n{21}\n\nStyle Rank:\n{22}\n\nItems:\n{23}\n\nAmmo:\n{24}\n\nPoogie Item:\n{25}\n\nRoad/Duremudira Skills:\n{26}\n", App.CurrentProgramVersion, this.GetWeaponClass(), GetGender(), GetMetadata, GetGearDescription, this.CurrentWeaponName, this.GetRealWeaponName, this.GetArmorHeadName, this.GetArmorChestName, this.GetArmorArmName, this.GetArmorWaistName, this.GetArmorLegName, this.GetCuffs, this.BloatedWeaponAttack().ToString(CultureInfo.InvariantCulture), this.TotalDefense().ToString(CultureInfo.InvariantCulture), this.GetZenithSkills, this.GetAutomaticSkills, showGouBoost, this.GetArmorSkills, this.GetCaravanSkills, GetDivaSkillNameFromID(this.DivaSkill()), GetArmorSkill(this.GuildFoodSkill()), this.GetGSRSkills, this.GetItemPouch, this.GetAmmoPouch, GetItemName(this.PoogieItemUseID()), this.GetRoadDureSkills); + var stats = string.Format( + CultureInfo.InvariantCulture, + @$"【MHF-Z】Overlay {App.CurrentProgramVersion} {this.GetWeaponClass()}({GetGender()}){GetMetadata} + +Set Name: {GetGearDescription} +{this.CurrentWeaponName}: {this.GetRealWeaponName} +Head: {this.GetArmorHeadName} +Chest: {this.GetArmorChestName} +Arms: {this.GetArmorArmName} +Waist: {this.GetArmorWaistName} +Legs: {this.GetArmorLegName} +Cuffs: {this.GetCuffs} + +Weapon Attack: {this.BloatedWeaponAttack().ToString(CultureInfo.InvariantCulture)} | Total Defense: {this.TotalDefense().ToString(CultureInfo.InvariantCulture)} + +Zenith Skills: +{this.GetZenithSkills} + +Automatic Skills: +{this.GetAutomaticSkills} + +Active Skills{showGouBoost}: +{this.GetArmorSkills} + +Caravan Skills: +{this.GetCaravanSkills} + +Diva: +{GetDivaSkillNameFromID(this.DivaSkill())} +Song {(DivaSongActive ? "ON" : "OFF")} + +Diva Prayer Gems: +{GetDivaPrayerGems()} + +Guild: +{GetArmorSkill(this.GuildFoodSkill())} +{GetGuildPoogieEffect()} + +Style Rank: +{this.GetGSRSkills} + +Items: +{this.GetItemPouch} + +Ammo: +{this.GetAmmoPouch} + +Poogie Item: +{GetItemName(this.PoogieItemUseID())} + +Road/Duremudira Skills: +{this.GetRoadDureSkills} + +Active Feature {(IsActiveFeatureOn(GetActiveFeature(), WeaponType()) ? "ON" : "OFF")} + +Courses: +Main: {GetMainCourses()} +Additional: {GetAdditionalCourses()} + +Halk: +{(HalkOn() ? "Active" : "Inactive")} +Halk Pot {(IsHalkPotEquipped() || HalkPotEffectOn() ? "ON" : "OFF")} +LV{HalkLevel()} +Element Type {GetHalkElement()} +Status Type {GetHalkStatus()} +Intimacy {HalkIntimacy()} +Health {HalkHealth()} +Attack {HalkAttack()} +Defense {HalkDefense()} +Intellect {HalkIntellect()} +{HalkSkill1()} | {HalkSkill2()} | {HalkSkill3()} + +Overlay Hash: {DatabaseManagerInstance.GetOverlayHash()} +"); + this.SavedGearStats = stats; + var formattedStats = string.Format( + CultureInfo.InvariantCulture, + @$"__【MHF-Z】Overlay {App.CurrentProgramVersion}__ *{this.GetWeaponClass()}({GetGender()})*{GetMetadata} + +Set Name: {GetGearDescription} +**{this.CurrentWeaponName}:** {this.GetRealWeaponName} +**Head:** {this.GetArmorHeadName} +**Chest:** {this.GetArmorChestName} +**Arms:** {this.GetArmorArmName} +**Waist:** {this.GetArmorWaistName} +**Legs:** {this.GetArmorLegName} +**Cuffs:** {this.GetCuffs} + +**Weapon Attack:** {this.BloatedWeaponAttack().ToString(CultureInfo.InvariantCulture)} | **Total Defense:** {this.TotalDefense().ToString(CultureInfo.InvariantCulture)} + +**Zenith Skills:** +{this.GetZenithSkills} + +**Automatic Skills:** +{this.GetAutomaticSkills} + +**Active Skills{showGouBoost}:** +{this.GetArmorSkills} + +**Caravan Skills:** +{this.GetCaravanSkills} + +**Diva:** +{GetDivaSkillNameFromID(this.DivaSkill())} +Song {(DivaSongActive ? "ON" : "OFF")} + +**Diva Prayer Gems:** +{GetDivaPrayerGems()} + +**Guild:** +{GetArmorSkill(this.GuildFoodSkill())} +{GetGuildPoogieEffect()} + +**Style Rank:** +{this.GetGSRSkills} + +**Items:** +{this.GetItemPouch} + +**Ammo:** +{this.GetAmmoPouch} + +**Poogie Item:** +{GetItemName(this.PoogieItemUseID())} + +**Road/Duremudira Skills:** +{this.GetRoadDureSkills} + +**Active Feature {(IsActiveFeatureOn(GetActiveFeature(), WeaponType()) ? "ON" : "OFF")}** + +**Courses:** +Main: {GetMainCourses()} +Additional: {GetAdditionalCourses()} + +**Halk:** +{(HalkOn() ? "Active" : "Inactive")} +Halk Pot {(IsHalkPotEquipped() || HalkPotEffectOn() ? "ON" : "OFF")} +LV{HalkLevel()} +Element Type {GetHalkElement()} +Status Type {GetHalkStatus()} +Intimacy {HalkIntimacy()} +Health {HalkHealth()} +Attack {HalkAttack()} +Defense {HalkDefense()} +Intellect {HalkIntellect()} +{HalkSkill1()} | {HalkSkill2()} | {HalkSkill3()} + +**Overlay Hash:** {DatabaseManagerInstance.GetOverlayHash()} +"); + this.MarkdownSavedGearStats = formattedStats; + return stats; } else { @@ -8056,6 +8393,32 @@ public string GetAdditionalCourses(long? rights) return string.Join(", ", courseNames).Trim(); } + public string GetMainCourses() + { + if (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() + { + if (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) @@ -8088,13 +8451,63 @@ private IEnumerable MapCourseRightsToNames(long rights, int bytePosition public bool IsActiveFeatureOn(long activeFeature, long weaponTypeID) { - if (activeFeature <= 0) + if (activeFeature <= 0 || activeFeature > (long)ActiveFeature.All) { return false; } - uint weaponFlag = (uint)Math.Pow(2, weaponTypeID); - return IsBitfieldContainingFlag((uint)activeFeature, (ActiveFeature)weaponFlag, (uint)ActiveFeature.All); + var weaponFlag = (ActiveFeature)Math.Pow(2, weaponTypeID); + var activeFeatureFlags = (ActiveFeature)activeFeature; + + return activeFeatureFlags.HasFlag(weaponFlag); + } + + public string GetHalkElement() + { + var element = "None"; + + if (HalkFire() >= 100) + { + return "Fire"; + } + if (HalkWater() >= 100) + { + return "Water"; + } + if (HalkThunder() >= 100) + { + return "Thunder"; + } + if (HalkIce() >= 100) + { + return "Ice"; + } + if (HalkDragon() >= 100) + { + return "Dragon"; + } + + return element; + } + + public string GetHalkStatus() + { + var status = "None"; + + if (HalkPoison() >= 100) + { + return "Poison"; + } + if (HalkSleep() >= 100) + { + return "Sleep"; + } + if (HalkParalysis() >= 100) + { + return "Paralysis"; + } + + return status; } public string GetHalkElement(QuestsHalk halk) @@ -8167,6 +8580,28 @@ public string GetGuildPoogieEffect(QuestsGuildPoogie poogie) return effect; } + public string GetGuildPoogieEffect() + { + var effect = "No Poogie"; + + if (GuildPoogie1Skill() >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[GuildPoogie1Skill()]; + } + + if (GuildPoogie2Skill() >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[GuildPoogie2Skill()]; + } + + if (GuildPoogie3Skill() >= 1) + { + return EZlion.Mapper.SkillGuildPoogie.IDName[GuildPoogie3Skill()]; + } + + return effect; + } + public string GetGuildPoogieEffect(List poogie) { var effect = "No Poogie"; @@ -8235,6 +8670,53 @@ public string GetDivaPrayerGems(QuestsDiva diva) return string.IsNullOrEmpty(gems) ? "None" : gems; } + public string GetDivaPrayerGems() + { + var gems = string.Empty; + var gemTypes = new long?[] { DivaPrayerGemRedSkill(), DivaPrayerGemYellowSkill(), DivaPrayerGemGreenSkill(), DivaPrayerGemBlueSkill() }; + var gemLevels = new long?[] { DivaPrayerGemRedLevel(), DivaPrayerGemYellowLevel(), DivaPrayerGemGreenLevel(), 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. /// @@ -8615,191 +9097,85 @@ public string GenerateCompendium() EZlion.Mapper.WeaponType.IDName.TryGetValue((int)mostUsedWeaponType, out var mostUsedWeaponTypeName); Item.IDName.TryGetValue((int)mostCommonDecorationID, out var mostCommonDecorationName); SkillArmor.IDName.TryGetValue((int)leastUsedArmorSkill, out var leastUsedArmorSkillName); + SkillGuildPoogie.IDName.TryGetValue((int)questCompendium.MostCommonGuildPoogie, out var mostCommonGuildPoogie); return string.Format( CultureInfo.InvariantCulture, - @"{0} (UTC) -{1} + $@"{createdAt} (UTC) +{createdBy} Quest -Most Completed Quest: {2} (Attempted {3}) [Quest ID {4}] -Most Attempted Quest: {5} (Completed {6}) [Quest ID {7}] -Total Quests Completed/Attempted: {8}/{9} -Quest Completion Time Elapsed (Average/Median): {10} / {11} -Total Time Elapsed during Quest: {12} -Most Completed Quest with Carts: {13} [Quest ID {14}] -Total Carts in Quest (Average/Median): {15} ({16}/{17}) -Quest Party Size (Average/Median/Mode): {18}/{19}/{20} -Percent of Solo Quests: {21} -Percent of Guild Food in Quests: {22} -Percent of Diva Skill in Quests: {23} -Percent of Skill Fruit in Quests: {24} -Most Common Diva Skill in Quests: {25} -Most Common Guild Food in Quests: {26} +Most Completed Quest: {mostCompletedQuest} (Attempted {mostCompletedQuestAttempts}) [Quest ID {mostCompletedQuestID}] +Most Attempted Quest: {mostAttemptedQuest} (Completed {mostAttemptedQuestCompletions}) [Quest ID {mostAttemptedQuestID}] +Total Quests Completed/Attempted: {totalQuestsCompleted}/{totalQuestsAttempted} +Quest Completion Time Elapsed (Average/Median): {TimeService.GetMinutesSecondsMillisecondsFromFrames((long)questCompletionTimeElapsedAverage)} / {TimeService.GetMinutesSecondsMillisecondsFromFrames((long)questCompletionTimeElapsedMedian)} +Total Time Elapsed during Quest: {TimeService.GetMinutesSecondsMillisecondsFromFrames(totalTimeElapsedDuringQuest)} +Most Completed Quest with Carts: {mostCompletedQuestWithCarts} [Quest ID {mostCompletedQuestWithCartsQuestID}] +Total Carts in Quest (Average/Median): {totalCartsInQuest} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", totalCartsInQuestAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", totalCartsInQuestMedian)}) +Quest Party Size (Average/Median/Mode): {string.Format(CultureInfo.InvariantCulture, "{0:0.##}", questPartySizeAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", questPartySizeMedian)}/{questPartySizeMode} +Percent of Solo Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", percentOfSoloQuests)} +Percent of Guild Poogie in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", questCompendium.PercentOfGuildPoogie)} +Percent of Guild Food in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", percentOfGuildFood)} +Percent of Diva Song in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", questCompendium.PercentOfDivaSong)} +Percent of Diva Skill in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", percentOfDivaSkill)} +Percent of Diva Prayer Gem in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", questCompendium.PercentOfDivaPrayerGem)} +Percent of Skill Fruit in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", percentOfSkillFruit)} +Percent of Halk in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", questCompendium.PercentOfHalkOn)} +Percent of Halk Pot Effect in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", questCompendium.PercentOfHalkPotEffectOn)} +Percent of Active Feature in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", questCompendium.PercentOfActiveFeature)} +Percent of Course Attack Boost in Quests: {string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", questCompendium.PercentOfCourseAttackBoost)} +Most Common Guild Poogie in Quests: {mostCommonGuildPoogie} +Most Common Guild Food in Quests: {mostCommonGuildFoodName} +Most Common Diva Skill in Quests: {mostCommonDivaSkillName} Gear -Most Used Weapon Type: {27} -Total Unique Armor Pieces/Weapons/Decorations used: {28}/{29}/{30} -Most Common Decoration: {31} [ID {32}] -Least Used Armor Skill: {33} +Most Used Weapon Type: {mostUsedWeaponTypeName} +Total Unique Armor Pieces/Weapons/Decorations used: {totalUniqueArmorPieces}/{totalUniqueWeapons}/{totalUniqueDecorations} +Most Common Decoration: {mostCommonDecorationName} [ID {mostCommonDecorationID.ToString("X", CultureInfo.InvariantCulture)}] +Least Used Armor Skill: {leastUsedArmorSkillName} Hunter Performance -Highest True Raw (Average/Median): {34} ({35}/{36}) [Run ID {37}] -Highest Single Hit Damage (Average/Median): {38} ({39}/{40}) [Run ID {41}] -Highest Hit Count (Average/Median): {42} ({43}/{44}) [Run ID {45}] -Highest Hits Taken/Blocked (Average/Median): {46} ({47}/{48}) [Run ID {49}] -Highest DPS (Average/Median): {50} ({51}/{52}) [Run ID {53}] -Highest Hits per Second (Average/Median): {54} ({55}/{56}) [Run ID {57}] -Highest Hits Taken/Blocked per Second (Average/Median): {58} ({59}/{60}) [Run ID {61}] -Highest Actions per Minute (Average/Median): {62} ({63}/{64}) [Run ID {65}] -Total Hits Count: {66} -Total Hits Taken/Blocked: {67} -Total Actions: {68} -Health (Average/Median/Mode): {69}/{70}/{71} -Stamina (Average/Median/Mode): {72}/{73}/{74} +Highest True Raw (Average/Median): {highestTrueRaw} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", trueRawAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", trueRawMedian)}) [Run ID {highestTrueRawRunID}] +Highest Single Hit Damage (Average/Median): {highestSingleHitDamage} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", singleHitDamageAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", singleHitDamageMedian)}) [Run ID {highestSingleHitDamageRunID}] +Highest Hit Count (Average/Median): {highestHitCount} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitCountAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitCountMedian)}) [Run ID {highestHitCountRunID}] +Highest Hits Taken/Blocked (Average/Median): {highestHitsTakenBlocked} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsTakenBlockedAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsTakenBlockedMedian)}) [Run ID {highestHitsTakenBlockedRunID}] +Highest DPS (Average/Median): {string.Format(CultureInfo.InvariantCulture, "{0:0.##}", highestDPS)} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", dPSAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", dPSMedian)}) [Run ID {highestDPSRunID}] +Highest Hits per Second (Average/Median): {string.Format(CultureInfo.InvariantCulture, "{0:0.##}", highestHitsPerSecond)} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsPerSecondAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsPerSecondMedian)}) [Run ID {highestHitsPerSecondRunID}] +Highest Hits Taken/Blocked per Second (Average/Median): {string.Format(CultureInfo.InvariantCulture, "{0:0.##}", highestHitsTakenBlockedPerSecond)} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsTakenBlockedPerSecondAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsTakenBlockedPerSecondMedian)}) [Run ID {highestHitsTakenBlockedPerSecondRunID}] +Highest Actions per Minute (Average/Median): {string.Format(CultureInfo.InvariantCulture, "{0:0.##}", highestActionsPerMinute)} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", actionsPerMinuteAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", actionsPerMinuteMedian)}) [Run ID {highestActionsPerMinuteRunID}] +Total Hits Count: {totalHitsCount} +Total Hits Taken/Blocked: {totalHitsTakenBlocked} +Total Actions: {totalActions} +Health (Average/Median/Mode): {string.Format(CultureInfo.InvariantCulture, "{0:0.##}", healthAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", healthMedian)}/{healthMode} +Stamina (Average/Median/Mode): {string.Format(CultureInfo.InvariantCulture, "{0:0.##}", staminaAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", staminaMedian)}/{staminaMode} Mezeporta Festival (MezFes) -Minigames Played: {75} -Uruki Pachinko Times Played: {76} -Uruki Pachinko High-score (Average/Median): {77} ({78}/{79}) -Guuku Scoop Times Played: {80} -Guuku Scoop High-score (Average/Median): {81} ({82}/{83}) -Nyanrendo Times Played: {84} -Nyanrendo High-score (Average/Median): {85} ({86}/{87}) -Panic Honey Times Played: {88} -Panic Honey High-score (Average/Median): {89} ({90}/{91}) -Dokkan Battle Cats Times Played: {92} -Dokkan Battle Cats High-score (Average/Median): {93} ({94}/{95}) +Minigames Played: {minigamesPlayed} +Uruki Pachinko Times Played: {urukiPachinkoTimesPlayed} +Uruki Pachinko High-score (Average/Median): {urukiPachinkoHighscore} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", urukiPachinkoScoreAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", urukiPachinkoScoreMedian)}) +Guuku Scoop Times Played: {guukuScoopTimesPlayed} +Guuku Scoop High-score (Average/Median): {guukuScoopHighscore} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", guukuScoopScoreAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", guukuScoopScoreMedian)}) +Nyanrendo Times Played: {nyanrendoTimesPlayed} +Nyanrendo High-score (Average/Median): {nyanrendoHighscore} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", nyanrendoScoreAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", nyanrendoScoreMedian)}) +Panic Honey Times Played: {panicHoneyTimesPlayed} +Panic Honey High-score (Average/Median): {panicHoneyHighscore} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", panicHoneyScoreAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", panicHoneyScoreMedian)}) +Dokkan Battle Cats Times Played: {dokkanBattleCatsTimesPlayed} +Dokkan Battle Cats High-score (Average/Median): {dokkanBattleCatsHighscore} ({string.Format(CultureInfo.InvariantCulture, "{0:0.##}", dokkanBattleCatsScoreAverage)}/{string.Format(CultureInfo.InvariantCulture, "{0:0.##}", dokkanBattleCatsScoreMedian)}) Monster -Highest Monster Attack Multiplier: {96} [Run ID {97}] -Lowest Monster Attack Multiplier: {98} [Run ID {99}] -Highest Monster Defense Rate: {100} [Run ID {101}] -Lowest Monster Defense Rate: {102} [Run ID {103}] -Highest Monster Size Multiplier: {104} [Run ID {105}] -Lowest Monster Size Multiplier: {106} [Run ID {107}] -Total Large Monsters Hunted: {108} -Total Small Monsters Hunted: {109} +Highest Monster Attack Multiplier: {monster1AttackMultiplierHighest} [Run ID {monster1AttackMultiplierHighestRunID}] +Lowest Monster Attack Multiplier: {monster1AttackMultiplierLowest} [Run ID {monster1AttackMultiplierLowestRunID}] +Highest Monster Defense Rate: {monster1DefenseRateHighest} [Run ID {monster1DefenseRateHighestRunID}] +Lowest Monster Defense Rate: {monster1DefenseRateLowest} [Run ID {monster1DefenseRateLowestRunID}] +Highest Monster Size Multiplier: {monster1SizeMultiplierHighest} [Run ID {monster1SizeMultiplierHighestRunID}] +Lowest Monster Size Multiplier: {monster1SizeMultiplierLowest} [Run ID {monster1SizeMultiplierLowestRunID}] +Total Large Monsters Hunted: {totalLargeMonstersHunted} +Total Small Monsters Hunted: {totalSmallMonstersHunted} Miscellaneous -Total Overlay Sessions: {110} -Session Duration (Highest/Lowest/Average/Median): {111} / {112} / {113} / {114} -", - createdAt, - createdBy, - mostCompletedQuest, - mostCompletedQuestAttempts, - mostCompletedQuestID, - mostAttemptedQuest, - mostAttemptedQuestCompletions, - mostAttemptedQuestID, - totalQuestsCompleted, - totalQuestsAttempted, - TimeService.GetMinutesSecondsMillisecondsFromFrames((long)questCompletionTimeElapsedAverage), - TimeService.GetMinutesSecondsMillisecondsFromFrames((long)questCompletionTimeElapsedMedian), - TimeService.GetMinutesSecondsMillisecondsFromFrames(totalTimeElapsedDuringQuest), - mostCompletedQuestWithCarts, - mostCompletedQuestWithCartsQuestID, - totalCartsInQuest, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", totalCartsInQuestAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", totalCartsInQuestMedian), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", questPartySizeAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", questPartySizeMedian), - questPartySizeMode, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", percentOfSoloQuests), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", percentOfGuildFood), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", percentOfDivaSkill), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}%", percentOfSkillFruit), - mostCommonDivaSkillName, - mostCommonGuildFoodName, - mostUsedWeaponTypeName, - totalUniqueArmorPieces, - totalUniqueWeapons, - totalUniqueDecorations, - mostCommonDecorationName, - mostCommonDecorationID.ToString("X", CultureInfo.InvariantCulture), - leastUsedArmorSkillName, - highestTrueRaw, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", trueRawAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", trueRawMedian), - highestTrueRawRunID, - highestSingleHitDamage, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", singleHitDamageAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", singleHitDamageMedian), - highestSingleHitDamageRunID, - highestHitCount, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitCountAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitCountMedian), - highestHitCountRunID, - highestHitsTakenBlocked, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsTakenBlockedAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsTakenBlockedMedian), - highestHitsTakenBlockedRunID, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", highestDPS), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", dPSAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", dPSMedian), - highestDPSRunID, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", highestHitsPerSecond), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsPerSecondAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsPerSecondMedian), - highestHitsPerSecondRunID, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", highestHitsTakenBlockedPerSecond), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsTakenBlockedPerSecondAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", hitsTakenBlockedPerSecondMedian), - highestHitsTakenBlockedPerSecondRunID, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", highestActionsPerMinute), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", actionsPerMinuteAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", actionsPerMinuteMedian), - highestActionsPerMinuteRunID, - totalHitsCount, - totalHitsTakenBlocked, - totalActions, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", healthAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", healthMedian), - healthMode, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", staminaAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", staminaMedian), - staminaMode, - minigamesPlayed, - urukiPachinkoTimesPlayed, - urukiPachinkoHighscore, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", urukiPachinkoScoreAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", urukiPachinkoScoreMedian), - guukuScoopTimesPlayed, - guukuScoopHighscore, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", guukuScoopScoreAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", guukuScoopScoreMedian), - nyanrendoTimesPlayed, - nyanrendoHighscore, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", nyanrendoScoreAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", nyanrendoScoreMedian), - panicHoneyTimesPlayed, - panicHoneyHighscore, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", panicHoneyScoreAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", panicHoneyScoreMedian), - dokkanBattleCatsTimesPlayed, - dokkanBattleCatsHighscore, - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", dokkanBattleCatsScoreAverage), - string.Format(CultureInfo.InvariantCulture, "{0:0.##}", dokkanBattleCatsScoreMedian), - monster1AttackMultiplierHighest, - monster1AttackMultiplierHighestRunID, - monster1AttackMultiplierLowest, - monster1AttackMultiplierLowestRunID, - monster1DefenseRateHighest, - monster1DefenseRateHighestRunID, - monster1DefenseRateLowest, - monster1DefenseRateLowestRunID, - monster1SizeMultiplierHighest, - monster1SizeMultiplierHighestRunID, - monster1SizeMultiplierLowest, - monster1SizeMultiplierLowestRunID, - totalLargeMonstersHunted, - totalSmallMonstersHunted, - totalOverlaySessions, - TimeSpan.FromSeconds(sessionDurationHighest).ToString(TimeFormats.HoursMinutesSecondsMilliseconds, CultureInfo.InvariantCulture), - TimeSpan.FromSeconds(sessionDurationLowest).ToString(TimeFormats.HoursMinutesSecondsMilliseconds, CultureInfo.InvariantCulture), - TimeSpan.FromSeconds(sessionDurationAverage).ToString(TimeFormats.HoursMinutesSecondsMilliseconds, CultureInfo.InvariantCulture), - TimeSpan.FromSeconds(sessionDurationMedian).ToString(TimeFormats.HoursMinutesSecondsMilliseconds, CultureInfo.InvariantCulture)); +Total Overlay Sessions: {totalOverlaySessions} +Session Duration (Highest/Lowest/Average/Median): {TimeSpan.FromSeconds(sessionDurationHighest).ToString(TimeFormats.HoursMinutesSecondsMilliseconds, CultureInfo.InvariantCulture)} / {TimeSpan.FromSeconds(sessionDurationLowest).ToString(TimeFormats.HoursMinutesSecondsMilliseconds, CultureInfo.InvariantCulture)} / {TimeSpan.FromSeconds(sessionDurationAverage).ToString(TimeFormats.HoursMinutesSecondsMilliseconds, CultureInfo.InvariantCulture)} / {TimeSpan.FromSeconds(sessionDurationMedian).ToString(TimeFormats.HoursMinutesSecondsMilliseconds, CultureInfo.InvariantCulture)} +"); } public static string GetGameArmorSkillsHealthAndStamina => "Health and Stamina\n\nHealth\t○\tHealth+50\t40\tMaximum Health +50\n\nHealth+40\t30\tMaximum Health +40\n\nHealth+30\t20\tMaximum Health +30\n\nHealth+20\t15\tMaximum Health +20\n\nHealth+10\t10\tMaximum Health +10\n\nHealth-10\t-10\tMaximum Health -10\n\nHealth-20\t-15\tMaximum Health -20\n\nHealth-30\t-20\tMaximum Health -30\n\nRecovery Speed\t○\tRecovery Speed+2\t20\t4x Health Recovery Speed\n\nRecovery Speed+1\t10\t3x Health Recovery Speed\n\nRecovery Speed-1\t-10\t3x Slower Health Recovery Speed\n\nRecovery Speed-2\t-20\t4x Slower Health Recovery Speed\n\nHunger\t○\tHunger Negated\t15\tStamina bar length does not decrease in length over time.\n\nHunger Halved\t10\tStamina bar length decreases at 0.5x the speed over time.\n\nHunger Up (Sm)\t-10\tStamina bar length decreases at 1.5x the speed over time\n\nHunger Up (Lg)\t-15\tStamina bar length decreases at 2.0x the speed over time\n\nRecovery\t×\tRecovery Items Up\t10\tRecovery item effect boosted 1.25x\n\nRecovery Items Down\t-10\tRecovery item effectlowered to 0.75x\n\nVampirism\t×\tVampirism+2\t20\tWhen attacking a monster, there is an 80% that your Health will recover.\n\nVampirism+1\t10\tWhen attacking a monster, there is a 60% that your Health will recover.\n\nHerbal Science\t×\tMedical Sage\t10\tInstant recovery of any Red HP when using any healing item.\n\nAdditional effects if multiple party members have the skill:\n\n2Players: recovery items apply to the entire party.\n\n3Players: recovery items apply to the entire party, +20extra HP Recovery\n\n4Players: recovery items apply to the entire party, +50extra HP Recovery\n\n※※Stacks with Recovery skill, only pure recovery items are party wide (e.g.Max Potions yes,Ancient Potions no.)\n\nStamina Recovery\t○\tStamina Recovery Up【Large】\t20\tDoubles stamina recovery speed over time\n\nStamina Rec (Small)\t10\tStamina recovery speed increases by 1.5 times over time.\n\nStamina Rec Down\t-10\tHalves stamina recovery speed over time\n\nStamina\t○\t\n\nStamina values usually decrease by 15 units\n\nPeerless\t20\tStamina decrease rate is halved (decrease is reduced to 8 units)\n\nIn addition, the reduction of stamina when evading or guarding is reduced to 50%.\n\nMarathon Runner\t10\tStamina decrease rate is halved (decrease is reduced to 8 units)\n\nIn addition, the reduction of stamina when evading or guarding is reduced to 75%.\n\nShort Sprinter\t-10\tStamina depletion speed is increased by 1.2 times (up to 18 units)\n\nEating\t×\tSpeed Eating\t10\tIncreases the speed of eating consumables such as meat and healing potions.\n\nSlow Eating\t-10\tReduces the speed of eating consumables such as meat and healing potions.\n\nGluttony\t×\tScavenger\t15\tUsing consumables restores 25 maximum stamina\n\nGourmand\t10\tStamina recovery when eating meat is increased by 25"; @@ -10230,18 +10606,9 @@ public string GetDivaSkillForImage public string GetPoogieItemForImage => GetItemName(this.PoogieItemUseID()); - public string GetAlternateMonsterImage(int id, bool forDiscord = false) + public string GetAlternateMonsterImage(int id) { - var pathContext = string.Empty; - - if (forDiscord) - { - pathContext = @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/monster/"; - } - else - { - pathContext = "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/monster/"; - } + var pathContext = @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/monster/"; switch (id) { @@ -12975,7 +13342,23 @@ public void ClearGraphCollections() } } - public string OverlayModeWatermarkText => ShowOverlayModeFinalMode() ? GetFinalOverlayModeForDisplay() : GetOverlayModeForStorage(); + public string OverlayModeWatermarkText + { + get + { + if (ShowOverlayModeFinalMode()) + { + return GetFinalOverlayModeForDisplay(); + } + + if (GetOverlayModeForStorage() == "Speedrun") + { + return $"Speedrun ({GetRunBuffsTag(GetRunBuffs())})"; + } + + return GetOverlayModeForStorage(); + } + } public string QuestIDBind => this.QuestID().ToString(CultureInfo.InvariantCulture); @@ -13005,6 +13388,22 @@ public void ClearGraphCollections() new QuestLogsOption { Name = "Quest Pace", IsSelected = false }, }; + public ObservableCollection RunBuffsSearchOption { get; set; } = new ObservableCollection() + { + new QuestLogsOption { Name = "Halk", IsSelected = false }, + new QuestLogsOption { Name = "Poogie Item", IsSelected = false }, + new QuestLogsOption { Name = "Diva Song", IsSelected = false }, + new QuestLogsOption { Name = "Halk Pot Effect", IsSelected = false }, + new QuestLogsOption { Name = "Bento", IsSelected = false }, + new QuestLogsOption { Name = "Guild Poogie", IsSelected = false }, + new QuestLogsOption { Name = "Active Feature", IsSelected = false }, + new QuestLogsOption { Name = "Guild Food", IsSelected = false }, + new QuestLogsOption { Name = "Diva Skill", IsSelected = false }, + new QuestLogsOption { Name = "Secret Technique", IsSelected = false }, + new QuestLogsOption { Name = "Diva Prayer Gem", IsSelected = false }, + new QuestLogsOption { Name = "Course Attack Boost", IsSelected = false }, + }; + public QuestLogsOption SelectedOption { get; set; } = new QuestLogsOption { Name = "Default", IsSelected = true }; public static string StaticReplaceFirstFF(string hexColor) @@ -13097,7 +13496,7 @@ public string GuildFoodTimeLeft } var expiry = GuildFoodStart() + (60 * 90); - double secondsLeft = expiry - ServerHeartbeat(); + double secondsLeft = expiry - ServerHeartbeat; if (secondsLeft <= 0) { @@ -13112,13 +13511,15 @@ public string DivaSongTimeLeft { get { - if (DivaSongStart() <= 0) + var divaSongStart = Math.Max(DivaSongStart(), DivaSongFromGuildStart()); + + if (divaSongStart <= 0) { return "0m"; } - var expiry = DivaSongStart() + (60 * 90); - double secondsLeft = expiry - ServerHeartbeat(); + var expiry = divaSongStart + (60 * 90); + double secondsLeft = expiry - ServerHeartbeat; if (secondsLeft <= 0) { @@ -13178,7 +13579,7 @@ public static bool ShowOverlayModeFinalMode() return s.OverlayWatermarkMode == "Final"; } - public static string FindAreaIcon(int id) + public static string FindAreaIcon(int id, bool forDiscord = false) { var areaGroup = new List { 0 }; @@ -13193,7 +13594,7 @@ public static string FindAreaIcon(int id) } } - return DetermineAreaIcon(areaGroup); + return DetermineAreaIcon(areaGroup, forDiscord); } /// @@ -13348,28 +13749,44 @@ public string GetArmorColor() /// /// The identifier. /// - public static string GetAreaIconFromID(int id) // TODO: are highlands, tidal island or painted falls icons correct? + public static string GetAreaIconFromID(int id, bool forDiscord = false) // TODO: are highlands, tidal island or painted falls icons correct? { if (id >= 470 && id < 0) { - return "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/cattleya.png"; + if (forDiscord) + { + return "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/cattleya.png"; + } + + return @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/cattleya.png"; } else { - return FindAreaIcon(id); + return FindAreaIcon(id, forDiscord); } } - public static string DetermineAreaIcon(List key) + public static string DetermineAreaIcon(List key, bool forDiscord = false) { var areaIcon = AreaIcons.AreaIconID.ContainsKey(key); if (!areaIcon) { - return "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/cattleya.png"; + if (forDiscord) + { + return "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/cattleya.png"; + } + + return @"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/cattleya.png"; } else { - return AreaIcons.AreaIconID[key]; + var areaIconValue = AreaIcons.AreaIconID[key]; + if (forDiscord) + { + areaIconValue = areaIconValue.ToString().Replace(@"pack://application:,,,/MHFZ_Overlay;component/Assets/Icons/png/area/", "https://raw.githubusercontent.com/DorielRivalet/mhfz-overlay/main/img/icon/"); + } + + return areaIconValue; } } diff --git a/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml b/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml index be7b2a2f..556505a7 100644 --- a/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml +++ b/MHFZ_Overlay/Views/Windows/ConfigWindow.xaml @@ -148,6 +148,9 @@ Select an option from the Section drop-down menu in order to view these statistics. The compendium section may take some time to load. + + + See the FAQ for checking the run buffs of old categories. @@ -290,6 +293,14 @@ + + + + + + + + + +