5180 fichiers 38.5 Mo 0 téléchargements 476 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / room / widgets / pet-breeding / MonsterPlantBreedingView.tsx
MonsterPlantBreedingView.tsx 21.4 Ko Télécharger le fichier
import {
    AddLinkEventTracker,
    BreedPetsMessageComposer,
    GetRoomEngine,
    GetSessionDataManager,
    ILinkEventTracker,
    IPetBreedingResultData,
    RemoveLinkEventTracker,
    RoomObjectCategory,
    RoomObjectType,
    RoomSessionPetBreedingEvent,
    RoomSessionPetBreedingResultEvent,
} from "@octane/renderer";
import { FC, useEffect, useState } from "react";
import {
    LocalizeText,
    localizeWithFallback,
    SendMessageComposer,
} from "../../../../api";
import {
    Button,
    LayoutFurniImageView,
    LayoutPetImageView,
    OctaneCardContentView,
    OctaneCardHeaderView,
    OctaneCardView,
    Text,
} from "../../../../common";
import { useOctaneEvent, useRoom } from "../../../../hooks";
import { ContextMenuHeaderView } from "../context-menu/ContextMenuHeaderView";
import { ContextMenuListItemView } from "../context-menu/ContextMenuListItemView";
import { ContextMenuView } from "../context-menu/ContextMenuView";
import '../../../../css/room/RoomWidgetsSweepAir.css';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

// Official RoomWidgetPetBreedingEvent states.
const STATE_OPEN = 0;
const STATE_CANCEL = 1;
const STATE_ACCEPT = 2;
const STATE_REQUEST = 3;

interface BreedTarget {
    roomIndex: number;
    name: string;
}

interface BreedPair {
    requestIndex: number;
    targetIndex: number;
}

const figureTypeId = (figure: string) =>
    parseInt((figure ?? "").split(" ")[0] ?? "-1", 10);

/* Official monster plant breeding (BreedPetView, BreedMonsterPlantsConfirmationView,
   BreedPetsResultView): "breed" on a grown plant marks the plants it can breed with, the owner
   of the other plant is asked when it is not yours, and both owners see the two seeds. */
