punish v6.8.18.0
This commit is contained in:
commit
060278c1b7
317 changed files with 554155 additions and 0 deletions
|
@ -0,0 +1,337 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Questionable.Controller.Steps.Shared;
|
||||
using Questionable.Controller.Utils;
|
||||
using Questionable.External;
|
||||
using Questionable.Functions;
|
||||
using Questionable.Model;
|
||||
using Questionable.Model.Questing;
|
||||
|
||||
namespace Questionable.Controller.Steps.Interactions;
|
||||
|
||||
internal static class Interact
|
||||
{
|
||||
internal sealed class Factory(AutomatonIpc automatonIpc, Configuration configuration) : ITaskFactory
|
||||
{
|
||||
public IEnumerable<ITask> CreateAllTasks(Quest quest, QuestSequence sequence, QuestStep step)
|
||||
{
|
||||
EInteractionType interactionType = step.InteractionType;
|
||||
if ((interactionType == EInteractionType.SinglePlayerDuty || (uint)(interactionType - 28) <= 1u) ? true : false)
|
||||
{
|
||||
if ((step.InteractionType == EInteractionType.CompleteQuest && configuration.Advanced.PreventQuestCompletion) || step.Emote.HasValue || step.ChatMessage != null || step.ItemId.HasValue || !step.DataId.HasValue)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
else if (step.InteractionType == EInteractionType.PurchaseItem)
|
||||
{
|
||||
if (!step.DataId.HasValue)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
else if (step.InteractionType == EInteractionType.Snipe)
|
||||
{
|
||||
if (!automatonIpc.IsAutoSnipeEnabled)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
else if (step.InteractionType == EInteractionType.UnlockTaxiStand)
|
||||
{
|
||||
if (!step.TaxiStandId.HasValue)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
}
|
||||
else if (step.InteractionType != EInteractionType.Interact)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
ArgumentNullException.ThrowIfNull(step.DataId, "step.DataId");
|
||||
if (sequence.Sequence == 0 && sequence.Steps.IndexOf(step) == 0)
|
||||
{
|
||||
yield return new WaitAtEnd.WaitDelay();
|
||||
}
|
||||
uint value = step.DataId.Value;
|
||||
EInteractionType interactionType2 = step.InteractionType;
|
||||
int skipMarkerCheck;
|
||||
if (!step.TargetTerritoryId.HasValue && !(quest.Id is SatisfactionSupplyNpcId))
|
||||
{
|
||||
SkipConditions skipConditions = step.SkipConditions;
|
||||
if (skipConditions != null)
|
||||
{
|
||||
SkipStepConditions stepIf = skipConditions.StepIf;
|
||||
if (stepIf != null && stepIf.Never)
|
||||
{
|
||||
goto IL_0247;
|
||||
}
|
||||
}
|
||||
if (step.InteractionType != EInteractionType.PurchaseItem)
|
||||
{
|
||||
skipMarkerCheck = ((step.DataId == 1052475) ? 1 : 0);
|
||||
goto IL_0248;
|
||||
}
|
||||
}
|
||||
goto IL_0247;
|
||||
IL_0247:
|
||||
skipMarkerCheck = 1;
|
||||
goto IL_0248;
|
||||
IL_0248:
|
||||
yield return new Task(value, quest, interactionType2, (byte)skipMarkerCheck != 0, step.PickUpItemId, step.TaxiStandId, step.SkipConditions?.StepIf, step.CompletionQuestVariablesFlags);
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed record Task : ITask
|
||||
{
|
||||
public uint DataId { get; init; }
|
||||
|
||||
public Quest? Quest { get; init; }
|
||||
|
||||
public EInteractionType InteractionType { get; init; }
|
||||
|
||||
public bool SkipMarkerCheck { get; init; }
|
||||
|
||||
public uint? PickUpItemId { get; init; }
|
||||
|
||||
public byte? TaxiStandId { get; init; }
|
||||
|
||||
public SkipStepConditions? SkipConditions { get; init; }
|
||||
|
||||
public List<QuestWorkValue?> CompletionQuestVariablesFlags { get; }
|
||||
|
||||
public bool HasCompletionQuestVariablesFlags { get; }
|
||||
|
||||
public Task(uint DataId, Quest? Quest, EInteractionType InteractionType, bool SkipMarkerCheck = false, uint? PickUpItemId = null, byte? TaxiStandId = null, SkipStepConditions? SkipConditions = null, List<QuestWorkValue?>? CompletionQuestVariablesFlags = null)
|
||||
{
|
||||
this.DataId = DataId;
|
||||
this.Quest = Quest;
|
||||
this.InteractionType = InteractionType;
|
||||
this.SkipMarkerCheck = SkipMarkerCheck;
|
||||
this.PickUpItemId = PickUpItemId;
|
||||
this.TaxiStandId = TaxiStandId;
|
||||
this.SkipConditions = SkipConditions;
|
||||
this.CompletionQuestVariablesFlags = CompletionQuestVariablesFlags ?? new List<QuestWorkValue>();
|
||||
HasCompletionQuestVariablesFlags = Quest != null && CompletionQuestVariablesFlags != null && QuestWorkUtils.HasCompletionFlags(CompletionQuestVariablesFlags);
|
||||
base._002Ector();
|
||||
}
|
||||
|
||||
public bool ShouldRedoOnInterrupt()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Interact{(HasCompletionQuestVariablesFlags ? "*" : "")}({DataId})";
|
||||
}
|
||||
|
||||
[CompilerGenerated]
|
||||
public void Deconstruct(out uint DataId, out Quest? Quest, out EInteractionType InteractionType, out bool SkipMarkerCheck, out uint? PickUpItemId, out byte? TaxiStandId, out SkipStepConditions? SkipConditions, out List<QuestWorkValue?>? CompletionQuestVariablesFlags)
|
||||
{
|
||||
DataId = this.DataId;
|
||||
Quest = this.Quest;
|
||||
InteractionType = this.InteractionType;
|
||||
SkipMarkerCheck = this.SkipMarkerCheck;
|
||||
PickUpItemId = this.PickUpItemId;
|
||||
TaxiStandId = this.TaxiStandId;
|
||||
SkipConditions = this.SkipConditions;
|
||||
CompletionQuestVariablesFlags = this.CompletionQuestVariablesFlags;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DoInteract(GameFunctions gameFunctions, QuestFunctions questFunctions, ICondition condition, ILogger<DoInteract> logger) : TaskExecutor<Task>(), IConditionChangeAware, ITaskExecutor
|
||||
{
|
||||
private enum EInteractionState
|
||||
{
|
||||
None,
|
||||
InteractionTriggered,
|
||||
InteractionConfirmed
|
||||
}
|
||||
|
||||
private bool _needsUnmount;
|
||||
|
||||
private EInteractionState _interactionState;
|
||||
|
||||
private DateTime _continueAt = DateTime.MinValue;
|
||||
|
||||
private bool delayedFinalCheck;
|
||||
|
||||
public Quest? Quest => base.Task.Quest;
|
||||
|
||||
public EInteractionType InteractionType { get; set; }
|
||||
|
||||
protected override bool Start()
|
||||
{
|
||||
InteractionType = base.Task.InteractionType;
|
||||
IGameObject gameObject = gameFunctions.FindObjectByDataId(base.Task.DataId);
|
||||
if (gameObject == null)
|
||||
{
|
||||
logger.LogWarning("No game object with dataId {DataId}", base.Task.DataId);
|
||||
return false;
|
||||
}
|
||||
if (!gameObject.IsTargetable)
|
||||
{
|
||||
SkipStepConditions skipConditions = base.Task.SkipConditions;
|
||||
if (skipConditions != null && !skipConditions.Never && skipConditions.NotTargetable)
|
||||
{
|
||||
logger.LogInformation("Not interacting with {DataId} because it is not targetable (but skippable)", base.Task.DataId);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!gameObject.IsTargetable && condition[ConditionFlag.Mounted] && gameObject.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.GatheringPoint)
|
||||
{
|
||||
logger.LogInformation("Preparing interaction for {DataId} by unmounting", base.Task.DataId);
|
||||
_needsUnmount = true;
|
||||
gameFunctions.Unmount();
|
||||
_continueAt = DateTime.Now.AddSeconds(1.0);
|
||||
return true;
|
||||
}
|
||||
if (gameObject.IsTargetable && HasAnyMarker(gameObject))
|
||||
{
|
||||
TriggerInteraction(gameObject);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public unsafe override ETaskResult Update()
|
||||
{
|
||||
if (DateTime.Now <= _continueAt)
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (_needsUnmount)
|
||||
{
|
||||
if (condition[ConditionFlag.Mounted])
|
||||
{
|
||||
gameFunctions.Unmount();
|
||||
_continueAt = DateTime.Now.AddSeconds(1.0);
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
_needsUnmount = false;
|
||||
}
|
||||
uint? pickUpItemId = base.Task.PickUpItemId;
|
||||
if (pickUpItemId.HasValue)
|
||||
{
|
||||
uint valueOrDefault = pickUpItemId.GetValueOrDefault();
|
||||
if (InventoryManager.Instance()->GetInventoryItemCount(valueOrDefault, isHq: false, checkEquipped: true, checkArmory: true, 0) > 0)
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
byte? taxiStandId = base.Task.TaxiStandId;
|
||||
if (taxiStandId.HasValue)
|
||||
{
|
||||
byte valueOrDefault2 = taxiStandId.GetValueOrDefault();
|
||||
if (UIState.Instance()->IsChocoboTaxiStandUnlocked(valueOrDefault2))
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (InteractionType == EInteractionType.Gather && condition[ConditionFlag.Gathering])
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
if (Quest != null && base.Task.HasCompletionQuestVariablesFlags)
|
||||
{
|
||||
QuestProgressInfo questProgressInfo = questFunctions.GetQuestProgressInfo(Quest.Id);
|
||||
if (questProgressInfo == null || !QuestWorkUtils.MatchesQuestWork(base.Task.CompletionQuestVariablesFlags, questProgressInfo))
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
if (base.ProgressContext != null)
|
||||
{
|
||||
if (base.ProgressContext.WasInterrupted())
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
if (base.ProgressContext.WasSuccessful() || _interactionState == EInteractionState.InteractionConfirmed)
|
||||
{
|
||||
if (delayedFinalCheck)
|
||||
{
|
||||
return ETaskResult.TaskComplete;
|
||||
}
|
||||
_continueAt = DateTime.Now.AddSeconds(0.2);
|
||||
delayedFinalCheck = true;
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IGameObject gameObject = gameFunctions.FindObjectByDataId(base.Task.DataId);
|
||||
if (gameObject == null || !gameObject.IsTargetable || !HasAnyMarker(gameObject))
|
||||
{
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
TriggerInteraction(gameObject);
|
||||
return ETaskResult.StillRunning;
|
||||
}
|
||||
|
||||
private void TriggerInteraction(IGameObject gameObject)
|
||||
{
|
||||
base.ProgressContext = InteractionProgressContext.FromActionUseOrDefault(delegate
|
||||
{
|
||||
if (gameFunctions.InteractWith(gameObject))
|
||||
{
|
||||
_interactionState = EInteractionState.InteractionTriggered;
|
||||
}
|
||||
else
|
||||
{
|
||||
_interactionState = EInteractionState.None;
|
||||
}
|
||||
return _interactionState != EInteractionState.None;
|
||||
});
|
||||
_continueAt = DateTime.Now.AddSeconds(0.5);
|
||||
}
|
||||
|
||||
private unsafe bool HasAnyMarker(IGameObject gameObject)
|
||||
{
|
||||
if (base.Task.SkipMarkerCheck || gameObject.ObjectKind != Dalamud.Game.ClientState.Objects.Enums.ObjectKind.EventNpc)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
GameObject* address = (GameObject*)gameObject.Address;
|
||||
return address->NamePlateIconId != 0;
|
||||
}
|
||||
|
||||
public void OnConditionChange(ConditionFlag flag, bool value)
|
||||
{
|
||||
if (base.ProgressContext == null || (!base.ProgressContext.WasInterrupted() && !base.ProgressContext.WasSuccessful()))
|
||||
{
|
||||
logger.LogDebug("Condition change: {Flag} = {Value}", flag, value);
|
||||
bool flag2 = _interactionState == EInteractionState.InteractionTriggered;
|
||||
if (flag2)
|
||||
{
|
||||
bool flag3 = (uint)(flag - 31) <= 1u;
|
||||
flag2 = flag3;
|
||||
}
|
||||
if (flag2 && value)
|
||||
{
|
||||
logger.LogInformation("Interaction was most likely triggered");
|
||||
_interactionState = EInteractionState.InteractionConfirmed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override bool ShouldInterruptOnDamage()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue