From f1a7a0cb99de9004dedff2eb31e92b6545f0f2a6 Mon Sep 17 00:00:00 2001 From: DrakiaXYZ Date: Sat, 9 Mar 2024 22:44:56 +0000 Subject: [PATCH] Fix LightKeeper tasks not progressing correctly (!91) To handle in-raid LK task unlocking, when a task is switched from AvailableAfter to Locked, instead switch it to AvailableForStart This handles the lack of `status` values for tasks, where the target state would normally be read from, without risking breaking non-LK tasks by adding that data. Co-authored-by: DrakiaXYZ <565558+TheDgtl@users.noreply.github.com> Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Modules/pulls/91 Co-authored-by: DrakiaXYZ Co-committed-by: DrakiaXYZ --- .../Aki.SinglePlayer/AkiSingleplayerPlugin.cs | 1 + .../Quests/InRaidQuestAvailablePatch.cs | 58 +++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 project/Aki.SinglePlayer/Patches/Quests/InRaidQuestAvailablePatch.cs diff --git a/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs b/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs index 2e18a34..1891988 100644 --- a/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs +++ b/project/Aki.SinglePlayer/AkiSingleplayerPlugin.cs @@ -42,6 +42,7 @@ namespace Aki.SinglePlayer new SpawnPmcPatch().Enable(); new PostRaidHealingPricePatch().Enable(); new EndByTimerPatch().Enable(); + new InRaidQuestAvailablePatch().Enable(); new PostRaidHealScreenPatch().Enable(); new VoIPTogglerPatch().Enable(); new MidRaidQuestChangePatch().Enable(); diff --git a/project/Aki.SinglePlayer/Patches/Quests/InRaidQuestAvailablePatch.cs b/project/Aki.SinglePlayer/Patches/Quests/InRaidQuestAvailablePatch.cs new file mode 100644 index 0000000..1a7c67e --- /dev/null +++ b/project/Aki.SinglePlayer/Patches/Quests/InRaidQuestAvailablePatch.cs @@ -0,0 +1,58 @@ +using Aki.Reflection.Patching; +using Aki.Reflection.Utils; +using EFT.Quests; +using HarmonyLib; +using System; +using System.Linq; +using System.Reflection; + +namespace Aki.SinglePlayer.Patches.Quests +{ + /** + * Lightkeeper quests change their state in-raid, and will change to the `AppearStatus` of the quest once + * the AvailableAfter time has been hit. This defaults to `Locked`, but should actually be `AvailableForStart` + * + * So if we get a quest state change from `AvailableAfter` to `Locked`, we should actually change to `AvailableForStart` + */ + public class InRaidQuestAvailablePatch : ModulePatch + { + private static PropertyInfo _questStatusProperty; + + protected override MethodBase GetTargetMethod() + { + var targetType = PatchConstants.EftTypes.FirstOrDefault(IsTargetType); + var targetMethod = AccessTools.Method(targetType, "SetStatus"); + + _questStatusProperty = AccessTools.Property(targetType, "QuestStatus"); + + Logger.LogDebug($"{this.GetType().Name} Type: {targetType?.Name}"); + Logger.LogDebug($"{this.GetType().Name} Method: {targetMethod?.Name}"); + Logger.LogDebug($"{this.GetType().Name} QuestStatus: {_questStatusProperty?.Name}"); + + return targetMethod; + } + + private bool IsTargetType(Type type) + { + if (type.GetProperty("StatusTransition") != null && + type.GetProperty("IsChangeAllowed") != null && + type.GetProperty("NeedCountdown") == null) + { + return true; + } + + return false; + } + + [PatchPrefix] + private static void PatchPrefix(object __instance, ref EQuestStatus status) + { + var currentStatus = (EQuestStatus)_questStatusProperty.GetValue(__instance); + + if (currentStatus == EQuestStatus.AvailableAfter && status == EQuestStatus.Locked) + { + status = EQuestStatus.AvailableForStart; + } + } + } +}