export const MonsterPlantBreedingView: FC = () => {
    const [bubbles, setBubbles] = useState<{
        requestIndex: number;
        targets: BreedTarget[];
    }>(null);
    const [confirm, setConfirm] = useState<BreedPair & { requested: boolean }>(
        null,
    );
    const [waiting, setWaiting] = useState<BreedPair>(null);
    const [cancelled, setCancelled] = useState(false);
    const [result, setResult] = useState<{
        first: IPetBreedingResultData;
        second: IPetBreedingResultData;
    }>(null);
    const { roomSession = null } = useRoom();

    const userData = (roomIndex: number) =>
        roomSession?.userDataManager?.getUserDataByIndex(roomIndex) ?? null;
    const roomIndexOfPet = (webId: number) =>
        roomSession?.userDataManager?.getPetData(webId)?.roomIndex ?? -1;

    const send = (state: number, pair: BreedPair) => {
        const first = userData(pair.requestIndex);
        const second = userData(pair.targetIndex);

        if (!first || !second) return;

        SendMessageComposer(
            new BreedPetsMessageComposer(state, first.webID, second.webID),
        );
    };

    useEffect(() => {
        const linkTracker: ILinkEventTracker = {
            linkReceived: (url: string) => {
                const parts = url.split("/");

                if (parts[1] !== "request" || !roomSession) return;

                const requestIndex = parseInt(parts[2] ?? "", 10);
                const plant =
                    roomSession.userDataManager?.getUserDataByIndex(
                        requestIndex,
                    );

                if (!plant) return;

                const ownUserId = GetSessionDataManager().userId;
                const typeId = figureTypeId(plant.figure);
                const targets: BreedTarget[] = [];

                for (const roomObject of GetRoomEngine().getRoomObjects(
                    roomSession.roomId,
                    RoomObjectCategory.UNIT,
                )) {
                    const pet = roomSession.userDataManager.getUserDataByIndex(
                        roomObject.id,
                    );

                    if (
                        !pet ||
                        pet.type !== RoomObjectType.PET ||
                        !pet.canBreed
                    )
                        continue;
                    if (!pet.hasBreedingPermission && pet.ownerId !== ownUserId)
                        continue;
                    if (!roomSession.userDataManager.getUserData(pet.ownerId))
                        continue;
                    if (
                        figureTypeId(pet.figure) !== typeId ||
                        pet.roomIndex === requestIndex
                    )
                        continue;

                    targets.push({ roomIndex: pet.roomIndex, name: pet.name });
                }

                setConfirm(null);
                setBubbles(targets.length ? { requestIndex, targets } : null);
            },
            eventUrlPrefix: "monsterplant-breeding/",
        };

        AddLinkEventTracker(linkTracker);

        return () => RemoveLinkEventTracker(linkTracker);
    }, [roomSession]);

    useOctaneEvent<RoomSessionPetBreedingEvent>(
        RoomSessionPetBreedingEvent.PET_BREEDING,
        (event) => {
            const pair = {
                requestIndex: roomIndexOfPet(event.ownPetId),
                targetIndex: roomIndexOfPet(event.otherPetId),
            };

            switch (event.state) {
                case STATE_OPEN:
                case STATE_REQUEST:
                    if (pair.requestIndex < 0 || pair.targetIndex < 0) return;

                    setConfirm({
                        ...pair,
                        requested: event.state === STATE_REQUEST,
                    });
                    return;
                case STATE_CANCEL:
                    setConfirm(null);
                    setWaiting(null);
                    setCancelled(true);
                    return;
                case STATE_ACCEPT:
                    setConfirm(null);
                    setWaiting(null);
                    return;
            }
        },
    );

    useOctaneEvent<RoomSessionPetBreedingResultEvent>(
        RoomSessionPetBreedingResultEvent.PET_BREEDING_RESULT,
        (event) => {
            setWaiting(null);
            setResult({
                first: event.resultData,
                second: event.otherResultData,
            });
        },
    );

    const confirmFirst = confirm ? userData(confirm.requestIndex) : null;
    const confirmSecond = confirm ? userData(confirm.targetIndex) : null;

    const cancelConfirm = () => {
        if (confirm) send(BreedPetsMessageComposer.STATE_CANCEL, confirm);
        setConfirm(null);
    };

    const useConfirm = () => {
        if (!confirm || !confirmFirst || !confirmSecond) return;

        send(BreedPetsMessageComposer.STATE_START, confirm);

        // A plant of somebody else: wait for them to answer.
        if (confirmFirst.ownerId !== confirmSecond.ownerId)
            setWaiting({
                requestIndex: confirm.requestIndex,
                targetIndex: confirm.targetIndex,
            });

        setConfirm(null);
    };

    const acceptConfirm = () => {
        if (confirm) send(BreedPetsMessageComposer.STATE_ACCEPT, confirm);
        setConfirm(null);
    };

    const ownUserId = GetSessionDataManager().userId;

    return (
        <NativeTextTree>
            <>
                {bubbles &&
                    bubbles.targets.map((target) => (
                        <ContextMenuView
                            key={target.roomIndex}
                            category={RoomObjectCategory.UNIT}
                            collapsable={true}
                            objectId={target.roomIndex}
                            userType={RoomObjectType.PET}
                            onClose={() => setBubbles(null)}
                        >
                            <ContextMenuHeaderView>
                                {target.name}
                            </ContextMenuHeaderView>
                            <ContextMenuListItemView
                                onClick={() => {
                                    setConfirm({
                                        requestIndex: bubbles.requestIndex,
                                        targetIndex: target.roomIndex,
                                        requested: false,
                                    });
                                    setBubbles(null);
                                }}
                            >
                                {LocalizeText("infostand.button.breed")}
                            </ContextMenuListItemView>
                        </ContextMenuView>
                    ))}

                {confirm && confirmFirst && confirmSecond && (
                    <OctaneCardView
                        className="octane-monsterplant-breeding"
                        theme="primary-slim"
                    >
                        <OctaneCardHeaderView
                            headerText={LocalizeText(
                                "breedpets.widget.title",
                                ["name"],
                                [confirmFirst.name],
                            )}
                            onCloseClick={cancelConfirm}
                        />
                        <OctaneCardContentView gap={2}>
                            <Text small>
                                {confirm.requested
                                    ? LocalizeText(
                                          "breedpets.widget.request",
                                          ["name"],
                                          [confirmSecond.ownerName],
                                      )
                                    : LocalizeText("breedpets.widget.text")}
                            </Text>
                            <div className="flex gap-2">
                                {[confirmFirst, confirmSecond].map(
                                    (plant, index) => (
                                        <div
                                            key={plant.roomIndex}
                                            className="octane-monsterplant-breeding__plant"
                                        >
                                            <div className="octane-monsterplant-breeding__preview">
                                                <LayoutPetImageView
                                                    direction={2}
                                                    figure={plant.figure}
                                                />
                                            </div>
                                            <Text bold truncate>
                                                {LocalizeText(
                                                    `breedpets.widget.plant${index + 1}.name`,
                                                    ["name"],
                                                    [plant.name],
                                                )}
                                            </Text>
                                            <Text small>
                                                {LocalizeText(
                                                    `breedpets.widget.plant${index + 1}.raritylevel`,
                                                    ["level"],
                                                    [String(plant.rarityLevel)],
                                                )}
                                            </Text>
                                            <Text small truncate variant="muted">
                                                {LocalizeText(
                                                    `breedpets.widget.plant${index + 1}.description`,
                                                    ["name"],
                                                    [plant.ownerName],
                                                )}
                                            </Text>
                                        </div>
                                    ),
                                )}
                            </div>
                            <Text small className="octane-monsterplant-breeding__info">
                                {LocalizeText("breedpets.widget.info")}
                            </Text>
                            <div className="flex justify-end gap-2">
                                <Button variant="secondary" onClick={cancelConfirm}>
                                    {LocalizeText("breedpets.widget.cancel")}
                                </Button>
                                {confirm.requested ? (
                                    <Button
                                        variant="success"
                                        onClick={acceptConfirm}
                                    >
                                        {LocalizeText("breedpets.widget.accept")}
                                    </Button>
                                ) : (
                                    <Button variant="success" onClick={useConfirm}>
                                        {LocalizeText("breedpets.widget.use")}
                                    </Button>
                                )}
                            </div>
                        </OctaneCardContentView>
                    </OctaneCardView>
                )}

                {waiting && (
                    <OctaneCardView
                        className="octane-monsterplant-breeding"
                        theme="primary-slim"
                    >
                        <OctaneCardHeaderView
                            headerText={LocalizeText(
                                "breedpets.confirmation.notification.title",
                            )}
                            onCloseClick={() => setWaiting(null)}
                        />
                        <OctaneCardContentView center gap={2}>
                            <Text center>
                                {LocalizeText(
                                    "breedpets.confirmation.notification.text",
                                )}
                            </Text>
                            <Button
                                variant="secondary"
                                onClick={() => {
                                    send(
                                        BreedPetsMessageComposer.STATE_CANCEL,
                                        waiting,
                                    );
                                    setWaiting(null);
                                }}
                            >
                                {LocalizeText("breedpets.widget.cancel")}
                            </Button>
                        </OctaneCardContentView>
                    </OctaneCardView>
                )}

                {cancelled && (
                    <OctaneCardView
                        className="octane-monsterplant-breeding"
                        theme="primary-slim"
                    >
                        <OctaneCardHeaderView
                            headerText={LocalizeText(
                                "breedpets.cancel.notification.title",
                            )}
                            onCloseClick={() => setCancelled(false)}
                        />
                        <OctaneCardContentView center gap={2}>
                            <Text center>
                                {LocalizeText("breedpets.cancel.notification.text")}
                            </Text>
                            <Button variant="secondary" onClick={() => setCancelled(false)}>
                                {localizeWithFallback("generic.ok", "OK")}
                            </Button>
                        </OctaneCardContentView>
                    </OctaneCardView>
                )}

                {result && (
                    <OctaneCardView
                        className="octane-monsterplant-breeding"
                        theme="primary-slim"
                    >
                        <OctaneCardHeaderView
                            headerText={LocalizeText(
                                "breedpetsresult.widget.title",
                            )}
                            onCloseClick={() => setResult(null)}
                        />
                        <OctaneCardContentView gap={2}>
                            {result.first.userId === ownUserId ||
                            result.second.userId === ownUserId ? (
                                <Text small>
                                    {LocalizeText("breedpetsresult.widget.text")}
                                </Text>
                            ) : (
                                <Text small>
                                    {LocalizeText(
                                        "breedpetsresult.widget.text.sorry",
                                        ["name"],
                                        [
                                            result.first.userName ||
                                                result.second.userName ||
                                                "",
                                        ],
                                    )}
                                </Text>
                            )}
                            <div className="flex gap-2">
                                {[result.first, result.second].map(
                                    (seed, index) => {
                                        // An empty slot: no seed for that side (-1 officially, 0 from the emulator).
                                        if (!seed || seed.stuffId <= 0) return null;

                                        const furni =
                                            GetSessionDataManager().getFloorItemData(
                                                seed.classId,
                                            );

                                        return (
                                            <div
                                                key={index}
                                                className="octane-monsterplant-breeding__plant"
                                            >
                                                <div className="octane-monsterplant-breeding__preview">
                                                    <LayoutFurniImageView
                                                        direction={2}
                                                        productClassId={
                                                            seed.classId
                                                        }
                                                        productType="s"
                                                    />
                                                </div>
                                                <Text bold truncate>
                                                    {LocalizeText(
                                                        `breedpetsresult.widget.seed${index + 1}.name`,
                                                        ["name"],
                                                        [furni?.name ?? ""],
                                                    )}
                                                </Text>
                                                <Text small>
                                                    {LocalizeText(
                                                        `breedpetsresult.widget.seed${index + 1}.raritylevel`,
                                                        ["level"],
                                                        [String(seed.rarityLevel)],
                                                    )}
                                                </Text>
                                                <Text
                                                    small
                                                    truncate
                                                    variant="muted"
                                                >
                                                    {LocalizeText(
                                                        `breedpetsresult.widget.seed${index + 1}.description`,
                                                        ["name"],
                                                        [seed.userName],
                                                    )}
                                                </Text>
                                                {seed.hasMutation && (
                                                    <Text small className="octane-monsterplant-breeding__info">
                                                        {LocalizeText(
                                                            "breedpetsresult.widget.info.mutation",
                                                        )}
                                                    </Text>
                                                )}
                                            </div>
                                        );
                                    },
                                )}
                            </div>
                            <div className="flex justify-end">
                                <Button variant="secondary" onClick={() => setResult(null)}>
                                    {LocalizeText("breedpetsresult.widget.close")}
                                </Button>
                            </div>
                        </OctaneCardContentView>
                    </OctaneCardView>
                )}
            </>
        </NativeTextTree>
    );
};
15Sujets
1Dépôts
20Membres
3En 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