5180 fichiers 38.5 Mo 0 téléchargements 242 vues mis à jour il y a 5 heures ui
useQuests.ts 6.7 Ko Télécharger le fichier
import {
    AcceptQuestMessageComposer,
    ActivateQuestMessageComposer,
    CancelQuestMessageComposer,
    GetDailyQuestMessageComposer,
    GetQuestsMessageComposer,
    OpenQuestTrackerMessageComposer,
    QuestCancelledMessageEvent,
    QuestCompletedMessageEvent,
    QuestDailyMessageEvent,
    QuestMessageData,
    QuestMessageEvent,
    QuestsMessageEvent,
    RejectQuestMessageComposer,
    StartCampaignMessageComposer
} from '@octane/renderer';
import { useCallback, useMemo, useState } from 'react';
import { registerSharedHook, useSharedHook } from '@/state/useSharedHook';
import { GetConfigurationValue, isSeasonalQuest, localizeWithFallback, NotificationAlertType, SendMessageComposer } from '../../api';
import { useMessageEvent } from '../events';
import { useNotification } from '../notification';
import { useRoom } from '../rooms';

export interface QuestCompletion {
    quest: QuestMessageData;
    showDialog: boolean;
    receivedAt: number;
}

export interface DailyQuestState {
    quest: QuestMessageData;
    easyQuestCount: number;
    hardQuestCount: number;
}

/**
 * The quest engine state of the official client (HabboQuestEngine + QuestController): the campaign
 * list, the tracked quest, the last completion and the daily quest of the landing widget.
 */
const useQuestsState = () => {
    const [quests, setQuests] = useState<QuestMessageData[]>([]);
    const [openRequests, setOpenRequests] = useState(0);
    const [trackedQuest, setTrackedQuest] = useState<QuestMessageData>(null);
    const [completion, setCompletion] = useState<QuestCompletion>(null);
    const [dailyQuest, setDailyQuest] = useState<DailyQuestState>(null);
    const [questClock, setQuestClock] = useState(0);
    const { roomSession = null } = useRoom();
    const { simpleAlert = null } = useNotification();

    const isInRoom = !!roomSession;

    const requestQuests = useCallback(() => SendMessageComposer(new GetQuestsMessageComposer()), []);

    /** Inside a room the official client accepts, outside it activates (hotel view, daily widget). */
    const acceptQuest = useCallback(
        (questId: number) => {
            if (isInRoom) SendMessageComposer(new AcceptQuestMessageComposer(questId));
            else SendMessageComposer(new ActivateQuestMessageComposer(questId));
        },
        [isInRoom]
    );

    const rejectQuest = useCallback((questId: number) => SendMessageComposer(new RejectQuestMessageComposer(questId)), []);

    const cancelDailyQuest = useCallback(() => SendMessageComposer(new CancelQuestMessageComposer()), []);

    /** The tracker asks for the next quest after the completion animation. */
    const requestNextQuest = useCallback(() => SendMessageComposer(new OpenQuestTrackerMessageComposer()), []);

    const startCampaign = useCallback((campaignCode: string) => SendMessageComposer(new StartCampaignMessageComposer(campaignCode)), []);

    const requestDailyQuest = useCallback((easy: boolean, index: number) => SendMessageComposer(new GetDailyQuestMessageComposer(easy, index)), []);

    const clearCompletion = useCallback(() => setCompletion(null), []);

    const clearTrackedQuest = useCallback(() => setTrackedQuest(null), []);

    /**
     * NextQuestTimer.refresh(): once the wait is over the timer zeroes it and hands the quest back to
     * the quest controller, so the tracker and the list show it as a normal quest.
     */
    const releaseDelayedQuest = useCallback((quest: QuestMessageData) => {
        if (!quest) return;

        quest.waitPeriodSeconds = 0;
        setQuests((prevValue) => [...prevValue]);
        setQuestClock(Date.now());
    }, []);

    const replaceQuestInList = useCallback((quest: QuestMessageData, accepted: boolean) => {
        setQuests((prevValue) =>
            prevValue.map((existing) => {
                if (existing.campaignCode !== quest.campaignCode) return existing;

                if (existing.id === quest.id) return quest;

                existing.accepted = accepted && existing.id === quest.id;

                return existing;
            })
        );
    }, []);

    useMessageEvent<QuestsMessageEvent>(QuestsMessageEvent, (event) => {
        const parser = event.getParser();

        // QuestsList.onQuests: the campaigns of the seasonal calendar live in their own window.
        const seasonalPrefix = String(GetConfigurationValue<string>('seasonalQuestCalendar.campaignPrefix', '') ?? '');

        setQuests(parser.quests.filter((quest) => !isSeasonalQuest(quest, seasonalPrefix)));

        if (parser.openWindow) setOpenRequests((prevValue) => prevValue + 1);
    });

    useMessageEvent<QuestMessageEvent>(QuestMessageEvent, (event) => {
        const quest = event.getParser().quest;

        if (!quest) return;

        setTrackedQuest(quest);
        replaceQuestInList(quest, quest.accepted);
    });

    useMessageEvent<QuestCompletedMessageEvent>(QuestCompletedMessageEvent, (event) => {
        const parser = event.getParser();
        const quest = parser.questData;

        if (!quest) return;

        setCompletion({ quest, showDialog: parser.showDialog, receivedAt: Date.now() });
        setTrackedQuest(quest);
    });

    useMessageEvent<QuestCancelledMessageEvent>(QuestCancelledMessageEvent, (event) => {
        const parser = event.getParser();
        const quest = parser.quest;

        if (!quest) return;

        setTrackedQuest((prevValue) => (prevValue && prevValue.campaignChainCode === quest.campaignChainCode ? null : prevValue));
        replaceQuestInList(quest, false);

        if (parser.expired && simpleAlert) {
            simpleAlert(
                localizeWithFallback('quests.expired.body', 'The quest you were doing has expired.'),
                NotificationAlertType.DEFAULT,
                null,
                null,
                localizeWithFallback('quests.expired.title', 'Quest expired')
            );
        }
    });

    useMessageEvent<QuestDailyMessageEvent>(QuestDailyMessageEvent, (event) => {
        const parser = event.getParser();

        setDailyQuest({ quest: parser.quest ?? null, easyQuestCount: parser.easyQuestCount ?? 0, hardQuestCount: parser.hardQuestCount ?? 0 });
    });

    const acceptedQuest = useMemo(() => quests.find((quest) => quest.accepted) ?? null, [quests]);

    return {
        quests,
        openRequests,
        trackedQuest,
        completion,
        dailyQuest,
        acceptedQuest,
        isInRoom,
        questClock,
        requestQuests,
        acceptQuest,
        rejectQuest,
        cancelDailyQuest,
        requestNextQuest,
        startCampaign,
        requestDailyQuest,
        clearCompletion,
        clearTrackedQuest,
        releaseDelayedQuest
    };
};

registerSharedHook(useQuestsState);

export const useQuests = () => useSharedHook(useQuestsState);
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser