Assignment(nameof(QuestStep.TargetClass), step.TargetClass,
emptyStep.TargetClass)
.AsSyntaxNodeOrToken(),
+ Assignment(nameof(QuestStep.TaxiStandId), step.TaxiStandId,
+ emptyStep.TaxiStandId)
+ .AsSyntaxNodeOrToken(),
Assignment(nameof(QuestStep.EnemySpawnType), step.EnemySpawnType,
emptyStep.EnemySpawnType)
.AsSyntaxNodeOrToken(),
{
"Sequence": 255,
"Steps": [
+ {
+ "DataId": 1002721,
+ "Position": {
+ "X": 187.9148,
+ "Y": 98.5214,
+ "Z": -193.19452
+ },
+ "TerritoryId": 134,
+ "InteractionType": "UnlockTaxiStand",
+ "TaxiStandId": 22,
+ "AetheryteShortcut": "Middle La Noscea - Summerford Farms"
+ },
{
"DataId": 1003239,
"Position": {
"Z": -249.34778
},
"TerritoryId": 134,
- "InteractionType": "CompleteQuest",
- "AethernetShortcut": [
- "[Limsa Lominsa] The Aftcastle",
- "[Limsa Lominsa] Zephyr Gate (Middle La Noscea)"
- ]
+ "InteractionType": "CompleteQuest"
}
]
}
"InteractionType": "WalkTo",
"TargetTerritoryId": 138
},
+ {
+ "DataId": 1002722,
+ "Position": {
+ "X": 667.68884,
+ "Y": 9.882242,
+ "Z": 487.32727
+ },
+ "TerritoryId": 138,
+ "InteractionType": "UnlockTaxiStand",
+ "TaxiStandId": 23
+ },
{
"TerritoryId": 138,
"InteractionType": "AttuneAetheryte",
"InteractionType": "WalkTo",
"TargetTerritoryId": 135
},
+ {
+ "DataId": 1002720,
+ "Position": {
+ "X": 49.271362,
+ "Y": 29.315498,
+ "Z": 605.27954
+ },
+ "TerritoryId": 135,
+ "InteractionType": "UnlockTaxiStand",
+ "TaxiStandId": 27
+ },
{
"TerritoryId": 135,
"InteractionType": "AttuneAetheryte",
"InteractionType": "AttuneAetheryte",
"Aetheryte": "Western La Noscea - Aleport"
},
+ {
+ "DataId": 1002723,
+ "Position": {
+ "X": 298.63428,
+ "Y": -25.004364,
+ "Z": 233.14258
+ },
+ "TerritoryId": 138,
+ "InteractionType": "UnlockTaxiStand",
+ "TaxiStandId": 24
+ },
{
"DataId": 1017075,
"Position": {
"Z": 17.135864
},
"TerritoryId": 138,
- "InteractionType": "Interact"
+ "InteractionType": "Interact",
+ "AetheryteShortcut": "Western La Noscea - Aleport",
+ "SkipConditions": {
+ "AetheryteShortcutIf": {
+ "InSameTerritory": true
+ }
+ }
}
]
},
"Gather",
"Snipe",
"SwitchClass",
+ "UnlockTaxiStand",
"Instruction",
"AcceptQuest",
"CompleteQuest",
}
}
},
+ {
+ "if": {
+ "properties": {
+ "InteractionType": {
+ "const": "UnlockTaxiStand"
+ }
+ }
+ },
+ "then": {
+ "properties": {
+ "TaxiStandId": {
+ "type": "number"
+ }
+ },
+ "required": [
+ "TaxiStandId"
+ ]
+ }
+ },
{
"if": {
"properties": {
{ EInteractionType.Gather, "Gather" },
{ EInteractionType.Snipe, "Snipe" },
{ EInteractionType.SwitchClass, "SwitchClass" },
+ { EInteractionType.UnlockTaxiStand, "UnlockTaxiStand" },
{ EInteractionType.Instruction, "Instruction" },
{ EInteractionType.AcceptQuest, "AcceptQuest" },
{ EInteractionType.CompleteQuest, "CompleteQuest" },
Gather,
Snipe,
SwitchClass,
+ UnlockTaxiStand,
/// <summary>
/// Needs to be manually continued.
public EAction? Action { get; set; }
public EStatus? Status { get; set; }
public EExtendedClassJob TargetClass { get; set; } = EExtendedClassJob.None;
+ public byte? TaxiStandId { get; set; }
public EEnemySpawnType? EnemySpawnType { get; set; }
public List<uint> KillEnemyDataIds { get; set; } = [];
using System;
+using System.Collections.Generic;
using System.Linq;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.Command;
using Dalamud.Plugin.Services;
+using FFXIVClientStructs.FFXIV.Client.Game.UI;
using Lumina.Excel.Sheets;
using Questionable.Functions;
using Questionable.Model.Questing;
else
_chatGui.PrintError("Could not query unlock links.", MessageTag, TagColor);
break;
+
+ case "taxi":
+ unsafe
+ {
+ List<string> taxiStands = [];
+ var taxiStandNames = _dataManager.GetExcelSheet<ChocoboTaxiStand>();
+ var uiState = UIState.Instance();
+ for (byte i = 0; i < uiState->ChocoboTaxiStandsBitmask.Length * 8; ++ i)
+ {
+ if (uiState->IsChocoboTaxiStandUnlocked(i))
+ taxiStands.Add($"{taxiStandNames.GetRow(i + 0x120000u).PlaceName} ({i})");
+ }
+
+ _chatGui.Print("Unlocked taxi stands:", MessageTag, TagColor);
+ foreach (var taxiStand in taxiStands)
+ _chatGui.Print($"- {taxiStand}", MessageTag, TagColor);
+ }
+ break;
}
}
if (currentQuest != null)
{
var quest = currentQuest.Quest;
+ bool isTaxiStandUnlock = false;
if (checkAllSteps)
{
var sequence = quest.FindSequence(currentQuest.Sequence);
var choices = sequence?.Steps.SelectMany(x => x.DialogueChoices);
if (choices != null)
dialogueChoices.AddRange(choices.Select(x => new DialogueChoiceInfo(quest, x)));
+
+ isTaxiStandUnlock = sequence?.Steps.Any(x => x.InteractionType == EInteractionType.UnlockTaxiStand) ?? false;
}
else
{
Prompt = null,
Answer = step.PurchaseMenu.Key,
}));
+
+ isTaxiStandUnlock = step.InteractionType == EInteractionType.UnlockTaxiStand;
}
}
+ if (isTaxiStandUnlock)
+ {
+ _logger.LogInformation("Adding chocobo taxi stand unlock dialogue choices");
+ dialogueChoices.Add(new DialogueChoiceInfo(quest, new DialogueChoice
+ {
+ Type = EDialogChoiceType.List,
+ ExcelSheet = "transport/ChocoboTaxiStand",
+ Prompt = ExcelRef.FromKey("TEXT_CHOCOBOTAXISTAND_00000_Q1_000_1"),
+ Answer = ExcelRef.FromKey("TEXT_CHOCOBOTAXISTAND_00000_A1_000_3")
+ }));
+ }
+
// add all travel dialogue choices
var targetTerritoryId = FindTargetTerritoryFromQuestStep(currentQuest);
if (targetTerritoryId != null)
_logger.LogInformation("SinglePlayerDutyYesNo: probably Single Player Duty");
return true;
}
+ else
+ {
+ _logger.LogInformation("SinglePlayerDuty: not enabled");
+ return false;
+ }
+ }
return false;
}
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game;
+using FFXIVClientStructs.FFXIV.Client.Game.UI;
using Microsoft.Extensions.Logging;
using Questionable.Controller.Steps.Shared;
using Questionable.Controller.Utils;
if (!automatonIpc.IsAutoSnipeEnabled)
yield break;
}
+ else if (step.InteractionType == EInteractionType.UnlockTaxiStand)
+ {
+ if (step.TaxiStandId == null)
+ yield break;
+ }
else if (step.InteractionType != EInteractionType.Interact)
yield break;
if (sequence.Sequence == 0 && sequence.Steps.IndexOf(step) == 0)
yield return new WaitAtEnd.WaitDelay();
- yield return new Task(step.DataId.Value, quest, step.InteractionType,
- step.TargetTerritoryId != null || quest.Id is SatisfactionSupplyNpcId ||
- step.SkipConditions is { StepIf.Never: true } || step.InteractionType == EInteractionType.PurchaseItem || step.DataId == 1052475,
- step.PickUpItemId, step.SkipConditions?.StepIf, step.CompletionQuestVariablesFlags);
+ yield return new Task(
+ DataId: step.DataId.Value,
+ Quest: quest,
+ InteractionType: step.InteractionType,
+ SkipMarkerCheck: step.TargetTerritoryId != null || quest.Id is SatisfactionSupplyNpcId ||
+ step.SkipConditions is { StepIf.Never: true } || step.InteractionType == EInteractionType.PurchaseItem || step.DataId == 1052475,
+ PickUpItemId: step.PickUpItemId,
+ TaxiStandId: step.TaxiStandId,
+ SkipConditions: step.SkipConditions?.StepIf,
+ CompletionQuestVariablesFlags: step.CompletionQuestVariablesFlags);
}
}
EInteractionType InteractionType,
bool SkipMarkerCheck = false,
uint? PickUpItemId = null,
+ byte? TaxiStandId = null,
SkipStepConditions? SkipConditions = null,
List<QuestWorkValue?>? CompletionQuestVariablesFlags = null) : ITask
{
_needsUnmount = false;
}
- if (Task.PickUpItemId != null)
+ if (Task.PickUpItemId is { } pickUpItemId)
{
unsafe
{
InventoryManager* inventoryManager = InventoryManager.Instance();
- if (inventoryManager->GetInventoryItemCount(Task.PickUpItemId.Value) > 0)
+ if (inventoryManager->GetInventoryItemCount(pickUpItemId) > 0)
+ return ETaskResult.TaskComplete;
+ }
+ }
+ else if (Task.TaxiStandId is { } taxiStandId)
+ {
+ unsafe
+ {
+ UIState* uiState = UIState.Instance();
+ if (uiState->IsChocoboTaxiStandUnlocked(taxiStandId))
return ETaskResult.TaskComplete;
}
}
if ((skipConditions == null || !skipConditions.HasSkipConditions()) &&
!QuestWorkUtils.HasCompletionFlags(step.CompletionQuestVariablesFlags) &&
step.RequiredQuestVariables.Count == 0 &&
+ step.TaxiStandId == null &&
step.PickUpQuestId == null &&
step.NextQuestId == null &&
step.RequiredCurrentJob.Count == 0 &&
if (CheckPickUpTurnInQuestIds(step))
return true;
+ if (CheckTaxiStandUnlocked(step))
+ return true;
+
return false;
}
return false;
}
+ private unsafe bool CheckTaxiStandUnlocked(QuestStep step)
+ {
+ UIState* uiState = UIState.Instance();
+ if (step.TaxiStandId is { } taxiStandId &&
+ uiState->IsChocoboTaxiStandUnlocked(taxiStandId))
+ {
+ logger.LogInformation("Skipping step, as taxi stand {TaxiStandId} is unlocked", taxiStandId);
+ return true;
+ }
+
+ return false;
+ }
+
public override ETaskResult Update() => ETaskResult.SkipRemainingTasksForStep;
public override bool ShouldInterruptOnDamage() => false;