forked from liza/Questionable
Add quest battle notes
This commit is contained in:
parent
a75286e927
commit
31eb121cf0
@ -126,6 +126,9 @@ internal static class QuestStepExtensions
|
||||
Assignment(nameof(QuestStep.BossModEnabled),
|
||||
step.BossModEnabled, emptyStep.BossModEnabled)
|
||||
.AsSyntaxNodeOrToken(),
|
||||
Assignment(nameof(QuestStep.BossModNotes),
|
||||
step.BossModNotes, emptyStep.BossModNotes)
|
||||
.AsSyntaxNodeOrToken(),
|
||||
Assignment(nameof(QuestStep.SinglePlayerDutyIndex),
|
||||
step.SinglePlayerDutyIndex, emptyStep.SinglePlayerDutyIndex)
|
||||
.AsSyntaxNodeOrToken(),
|
||||
|
@ -103,7 +103,11 @@
|
||||
"Z": 479.9724
|
||||
},
|
||||
"TerritoryId": 1053,
|
||||
"InteractionType": "SinglePlayerDuty"
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"BossModEnabled": false,
|
||||
"BossModNotes": [
|
||||
"Doesn't handle death properly"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -61,7 +61,19 @@
|
||||
"TerritoryId": 156,
|
||||
"InteractionType": "Interact",
|
||||
"AetheryteShortcut": "Mor Dhona",
|
||||
"TargetTerritoryId": 351
|
||||
"TargetTerritoryId": 351,
|
||||
"SkipConditions": {
|
||||
"AetheryteShortcutIf": {
|
||||
"InTerritory": [
|
||||
351
|
||||
]
|
||||
},
|
||||
"StepIf": {
|
||||
"InTerritory": [
|
||||
351
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"DataId": 1032081,
|
||||
@ -73,13 +85,14 @@
|
||||
"TerritoryId": 351,
|
||||
"InteractionType": "SinglePlayerDuty",
|
||||
"Comment": "Estinien vs. Arch Ultima",
|
||||
"DialogueChoices": [
|
||||
{
|
||||
"Type": "YesNo",
|
||||
"Prompt": "TEXT_LUCKMG110_03682_Q1_100_125",
|
||||
"Yes": true
|
||||
}
|
||||
]
|
||||
"BossModEnabled": false,
|
||||
"BossModNotes": [
|
||||
"AI doesn't move automatically for the first boss",
|
||||
"AI doesn't move automatically for the dialogue with gaius on the bridge",
|
||||
"After walking downstairs automatically, AI tries to run back towards the stairs (ignoring the arena boudnary)",
|
||||
"After moving from the arena boundary, AI doesn't move into melee range and stops too far away when initially attacking"
|
||||
],
|
||||
"$.1": "This doesn't have a duty confirmation dialog, so we're treating TEXT_LUCKMG110_03682_Q1_100_125 as one"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -1270,6 +1270,12 @@
|
||||
"BossModEnabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"BossModNotes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"SinglePlayerDutyIndex": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
|
@ -76,6 +76,7 @@ public sealed class QuestStep
|
||||
public uint? ContentFinderConditionId { get; set; }
|
||||
public bool AutoDutyEnabled { get; set; }
|
||||
public bool BossModEnabled { get; set; }
|
||||
public List<string> BossModNotes { get; set; } = [];
|
||||
public byte SinglePlayerDutyIndex { get; set; }
|
||||
public SkipConditions? SkipConditions { get; set; }
|
||||
|
||||
|
@ -19,6 +19,7 @@ using Lumina.Excel.Sheets;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps.Interactions;
|
||||
using Questionable.Data;
|
||||
using Questionable.External;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Gathering;
|
||||
@ -45,6 +46,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||
private readonly ITargetManager _targetManager;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly ShopController _shopController;
|
||||
private readonly BossModIpc _bossModIpc;
|
||||
private readonly ILogger<InteractionUiController> _logger;
|
||||
private readonly Regex _returnRegex;
|
||||
private readonly Regex _purchaseItemRegex;
|
||||
@ -68,6 +70,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||
IPluginLog pluginLog,
|
||||
IClientState clientState,
|
||||
ShopController shopController,
|
||||
BossModIpc bossModIpc,
|
||||
ILogger<InteractionUiController> logger)
|
||||
{
|
||||
_addonLifecycle = addonLifecycle;
|
||||
@ -85,6 +88,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||
_targetManager = targetManager;
|
||||
_clientState = clientState;
|
||||
_shopController = shopController;
|
||||
_bossModIpc = bossModIpc;
|
||||
_logger = logger;
|
||||
|
||||
_returnRegex = _dataManager.GetExcelSheet<Addon>().GetRow(196).GetRegex(addon => addon.Text, pluginLog)!;
|
||||
@ -176,8 +180,11 @@ internal sealed class InteractionUiController : IDisposable
|
||||
|
||||
int? answer = HandleListChoice(actualPrompt, answers, checkAllSteps) ?? HandleInstanceListChoice(actualPrompt);
|
||||
if (answer != null)
|
||||
{
|
||||
_logger.LogInformation("Using choice {Choice} for list prompt '{Prompt}'", answer, actualPrompt);
|
||||
addonSelectString->AtkUnitBase.FireCallbackInt(answer.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe void CutsceneSelectStringPostSetup(AddonEvent type, AddonArgs args)
|
||||
{
|
||||
@ -224,6 +231,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||
int? answer = HandleListChoice(actualPrompt, answers, checkAllSteps);
|
||||
if (answer != null)
|
||||
{
|
||||
_logger.LogInformation("Using choice {Choice} for list prompt '{Prompt}'", answer, actualPrompt);
|
||||
addonSelectIconString->AtkUnitBase.FireCallbackInt(answer.Value);
|
||||
return;
|
||||
}
|
||||
@ -266,6 +274,7 @@ internal sealed class InteractionUiController : IDisposable
|
||||
int questSelection = answers.FindIndex(x => GameFunctions.GameStringEquals(questName, x));
|
||||
if (questSelection >= 0)
|
||||
{
|
||||
_logger.LogInformation("Selecting quest {QuestName}", questName);
|
||||
addonSelectIconString->AtkUnitBase.FireCallbackInt(questSelection);
|
||||
return true;
|
||||
}
|
||||
@ -655,13 +664,21 @@ internal sealed class InteractionUiController : IDisposable
|
||||
continue;
|
||||
}
|
||||
|
||||
_logger.LogInformation("Returning {YesNo} for '{Prompt}'", dialogueChoice.Yes ? "Yes" : "No", actualPrompt);
|
||||
addonSelectYesno->AtkUnitBase.FireCallbackInt(dialogueChoice.Yes ? 0 : 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (step is { InteractionType: EInteractionType.SinglePlayerDuty, BossModEnabled: true })
|
||||
if (step is { InteractionType: EInteractionType.SinglePlayerDuty } &&
|
||||
_bossModIpc.IsConfiguredToRunSoloInstance(quest.Id, step.SinglePlayerDutyIndex, step.BossModEnabled))
|
||||
{
|
||||
_logger.LogTrace("DefaultYesNo: probably Single Player Duty");
|
||||
// Most of these are yes/no dialogs "Duty calls, ...".
|
||||
//
|
||||
// For 'Vows of Virtue, Deeds of Cruelty', there's no such dialog, and it just puts you into the instance
|
||||
// after you confirm 'Wait for Krile?'. However, if you fail that duty, you'll get a DifficultySelectYesNo.
|
||||
|
||||
// DifficultySelectYesNo → [0, 2] for very easy
|
||||
_logger.LogInformation("DefaultYesNo: probably Single Player Duty");
|
||||
addonSelectYesno->AtkUnitBase.FireCallbackInt(0);
|
||||
return true;
|
||||
}
|
||||
|
3
Questionable/External/BossModIpc.cs
vendored
3
Questionable/External/BossModIpc.cs
vendored
@ -84,6 +84,9 @@ internal sealed class BossModIpc
|
||||
|
||||
public bool IsConfiguredToRunSoloInstance(ElementId questId, byte dutyIndex, bool enabledByDefault)
|
||||
{
|
||||
if (!IsSupported())
|
||||
return false;
|
||||
|
||||
if (!_configuration.SinglePlayerDuties.RunSoloInstancesWithBossMod)
|
||||
return false;
|
||||
|
||||
|
@ -40,12 +40,22 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||
(EClassJob.BlackMage, "Magical Ranged Role Quests"),
|
||||
];
|
||||
|
||||
private ImmutableDictionary<EAetheryteLocation, List<SinglePlayerDutyInfo>> _startingCityBattles = ImmutableDictionary<EAetheryteLocation, List<SinglePlayerDutyInfo>>.Empty;
|
||||
private ImmutableDictionary<EExpansionVersion, List<SinglePlayerDutyInfo>> _mainScenarioBattles = ImmutableDictionary<EExpansionVersion, List<SinglePlayerDutyInfo>>.Empty;
|
||||
private ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>> _jobQuestBattles = ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>>.Empty;
|
||||
private ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>> _roleQuestBattles = ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>>.Empty;
|
||||
private ImmutableDictionary<EAetheryteLocation, List<SinglePlayerDutyInfo>> _startingCityBattles =
|
||||
ImmutableDictionary<EAetheryteLocation, List<SinglePlayerDutyInfo>>.Empty;
|
||||
|
||||
private ImmutableDictionary<EExpansionVersion, List<SinglePlayerDutyInfo>> _mainScenarioBattles =
|
||||
ImmutableDictionary<EExpansionVersion, List<SinglePlayerDutyInfo>>.Empty;
|
||||
|
||||
private ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>> _jobQuestBattles =
|
||||
ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>>.Empty;
|
||||
|
||||
private ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>> _roleQuestBattles =
|
||||
ImmutableDictionary<EClassJob, List<SinglePlayerDutyInfo>>.Empty;
|
||||
|
||||
private ImmutableList<SinglePlayerDutyInfo> _otherRoleQuestBattles = ImmutableList<SinglePlayerDutyInfo>.Empty;
|
||||
private ImmutableList<(string Label, List<SinglePlayerDutyInfo>)> _otherQuestBattles = ImmutableList<(string Label, List<SinglePlayerDutyInfo>)>.Empty;
|
||||
|
||||
private ImmutableList<(string Label, List<SinglePlayerDutyInfo>)> _otherQuestBattles =
|
||||
ImmutableList<(string Label, List<SinglePlayerDutyInfo>)>.Empty;
|
||||
|
||||
public SinglePlayerDutyConfigComponent(
|
||||
IDalamudPluginInterface pluginInterface,
|
||||
@ -122,7 +132,9 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||
x.Step.SinglePlayerDutyIndex == index);
|
||||
if (foundStep == default)
|
||||
{
|
||||
_logger.LogWarning("Disabling quest battle for quest {QuestId}, no battle with index {Index} found", questId, index);
|
||||
_logger.LogWarning(
|
||||
"Disabling quest battle for quest {QuestId}, no battle with index {Index} found", questId,
|
||||
index);
|
||||
enabled = false;
|
||||
}
|
||||
else
|
||||
@ -156,7 +168,8 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||
questInfo.SortKey,
|
||||
questStep.SinglePlayerDutyIndex,
|
||||
enabled,
|
||||
questStep.BossModEnabled);
|
||||
questStep.BossModEnabled,
|
||||
questStep.BossModNotes);
|
||||
|
||||
if (cfcData.ContentFinderConditionId is 332 or 333 or 313 or 334)
|
||||
startingCityBattles[EAetheryteLocation.Limsa].Add(dutyInfo);
|
||||
@ -343,7 +356,7 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||
}
|
||||
}
|
||||
|
||||
if(ImGui.CollapsingHeader("General Role Quests"))
|
||||
if (ImGui.CollapsingHeader("General Role Quests"))
|
||||
DrawQuestTable("RoleQuestsGeneral", _otherRoleQuestBattles);
|
||||
}
|
||||
|
||||
@ -380,9 +393,9 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||
? SupportedCfcOptions
|
||||
: UnsupportedCfcOptions;
|
||||
int value = 0;
|
||||
if (Configuration.Duties.WhitelistedDutyCfcIds.Contains(dutyInfo.CfcId))
|
||||
if (Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Contains(dutyInfo.CfcId))
|
||||
value = 1;
|
||||
if (Configuration.Duties.BlacklistedDutyCfcIds.Contains(dutyInfo.CfcId))
|
||||
if (Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Contains(dutyInfo.CfcId))
|
||||
value = 2;
|
||||
|
||||
if (ImGui.TableNextColumn())
|
||||
@ -407,6 +420,25 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||
ImGuiComponents.HelpMarker("Questionable doesn't include support for this quest.",
|
||||
FontAwesomeIcon.Times, ImGuiColors.DalamudRed);
|
||||
}
|
||||
else if (dutyInfo.Notes.Count > 0)
|
||||
{
|
||||
using var color = new ImRaii.Color();
|
||||
color.Push(ImGuiCol.TextDisabled, ImGuiColors.DalamudYellow);
|
||||
ImGui.SameLine();
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.TextDisabled(FontAwesomeIcon.ExclamationTriangle.ToIconString());
|
||||
}
|
||||
|
||||
if (ImGui.IsItemHovered())
|
||||
{
|
||||
using var _ = ImRaii.Tooltip();
|
||||
|
||||
ImGui.TextColored(ImGuiColors.DalamudYellow, "While testing, the following issues have been found:");
|
||||
foreach (string note in dutyInfo.Notes)
|
||||
ImGui.BulletText(note);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ImGui.TableNextColumn())
|
||||
@ -417,13 +449,13 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||
ImGui.SetNextItemWidth(200);
|
||||
if (ImGui.Combo(string.Empty, ref value, labels, labels.Length))
|
||||
{
|
||||
Configuration.Duties.WhitelistedDutyCfcIds.Remove(dutyInfo.CfcId);
|
||||
Configuration.Duties.BlacklistedDutyCfcIds.Remove(dutyInfo.CfcId);
|
||||
Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Remove(dutyInfo.CfcId);
|
||||
Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Remove(dutyInfo.CfcId);
|
||||
|
||||
if (value == 1)
|
||||
Configuration.Duties.WhitelistedDutyCfcIds.Add(dutyInfo.CfcId);
|
||||
Configuration.SinglePlayerDuties.WhitelistedSinglePlayerDutyCfcIds.Add(dutyInfo.CfcId);
|
||||
else if (value == 2)
|
||||
Configuration.Duties.BlacklistedDutyCfcIds.Add(dutyInfo.CfcId);
|
||||
Configuration.SinglePlayerDuties.BlacklistedSinglePlayerDutyCfcIds.Add(dutyInfo.CfcId);
|
||||
|
||||
Save();
|
||||
}
|
||||
@ -460,5 +492,6 @@ internal sealed class SinglePlayerDutyConfigComponent : ConfigComponent
|
||||
ushort SortKey,
|
||||
byte Index,
|
||||
bool Enabled,
|
||||
bool BossModEnabledByDefault);
|
||||
bool BossModEnabledByDefault,
|
||||
List<string> Notes);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user