2023-01-07 23:38:50 +00:00
using Lumina.Excel.GeneratedSheets ;
using System.Collections.Generic ;
using System.Linq ;
namespace QuestMap
{
internal class Filters
{
private Plugin Plugin ;
private List < IFiltered > FilterConditions { get ; } = new List < IFiltered > {
// starting city questlines
new OneQuestOf ( 65_575 , 65_643 , 66_130 ) , // Coming to [starting city]
new OneQuestOf ( 65_621 , 65_644 , 65_645 , 65_659 , 65_660 , 66_104 , 66_105 , 66_106 ) , // Close to Home (one per starting class)
#region Gridania
new ConditionalQuests (
65_575 , // Coming to Gridania
// MSQ
65_564 , // To the Bannock
65_737 , // Passing Muster
65_981 , // Chasing Shadows
65_664 , // Eggs over Queasy (old)
69_390 , // Eggs over Queasy
65_711 , // Surveying the Damage
65_734 , // Butcher of Greentear (removed)
65_661 , // A Soldier's Breakfast (old)
69_391 , // A Soldier's Breakfast
65_665 , // Spirithold Broken
65_712 , // On the Bentbranch
65_912 , // You Shall Not Trespass
65_913 , // Don't Look Down
65_915 , // In the Grim Darkness of the Forest
65_916 , // Threat Level Elevated
65_917 , // Migrant Marauders
65_920 , // A Hearer Is Often Late
65_923 , // Salvaging the Scene
65_697 , // Leia's Legacy
65_982 , // Dread is in the Air
65_983 , // To Guard a Guardian
65_984 , // Festive Endeavors
65_985 , // Renewing the Covenant
66_043 , // The Gridanian Envoy
66_210 , // Call of the Sea, used in both Gridania & Limsa
// side quests
65_756 , // Leves of Bentbranch
65_596 , // Simply the Hest
65_537 , // A Good Adventurer is Hard to Find
65_573 , // Population Control
65_568 , // A Hard Nut to Crack
65_570 , // Derision of Labor
65_732 , // An Eft for Effort
65_708 , // More than a Flesh Wound
65_663 , // Parasite Cleave
65_666 , // Soil Despoilers
65_914 // Look, but Won't Touch
// This may not be a complete list, my main char is from Gridania so this doesn't matter much to me
) ,
new ReplacedQuest ( 65_664 , 69_390 ) , // Eggs over Queasy
new ReplacedQuest ( 65_661 , 69_391 ) , // A Soldier's Breakfast
new UnobtainableQuest ( 66_964 ) , // He's Got a Ticket to Ride
new UnobtainableQuest ( 65_734 ) , // Butcher of Greentear
new UnobtainableQuest ( 65_910 ) , // Feeding Time
new UnobtainableQuest ( 65_692 ) , // Ruffled Feathers
new UnobtainableQuest ( 65_918 ) , // Skeletons in My Deepcroft
new UnobtainableQuest ( 65_695 ) , // Lights Out
#endregion Gridania
#region Limsa
new ConditionalQuests (
65_643 , // Coming to Limsa Lominsa
// MSQ
65_998 , // On to Summerford
65_999 , // Dressed to Call
66_079 , // Lurkers in the Grotto
66_001 , // Washed Up
66_002 , // Double Dealing
66_003 , // Loam Maintenance
66_004 , // Plowshares to Swords
66_005 , // Just Deserts
65_933 , // Sky-high
65_938 , // Thanks a Million
65_939 , // Relighting the Torch
65_942 , // On the Drydocks
65_948 , // Without a Doubt
65_951 , // Righting the Shipwright
65_949 , // Do Angry Pirates Dream
65_950 , // Victory in Peril
66_225 , // Men of the Blue Tattoos
66_080 , // Feint and Strike
66_226 , // High Society
66_081 , // A Mizzenmast Repast
66_082 , // The Lominsan Envoy
66_210 , // Call of the Sea, used in both Gridania & Limsa
// side quests
66_229 , // Leves of Swiftperch
65_595 , // Simply the Hest
65_647 , // Making a Name
65_648 , // Suspiciously Sober
65_658 , // Glory Days
66_199 , // Fool Me Once
66_008 , // The Time Is Ripe
66_009 , // Orange Crush
66_000 , // Further Afield
66_006 , // Yarzon, Yarzoff
66_001 , // Washed Up,
66_002 , // Double Dealing
66_010 , // A Pound of Cure
66_023 , // Meet, Greet, and Deceit
65_936 , // Keeping it Fresh
65_937 , // Baiting Buzzards
65_940 , // Farmer of Fortune
65_941 , // Need to Breed
66_011 , // Cry Me a Liver
66_012 , // Wool's Errand
66_013 , // Flour Power
66_014 , // Kobolds and Ingredients
66_015 , // Bait and Swat
66_022 // Kobolds Ahoy
) ,
new UnobtainableQuest ( 65_934 ) , // Courier for a Day
#endregion Limsa
#region Ul ' dah
new ConditionalQuests (
66_130 , // Coming to Ul'dah
// MSQ
66_131 , // We Must Rebuild
66_207 , // Nothing to See Here
66_086 , // Underneath the Sultantree
65_839 , // Step Nine
65_842 , // Prudence at this Junction (old)
69_388 , // Prudence at this Junction
65_843 , // Out of House and Home
65_856 , // Way Down in the Hole
66_159 , // Takin' What They're Givin'
65_864 , // Supply & Demand
66_039 , // Give It to Me Raw
65_865 , // The Perfect Swarm
65_866 , // The Letter to Lost Hope
65_867 , // Heir Today, Gone Tomorrow (old)
69_389 , // Heir Today, Gone Tomorrow
65_868 , // Passing the Blade
65_869 , // Following Footfalls
65_870 , // Storms on the Horizon
65_872 , // Oh Captain, My Captain
66_164 , // Secrets and Lies
66_087 , // Duty, Honor, Country
66_177 , // A Matter of Tradition
66_088 , // A Royal Reception
66_064 , // The Ul'dahn Envoy
66_209 , // Call of the Sea, used only in Ul'dah
// side quests
66_223 , // Leves of Horizon
65_594 , // Simply the Hest
65_857 , // The Slaying of the Shrews
65_858 , // Listen to Your Fish
65_840 , // The Tasting of the Shrews
65_862 , // Sometimes the Old Ways Are Best
65_844 , // In the Court of the Rat King
65_877 , // The Scent of a Mongrel
65_878 , // Lominsan Rubbish
65_924 , // Bloodied and Bowed
65_925 , // Fantastic Voyage
65_926 , // Catch Your Breath
66_040 , // No Tool Gets Left Behind
66_041 , // Angling Ankle-Biters
66_042 , // This Fishwife's Life
66_066 , // Alternative Medicine
66_067 , // Need Not Apply in Person
66_109 // Fringe Benefits
) ,
new UnobtainableQuest ( 65_860 ) , // Disorderly Conduct
new UnobtainableQuest ( 65_841 ) , // Until a Quieter Time
new UnobtainableQuest ( 65_863 ) , // Spriggan Cleaning
new UnobtainableQuest ( 65_871 ) , // Compulsory Catering
new UnobtainableQuest ( 66_965 ) , // Lend Me Your Ears Already
new ReplacedQuest ( 65_842 , 69_388 ) , // Prudence at this Junction
new ReplacedQuest ( 65_867 , 69_389 ) , // Heir Today, Gone Tomorrow
#endregion Ul ' dah
// Grand Company specific quests - can only complete them for one GC, even if you switch later
// Shadows Uncast & Gilding the Bilbious can be done once per GC, so they're not exclusive
new OneQuestOf ( 66_216 , 66_217 , 66_218 ) , // The Company You Keep
new OneQuestOf ( 66_219 , 66_220 , 66_221 ) , // The Company You Keep follow-up quest
new OneQuestOf ( 66_236 , 66_237 , 66_238 ) , // My Little Chocobo
new OneQuestOf ( 66_640 , 66_641 , 66_642 ) , // A Pup No Longer
new OneQuestOf ( 67_001 , 67_002 , 67_003 ) , // Call of the Wild
new OneQuestOf ( 67_063 , 67_064 , 67_065 ) , // Like Civilized Men and Women
new OneQuestOf ( 67_099 , 67_100 , 67_101 ) , // Let the Hunt Begin
new OneQuestOf ( 67_925 , 67_926 , 67_927 ) , // Squadron and Commander
// class quests: depending on whether or not it's your starting class, you get a different quest
// Format: ([quest id if this was your starting class], [so you want to be a lancer], [way of the lancer, if picked up later], [your first spear])
new StartingJobQuest ( 65_557 , 65_717 , 65_667 , 65_755 ) , // ARC
new StartingJobQuest ( 65_558 , 65_718 , 65_669 , 65_747 ) , // CNJ // seems odd that the replaced if for CNJ & LNC aren't the same order as the original ids
new StartingJobQuest ( 65_559 , 65_716 , 65_668 , 65_754 ) , // LNC
new StartingJobQuest ( 65_789 , 65_713 , 65_821 , 65_822 ) , // GLA
new StartingJobQuest ( 65_847 , 65_715 , 65_846 , 65_848 ) , // MRD
new StartingJobQuest ( 65_881 , 65_719 , 65_880 , 65_882 ) , // THM
new StartingJobQuest ( 65_989 , 65_987 , 65_988 , 65_990 ) , // ACN
new StartingJobQuest ( 66_069 , 65_714 , 66_068 , 66_089 ) , // PGL
// duplicate quests - unsure what happened to those, as the quest ids are very close; might be dependent on your starting job/city but isn't a thing for all classes
new OneQuestOf ( 65_571 , 65_679 ) , // LNC: Courage of Stone
new OneQuestOf ( 65_850 , 65_851 ) , // MRD: Wake of Destruction
new OneQuestOf ( 65_884 , 65_885 ) , // THM: The Threat of Paucity
new OneQuestOf ( 65_992 , 65_993 ) , // ACN: Tactical Planning
new OneQuestOf ( 65_797 , 65_824 ) , // GLA: Ul'dah's Most Wanted, large id difference
new OneQuestOf ( 66_091 , 66_234 ) , // PGL: Burning Up the Quarter Malm
// quest choices
new OneQuestOf ( 66_968 , 66_969 , 66_970 ) , // An Ill-conceived Venture
new OneQuestOf ( 69_256 , 69_257 ) , // NieR: Tails, You Lose -- Heads, I Win
new OneQuestOf ( 69_336 , 69_337 ) , // Qitari: First Stela
new OneQuestOf ( 69_338 , 69_339 ) , // Qitari: Second Stela
new OneQuestOf ( 69_340 , 69_341 ) , // Qitari: Third Stela
new IslandSanctuaryQuest ( ) ,
// Ishgard Restoration, I think this was something to do with interacting with the board when the relvant stage was finished
// These aren't in the journal, and they don't have any wiki pages either. As of 6.28, none of them seems obtainable.
new UnobtainableQuest ( 69_296 ) , // The Mendicant's Court
new UnobtainableQuest ( 69_377 ) , // The New Nest
new UnobtainableQuest ( 69_508 ) , // Featherfall
new UnobtainableQuest ( 69_578 ) , // The Risensong Quarter
// updated quests
new ReplacedQuest ( 65_603 , 65_670 ) , // BRD: School of Hard Nooks -> Training with Leih
new ReplacedQuest ( 65_627 , 65_683 ) , // WHM: Trial by Wind
new ReplacedQuest ( 66_957 , 68_553 ) , // Glamour unlock
new ReplacedQuest ( 66_958 , 68_554 ) , // Glamour prism crafting
new ReplacedQuest ( 66_097 , 67_823 ) , // ARR Relics: The Vital Title
new UnobtainableQuest ( 67_819 ) , // A Seat at the Feast
2023-01-19 09:57:51 +00:00
new UnobtainableQuest ( 66_033 ) , // But I Hardly Noah
new UnobtainableQuest ( 66_034 ) , // The Gift of the Archmagus
2023-01-07 23:38:50 +00:00
} ;
public Filters ( Plugin plugin )
{
Plugin = plugin ;
}
public bool IsObtainable ( Quest quest )
{
if ( Plugin . Common . Functions . Journal . IsQuestCompleted ( quest ) )
return true ;
if ( FilterConditions . Any ( f = > f . IsUnobtainable ( Plugin , quest . RowId ) ) )
return false ;
return true ;
}
internal interface IFiltered
{
bool IsUnobtainable ( Plugin plugin , uint quest ) ;
}
internal class OneQuestOf : IFiltered
{
public List < uint > QuestIds { get ; }
public OneQuestOf ( params uint [ ] questIds )
{
QuestIds = questIds . ToList ( ) ;
}
public bool IsUnobtainable ( Plugin plugin , uint quest )
{
return QuestIds . Contains ( quest ) & & QuestIds . Any ( plugin . Common . Functions . Journal . IsQuestCompleted ) ;
}
}
internal class ReplacedQuest : IFiltered
{
public uint OriginalQuestId { get ; }
public uint NewQuestId { get ; }
public ReplacedQuest ( uint originalQuestId , uint newQuestId )
{
OriginalQuestId = originalQuestId ;
NewQuestId = newQuestId ;
}
public bool IsUnobtainable ( Plugin plugin , uint quest )
{
return quest = = OriginalQuestId | | ( quest = = NewQuestId & & plugin . Common . Functions . Journal . IsQuestCompleted ( OriginalQuestId ) ) ;
}
}
internal class ConditionalQuests : IFiltered
{
public uint RequiredQuest { get ; }
public List < uint > FollowUpQuests { get ; }
public ConditionalQuests ( uint requiredQuest , params uint [ ] followUpQuestIds )
{
RequiredQuest = requiredQuest ;
FollowUpQuests = followUpQuestIds . ToList ( ) ;
}
public bool IsUnobtainable ( Plugin plugin , uint quest )
{
if ( plugin . Common . Functions . Journal . IsQuestCompleted ( RequiredQuest ) )
return false ;
return FollowUpQuests . Contains ( quest ) ;
}
}
internal class StartingJobQuest : IFiltered
{
public uint StartingClassQuestId ;
public List < uint > LaterClassQuestIds ;
public StartingJobQuest ( uint wayOfTheMsqQuestId , uint soYouWantToBeAQuestId , uint wayOfTheSideQuestId , uint myFirstWeaponQuestId )
{
StartingClassQuestId = wayOfTheMsqQuestId ;
LaterClassQuestIds = new List < uint > { soYouWantToBeAQuestId , wayOfTheSideQuestId , myFirstWeaponQuestId } ;
}
public bool IsUnobtainable ( Plugin plugin , uint quest )
{
if ( plugin . Common . Functions . Journal . IsQuestCompleted ( StartingClassQuestId ) )
return LaterClassQuestIds . Contains ( quest ) ;
else
return quest = = StartingClassQuestId ;
}
}
internal class UnobtainableQuest : IFiltered
{
public uint QuestId { get ; }
public UnobtainableQuest ( uint questId )
{
this . QuestId = questId ;
}
public bool IsUnobtainable ( Plugin plugin , uint quest )
{
return quest = = QuestId ;
}
}
internal class IslandSanctuaryQuest : IFiltered
{
// Seeing the Cieldalaes doesn't seem to be available after unlocking the Island Sanctuary
// - Seeking the Cieldalaes is unlockable after the Praetorium
// - Seeking Sanctuary is unlockable after 6.0
public bool IsUnobtainable ( Plugin plugin , uint quest )
{
return quest = = 70_180 & & plugin . Common . Functions . Journal . IsQuestCompleted ( 70_179 ) ;
}
}
}
}