Fix patches for Questify, SilentTyping, SMYN on Canary. (#670)
* Questify * SilentTyping * ShowMeYourName
This commit is contained in:
parent
f4bef87da1
commit
56eab42950
6 changed files with 231 additions and 106 deletions
|
|
@ -19,8 +19,8 @@ import { ContextMenuApi, Menu, NavigationRouter, RestAPI, useEffect, useState }
|
|||
import { JSX } from "react";
|
||||
|
||||
import { addIgnoredQuest, addRerenderCallback, autoFetchCompatible, fetchAndAlertQuests, maximumAutoFetchIntervalValue, minimumAutoFetchIntervalValue, questIsIgnored, removeIgnoredQuest, rerenderQuests, settings, startAutoFetchingQuests, stopAutoFetchingQuests, validateAndOverwriteIgnoredQuests } from "./settings";
|
||||
import { ExcludedQuestMap, GuildlessServerListItem, Quest, QuestIcon, QuestMap, QuestStatus, RGB } from "./utils/components";
|
||||
import { adjustRGB, decimalToRGB, fetchAndDispatchQuests, formatLowerBadge, getFormattedNow, getIgnoredQuestIDs, getQuestStatus, isDarkish, leftClick, middleClick, normalizeQuestName, q, QuestifyLogger, questPath, QuestsStore, refreshQuest, reportPlayGameQuestProgress, reportVideoQuestProgress, rightClick, setIgnoredQuestIDs, videoQuestLeeway, waitUntilEnrolled } from "./utils/misc";
|
||||
import { ExcludedQuestMap, GuildlessServerListItem, Quest, QuestIcon, QuestMap, QuestStatus, QuestTaskType, RGB } from "./utils/components";
|
||||
import { adjustRGB, decimalToRGB, fetchAndDispatchQuests, formatLowerBadge, getFormattedNow, getIgnoredQuestIDs, getQuestProgress, getQuestStatus, getQuestTarget, getQuestTask, isDarkish, leftClick, middleClick, normalizeQuestName, q, QuestifyLogger, questPath, QuestsStore, refreshQuest, reportPlayGameQuestProgress, reportVideoQuestProgress, rightClick, setIgnoredQuestIDs, videoQuestLeeway, waitUntilEnrolled } from "./utils/misc";
|
||||
|
||||
const QuestifyNative = VencordNative.pluginHelpers.Questify as PluginNative<typeof import("./native")>;
|
||||
const patchedMobileQuests = new Set<string>();
|
||||
|
|
@ -206,8 +206,7 @@ function shouldHideBadgeOnUserProfiles(): boolean {
|
|||
function shouldHideQuestPopup(quest: Quest | null): boolean {
|
||||
const {
|
||||
disableQuestsPopupAboveAccountPanel,
|
||||
disableQuestsEverything,
|
||||
triggerQuestsRerender
|
||||
disableQuestsEverything
|
||||
} = settings.use([
|
||||
"disableQuestsPopupAboveAccountPanel",
|
||||
"disableQuestsEverything",
|
||||
|
|
@ -291,8 +290,6 @@ function QuestTileContextMenu(children: React.ReactNode[], props: { quest: any;
|
|||
|
||||
export function getQuestTileClasses(originalClasses: string, quest: Quest, color: number | null | undefined, gradient: string | undefined): string {
|
||||
const {
|
||||
ignoredQuestIDs,
|
||||
ignoredQuestProfile,
|
||||
restyleQuestsUnclaimed,
|
||||
restyleQuestsClaimed,
|
||||
restyleQuestsIgnored,
|
||||
|
|
@ -366,7 +363,7 @@ export function getQuestTileClasses(originalClasses: string, quest: Quest, color
|
|||
}
|
||||
|
||||
function makeDesktopCompatible(quests: Quest[]): void {
|
||||
const { makeMobileQuestsDesktopCompatible, triggerQuestsRerender } = settings.use(["makeMobileQuestsDesktopCompatible", "triggerQuestsRerender"]);
|
||||
const { makeMobileQuestsDesktopCompatible } = settings.use(["makeMobileQuestsDesktopCompatible", "triggerQuestsRerender"]);
|
||||
|
||||
if (makeMobileQuestsDesktopCompatible) {
|
||||
quests.forEach(quest => {
|
||||
|
|
@ -378,7 +375,7 @@ function makeDesktopCompatible(quests: Quest[]): void {
|
|||
|
||||
tasks.WATCH_VIDEO = {
|
||||
...tasks.WATCH_VIDEO_ON_MOBILE,
|
||||
type: "WATCH_VIDEO"
|
||||
type: QuestTaskType.WATCH_VIDEO
|
||||
};
|
||||
}
|
||||
});
|
||||
|
|
@ -398,17 +395,11 @@ function makeDesktopCompatible(quests: Quest[]): void {
|
|||
|
||||
function sortQuests(quests: Quest[], skip?: boolean): Quest[] {
|
||||
const {
|
||||
ignoredQuestIDs,
|
||||
ignoredQuestProfile,
|
||||
reorderQuests,
|
||||
unclaimedSubsort,
|
||||
claimedSubsort,
|
||||
ignoredSubsort,
|
||||
expiredSubsort,
|
||||
completeVideoQuestsInBackground,
|
||||
completeGameQuestsInBackground,
|
||||
completeAchievementQuestsInBackground,
|
||||
triggerQuestsRerender
|
||||
} = settings.use([
|
||||
"ignoredQuestIDs",
|
||||
"ignoredQuestProfile",
|
||||
|
|
@ -510,11 +501,7 @@ function sortQuests(quests: Quest[], skip?: boolean): Quest[] {
|
|||
}
|
||||
|
||||
export function getQuestTileStyle(quest: Quest | null): Record<string, string> {
|
||||
const {
|
||||
restyleQuests,
|
||||
ignoredQuestIDs,
|
||||
ignoredQuestProfile
|
||||
} = settings.use([
|
||||
settings.use([
|
||||
"restyleQuests",
|
||||
"ignoredQuestIDs",
|
||||
"ignoredQuestProfile"
|
||||
|
|
@ -684,8 +671,8 @@ async function startVideoProgressTracking(quest: Quest, questTarget: number): Pr
|
|||
async function startPlayGameProgressTracking(quest: Quest, questTarget: number): Promise<void> {
|
||||
const questName = normalizeQuestName(quest.config.messages.questName);
|
||||
const questEnrolledAt = quest.userStatus?.enrolledAt ? new Date(quest.userStatus.enrolledAt) : null;
|
||||
const playType = quest.config.taskConfigV2?.tasks.PLAY_ON_DESKTOP || quest.config.taskConfigV2?.tasks.PLAY_ON_XBOX || quest.config.taskConfigV2?.tasks.PLAY_ON_PLAYSTATION || quest.config.taskConfigV2?.tasks.PLAY_ACTIVITY;
|
||||
const initialProgress = quest.userStatus?.progress?.[playType?.type || ""]?.value || 0;
|
||||
const task = getQuestTask(quest);
|
||||
const initialProgress = getQuestProgress(quest, task) || 0;
|
||||
const remaining = Math.max(0, questTarget - initialProgress);
|
||||
const heartbeatInterval = 20; // Heartbeats must be at most 2 minutes apart.
|
||||
activeQuestIntervals.set(quest.id, { progressTimeout: null as any, rerenderTimeout: null as any, progress: initialProgress, type: "play" });
|
||||
|
|
@ -872,19 +859,23 @@ async function startAchievementActivityProgressTracking(quest: Quest, questTarge
|
|||
|
||||
function processQuestForAutoComplete(quest: Quest): boolean {
|
||||
const questName = normalizeQuestName(quest.config.messages.questName);
|
||||
const { completeVideoQuestsInBackground, completeGameQuestsInBackground, completeAchievementQuestsInBackground, makeMobileQuestsDesktopCompatible } = settings.store;
|
||||
const playType = quest.config.taskConfigV2?.tasks.PLAY_ON_DESKTOP || quest.config.taskConfigV2?.tasks.PLAY_ON_XBOX || quest.config.taskConfigV2?.tasks.PLAY_ON_PLAYSTATION || quest.config.taskConfigV2?.tasks.PLAY_ACTIVITY;
|
||||
const watchType = (makeMobileQuestsDesktopCompatible && quest.config.taskConfigV2?.tasks.WATCH_VIDEO_ON_MOBILE) || quest.config.taskConfigV2?.tasks.WATCH_VIDEO;
|
||||
const achievementType = quest.config.taskConfigV2?.tasks.ACHIEVEMENT_IN_ACTIVITY;
|
||||
const questTarget = playType?.target || watchType?.target || achievementType?.target || 0;
|
||||
const { completeVideoQuestsInBackground, completeGameQuestsInBackground, completeAchievementQuestsInBackground } = settings.store;
|
||||
|
||||
const task = getQuestTask(quest);
|
||||
const questTarget = getQuestTarget(task);
|
||||
const existingInterval = activeQuestIntervals.get(quest.id);
|
||||
const watchTypeIncompatible = watchType && !completeVideoQuestsInBackground;
|
||||
const playTypeIncompatible = playType && (!completeGameQuestsInBackground || !IS_DISCORD_DESKTOP);
|
||||
const achievementTypeIncompatible = achievementType && (!completeAchievementQuestsInBackground || !IS_DISCORD_DESKTOP);
|
||||
|
||||
const isWatch = task?.type === QuestTaskType.WATCH_VIDEO || task?.type === QuestTaskType.WATCH_VIDEO_ON_MOBILE;
|
||||
const isPlay = task?.type === QuestTaskType.PLAY_ON_DESKTOP || task?.type === QuestTaskType.PLAY_ON_XBOX || task?.type === QuestTaskType.PLAY_ON_PLAYSTATION || task?.type === QuestTaskType.PLAY_ACTIVITY;
|
||||
const isAchievement = task?.type === QuestTaskType.ACHIEVEMENT_IN_ACTIVITY;
|
||||
|
||||
const watchTypeIncompatible = isWatch && !completeVideoQuestsInBackground;
|
||||
const playTypeIncompatible = isPlay && (!completeGameQuestsInBackground || !IS_DISCORD_DESKTOP);
|
||||
const achievementTypeIncompatible = isAchievement && (!completeAchievementQuestsInBackground || !IS_DISCORD_DESKTOP);
|
||||
|
||||
if (quest.userStatus?.completedAt || existingInterval) {
|
||||
return false;
|
||||
} else if (!playType && !watchType && !achievementType) {
|
||||
} else if (!task) {
|
||||
QuestifyLogger.warn(`[${getFormattedNow()}] Could not recognize the Quest type for ${questName}.`);
|
||||
return false;
|
||||
} else if (watchTypeIncompatible || playTypeIncompatible || achievementTypeIncompatible) {
|
||||
|
|
@ -892,13 +883,13 @@ function processQuestForAutoComplete(quest: Quest): boolean {
|
|||
} else if (!questTarget) {
|
||||
QuestifyLogger.warn(`[${getFormattedNow()}] Could not find target for Quest ${questName}.`);
|
||||
return false;
|
||||
} else if (watchType) {
|
||||
} else if (isWatch) {
|
||||
startVideoProgressTracking(quest, questTarget);
|
||||
return true;
|
||||
} else if (playType) {
|
||||
} else if (isPlay) {
|
||||
startPlayGameProgressTracking(quest, questTarget);
|
||||
return true;
|
||||
} else if (achievementType) {
|
||||
} else if (isAchievement) {
|
||||
startAchievementActivityProgressTracking(quest, questTarget);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -921,17 +912,20 @@ function shouldDisableQuestAcceptedButton(quest: Quest): boolean | null {
|
|||
}
|
||||
|
||||
function getQuestUnacceptedButtonText(quest: Quest): string | null {
|
||||
const { completeGameQuestsInBackground, completeVideoQuestsInBackground, completeAchievementQuestsInBackground, makeMobileQuestsDesktopCompatible } = settings.store;
|
||||
const playType = quest.config.taskConfigV2?.tasks.PLAY_ON_DESKTOP || quest.config.taskConfigV2?.tasks.PLAY_ON_XBOX || quest.config.taskConfigV2?.tasks.PLAY_ON_PLAYSTATION || quest.config.taskConfigV2?.tasks.PLAY_ACTIVITY;
|
||||
const watchType = (makeMobileQuestsDesktopCompatible && quest.config.taskConfigV2?.tasks.WATCH_VIDEO_ON_MOBILE) || quest.config.taskConfigV2?.tasks.WATCH_VIDEO;
|
||||
const achievementType = quest.config.taskConfigV2?.tasks.ACHIEVEMENT_IN_ACTIVITY;
|
||||
const target = (playType?.target || (watchType?.target ? watchType.target - videoQuestLeeway : undefined) || achievementType?.target || 0);
|
||||
const { completeGameQuestsInBackground, completeVideoQuestsInBackground, completeAchievementQuestsInBackground } = settings.store;
|
||||
|
||||
const task = getQuestTask(quest);
|
||||
const target = getQuestTarget(task);
|
||||
const targetFormatted = `${String(Math.floor(target / 60)).padStart(2, "0")}:${String(target % 60).padStart(2, "0")}`;
|
||||
|
||||
const isWatch = task?.type === QuestTaskType.WATCH_VIDEO || task?.type === QuestTaskType.WATCH_VIDEO_ON_MOBILE;
|
||||
const isPlay = task?.type === QuestTaskType.PLAY_ON_DESKTOP || task?.type === QuestTaskType.PLAY_ON_XBOX || task?.type === QuestTaskType.PLAY_ON_PLAYSTATION || task?.type === QuestTaskType.PLAY_ACTIVITY;
|
||||
const isAchievement = task?.type === QuestTaskType.ACHIEVEMENT_IN_ACTIVITY;
|
||||
|
||||
if (target > 0) {
|
||||
if ((playType && completeGameQuestsInBackground && IS_DISCORD_DESKTOP) || (watchType && completeVideoQuestsInBackground)) {
|
||||
if ((isPlay && completeGameQuestsInBackground && IS_DISCORD_DESKTOP) || (isWatch && completeVideoQuestsInBackground)) {
|
||||
return `Complete (${targetFormatted})`;
|
||||
} else if (achievementType && completeAchievementQuestsInBackground) {
|
||||
} else if (isAchievement && completeAchievementQuestsInBackground) {
|
||||
return "Complete (Immediate)";
|
||||
}
|
||||
}
|
||||
|
|
@ -939,30 +933,36 @@ function getQuestUnacceptedButtonText(quest: Quest): string | null {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getQuestAcceptedButtonText(quest: Quest): string | null {
|
||||
const { completeGameQuestsInBackground, completeVideoQuestsInBackground, completeAchievementQuestsInBackground, makeMobileQuestsDesktopCompatible } = settings.store;
|
||||
function getQuestAcceptedButtonText(quest: Quest, prepositional: boolean = false): string | null {
|
||||
const { completeGameQuestsInBackground, completeVideoQuestsInBackground, completeAchievementQuestsInBackground } = settings.store;
|
||||
const questEnrolledAt = quest.userStatus?.enrolledAt ? new Date(quest.userStatus.enrolledAt) : null;
|
||||
const playType = quest.config.taskConfigV2?.tasks.PLAY_ON_DESKTOP || quest.config.taskConfigV2?.tasks.PLAY_ON_XBOX || quest.config.taskConfigV2?.tasks.PLAY_ON_PLAYSTATION || quest.config.taskConfigV2?.tasks.PLAY_ACTIVITY;
|
||||
const watchType = (makeMobileQuestsDesktopCompatible && quest.config.taskConfigV2?.tasks.WATCH_VIDEO_ON_MOBILE) || quest.config.taskConfigV2?.tasks.WATCH_VIDEO;
|
||||
const achievementType = quest.config.taskConfigV2?.tasks.ACHIEVEMENT_IN_ACTIVITY;
|
||||
const task = getQuestTask(quest);
|
||||
const intervalData = activeQuestIntervals.get(quest.id);
|
||||
|
||||
const isWatch = task?.type === QuestTaskType.WATCH_VIDEO || task?.type === QuestTaskType.WATCH_VIDEO_ON_MOBILE;
|
||||
const isPlay = task?.type === QuestTaskType.PLAY_ON_DESKTOP || task?.type === QuestTaskType.PLAY_ON_XBOX || task?.type === QuestTaskType.PLAY_ON_PLAYSTATION || task?.type === QuestTaskType.PLAY_ACTIVITY;
|
||||
const isAchievement = task?.type === QuestTaskType.ACHIEVEMENT_IN_ACTIVITY;
|
||||
|
||||
if (questEnrolledAt) {
|
||||
if (((playType && completeGameQuestsInBackground && IS_DISCORD_DESKTOP) || (watchType && completeVideoQuestsInBackground))) {
|
||||
const taskType = playType || watchType;
|
||||
const duration = taskType?.target || 0;
|
||||
const durationWithLeeway = watchType ? duration - videoQuestLeeway : duration;
|
||||
const progress = Math.min((intervalData?.progress ?? (quest.userStatus?.progress?.[taskType?.type || ""]?.value || 0)), durationWithLeeway);
|
||||
if (((isPlay && completeGameQuestsInBackground && IS_DISCORD_DESKTOP) || (isWatch && completeVideoQuestsInBackground))) {
|
||||
const durationWithLeeway = getQuestTarget(task);
|
||||
const currentProgress = getQuestProgress(quest, task) || 0;
|
||||
const progress = Math.min((intervalData?.progress ?? currentProgress), durationWithLeeway);
|
||||
const timeRemaining = Math.max(0, durationWithLeeway - progress);
|
||||
const canCompleteImmediately = watchType && questEnrolledAt && ((new Date().getTime() - questEnrolledAt.getTime()) / 1000) >= durationWithLeeway;
|
||||
const canCompleteImmediately = isWatch && questEnrolledAt && ((new Date().getTime() - questEnrolledAt.getTime()) / 1000) >= durationWithLeeway;
|
||||
const progressFormatted = `${String(Math.floor(timeRemaining / 60)).padStart(2, "0")}:${String(timeRemaining % 60).padStart(2, "0")}`;
|
||||
const progressFormattedAsPreposition = timeRemaining >= 60
|
||||
? `${Math.floor(timeRemaining / 60)}m ${timeRemaining % 60}s`
|
||||
: `${timeRemaining % 60}s`;
|
||||
|
||||
if (!!intervalData) {
|
||||
return !canCompleteImmediately && timeRemaining ? `Completing (${progressFormatted})` : "Completing...";
|
||||
} else if (watchType || playType) {
|
||||
return canCompleteImmediately || !timeRemaining
|
||||
? "Completing..."
|
||||
: `Completing ${prepositional ? `in ${progressFormattedAsPreposition}` : `(${progressFormatted})`}`;
|
||||
} else if (isWatch || isPlay) {
|
||||
return canCompleteImmediately ? "Complete (Immediate)" : timeRemaining === durationWithLeeway ? `Complete (${progressFormatted})` : `Resume (${progressFormatted})`;
|
||||
}
|
||||
} else if (achievementType && completeAchievementQuestsInBackground) {
|
||||
} else if (isAchievement && completeAchievementQuestsInBackground) {
|
||||
if (!!intervalData) {
|
||||
return "Completing...";
|
||||
} else {
|
||||
|
|
@ -974,8 +974,56 @@ function getQuestAcceptedButtonText(quest: Quest): string | null {
|
|||
return null;
|
||||
}
|
||||
|
||||
function getQuestPanelPercentComplete({ quest, percentCompleteText }: { quest: Quest; percentCompleteText?: string; }): { percentComplete: number; } | { percentComplete: number; percentCompleteText: string; } | null {
|
||||
const task = getQuestTask(quest);
|
||||
|
||||
if (!task) { return null; }
|
||||
|
||||
const questTarget = getQuestTarget(task);
|
||||
const questProgress = getQuestProgress(quest, task);
|
||||
|
||||
if (!questTarget || questProgress === null) { return null; }
|
||||
|
||||
const decimal = Math.min(1, questProgress / questTarget);
|
||||
|
||||
return percentCompleteText ? {
|
||||
percentComplete: decimal,
|
||||
percentCompleteText: `${Math.floor(decimal * 100)}%`
|
||||
} : {
|
||||
percentComplete: decimal
|
||||
};
|
||||
}
|
||||
|
||||
function getQuestPanelSubtitleText(quest: Quest): string | null {
|
||||
const intervalData = activeQuestIntervals.get(quest.id);
|
||||
|
||||
if (!intervalData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const rewardItem = quest.config.rewardsConfig.rewards[0] || null;
|
||||
const completingText = getQuestAcceptedButtonText(quest, true) || "Completing";
|
||||
|
||||
if (rewardItem.orbQuantity) {
|
||||
return `${completingText} for ${rewardItem.orbQuantity} Orbs.`;
|
||||
} else if (rewardItem.messages?.nameWithArticle) {
|
||||
return `${completingText} for ${rewardItem.messages.nameWithArticle}.`;
|
||||
} else {
|
||||
return `${completingText} for an unrecognized reward.`;
|
||||
}
|
||||
}
|
||||
|
||||
function getQuestPanelTitleText(quest: Quest): string | null {
|
||||
const intervalData = activeQuestIntervals.get(quest.id);
|
||||
|
||||
if (!intervalData) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return normalizeQuestName(quest.config.messages.questName);
|
||||
}
|
||||
|
||||
function getQuestPanelOverride(): Quest | null {
|
||||
const { makeMobileQuestsDesktopCompatible } = settings.store;
|
||||
let closestQuest: Quest | null = null;
|
||||
let closestTimeRemaining = Infinity;
|
||||
|
||||
|
|
@ -986,10 +1034,8 @@ function getQuestPanelOverride(): Quest | null {
|
|||
return;
|
||||
}
|
||||
|
||||
const playType = quest.config.taskConfigV2?.tasks.PLAY_ON_DESKTOP || quest.config.taskConfigV2?.tasks.PLAY_ON_XBOX || quest.config.taskConfigV2?.tasks.PLAY_ON_PLAYSTATION || quest.config.taskConfigV2?.tasks.PLAY_ACTIVITY;
|
||||
const watchType = (makeMobileQuestsDesktopCompatible && quest.config.taskConfigV2?.tasks.WATCH_VIDEO_ON_MOBILE) || quest.config.taskConfigV2?.tasks.WATCH_VIDEO;
|
||||
const achievementType = quest.config.taskConfigV2?.tasks.ACHIEVEMENT_IN_ACTIVITY;
|
||||
const duration = playType?.target || (watchType?.target ? watchType.target - videoQuestLeeway : undefined) || achievementType?.target || 0;
|
||||
const task = getQuestTask(quest);
|
||||
const duration = getQuestTarget(task);
|
||||
|
||||
if (!duration) {
|
||||
return;
|
||||
|
|
@ -1037,7 +1083,7 @@ function disguiseHomeButton(location: string): boolean {
|
|||
}
|
||||
|
||||
function useQuestRerender(): number {
|
||||
const { triggerQuestsRerender } = settings.use(["triggerQuestsRerender"]);
|
||||
settings.use(["triggerQuestsRerender"]);
|
||||
const [renderTrigger, setRenderTrigger] = useState(0);
|
||||
useEffect(() => addRerenderCallback(() => setRenderTrigger(prev => prev + 1)), []);
|
||||
return renderTrigger;
|
||||
|
|
@ -1064,17 +1110,17 @@ function setLastFilterChoices(filters: { group: string; filter: string; }[]): vo
|
|||
|
||||
function getQuestAcceptedButtonProps(quest: Quest, text: string, disabled: boolean, onClick?: () => void) {
|
||||
const validTasks = [
|
||||
"WATCH_VIDEO",
|
||||
"WATCH_VIDEO_ON_MOBILE",
|
||||
"PLAY_ON_DESKTOP",
|
||||
"PLAY_ON_XBOX",
|
||||
"PLAY_ON_PLAYSTATION",
|
||||
"PLAY_ACTIVITY",
|
||||
"ACHIEVEMENT_IN_ACTIVITY"
|
||||
QuestTaskType.WATCH_VIDEO,
|
||||
QuestTaskType.WATCH_VIDEO_ON_MOBILE,
|
||||
QuestTaskType.PLAY_ON_DESKTOP,
|
||||
QuestTaskType.PLAY_ON_XBOX,
|
||||
QuestTaskType.PLAY_ON_PLAYSTATION,
|
||||
QuestTaskType.PLAY_ACTIVITY,
|
||||
QuestTaskType.ACHIEVEMENT_IN_ACTIVITY
|
||||
];
|
||||
|
||||
const validTask = Array.from(validTasks).some(taskType => Object.values(quest.config.taskConfigV2?.tasks || {}).some(
|
||||
task => task.type === taskType && (task.type !== "WATCH_VIDEO_ON_MOBILE" || settings.store.makeMobileQuestsDesktopCompatible)
|
||||
task => task.type === taskType && (task.type !== QuestTaskType.WATCH_VIDEO_ON_MOBILE || settings.store.makeMobileQuestsDesktopCompatible)
|
||||
));
|
||||
|
||||
if (!validTask) {
|
||||
|
|
@ -1121,9 +1167,12 @@ export default definePlugin({
|
|||
shouldHideFriendsListActiveNowPromotion,
|
||||
shouldHideMembersListActivelyPlayingIcon,
|
||||
getQuestUnacceptedButtonText,
|
||||
getQuestPanelPercentComplete,
|
||||
processQuestForAutoComplete,
|
||||
getQuestAcceptedButtonProps,
|
||||
getQuestAcceptedButtonText,
|
||||
getQuestPanelSubtitleText,
|
||||
getQuestPanelTitleText,
|
||||
getQuestPanelOverride,
|
||||
setLastFilterChoices,
|
||||
getLastFilterChoices,
|
||||
|
|
@ -1138,8 +1187,8 @@ export default definePlugin({
|
|||
// Hides the notice in the gift inventory that Quests have been relocated to the Discovery tab.
|
||||
find: "quests-wumpus-hikes-mountain-transparent-background",
|
||||
replacement: {
|
||||
match: /return(\(0,\i.\i\)\("div",{className:)/,
|
||||
replace: "return $self.shouldHideGiftInventoryRelocationNotice()?null:$1"
|
||||
match: /return(?=\(0,\i.\i\)\("div",{className:)/,
|
||||
replace: "return $self.shouldHideGiftInventoryRelocationNotice()?null:"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
@ -1217,6 +1266,23 @@ export default definePlugin({
|
|||
replace: "return !$self.shouldHideQuestPopup($1)&&("
|
||||
}
|
||||
},
|
||||
{
|
||||
// Fixes the progress tracking for auto-completing Quests.
|
||||
find: ",{progressTextAnimation:",
|
||||
replacement: {
|
||||
match: /(?<=children:\i}=)(\i)/,
|
||||
replace: "Object.assign({},$1,$self.getQuestPanelPercentComplete($1))"
|
||||
}
|
||||
},
|
||||
{
|
||||
// Overrides the title and subtitle to provide more
|
||||
// useful information for Quests being auto-completed.
|
||||
find: '"progress-title"',
|
||||
replacement: {
|
||||
match: /(?<=return.{0,150}?quest:(\i),percentComplete:\i.{0,280}?"progress-title",children.{0,115}?children:)(\i.{0,50}"progress-subtitle",isTextTransition:!0,children.{0,115}?children:)/,
|
||||
replace: "$self.getQuestPanelTitleText($1)??$2$self.getQuestPanelSubtitleText($1)??"
|
||||
}
|
||||
},
|
||||
{
|
||||
// Replaces the default displayed Quest with the soonest to
|
||||
// be completed Quest which is actively being auto-completed.
|
||||
|
|
@ -1265,8 +1331,8 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
// Extracts the custom dropdown prop before the variable is overwritten.
|
||||
match: /(\((\i),\i\){)(var{options:\i,)/,
|
||||
replace: "$1const vcDynamicDropdownFeedback=$2.feedback;$3"
|
||||
match: /(?<=forwardRef\(function\((\i),\i\){)/,
|
||||
replace: "const vcDynamicDropdownFeedback=$1.feedback;"
|
||||
},
|
||||
{
|
||||
// Passes the custom prop to the dropdown's invalid handler.
|
||||
|
|
@ -1287,7 +1353,7 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
// Extracts the custom maxDigits prop.
|
||||
match: /(=>{var{count:\i,)/,
|
||||
match: /(=>{let{count:\i,)/,
|
||||
replace: "$1maxDigits,"
|
||||
},
|
||||
{
|
||||
|
|
@ -1310,8 +1376,8 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
// Restyles Quest tiles with colors.
|
||||
match: /className:(\i\(\)\(\i.container,\i\)),/,
|
||||
replace: "className:$self.getQuestTileClasses($1,arguments[0].quest),style:$self.getQuestTileStyle(arguments[0].quest),"
|
||||
match: /(?<=\i.current=\i},className:)(\i\(\)\(\i.\i,\i\)),/,
|
||||
replace: "$self.getQuestTileClasses($1,arguments[0].quest),style:$self.getQuestTileStyle(arguments[0].quest),"
|
||||
},
|
||||
{
|
||||
// Encourages banners to load quicker if the setting is enabled.
|
||||
|
|
@ -1383,7 +1449,7 @@ export default definePlugin({
|
|||
{
|
||||
// Loads the last used sort method and filter choices.
|
||||
// Defaults to sorting by "Questify" and no filters.
|
||||
find: "headingControls,children:",
|
||||
find: "({resetSortingFiltering:()",
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
|
|
@ -1417,7 +1483,7 @@ export default definePlugin({
|
|||
// Whether preloading assets is enabled or not, the placeholders loading
|
||||
// before the assets causes a lot of element shifting, whereas if
|
||||
// the elements load immediately instead, it doesn't.
|
||||
find: "rewardDescriptionContainer,children",
|
||||
find: ",{rewardWithArticleHook:()",
|
||||
replacement: {
|
||||
match: /showPlaceholder:!\i/,
|
||||
replace: "showPlaceholder:false"
|
||||
|
|
@ -1430,7 +1496,7 @@ export default definePlugin({
|
|||
replacement: [
|
||||
{
|
||||
// Resume Video Quest.
|
||||
match: /(onClick:\(\)=>)(\(0,\i.openVideoQuestModal\)\({quest:(\i))/,
|
||||
match: /(onClick:\(\)=>)(\(0,\i.\i\)\({quest:(\i))/,
|
||||
replace: "$1!$self.processQuestForAutoComplete($3)&&$2"
|
||||
},
|
||||
{
|
||||
|
|
@ -1473,7 +1539,7 @@ export default definePlugin({
|
|||
{
|
||||
// Sets intervals to progress Play Game Quests in the background.
|
||||
// Triggers if a Quest has already been started but was interrupted, such as by a reload.
|
||||
find: "platformSelectorPrimary,",
|
||||
find: "WATCH_VIDEO,skipEnrollmentCheck:!0})",
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
|
|
|
|||
|
|
@ -364,7 +364,6 @@ function validateQuestButtonSetting() {
|
|||
|
||||
function validateDisableQuestSetting() {
|
||||
const {
|
||||
disableQuestsEverything,
|
||||
disableQuestsDiscoveryTab,
|
||||
disableQuestsFetchingQuests,
|
||||
disableQuestsDirectMessagesTab,
|
||||
|
|
|
|||
|
|
@ -72,6 +72,21 @@ export interface ExcludedQuest {
|
|||
id: string;
|
||||
}
|
||||
|
||||
export enum QuestTaskType {
|
||||
WATCH_VIDEO = "WATCH_VIDEO",
|
||||
WATCH_VIDEO_ON_MOBILE = "WATCH_VIDEO_ON_MOBILE",
|
||||
PLAY_ON_DESKTOP = "PLAY_ON_DESKTOP",
|
||||
PLAY_ON_XBOX = "PLAY_ON_XBOX",
|
||||
PLAY_ON_PLAYSTATION = "PLAY_ON_PLAYSTATION",
|
||||
PLAY_ACTIVITY = "PLAY_ACTIVITY",
|
||||
ACHIEVEMENT_IN_ACTIVITY = "ACHIEVEMENT_IN_ACTIVITY"
|
||||
}
|
||||
|
||||
export interface QuestTask {
|
||||
type: QuestTaskType;
|
||||
target: number;
|
||||
}
|
||||
|
||||
export interface Quest {
|
||||
questifyNumber: number;
|
||||
id: string;
|
||||
|
|
@ -88,36 +103,40 @@ export interface Quest {
|
|||
rewardsConfig: {
|
||||
rewards: {
|
||||
type: QuestRewardType;
|
||||
orbQuantity?: number;
|
||||
messages?: {
|
||||
nameWithArticle: string;
|
||||
};
|
||||
}[];
|
||||
},
|
||||
taskConfigV2: {
|
||||
tasks: {
|
||||
WATCH_VIDEO?: {
|
||||
type: "WATCH_VIDEO";
|
||||
type: QuestTaskType.WATCH_VIDEO;
|
||||
target: number;
|
||||
},
|
||||
WATCH_VIDEO_ON_MOBILE?: {
|
||||
type: "WATCH_VIDEO_ON_MOBILE";
|
||||
type: QuestTaskType.WATCH_VIDEO_ON_MOBILE;
|
||||
target: number;
|
||||
},
|
||||
PLAY_ON_DESKTOP?: {
|
||||
type: "PLAY_ON_DESKTOP";
|
||||
type: QuestTaskType.PLAY_ON_DESKTOP;
|
||||
target: number;
|
||||
},
|
||||
PLAY_ON_XBOX?: {
|
||||
type: "PLAY_ON_XBOX";
|
||||
type: QuestTaskType.PLAY_ON_XBOX;
|
||||
target: number;
|
||||
},
|
||||
PLAY_ON_PLAYSTATION?: {
|
||||
type: "PLAY_ON_PLAYSTATION";
|
||||
type: QuestTaskType.PLAY_ON_PLAYSTATION;
|
||||
target: number;
|
||||
},
|
||||
PLAY_ACTIVITY?: {
|
||||
type: "PLAY_ACTIVITY";
|
||||
type: QuestTaskType.PLAY_ACTIVITY;
|
||||
target: number;
|
||||
};
|
||||
ACHIEVEMENT_IN_ACTIVITY?: {
|
||||
type: "ACHIEVEMENT_IN_ACTIVITY";
|
||||
type: QuestTaskType.ACHIEVEMENT_IN_ACTIVITY;
|
||||
target: number;
|
||||
eventName: "progress";
|
||||
applications: {
|
||||
|
|
@ -134,27 +153,27 @@ export interface Quest {
|
|||
enrolledAt: string | null;
|
||||
progress: null | {
|
||||
WATCH_VIDEO?: {
|
||||
eventName: "WATCH_VIDEO";
|
||||
eventName: QuestTaskType.WATCH_VIDEO;
|
||||
value: number;
|
||||
},
|
||||
WATCH_VIDEO_ON_MOBILE?: {
|
||||
eventName: "WATCH_VIDEO_ON_MOBILE";
|
||||
eventName: QuestTaskType.WATCH_VIDEO_ON_MOBILE;
|
||||
value: number;
|
||||
},
|
||||
PLAY_ON_DESKTOP?: {
|
||||
eventName: "PLAY_ON_DESKTOP";
|
||||
eventName: QuestTaskType.PLAY_ON_DESKTOP;
|
||||
value: number;
|
||||
},
|
||||
PLAY_ON_XBOX?: {
|
||||
eventName: "PLAY_ON_XBOX";
|
||||
eventName: QuestTaskType.PLAY_ON_XBOX;
|
||||
value: number;
|
||||
},
|
||||
PLAY_ON_PLAYSTATION?: {
|
||||
eventName: "PLAY_ON_PLAYSTATION";
|
||||
eventName: QuestTaskType.PLAY_ON_PLAYSTATION;
|
||||
value: number;
|
||||
},
|
||||
PLAY_ACTIVITY?: {
|
||||
eventName: "PLAY_ACTIVITY";
|
||||
eventName: QuestTaskType.PLAY_ACTIVITY;
|
||||
value: number;
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@
|
|||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*/
|
||||
|
||||
import { questIsIgnored, settings } from "@equicordplugins/questify/settings";
|
||||
import { classNameFactory } from "@utils/css";
|
||||
import { Logger } from "@utils/Logger";
|
||||
import { findByPropsLazy } from "@webpack";
|
||||
import { FluxDispatcher, RestAPI, UserStore } from "@webpack/common";
|
||||
|
||||
import { Quest, QuestStatus, RGB } from "./components";
|
||||
import { activeQuestIntervals } from "..";
|
||||
import { questIsIgnored, settings } from "../settings";
|
||||
import { Quest, QuestStatus, QuestTask, QuestTaskType, RGB } from "./components";
|
||||
|
||||
export const q = classNameFactory("questify-");
|
||||
export const QuestifyLogger = new Logger("Questify");
|
||||
|
|
@ -38,6 +39,46 @@ export function getIgnoredQuestIDs(userId?: string): string[] {
|
|||
return ignoredQuestIDs[key];
|
||||
}
|
||||
|
||||
export function getQuestTask(quest: Quest): QuestTask {
|
||||
const tasks = quest.config.taskConfigV2?.tasks;
|
||||
|
||||
return (tasks.PLAY_ON_DESKTOP ||
|
||||
tasks.PLAY_ON_XBOX ||
|
||||
tasks.PLAY_ON_PLAYSTATION ||
|
||||
tasks.PLAY_ACTIVITY ||
|
||||
tasks.WATCH_VIDEO ||
|
||||
tasks.WATCH_VIDEO_ON_MOBILE ||
|
||||
tasks.ACHIEVEMENT_IN_ACTIVITY) as QuestTask;
|
||||
}
|
||||
|
||||
export function getQuestProgress(quest: Quest, task: QuestTask) {
|
||||
const intervalData = activeQuestIntervals.get(quest.id);
|
||||
|
||||
if (intervalData) { return intervalData.progress; }
|
||||
|
||||
const progressMap = quest.userStatus?.progress;
|
||||
|
||||
if (!progressMap) { return null; }
|
||||
|
||||
if (task.type === QuestTaskType.WATCH_VIDEO || task.type === QuestTaskType.WATCH_VIDEO_ON_MOBILE) {
|
||||
const watchProgress = progressMap.WATCH_VIDEO?.value;
|
||||
const mobileProgress = progressMap.WATCH_VIDEO_ON_MOBILE?.value;
|
||||
|
||||
if (watchProgress !== undefined || mobileProgress !== undefined) {
|
||||
return Math.max(watchProgress ?? 0, mobileProgress ?? 0);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return progressMap[task.type]?.value ?? null;
|
||||
}
|
||||
|
||||
export function getQuestTarget(task: QuestTask) {
|
||||
const isWatch = task.type === QuestTaskType.WATCH_VIDEO || task.type === QuestTaskType.WATCH_VIDEO_ON_MOBILE;
|
||||
return task.target - (isWatch ? videoQuestLeeway : 0);
|
||||
}
|
||||
|
||||
export function getQuestStatus(quest: Quest, checkIgnored: boolean = true): QuestStatus {
|
||||
const completedQuest = quest.userStatus?.completedAt;
|
||||
const claimedQuest = quest.userStatus?.claimedAt;
|
||||
|
|
|
|||
|
|
@ -959,7 +959,7 @@ export default definePlugin({
|
|||
},
|
||||
{
|
||||
// Replace names in profile popouts.
|
||||
find: "clickableUsername,\"aria-label\":",
|
||||
find: "shouldWrap:!0,loop:!0,inProfile:!0",
|
||||
replacement: {
|
||||
match: /(tags:\i,)nickname:(\i)/,
|
||||
replace: "$1showMeYourNameNickname:$2=$self.getMemberListProfilesReactionsVoiceNameText({...arguments[0],type:\"profilesPopout\"})??(arguments[0].nickname)"
|
||||
|
|
@ -968,7 +968,7 @@ export default definePlugin({
|
|||
{
|
||||
// Replace names in the profile tooltip for switching between guild and global profiles.
|
||||
// You must open a profile modal before the code this is patching will be searchable.
|
||||
find: "\"view-main-profile\",",
|
||||
find: 'id:"view-server-profile",',
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
|
|
@ -990,18 +990,18 @@ export default definePlugin({
|
|||
}
|
||||
},
|
||||
{
|
||||
find: "discriminator,forceUsername",
|
||||
find: "MESSAGE,userId:",
|
||||
group: true,
|
||||
replacement: [
|
||||
{
|
||||
// Replace names in reaction popouts.
|
||||
match: /(?<=className:\i.reactorInfo,children:)(\[.{0,450}?}\)\])/,
|
||||
replace: "($self.getMemberListProfilesReactionsVoiceNameElement({user:arguments[0].user,guildId:arguments[0].guildId,type:\"reactionsPopout\"}))??($1)"
|
||||
// Track hovering over reaction popouts.
|
||||
match: /(?<=return\(0,\i.\i\)\(\i.\i,{className:\i.\i,)(?=onContextMenu:\i=>)/,
|
||||
replace: "onMouseEnter:()=>{$self.addHoveringReactionPopout(arguments[0].user.id)},onMouseLeave:()=>{$self.removeHoveringReactionPopout(arguments[0].user.id)},$2"
|
||||
},
|
||||
{
|
||||
// Track hovering over reaction popouts.
|
||||
match: /(return\(0,\i.\i\)\(\i.\i,{className:\i.reactor,)(onContextMenu)/,
|
||||
replace: "$1onMouseEnter:()=>{$self.addHoveringReactionPopout(arguments[0].user.id)},onMouseLeave:()=>{$self.removeHoveringReactionPopout(arguments[0].user.id)},$2"
|
||||
// Replace names in reaction popouts.
|
||||
match: /(?<=Child,{className:\i.\i,children:)/,
|
||||
replace: "($self.getMemberListProfilesReactionsVoiceNameElement({user:arguments[0].user,guildId:arguments[0].guildId,type:\"reactionsPopout\"}))??"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -328,8 +328,8 @@ export default definePlugin({
|
|||
replace: "const silentTypingShouldHideChatBarTypingIndicators=$self.shouldHideChatBarTypingIndicators();$1"
|
||||
},
|
||||
{
|
||||
match: /(typingDots,ref:\i,children:)(\[.{0,340}?}\)\])/,
|
||||
replace: "$1silentTypingShouldHideChatBarTypingIndicators?[]:$2"
|
||||
match: /("stop-animation".{0,80}?ref:\i,children:)/,
|
||||
replace: "$1silentTypingShouldHideChatBarTypingIndicators?[]:"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue