Make 'TargetTerritoryId' auto-pick warps for SelectString/SelectIconString (except for lifts in Ul'dah/Limsa, since airship landings are in normal territories)
This commit is contained in:
parent
c521860851
commit
320ce14aed
2
LLib
2
LLib
@ -1 +1 @@
|
|||||||
Subproject commit 93fac6efb01a1272192d929fd863328271512ea4
|
Subproject commit aec507a840b7f0a20635c6ddbc7862e9025cea4f
|
@ -85,15 +85,7 @@
|
|||||||
"StopDistance": 7,
|
"StopDistance": 7,
|
||||||
"TerritoryId": 129,
|
"TerritoryId": 129,
|
||||||
"InteractionType": "Interact",
|
"InteractionType": "Interact",
|
||||||
"TargetTerritoryId": 138,
|
"TargetTerritoryId": 138
|
||||||
"DialogueChoices": [
|
|
||||||
{
|
|
||||||
"Type": "List",
|
|
||||||
"ExcelSheet": "Warp",
|
|
||||||
"Prompt": null,
|
|
||||||
"Answer": 131109
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"DataId": 14,
|
"DataId": 14,
|
||||||
|
@ -63,14 +63,6 @@
|
|||||||
"AethernetShortcut": [
|
"AethernetShortcut": [
|
||||||
"[Gridania] Aetheryte Plaza",
|
"[Gridania] Aetheryte Plaza",
|
||||||
"[Gridania] Lancers' Guild"
|
"[Gridania] Lancers' Guild"
|
||||||
],
|
|
||||||
"DialogueChoices": [
|
|
||||||
{
|
|
||||||
"Type": "List",
|
|
||||||
"ExcelSheet": "Warp",
|
|
||||||
"Prompt": null,
|
|
||||||
"Answer": 131077
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -21,6 +21,21 @@ public class ExcelRef
|
|||||||
Type = EType.RowId;
|
Type = EType.RowId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Only used internally (not serialized) with specific values that have been read from the sheets already.
|
||||||
|
/// </summary>
|
||||||
|
private ExcelRef(string value, bool v)
|
||||||
|
{
|
||||||
|
if (!v)
|
||||||
|
throw new ArgumentException(nameof(v));
|
||||||
|
|
||||||
|
_stringValue = value;
|
||||||
|
_rowIdValue = null;
|
||||||
|
Type = EType.RawString;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ExcelRef FromSheetValue(string value) => new(value, true);
|
||||||
|
|
||||||
public EType Type { get; }
|
public EType Type { get; }
|
||||||
|
|
||||||
public string AsKey()
|
public string AsKey()
|
||||||
@ -39,10 +54,19 @@ public class ExcelRef
|
|||||||
return _rowIdValue!.Value;
|
return _rowIdValue!.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string AsRawString()
|
||||||
|
{
|
||||||
|
if (Type != EType.RawString)
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
|
return _stringValue!;
|
||||||
|
}
|
||||||
|
|
||||||
public enum EType
|
public enum EType
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
Key,
|
Key,
|
||||||
RowId,
|
RowId,
|
||||||
|
RawString,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Dalamud.Game.Addon.Lifecycle;
|
using Dalamud.Game.Addon.Lifecycle;
|
||||||
@ -179,7 +180,8 @@ internal sealed class GameUiController : IDisposable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe bool CheckQuestSelection(AddonSelectIconString* addonSelectIconString, Quest quest, List<string?> answers)
|
private unsafe bool CheckQuestSelection(AddonSelectIconString* addonSelectIconString, Quest quest,
|
||||||
|
List<string?> answers)
|
||||||
{
|
{
|
||||||
// it is possible for this to be a quest selection
|
// it is possible for this to be a quest selection
|
||||||
string questName = quest.Info.Name;
|
string questName = quest.Info.Name;
|
||||||
@ -197,7 +199,7 @@ internal sealed class GameUiController : IDisposable
|
|||||||
{
|
{
|
||||||
List<string?> answers = new();
|
List<string?> answers = new();
|
||||||
for (ushort i = 0; i < addonSelectIconString->AtkUnitBase.AtkValues[5].Int; i++)
|
for (ushort i = 0; i < addonSelectIconString->AtkUnitBase.AtkValues[5].Int; i++)
|
||||||
answers.Add( addonSelectIconString->AtkValues[i * 3 + 7].ReadAtkString());
|
answers.Add(addonSelectIconString->AtkValues[i * 3 + 7].ReadAtkString());
|
||||||
|
|
||||||
return answers;
|
return answers;
|
||||||
}
|
}
|
||||||
@ -205,7 +207,7 @@ internal sealed class GameUiController : IDisposable
|
|||||||
private int? HandleListChoice(string? actualPrompt, List<string?> answers, bool checkAllSteps)
|
private int? HandleListChoice(string? actualPrompt, List<string?> answers, bool checkAllSteps)
|
||||||
{
|
{
|
||||||
List<DialogueChoiceInfo> dialogueChoices = [];
|
List<DialogueChoiceInfo> dialogueChoices = [];
|
||||||
var currentQuest = _questController.StartedQuest;
|
var currentQuest = _questController.SimulatedQuest ?? _questController.StartedQuest;
|
||||||
if (currentQuest != null)
|
if (currentQuest != null)
|
||||||
{
|
{
|
||||||
var quest = currentQuest.Quest;
|
var quest = currentQuest.Quest;
|
||||||
@ -224,6 +226,29 @@ internal sealed class GameUiController : IDisposable
|
|||||||
else
|
else
|
||||||
dialogueChoices.AddRange(step.DialogueChoices.Select(x => new DialogueChoiceInfo(quest, x)));
|
dialogueChoices.AddRange(step.DialogueChoices.Select(x => new DialogueChoiceInfo(quest, x)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add all travel dialogue choices
|
||||||
|
var targetTerritoryId = FindTargetTerritoryFromQuestStep(currentQuest);
|
||||||
|
if (targetTerritoryId != null)
|
||||||
|
{
|
||||||
|
foreach (string? answer in answers)
|
||||||
|
{
|
||||||
|
if (answer == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (TryFindWarp(targetTerritoryId.Value, answer, out uint? warpId, out string? warpText))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Adding warp {Id}, {Prompt}", warpId, warpText);
|
||||||
|
dialogueChoices.Add(new DialogueChoiceInfo(quest, new DialogueChoice
|
||||||
|
{
|
||||||
|
Type = EDialogChoiceType.List,
|
||||||
|
ExcelSheet = null,
|
||||||
|
Prompt = null,
|
||||||
|
Answer = ExcelRef.FromSheetValue(warpText),
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
_logger.LogDebug("Ignoring current quest dialogue choices, no active quest");
|
_logger.LogDebug("Ignoring current quest dialogue choices, no active quest");
|
||||||
@ -242,7 +267,8 @@ internal sealed class GameUiController : IDisposable
|
|||||||
.ToList();
|
.ToList();
|
||||||
if (questChoices != null && questChoices.Count > 0)
|
if (questChoices != null && questChoices.Count > 0)
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Adding {Count} dialogue choices from not accepted quest {QuestName}", questChoices.Count, questInfo.Name);
|
_logger.LogInformation("Adding {Count} dialogue choices from not accepted quest {QuestName}",
|
||||||
|
questChoices.Count, questInfo.Name);
|
||||||
dialogueChoices.AddRange(questChoices.Select(x => new DialogueChoiceInfo(knownQuest, x)));
|
dialogueChoices.AddRange(questChoices.Select(x => new DialogueChoiceInfo(knownQuest, x)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -334,9 +360,8 @@ internal sealed class GameUiController : IDisposable
|
|||||||
_logger.LogTrace("Prompt: '{Prompt}'", actualPrompt);
|
_logger.LogTrace("Prompt: '{Prompt}'", actualPrompt);
|
||||||
|
|
||||||
var currentQuest = _questController.StartedQuest;
|
var currentQuest = _questController.StartedQuest;
|
||||||
if (currentQuest == null)
|
if (currentQuest != null)
|
||||||
return;
|
{
|
||||||
|
|
||||||
var quest = currentQuest.Quest;
|
var quest = currentQuest.Quest;
|
||||||
if (checkAllSteps)
|
if (checkAllSteps)
|
||||||
{
|
{
|
||||||
@ -352,7 +377,13 @@ internal sealed class GameUiController : IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
HandleTravelYesNo(addonSelectYesno, currentQuest, actualPrompt);
|
if (HandleTravelYesNo(addonSelectYesno, currentQuest, actualPrompt))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var simulatedQuest = _questController.SimulatedQuest;
|
||||||
|
if (simulatedQuest != null)
|
||||||
|
HandleTravelYesNo(addonSelectYesno, simulatedQuest, actualPrompt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe bool HandleDefaultYesNo(AddonSelectYesno* addonSelectYesno, Quest quest,
|
private unsafe bool HandleDefaultYesNo(AddonSelectYesno* addonSelectYesno, Quest quest,
|
||||||
@ -387,21 +418,35 @@ internal sealed class GameUiController : IDisposable
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void HandleTravelYesNo(AddonSelectYesno* addonSelectYesno,
|
private unsafe bool HandleTravelYesNo(AddonSelectYesno* addonSelectYesno,
|
||||||
QuestController.QuestProgress currentQuest, string actualPrompt)
|
QuestController.QuestProgress currentQuest, string actualPrompt)
|
||||||
{
|
{
|
||||||
if (_gameFunctions.ReturnRequestedAt >= DateTime.Now.AddSeconds(-2) && _returnRegex.IsMatch(actualPrompt))
|
if (_gameFunctions.ReturnRequestedAt >= DateTime.Now.AddSeconds(-2) && _returnRegex.IsMatch(actualPrompt))
|
||||||
{
|
{
|
||||||
_logger.LogInformation("Automatically confirming return...");
|
_logger.LogInformation("Automatically confirming return...");
|
||||||
addonSelectYesno->AtkUnitBase.FireCallbackInt(0);
|
addonSelectYesno->AtkUnitBase.FireCallbackInt(0);
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var targetTerritoryId = FindTargetTerritoryFromQuestStep(currentQuest);
|
||||||
|
if (targetTerritoryId != null &&
|
||||||
|
TryFindWarp(targetTerritoryId.Value, actualPrompt, out uint? warpId, out string? warpText))
|
||||||
|
{
|
||||||
|
_logger.LogInformation("Using warp {Id}, {Prompt}", warpId, warpText);
|
||||||
|
addonSelectYesno->AtkUnitBase.FireCallbackInt(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ushort? FindTargetTerritoryFromQuestStep(QuestController.QuestProgress currentQuest)
|
||||||
|
{
|
||||||
// this can be triggered either manually (in which case we should increase the step counter), or automatically
|
// this can be triggered either manually (in which case we should increase the step counter), or automatically
|
||||||
// (in which case it is ~1 frame later, and the step counter has already been increased)
|
// (in which case it is ~1 frame later, and the step counter has already been increased)
|
||||||
var sequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
|
var sequence = currentQuest.Quest.FindSequence(currentQuest.Sequence);
|
||||||
if (sequence == null)
|
if (sequence == null)
|
||||||
return;
|
return null;
|
||||||
|
|
||||||
QuestStep? step = sequence.FindStep(currentQuest.Step);
|
QuestStep? step = sequence.FindStep(currentQuest.Step);
|
||||||
if (step != null)
|
if (step != null)
|
||||||
@ -421,24 +466,44 @@ internal sealed class GameUiController : IDisposable
|
|||||||
if (step == null || step.TargetTerritoryId == null)
|
if (step == null || step.TargetTerritoryId == null)
|
||||||
{
|
{
|
||||||
_logger.LogTrace("TravelYesNo: Not found");
|
_logger.LogTrace("TravelYesNo: Not found");
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.LogDebug("Target territory for quest step: {TargetTerritory}", step.TargetTerritoryId);
|
||||||
|
return step.TargetTerritoryId;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryFindWarp(ushort targetTerritoryId, string actualPrompt, [NotNullWhen(true)] out uint? warpId,
|
||||||
|
[NotNullWhen(true)] out string? warpText)
|
||||||
|
{
|
||||||
var warps = _dataManager.GetExcelSheet<Warp>()!
|
var warps = _dataManager.GetExcelSheet<Warp>()!
|
||||||
.Where(x => x.RowId > 0 && x.TerritoryType.Row == step.TargetTerritoryId);
|
.Where(x => x.RowId > 0 && x.TerritoryType.Row == targetTerritoryId);
|
||||||
foreach (var entry in warps)
|
foreach (var entry in warps)
|
||||||
{
|
{
|
||||||
string? excelPrompt = entry.Question?.ToString();
|
string? excelName = entry.Name?.ToString();
|
||||||
if (excelPrompt == null || !GameStringEquals(excelPrompt, actualPrompt))
|
string? excelQuestion = entry.Question?.ToString();
|
||||||
|
|
||||||
|
if (excelQuestion != null && GameStringEquals(excelQuestion, actualPrompt))
|
||||||
{
|
{
|
||||||
_logger.LogDebug("Ignoring prompt '{Prompt}'", excelPrompt);
|
warpId = entry.RowId;
|
||||||
continue;
|
warpText = excelQuestion;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (excelName != null && GameStringEquals(excelName, actualPrompt))
|
||||||
|
{
|
||||||
|
warpId = entry.RowId;
|
||||||
|
warpText = excelName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Ignoring prompt '{Prompt}'", excelQuestion);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogInformation("Using warp {Id}, {Prompt}", entry.RowId, excelPrompt);
|
warpId = null;
|
||||||
addonSelectYesno->AtkUnitBase.FireCallbackInt(0);
|
warpText = null;
|
||||||
return;
|
return false;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe void PointMenuPostSetup(AddonEvent type, AddonArgs args)
|
private unsafe void PointMenuPostSetup(AddonEvent type, AddonArgs args)
|
||||||
@ -551,6 +616,8 @@ internal sealed class GameUiController : IDisposable
|
|||||||
return _gameFunctions.GetDialogueText(quest, excelSheet, excelRef.AsKey());
|
return _gameFunctions.GetDialogueText(quest, excelSheet, excelRef.AsKey());
|
||||||
else if (excelRef.Type == ExcelRef.EType.RowId)
|
else if (excelRef.Type == ExcelRef.EType.RowId)
|
||||||
return _gameFunctions.GetDialogueTextByRowId(excelSheet, excelRef.AsRowId());
|
return _gameFunctions.GetDialogueTextByRowId(excelSheet, excelRef.AsRowId());
|
||||||
|
else if (excelRef.Type == ExcelRef.EType.RawString)
|
||||||
|
return excelRef.AsRawString();
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user