From 6dc2bbbf8c3d89c2b512b79d59b234bbcb0f9b3d Mon Sep 17 00:00:00 2001 From: dank074 Date: Tue, 3 Jan 2023 01:04:27 -0600 Subject: [PATCH] Feature/mystery box (#85) * create furniture interaction view * add right-side view for mysterybox * update dialogue view * style the mysterybox extension * fix box overlay blending * convert mode to enum Co-authored-by: Bill --- src/api/utils/ColorUtils.ts | 11 +++ .../chain_mysterybox_box_overlay.png | Bin 0 -> 369 bytes src/assets/images/mysterybox/key_overlay.png | Bin 0 -> 260 bytes src/assets/images/mysterybox/mystery_box.png | Bin 0 -> 514 bytes .../images/mysterybox/mystery_box_key.png | Bin 0 -> 487 bytes src/assets/images/prize/prize_background.png | Bin 0 -> 5861 bytes src/common/layout/LayoutFurniImageView.tsx | 2 +- .../layout/LayoutPrizeProductImageView.tsx | 30 +++++++ src/components/right-side/RightSideView.tsx | 2 + src/components/room/widgets/RoomWidgets.scss | 1 + .../FurnitureMysteryBoxOpenDialogView.tsx | 81 ++++++++++++++++++ .../widgets/furniture/FurnitureWidgets.scss | 15 ++++ .../context-menu/FurnitureContextMenuView.tsx | 24 ++++-- .../mysterybox/MysteryBoxExtensionView.scss | 52 +++++++++++ .../mysterybox/MysteryBoxExtensionView.tsx | 66 ++++++++++++++ .../useFurnitureContextMenuWidget.ts | 27 ++++-- 16 files changed, 295 insertions(+), 16 deletions(-) create mode 100644 src/assets/images/mysterybox/chain_mysterybox_box_overlay.png create mode 100644 src/assets/images/mysterybox/key_overlay.png create mode 100644 src/assets/images/mysterybox/mystery_box.png create mode 100644 src/assets/images/mysterybox/mystery_box_key.png create mode 100644 src/assets/images/prize/prize_background.png create mode 100644 src/common/layout/LayoutPrizeProductImageView.tsx create mode 100644 src/components/room/widgets/furniture/FurnitureMysteryBoxOpenDialogView.tsx create mode 100644 src/components/room/widgets/mysterybox/MysteryBoxExtensionView.scss create mode 100644 src/components/room/widgets/mysterybox/MysteryBoxExtensionView.tsx diff --git a/src/api/utils/ColorUtils.ts b/src/api/utils/ColorUtils.ts index e31643b6..c32f8fba 100644 --- a/src/api/utils/ColorUtils.ts +++ b/src/api/utils/ColorUtils.ts @@ -51,4 +51,15 @@ export class ColorUtils { return (((val1) << 24) + ((val2) << 16) + ((val3) << 8) + (val4| 0)); } + + public static int2rgb(color: number): string + { + color >>>= 0; + const b = color & 0xFF; + const g = (color & 0xFF00) >>> 8; + const r = (color & 0xFF0000) >>> 16; + const a = ((color & 0xFF000000) >>> 24) / 255; + + return 'rgba(' + [ r, g, b, 1 ].join(',') + ')'; + } } diff --git a/src/assets/images/mysterybox/chain_mysterybox_box_overlay.png b/src/assets/images/mysterybox/chain_mysterybox_box_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..5914aa5a271fe25af79a641e30a45c5da3d41d25 GIT binary patch literal 369 zcmV-%0gnEOP)3Gx6&2>W13hFi)ZBcMzd0!0Nqkz>VLB0nOgNf zS@BG*`k(B0rfIoNOgvMw{YP;;lNJBSwG<`sOji8U!nbru)uUh(3>g3bS^C6Ts=iT~ P00000NkvXXu0mjf#8I%7 literal 0 HcmV?d00001 diff --git a/src/assets/images/mysterybox/key_overlay.png b/src/assets/images/mysterybox/key_overlay.png new file mode 100644 index 0000000000000000000000000000000000000000..8f8c2a5bed7d0d06872c2e34613899589a16abcf GIT binary patch literal 260 zcmV+f0sH=mP)HY@RK!QR(ACl#y%OXjCs>k(Wv|#qW8y#SP z+3V(TG=L7amF}8DGC0`4)&}$}lY41^4pxEouRDfk08InzvF;9bV2GH)L5z5uy>tg7 z;wZ-yab`(+#5jlbe7MFD@m37i%h=*{2YvRUAmA8H#BKi8^A=|o1ZNPz_!c#~2T=9Q z5pe}P*38sms))ZVYMK|!co*|Lui_SA0y~RXKQ@viNs=TH$6>u0ZYXe|37>7?3_7sPMkQgW57>A> z76qQ8Tvis%_x|tseMzjPe{GjXP}d6EY>A0~J3bz<*dSuQ%q)*}gE`}(tBc#d9SbZv z_V4WTiMNhi`mDM^>*SBhy|O%;U&XdrT=UZm{k+HKa$5TH%?1;lKNz)6v|PdQE^xc* zo};fh*Ol=kpB1;|ZB#mZ;QJ%LwJ)j~GF{d!^Qr3ERD1ZuD>IFN=Y~A(flR+V?_HU` zFmU;r=865w`rlvXV@s;l3I5)#^!WGIXEuC+bEntt*WSME+2x;q*{(~MFkCTxe@tG& zSLJ@0xi4#}>drI9_kH%PzNRnV*l*WxZ*I%I(lV~+CBN9`x)(l;Dz2M&I-@8jlH*X$ z-L)z4O?)=Kaj6+hvWs@g24t>lTPR`j>F{OsQ0>Qjv;Onxx0h=idf_ShV8!}uDe13& yJFBI-TKC!XF5-=Qaq4b^e#vu*eJ>=>e`enxD!^x~!@~v)YX(nOKbLh*2~7ZPWa%0J literal 0 HcmV?d00001 diff --git a/src/assets/images/mysterybox/mystery_box_key.png b/src/assets/images/mysterybox/mystery_box_key.png new file mode 100644 index 0000000000000000000000000000000000000000..79b43deee659e915eed87ae86ce3c6acb712c490 GIT binary patch literal 487 zcmeAS@N?(olHy`uVBq!ia0vp^>LAR)3?z5gE@TH%jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCf`V@Ck7R(*OVbJA3wQVPWC2Wy^kk|M~Ly%LNM-96We%_wL>6)~(yRbt_Pf zb^G!6K#I2{$S?Rm5@4`>q0|PH;4JWnEM{QfI}E~%$MaXD04+E0ba4!^@bA4GIq9$h z4@*GDWW~PP|DXNJxi_v-yDWdNLN$@=(q2`?uN&2WOq%GMr}vcIY2}smvxTiyM5lLe z&hmHSUc&q0mFLf|hXWnAKJ!(UTE8)iC&6#&l=j0HD@~tOu8?{7s>-zOL*3#z2j8Wo zeW+b7v~#nRtEhAN8-o(nrpi*)mKkT?m>iUSB(#I~QEWkJ;OnD_Z898D>wg=zrQV3+ z3e#%&VPmz)pXK1OuZOE&epvNML|S$h)3*KF=IC#Hw&A+P&QnpZqt;rQoL%$$OjP{z z&98Fu?p;|EWnH|SwXjWkm9UwaReFSuoZ`HD$6i##{koHLCL_Jz7pqTxij?Ck<)+Ct ze-8yDb?M%|W5V_Qzx|Az?|u4m;#zI3PR6gkc(wSWx$*b4nuh|{y{HMecIUf3`#$x# Um)HD@1_mgDr>mdKI;Vst0L75q*8l(j literal 0 HcmV?d00001 diff --git a/src/assets/images/prize/prize_background.png b/src/assets/images/prize/prize_background.png new file mode 100644 index 0000000000000000000000000000000000000000..ec9c0306536734ee07dc697eec63304e2c0721c6 GIT binary patch literal 5861 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 vEe_GQ{n3LsW(ekZI+OkEH5`9>uD$*r;of+ = props => if(imageResult) { const image = imageResult.getImage(); - + image.onload = () => setImageElement(image); } }, [ productType, productClassId, direction, extraData ]); diff --git a/src/common/layout/LayoutPrizeProductImageView.tsx b/src/common/layout/LayoutPrizeProductImageView.tsx new file mode 100644 index 00000000..206c7a80 --- /dev/null +++ b/src/common/layout/LayoutPrizeProductImageView.tsx @@ -0,0 +1,30 @@ +import { FC } from 'react'; +import { ProductTypeEnum } from '../../api'; +import { LayoutBadgeImageView } from './LayoutBadgeImageView'; +import { LayoutCurrencyIcon } from './LayoutCurrencyIcon'; +import { LayoutFurniImageView } from './LayoutFurniImageView'; + +interface LayoutPrizeProductImageViewProps +{ + productType: string; + classId: number; + extraParam?: string; +} + +export const LayoutPrizeProductImageView: FC = props => +{ + const { productType = ProductTypeEnum.FLOOR, classId = -1, extraParam = undefined } = props; + + switch(productType) + { + case ProductTypeEnum.WALL: + case ProductTypeEnum.FLOOR: + return + case ProductTypeEnum.BADGE: + return + case ProductTypeEnum.HABBO_CLUB: + return + } + + return null; +} diff --git a/src/components/right-side/RightSideView.tsx b/src/components/right-side/RightSideView.tsx index c679711a..92e81290 100644 --- a/src/components/right-side/RightSideView.tsx +++ b/src/components/right-side/RightSideView.tsx @@ -4,6 +4,7 @@ import { OfferView } from '../catalog/views/targeted-offer/OfferView'; import { GroupRoomInformationView } from '../groups/views/GroupRoomInformationView'; import { NotificationCenterView } from '../notification-center/NotificationCenterView'; import { PurseView } from '../purse/PurseView'; +import { MysteryBoxExtensionView } from '../room/widgets/mysterybox/MysteryBoxExtensionView'; import { RoomPromotesWidgetView } from '../room/widgets/room-promotes/RoomPromotesWidgetView'; export const RightSideView: FC<{}> = props => @@ -13,6 +14,7 @@ export const RightSideView: FC<{}> = props => + diff --git a/src/components/room/widgets/RoomWidgets.scss b/src/components/room/widgets/RoomWidgets.scss index 38270c32..d529dcca 100644 --- a/src/components/room/widgets/RoomWidgets.scss +++ b/src/components/room/widgets/RoomWidgets.scss @@ -106,3 +106,4 @@ @import './context-menu/ContextMenu'; @import './friend-request/FriendRequestDialogView'; @import './furniture/FurnitureWidgets'; +@import './mysterybox/MysteryBoxExtensionView'; diff --git a/src/components/room/widgets/furniture/FurnitureMysteryBoxOpenDialogView.tsx b/src/components/room/widgets/furniture/FurnitureMysteryBoxOpenDialogView.tsx new file mode 100644 index 00000000..88821e0f --- /dev/null +++ b/src/components/room/widgets/furniture/FurnitureMysteryBoxOpenDialogView.tsx @@ -0,0 +1,81 @@ +import { CancelMysteryBoxWaitMessageEvent, GotMysteryBoxPrizeMessageEvent, MysteryBoxWaitingCanceledMessageComposer, ShowMysteryBoxWaitMessageEvent } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { GetSessionDataManager, LocalizeText, SendMessageComposer } from '../../../../api'; +import { Button, Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common'; +import { LayoutPrizeProductImageView } from '../../../../common/layout/LayoutPrizeProductImageView'; +import { useMessageEvent } from '../../../../hooks'; + +interface FurnitureMysteryBoxOpenDialogViewProps +{ + ownerId: number; +} + +type PrizeData = { + contentType:string; + classId:number; +} + +enum ViewMode { + HIDDEN, + WAITING, + PRIZE +} + +export const FurnitureMysteryBoxOpenDialogView: FC = props => +{ + const { ownerId = -1 } = props; + const [ mode, setMode ] = useState(ViewMode.HIDDEN); + const [ prizeData, setPrizeData ] = useState(undefined); + + const close = () => + { + if(mode === ViewMode.WAITING) SendMessageComposer(new MysteryBoxWaitingCanceledMessageComposer(ownerId)); + setMode(ViewMode.HIDDEN); + setPrizeData(undefined); + } + + useMessageEvent(ShowMysteryBoxWaitMessageEvent, event => + { + setMode(ViewMode.WAITING); + }); + + useMessageEvent(CancelMysteryBoxWaitMessageEvent, event => + { + setMode(ViewMode.HIDDEN); + setPrizeData(undefined); + }); + + useMessageEvent(GotMysteryBoxPrizeMessageEvent, event => + { + const parser = event.getParser(); + setPrizeData({ contentType: parser.contentType, classId: parser.classId }); + setMode(ViewMode.PRIZE); + }); + + const isOwner = GetSessionDataManager().userId === ownerId; + + if(mode === ViewMode.HIDDEN) return null; + + return ( + + + + { mode === ViewMode.WAITING && <> + { LocalizeText(`mysterybox.dialog.${ isOwner ? 'owner' : 'other' }.subtitle`) } + { LocalizeText(`mysterybox.dialog.${ isOwner ? 'owner' : 'other' }.description`) } + { LocalizeText(`mysterybox.dialog.${ isOwner ? 'owner' : 'other' }.waiting`) } + + + } + { mode === ViewMode.PRIZE && prizeData && <> + { LocalizeText('mysterybox.reward.text') } + + + + + + } + + + ); +} diff --git a/src/components/room/widgets/furniture/FurnitureWidgets.scss b/src/components/room/widgets/furniture/FurnitureWidgets.scss index 433a139c..f1783b61 100644 --- a/src/components/room/widgets/furniture/FurnitureWidgets.scss +++ b/src/components/room/widgets/furniture/FurnitureWidgets.scss @@ -406,6 +406,7 @@ &:not(.playing-song):not(.selected-song) { -webkit-mask-image: url("../../../../assets/images/room-widgets/playlist-editor/disk_2.png"); + mask-image: url("../../../../assets/images/room-widgets/playlist-editor/disk_2.png"); } } @@ -442,8 +443,22 @@ .disk-image { background: url("../../../../assets/images/room-widgets/playlist-editor/disk_image.png"); -webkit-mask-image: url("../../../../assets/images/room-widgets/playlist-editor/disk_image.png"); + mask-image: url("../../../../assets/images/room-widgets/playlist-editor/disk_image.png"); height: 76px; width: 76px; } } } + +.nitro-mysterybox-dialog { + width: 375px; + height: 210px; + + .prize-container { + height: 80px; + width: 81px; + background-image: url('../../../../assets/images/prize/prize_background.png'); + background-repeat: no-repeat; + background-position: center; + } +} diff --git a/src/components/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx b/src/components/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx index a0795b58..6eacf27b 100644 --- a/src/components/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx +++ b/src/components/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx @@ -1,22 +1,18 @@ import { ContextMenuEnum, CustomUserNotificationMessageEvent, RoomObjectCategory } from '@nitrots/nitro-renderer'; import { FC } from 'react'; -import { GetGroupInformation, LocalizeText } from '../../../../../api'; -import { useFurnitureContextMenuWidget, useMessageEvent, useNotification } from '../../../../../hooks'; +import { GetGroupInformation, GetSessionDataManager, LocalizeText } from '../../../../../api'; +import { EFFECTBOX_OPEN, GROUP_FURNITURE, MONSTERPLANT_SEED_CONFIRMATION, PURCHASABLE_CLOTHING_CONFIRMATION, useFurnitureContextMenuWidget, useMessageEvent, useNotification } from '../../../../../hooks'; import { ContextMenuHeaderView } from '../../context-menu/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../context-menu/ContextMenuListItemView'; import { ContextMenuView } from '../../context-menu/ContextMenuView'; +import { FurnitureMysteryBoxOpenDialogView } from '../FurnitureMysteryBoxOpenDialogView'; import { EffectBoxConfirmView } from './EffectBoxConfirmView'; import { MonsterPlantSeedConfirmView } from './MonsterPlantSeedConfirmView'; import { PurchasableClothingConfirmView } from './PurchasableClothingConfirmView'; -const MONSTERPLANT_SEED_CONFIRMATION: string = 'MONSTERPLANT_SEED_CONFIRMATION'; -const PURCHASABLE_CLOTHING_CONFIRMATION: string = 'PURCHASABLE_CLOTHING_CONFIRMATION'; -const GROUP_FURNITURE: string = 'GROUP_FURNITURE'; -const EFFECTBOX_OPEN: string = 'EFFECTBOX_OPEN'; - export const FurnitureContextMenuView: FC<{}> = props => { - const { closeConfirm = null, processAction = null, onClose = null, objectId = -1, mode = null, confirmMode = null, confirmingObjectId = -1, groupData = null, isGroupMember = false } = useFurnitureContextMenuWidget(); + const { closeConfirm = null, processAction = null, onClose = null, objectId = -1, mode = null, confirmMode = null, confirmingObjectId = -1, groupData = null, isGroupMember = false, objectOwnerId = -1 } = useFurnitureContextMenuWidget(); const { simpleAlert = null } = useNotification(); useMessageEvent(CustomUserNotificationMessageEvent, event => @@ -41,6 +37,8 @@ export const FurnitureContextMenuView: FC<{}> = props => } }); + const isOwner = GetSessionDataManager().userId === objectOwnerId; + return ( <> { (confirmMode === MONSTERPLANT_SEED_CONFIRMATION) && @@ -49,6 +47,7 @@ export const FurnitureContextMenuView: FC<{}> = props => } { (confirmMode === EFFECTBOX_OPEN) && } + { (objectId >= 0) && mode && { (mode === ContextMenuEnum.FRIEND_FURNITURE) && @@ -87,6 +86,15 @@ export const FurnitureContextMenuView: FC<{}> = props => { LocalizeText('widget.generic_usable.button.use') } } + { (mode === ContextMenuEnum.MYSTERY_BOX) && + <> + + { LocalizeText('mysterybox.context.title') } + + processAction('use_mystery_box') }> + { LocalizeText('mysterybox.context.' + ((isOwner) ? 'owner' : 'other') + '.use') } + + } { (mode === GROUP_FURNITURE) && groupData && <> GetGroupInformation(groupData.guildId) }> diff --git a/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.scss b/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.scss new file mode 100644 index 00000000..6fed0381 --- /dev/null +++ b/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.scss @@ -0,0 +1,52 @@ +.mysterybox-extension { + + .mysterybox-container { + max-width: 50px; + max-height: 50px; + width: 50px; + height: 50px; + + background-color: rgba(28, 28, 32, 0.95); + box-shadow: inset 0px 5px rgb(34 34 39 / 60%), inset 0 -4px rgb(18 18 21 / 60%); + border-color: #5b5a57; + } + + .box-image { + width: 31px; + height: 36px; + position: relative; + background-image: url('../../../../assets/images/mysterybox/mystery_box.png'); + -webkit-mask-image: url('../../../../assets/images/mysterybox/mystery_box.png'); + mask-image: url('../../../../assets/images/mysterybox/mystery_box.png'); + + .chain-overlay-image { + width: 31px; + height: 36px; + position: absolute; + background-image: url('../../../../assets/images/mysterybox/chain_mysterybox_box_overlay.png'); + } + } + + .key-image { + width: 39px; + height: 39px; + position: relative; + background-image: url('../../../../assets/images/mysterybox/mystery_box_key.png'); + -webkit-mask-image: url('../../../../assets/images/mysterybox/mystery_box_key.png'); + mask-image: url('../../../../assets/images/mysterybox/mystery_box_key.png'); + + .key-overlay-image { + width: 39px; + height: 39px; + position: absolute; + background-image: url('../../../../assets/images/mysterybox/key_overlay.png'); + } + } + + .box-image, + .key-image { + background-blend-mode: multiply; + background-position: center; + background-repeat: no-repeat; + } +} diff --git a/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.tsx b/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.tsx new file mode 100644 index 00000000..3dd3e935 --- /dev/null +++ b/src/components/room/widgets/mysterybox/MysteryBoxExtensionView.tsx @@ -0,0 +1,66 @@ +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { MysteryBoxKeysUpdateEvent } from '@nitrots/nitro-renderer'; +import { FC, useState } from 'react'; +import { ColorUtils, LocalizeText } from '../../../../api'; +import { Base, Column, Flex, LayoutGridItem, Text } from '../../../../common'; +import { useSessionDataManagerEvent } from '../../../../hooks'; + +const colorMap = { + 'purple': 9452386, + 'blue': 3891856, + 'green': 6459451, + 'yellow': 10658089, + 'lilac': 6897548, + 'orange': 10841125, + 'turquoise': 2661026, + 'red': 10104881 +} + +export const MysteryBoxExtensionView: FC<{}> = props => +{ + const [ isOpen, setIsOpen ] = useState(true); + const [ keyColor, setKeyColor ] = useState(''); + const [ boxColor, setBoxColor ] = useState(''); + + useSessionDataManagerEvent(MysteryBoxKeysUpdateEvent.MYSTERY_BOX_KEYS_UPDATE, event => + { + setKeyColor(event.keyColor); + setBoxColor(event.boxColor); + }); + + const getRgbColor = (color: string) => + { + const colorInt = colorMap[color]; + + return ColorUtils.int2rgb(colorInt); + } + + if(keyColor === '' && boxColor === '') return null; + + return ( + + + setIsOpen(value => !value) }> + { LocalizeText('mysterybox.tracker.title') } + + + { isOpen && + <> + { LocalizeText('mysterybox.tracker.description') } + + +
+
+
+ + +
+
+
+ + + } + + + ); +} diff --git a/src/hooks/rooms/widgets/furniture/useFurnitureContextMenuWidget.ts b/src/hooks/rooms/widgets/furniture/useFurnitureContextMenuWidget.ts index 22b735c8..53e4e0fd 100644 --- a/src/hooks/rooms/widgets/furniture/useFurnitureContextMenuWidget.ts +++ b/src/hooks/rooms/widgets/furniture/useFurnitureContextMenuWidget.ts @@ -1,13 +1,13 @@ -import { ContextMenuEnum, GroupFurniContextMenuInfoMessageEvent, GroupFurniContextMenuInfoMessageParser, RoomEngineTriggerWidgetEvent, RoomObjectCategory } from '@nitrots/nitro-renderer'; +import { ContextMenuEnum, GroupFurniContextMenuInfoMessageEvent, GroupFurniContextMenuInfoMessageParser, RoomEngineTriggerWidgetEvent, RoomObjectCategory, RoomObjectVariable } from '@nitrots/nitro-renderer'; import { useState } from 'react'; import { GetRoomEngine, IsOwnerOfFurniture, TryJoinGroup, TryVisitRoom } from '../../../../api'; import { useMessageEvent, useRoomEngineEvent } from '../../../events'; import { useRoom } from '../../useRoom'; -const MONSTERPLANT_SEED_CONFIRMATION: string = 'MONSTERPLANT_SEED_CONFIRMATION'; -const PURCHASABLE_CLOTHING_CONFIRMATION: string = 'PURCHASABLE_CLOTHING_CONFIRMATION'; -const GROUP_FURNITURE: string = 'GROUP_FURNITURE'; -const EFFECTBOX_OPEN: string = 'EFFECTBOX_OPEN'; +export const MONSTERPLANT_SEED_CONFIRMATION: string = 'MONSTERPLANT_SEED_CONFIRMATION'; +export const PURCHASABLE_CLOTHING_CONFIRMATION: string = 'PURCHASABLE_CLOTHING_CONFIRMATION'; +export const GROUP_FURNITURE: string = 'GROUP_FURNITURE'; +export const EFFECTBOX_OPEN: string = 'EFFECTBOX_OPEN'; const useFurnitureContextMenuWidgetState = () => { @@ -17,6 +17,7 @@ const useFurnitureContextMenuWidgetState = () => const [ confirmingObjectId, setConfirmingObjectId ] = useState(-1); const [ groupData, setGroupData ] = useState(null); const [ isGroupMember, setIsGroupMember ] = useState(false); + const [ objectOwnerId, setObjectOwnerId ] = useState(-1); const { roomSession = null } = useRoom(); const onClose = () => @@ -53,6 +54,9 @@ const useFurnitureContextMenuWidgetState = () => setConfirmMode(PURCHASABLE_CLOTHING_CONFIRMATION); setConfirmingObjectId(objectId); break; + case 'use_mystery_box': + roomSession.useMultistateItem(objectId); + break; case 'join_group': TryJoinGroup(groupData.guildId); setIsGroupMember(true); @@ -71,13 +75,16 @@ const useFurnitureContextMenuWidgetState = () => RoomEngineTriggerWidgetEvent.CLOSE_FURNI_CONTEXT_MENU, RoomEngineTriggerWidgetEvent.REQUEST_MONSTERPLANT_SEED_PLANT_CONFIRMATION_DIALOG, RoomEngineTriggerWidgetEvent.REQUEST_PURCHASABLE_CLOTHING_CONFIRMATION_DIALOG, - RoomEngineTriggerWidgetEvent.REQUEST_EFFECTBOX_OPEN_DIALOG + RoomEngineTriggerWidgetEvent.REQUEST_EFFECTBOX_OPEN_DIALOG, + RoomEngineTriggerWidgetEvent.REQUEST_MYSTERYBOX_OPEN_DIALOG ], event => { const object = GetRoomEngine().getRoomObject(roomSession.roomId, event.objectId, event.category); if(!object) return; + setObjectOwnerId(object.model.getValue(RoomObjectVariable.FURNITURE_OWNER_ID)); + switch(event.type) { case RoomEngineTriggerWidgetEvent.REQUEST_MONSTERPLANT_SEED_PLANT_CONFIRMATION_DIALOG: @@ -102,6 +109,11 @@ const useFurnitureContextMenuWidgetState = () => setConfirmingObjectId(object.id); setConfirmMode(PURCHASABLE_CLOTHING_CONFIRMATION); + onClose(); + return; + case RoomEngineTriggerWidgetEvent.REQUEST_MYSTERYBOX_OPEN_DIALOG: + roomSession.useMultistateItem(object.id); + onClose(); return; case RoomEngineTriggerWidgetEvent.OPEN_FURNI_CONTEXT_MENU: @@ -117,6 +129,7 @@ const useFurnitureContextMenuWidgetState = () => if(IsOwnerOfFurniture(object)) setMode(ContextMenuEnum.MONSTERPLANT_SEED); return; case ContextMenuEnum.MYSTERY_BOX: + setMode(ContextMenuEnum.MYSTERY_BOX); return; case ContextMenuEnum.RANDOM_TELEPORT: setMode(ContextMenuEnum.RANDOM_TELEPORT); @@ -143,7 +156,7 @@ const useFurnitureContextMenuWidgetState = () => setMode(GROUP_FURNITURE); }); - return { objectId, mode, confirmMode, confirmingObjectId, groupData, isGroupMember, closeConfirm, processAction, onClose }; + return { objectId, mode, confirmMode, confirmingObjectId, groupData, isGroupMember, objectOwnerId, closeConfirm, processAction, onClose }; } export const useFurnitureContextMenuWidget = useFurnitureContextMenuWidgetState;