diff --git a/src/api/nitro/session/GetFurnitureDataForRoomObject.ts b/src/api/nitro/session/GetFurnitureDataForRoomObject.ts new file mode 100644 index 00000000..e1739f76 --- /dev/null +++ b/src/api/nitro/session/GetFurnitureDataForRoomObject.ts @@ -0,0 +1,22 @@ +import { IFurnitureData, RoomObjectCategory, RoomObjectVariable } from 'nitro-renderer'; +import { GetRoomEngine } from '../room'; +import { GetSessionDataManager } from './GetSessionDataManager'; + +export function GetFurnitureDataForRoomObject(roomId: number, objectId: number, category: number): IFurnitureData +{ + const roomObject = GetRoomEngine().getRoomObject(roomId, objectId, category); + + if(!roomObject) return; + + const typeId = roomObject.model.getValue(RoomObjectVariable.FURNITURE_TYPE_ID); + + switch(category) + { + case RoomObjectCategory.FLOOR: + return GetSessionDataManager().getFloorItemData(typeId); + case RoomObjectCategory.WALL: + return GetSessionDataManager().getWallItemData(typeId); + } + + return null; +} diff --git a/src/api/nitro/session/index.ts b/src/api/nitro/session/index.ts index ff45e484..ff62191c 100644 --- a/src/api/nitro/session/index.ts +++ b/src/api/nitro/session/index.ts @@ -2,6 +2,7 @@ export * from './CanManipulateFurniture'; export * from './GetCanStandUp'; export * from './GetCanUseExpression'; export * from './GetFurnitureDataForProductOffer'; +export * from './GetFurnitureDataForRoomObject'; export * from './GetOwnPosture'; export * from './GetProductDataForLocalization'; export * from './GetRoomSession'; diff --git a/src/views/inventory/views/pet/InventoryPetView.tsx b/src/views/inventory/views/pet/InventoryPetView.tsx index df943500..5723c190 100644 --- a/src/views/inventory/views/pet/InventoryPetView.tsx +++ b/src/views/inventory/views/pet/InventoryPetView.tsx @@ -60,7 +60,7 @@ export const InventoryPetView: FC = props => roomPreviewer.reset(false); roomPreviewer.updateRoomWallsAndFloorVisibility(true, true); roomPreviewer.updateObjectRoom(floorType, wallType, landscapeType); - roomPreviewer.addPetIntoRoom(petData.figureData.figuredata); + roomPreviewer.addPetIntoRoom(petData.figureString); }, [ roomPreviewer, petItem ]); if(!petItems || !petItems.length) diff --git a/src/views/inventory/views/pet/item/InventoryPetItemView.tsx b/src/views/inventory/views/pet/item/InventoryPetItemView.tsx index d9a56dda..0cbc8e8f 100644 --- a/src/views/inventory/views/pet/item/InventoryPetItemView.tsx +++ b/src/views/inventory/views/pet/item/InventoryPetItemView.tsx @@ -36,10 +36,10 @@ export const InventoryPetItemView: FC = props => return; } }, [ isActive, isMouseDown, petItem, dispatchPetState ]); - + return ( - + ); } diff --git a/src/views/room/events/RoomWidgetUpdateInfostandPetEvent.ts b/src/views/room/events/RoomWidgetUpdateInfostandPetEvent.ts index f4404e6d..be193d60 100644 --- a/src/views/room/events/RoomWidgetUpdateInfostandPetEvent.ts +++ b/src/views/room/events/RoomWidgetUpdateInfostandPetEvent.ts @@ -1,4 +1,3 @@ -import { PetFigureData } from 'nitro-renderer'; import { RoomWidgetUpdateInfostandEvent } from './RoomWidgetUpdateInfostandEvent'; export class RoomWidgetUpdateInfostandPetEvent extends RoomWidgetUpdateInfostandEvent @@ -21,7 +20,7 @@ export class RoomWidgetUpdateInfostandPetEvent extends RoomWidgetUpdateInfostand public image: HTMLImageElement = null; public petType: number = 0; public petBreed: number = 0; - public petFigure: PetFigureData = null; + public petFigure: string = ''; public posture: string = 'std'; public isOwner: boolean = false; public ownerId: number = -1; diff --git a/src/views/room/events/RoomWidgetUseProductBubbleEvent.ts b/src/views/room/events/RoomWidgetUseProductBubbleEvent.ts new file mode 100644 index 00000000..54c8ef62 --- /dev/null +++ b/src/views/room/events/RoomWidgetUseProductBubbleEvent.ts @@ -0,0 +1,21 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; +import { UseProductItem } from './UseProductItem'; + +export class RoomWidgetUseProductBubbleEvent extends RoomWidgetUpdateEvent +{ + public static USE_PRODUCT_BUBBLES: string = 'RWUPBE_USE_PRODUCT_BUBBLES'; + + private _items: UseProductItem[]; + + constructor(type: string, items: UseProductItem[]) + { + super(type); + + this._items = items; + } + + public get items(): UseProductItem[] + { + return this._items; + } +} diff --git a/src/views/room/events/UseProductItem.ts b/src/views/room/events/UseProductItem.ts new file mode 100644 index 00000000..c886c403 --- /dev/null +++ b/src/views/room/events/UseProductItem.ts @@ -0,0 +1,50 @@ +export class UseProductItem +{ + private _id: number; + private _category: number; + private _name: string; + private _requestRoomObjectId: number; + private _targetRoomObjectId: number; + private _requestInventoryStripId: number; + private _replace: boolean; + + constructor(id: number, category: number, name: string, requestRoomObjectId: number, targetRoomObjectId: number, requestInventoryStripId: number, replace: boolean) + { + this._id = id; + this._category = category; + this._name = name; + this._requestRoomObjectId = requestRoomObjectId; + this._requestInventoryStripId = requestInventoryStripId; + this._replace = replace; + } + + public get id(): number + { + return this._id; + } + + public get category(): number + { + return this._category; + } + + public get name(): string + { + return this._name; + } + + public get requestRoomObjectId(): number + { + return this._requestRoomObjectId; + } + + public get requestInventoryStripId(): number + { + return this._requestInventoryStripId; + } + + public get replace(): boolean + { + return this._replace; + } +} diff --git a/src/views/room/events/index.ts b/src/views/room/events/index.ts index d281c2fc..88858e0f 100644 --- a/src/views/room/events/index.ts +++ b/src/views/room/events/index.ts @@ -14,3 +14,5 @@ export * from './RoomWidgetUpdateInfostandRentableBotEvent'; export * from './RoomWidgetUpdateInfostandUserEvent'; export * from './RoomWidgetUpdateRentableBotChatEvent'; export * from './RoomWidgetUpdateUserDataEvent'; +export * from './RoomWidgetUseProductBubbleEvent'; +export * from './UseProductItem'; diff --git a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts index c88ce7d4..5b7f5538 100644 --- a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts +++ b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts @@ -1,7 +1,8 @@ -import { NitroEvent, RoomSessionDanceEvent, RoomSessionUserDataUpdateEvent } from 'nitro-renderer'; -import { GetRoomSession, GetSessionDataManager } from '../../../api'; -import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateUserDataEvent } from '../events'; -import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages'; +import { NitroEvent, RoomEngineUseProductEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionDanceEvent, RoomSessionUserDataUpdateEvent } from 'nitro-renderer'; +import { GetRoomEngine, GetRoomSession, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; +import { FurniCategory } from '../../inventory/common/FurniCategory'; +import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateUserDataEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../events'; +import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUseProductMessage, RoomWidgetUserActionMessage } from '../messages'; import { RoomWidgetHandler } from './RoomWidgetHandler'; export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler @@ -24,6 +25,11 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateDanceStatusEvent(isDancing)); return; + case RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY: + return; + case RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM: + this.processUsableRoomObject((event as RoomEngineUseProductEvent).objectId); + return; } } @@ -56,6 +62,12 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler GetRoomSession().sendPostureMessage(postureMessage.posture); break; } + case RoomWidgetUseProductMessage.PET_PRODUCT: { + const productMessage = (message as RoomWidgetUseProductMessage); + + GetRoomSession().usePetProduct(productMessage.objectId, productMessage.petId); + break; + } } return null; @@ -71,11 +83,81 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler if(userData) this.container.eventDispatcher.dispatchEvent(new RoomWidgetAvatarInfoEvent(userId, userName, userData.type, userData.roomIndex, allowNameChange)); } + private processUsableRoomObject(objectId: number): void + { + const roomId = this.container.roomSession.roomId; + const roomObject = GetRoomEngine().getRoomObject(roomId, objectId, RoomObjectCategory.FLOOR); + + if(!roomObject || !IsOwnerOfFurniture(roomObject)) return; + + const ownerId = roomObject.model.getValue(RoomObjectVariable.FURNITURE_OWNER_ID); + const typeId = roomObject.model.getValue(RoomObjectVariable.FURNITURE_TYPE_ID); + const furniData = GetSessionDataManager().getFloorItemData(typeId); + const parts = furniData.customParams.split(' '); + const part = (parts.length ? parseInt(parts[0]) : -1); + + if(part === -1) return; + + this.processUseableProduct(roomId, objectId, part, furniData.specialType, ownerId); + } + + private processUseableProduct(roomId: number, objectId: number, part: number, specialType: number, ownerId: number, arg6 = -1): void + { + const useProductBubbles: UseProductItem[] = []; + const roomObjects = GetRoomEngine().getRoomObjects(roomId, RoomObjectCategory.UNIT); + + for(const roomObject of roomObjects) + { + const userData = this.container.roomSession.userDataManager.getUserDataByIndex(roomObject.id); + + let replace = false; + + if(!userData || (userData.type !== RoomObjectType.PET)) + { + + } + else + { + if(userData.ownerId === ownerId) + { + if(userData.hasSaddle && (specialType === FurniCategory._Str_6096)) replace = true; + + const figureParts = userData.figure.split(' '); + const figurePart = (figureParts.length ? parseInt(figureParts[0]) : -1); + + if(figurePart === part) + { + if(specialType === FurniCategory._Str_6915) + { + if(!userData.canRevive) continue; + } + + if(specialType === FurniCategory._Str_8726) + { + if((userData.petLevel < 7) || userData.canRevive || userData.canBreed) continue; + } + + if(specialType === FurniCategory._Str_9449) + { + if((userData.petLevel >= 7) || userData.canRevive) continue; + } + + useProductBubbles.push(new UseProductItem(userData.roomIndex, RoomObjectCategory.UNIT, userData.name, objectId, roomObject.id, arg6, replace)); + } + } + } + } + + if(useProductBubbles.length) this.container.eventDispatcher.dispatchEvent(new RoomWidgetUseProductBubbleEvent(RoomWidgetUseProductBubbleEvent.USE_PRODUCT_BUBBLES, useProductBubbles)); + } + public get eventTypes(): string[] { return [ RoomSessionUserDataUpdateEvent.USER_DATA_UPDATED, - RoomSessionDanceEvent.RSDE_DANCE + RoomSessionDanceEvent.RSDE_DANCE, + RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY, + RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM ]; } @@ -85,7 +167,9 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler RoomWidgetRoomObjectMessage.GET_OWN_CHARACTER_INFO, RoomWidgetDanceMessage.DANCE, RoomWidgetAvatarExpressionMessage.AVATAR_EXPRESSION, - RoomWidgetChangePostureMessage.CHANGE_POSTURE + RoomWidgetChangePostureMessage.CHANGE_POSTURE, + RoomWidgetUseProductMessage.PET_PRODUCT, + RoomWidgetUseProductMessage.MONSTERPLANT_SEED ]; } } diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 1ec12c3a..463955e9 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -7,7 +7,7 @@ import { SendMessageHook } from '../../../hooks/messages'; import { LocalizeText } from '../../../utils/LocalizeText'; import { RoomWidgetObjectNameEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events'; import { RoomWidgetChangeMottoMessage, RoomWidgetFurniActionMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages'; -import { PetSupplementEnum } from '../widgets/avatar-info/utils/PetSupplementEnum'; +import { PetSupplementEnum } from '../widgets/avatar-info/common/PetSupplementEnum'; import { RoomWidgetHandler } from './RoomWidgetHandler'; export class RoomWidgetInfostandHandler extends RoomWidgetHandler @@ -128,18 +128,18 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler case RoomWidgetUserActionMessage.MOUNT_PET: this.container.roomSession.mountPet(userId); break; - // case RoomWidgetUserActionMessage.RWUAM_TOGGLE_PET_RIDING_PERMISSION: - // this._container.roomSession._Str_21025(_local_2); - // break; - // case RoomWidgetUserActionMessage.RWUAM_TOGGLE_PET_BREEDING_PERMISSION: - // this._container.roomSession._Str_21562(_local_2); - // break; + case RoomWidgetUserActionMessage.TOGGLE_PET_RIDING_PERMISSION: + this.container.roomSession.togglePetRiding(userId); + break; + case RoomWidgetUserActionMessage.TOGGLE_PET_BREEDING_PERMISSION: + this.container.roomSession.togglePetBreeding(userId); + break; case RoomWidgetUserActionMessage.DISMOUNT_PET: this.container.roomSession.dismountPet(userId); break; - // case RoomWidgetUserActionMessage.RWUAM_SADDLE_OFF: - // this._container.roomSession._Str_21635(_local_2); - // break; + case RoomWidgetUserActionMessage.SADDLE_OFF: + this.container.roomSession.removePetSaddle(userId); + break; case RoomWidgetUserActionMessage.PASS_CARRY_ITEM: SendMessageHook(new RoomUnitGiveHandItemComposer(userId)); break; @@ -620,7 +620,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler infostandEvent.rarityLevel = petData.rarityLevel; infostandEvent.petType = figure.typeId; infostandEvent.petBreed = figure.paletteId; - infostandEvent.petFigure = figure; + infostandEvent.petFigure = roomPetData.figure; infostandEvent.posture = posture; infostandEvent.isOwner = isOwner; infostandEvent.roomIndex = roomPetData.roomIndex; diff --git a/src/views/room/messages/RoomWidgetUseProductMessage.ts b/src/views/room/messages/RoomWidgetUseProductMessage.ts new file mode 100644 index 00000000..deef093c --- /dev/null +++ b/src/views/room/messages/RoomWidgetUseProductMessage.ts @@ -0,0 +1,28 @@ +import { RoomWidgetMessage } from './RoomWidgetMessage'; + +export class RoomWidgetUseProductMessage extends RoomWidgetMessage +{ + public static PET_PRODUCT: string = 'RWUPM_PET_PRODUCT'; + public static MONSTERPLANT_SEED: string = 'RWUPM_MONSTERPLANT_SEED'; + + private _objectId: number; + public _petId: number; + + constructor(type: string, objectId: number, petId: number = -1) + { + super(type); + + this._objectId = objectId; + this._petId = petId; + } + + public get objectId(): number + { + return this._objectId; + } + + public get petId(): number + { + return this._petId; + } +} diff --git a/src/views/room/messages/index.ts b/src/views/room/messages/index.ts index b11cc9a7..d3ccbe7d 100644 --- a/src/views/room/messages/index.ts +++ b/src/views/room/messages/index.ts @@ -9,4 +9,5 @@ export * from './RoomWidgetFurniActionMessage'; export * from './RoomWidgetMessage'; export * from './RoomWidgetRequestWidgetMessage'; export * from './RoomWidgetRoomObjectMessage'; +export * from './RoomWidgetUseProductMessage'; export * from './RoomWidgetUserActionMessage'; diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index e0cd7f19..57523e17 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -1,6 +1,6 @@ -import { RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent } from 'nitro-renderer'; +import { NitroEvent, RoomEngineUseProductEvent, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; -import { useRoomSessionManagerEvent } from '../../../hooks/events'; +import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events'; import { LocalizeText } from '../../../utils/LocalizeText'; import { useRoomContext } from '../context/RoomContext'; import { AvatarInfoWidgetView } from './avatar-info/AvatarInfoWidgetView'; @@ -15,24 +15,26 @@ export const RoomWidgetsView: FC = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); - const onRoomSessionEvent = useCallback((event: RoomSessionEvent) => + const onNitroEvent = useCallback((event: NitroEvent) => { if(!widgetHandler) return; widgetHandler.processEvent(event); }, [ widgetHandler ]); - useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionChatEvent.FLOOD_EVENT, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDanceEvent.RSDE_DANCE, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionUserBadgesEvent.RSUBE_BADGES, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.DOORBELL, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_ACCEPTED, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDimmerPresetsEvent.ROOM_DIMMER_PRESETS, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionChatEvent.FLOOD_EVENT, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDanceEvent.RSDE_DANCE, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionUserBadgesEvent.RSUBE_BADGES, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.DOORBELL, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_ACCEPTED, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDimmerPresetsEvent.ROOM_DIMMER_PRESETS, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onNitroEvent); + useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY, onNitroEvent); + useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM, onNitroEvent); const onRoomErrorEvent = useCallback((event: RoomSessionEvent) => { diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx index 1514df9e..d691e06e 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx @@ -5,7 +5,7 @@ import { FriendEnteredRoomEvent } from '../../../../events'; import { useUiEvent } from '../../../../hooks/events'; import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base'; import { useRoomContext } from '../../context/RoomContext'; -import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent } from '../../events'; +import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../../events'; import { RoomWidgetRoomObjectMessage } from '../../messages'; import { AvatarInfoWidgetViewProps } from './AvatarInfoWidgetView.types'; import { AvatarInfoWidgetAvatarView } from './views/avatar/AvatarInfoWidgetAvatarView'; @@ -16,12 +16,16 @@ import { AvatarInfoWidgetOwnPetView } from './views/own-pet/AvatarInfoWidgetOwnP import { AvatarInfoWidgetPetView } from './views/pet/AvatarInfoWidgetPetView'; import { AvatarInfoRentableBotChatView } from './views/rentable-bot-chat/AvatarInfoRentableBotChatView'; import { AvatarInfoWidgetRentableBotView } from './views/rentable-bot/AvatarInfoWidgetRentableBotView'; +import { AvatarInfoUseProductConfirmView } from './views/use-product-confirm/AvatarInfoUseProductConfirmView'; +import { AvatarInfoUseProductView } from './views/use-product/AvatarInfoUseProductView'; export const AvatarInfoWidgetView: FC = props => { - const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); + const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ name, setName ] = useState(null); const [ nameBubbles, setNameBubbles ] = useState([]); + const [ productBubbles, setProductBubbles ] = useState([]); + const [ confirmingProduct, setConfirmingProduct ] = useState(null); const [ infoStandEvent, setInfoStandEvent ] = useState(null); const [ isGameMode, setGameMode ] = useState(false); const [ isDancing, setIsDancing ] = useState(false); @@ -40,6 +44,19 @@ export const AvatarInfoWidgetView: FC = props => }); }, []); + const removeProductBubble = useCallback((index: number) => + { + setProductBubbles(prevValue => + { + const newValue = [ ...prevValue ]; + const item = newValue.splice(index, 1)[0]; + + if(confirmingProduct === item) setConfirmingProduct(null); + + return newValue; + }); + }, [ confirmingProduct ]); + const clearInfoStandEvent = useCallback(() => { setInfoStandEvent(null); @@ -83,6 +100,31 @@ export const AvatarInfoWidgetView: FC = props => }); if(nameBubbleIndex > -1) removeNameBubble(nameBubbleIndex); + + if(productBubbles.length) + { + setProductBubbles(prevValue => + { + return prevValue.filter(bubble => + { + return (bubble.id !== event.id); + }); + }); + } + } + + else if(event.category === RoomObjectCategory.FLOOR) + { + if(productBubbles.length) + { + setProductBubbles(prevValue => + { + return prevValue.filter(bubble => + { + return (bubble.requestRoomObjectId !== event.id); + }); + }); + } } if(infoStandEvent) @@ -102,7 +144,7 @@ export const AvatarInfoWidgetView: FC = props => if(infoStandEvent.roomIndex === event.id) setInfoStandEvent(null); } } - }, [ name, infoStandEvent, nameBubbles, removeNameBubble ]); + }, [ name, infoStandEvent, nameBubbles, productBubbles, removeNameBubble ]); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomObjectRemoved); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomObjectRemoved); @@ -137,10 +179,9 @@ export const AvatarInfoWidgetView: FC = props => const onObjectDeselected = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => { - if(!infoStandEvent) return; - - setInfoStandEvent(null); - }, [ infoStandEvent ]); + if(infoStandEvent) setInfoStandEvent(null); + if(productBubbles.length) setProductBubbles([]); + }, [ infoStandEvent, productBubbles ]); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onObjectDeselected); @@ -182,6 +223,27 @@ export const AvatarInfoWidgetView: FC = props => CreateEventDispatcherHook(RoomWidgetUpdateRentableBotChatEvent.UPDATE_CHAT, eventDispatcher, onRoomWidgetUpdateRentableBotChatEvent); + const onRoomWidgetUseProductBubbleEvent = useCallback((event: RoomWidgetUseProductBubbleEvent) => + { + setProductBubbles(prevValue => + { + const newBubbles = [ ...prevValue ]; + + for(const item of event.items) + { + const index = newBubbles.findIndex(bubble => (bubble.id === item.id)); + + if(index > -1) newBubbles.splice(index, 1); + + newBubbles.push(item); + } + + return newBubbles; + }); + }, []); + + CreateEventDispatcherHook(RoomWidgetUseProductBubbleEvent.USE_PRODUCT_BUBBLES, eventDispatcher, onRoomWidgetUseProductBubbleEvent); + const onFriendEnteredRoomEvent = useCallback((event: FriendEnteredRoomEvent) => { setNameBubbles(prevValue => @@ -278,7 +340,12 @@ export const AvatarInfoWidgetView: FC = props => { return removeNameBubble(index) } />; }) } + { (productBubbles.length > 0) && productBubbles.map((item, index) => + { + return removeProductBubble(index) } />; + }) } { rentableBotChatEvent && } + { confirmingProduct && setConfirmingProduct(null) } /> } ) } diff --git a/src/views/room/widgets/avatar-info/utils/BotSkillsEnum.ts b/src/views/room/widgets/avatar-info/common/BotSkillsEnum.ts similarity index 100% rename from src/views/room/widgets/avatar-info/utils/BotSkillsEnum.ts rename to src/views/room/widgets/avatar-info/common/BotSkillsEnum.ts diff --git a/src/views/room/widgets/avatar-info/utils/PetSupplementEnum.ts b/src/views/room/widgets/avatar-info/common/PetSupplementEnum.ts similarity index 100% rename from src/views/room/widgets/avatar-info/utils/PetSupplementEnum.ts rename to src/views/room/widgets/avatar-info/common/PetSupplementEnum.ts diff --git a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx index bcc54ac7..a5b3a2ff 100644 --- a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx +++ b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx @@ -70,18 +70,15 @@ export const AvatarInfoWidgetOwnPetView: FC = p break; case 'pick_up': messageType = RoomWidgetUserActionMessage.PICKUP_PET; - //this.widget._Str_25401(); break; case 'mount': messageType = RoomWidgetUserActionMessage.MOUNT_PET; break; case 'toggle_riding_permission': messageType = RoomWidgetUserActionMessage.TOGGLE_PET_RIDING_PERMISSION; - // update riding checkbox break; case 'toggle_breeding_permission': - messageType = RoomWidgetUserActionMessage.TOGGLE_PET_BREEDING_PERMISSION - // update breeding checkbox; + messageType = RoomWidgetUserActionMessage.TOGGLE_PET_BREEDING_PERMISSION; break; case 'dismount': messageType = RoomWidgetUserActionMessage.DISMOUNT_PET; @@ -162,7 +159,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p processAction('buy_saddle') }> { LocalizeText('infostand.button.buy_saddle') } } - { ([ PetType.BEAR, PetType.TERRIER, PetType.CAT, PetType.DOG, PetType.PIG].indexOf(petData.petType) > -1) && + { ([ PetType.BEAR, PetType.TERRIER, PetType.CAT, PetType.DOG, PetType.PIG ].indexOf(petData.petType) > -1) && processAction('breed') }> { LocalizeText('infostand.button.breed') } } @@ -173,6 +170,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p { LocalizeText('infostand.button.mount') } processAction('toggle_riding_permission') }> + { LocalizeText('infostand.button.toggle_riding_permission') } { (respectsLeft > 0) && @@ -186,7 +184,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p { LocalizeText('infostand.button.pickup') } processAction('saddle_off') }> - { LocalizeText('infostand.button.saddle_off') } + { LocalizeText('infostand.button.saddleoff') } } { (mode === _Str_5938) && @@ -219,6 +217,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p { !petData.dead && (petData.level === petData.maximumLevel) && petData.breedable && <> processAction('toggle_breeding_permission') }> + { LocalizeText('infostand.button.toggle_breeding_permission') } processAction('breed') }> diff --git a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx index ed82968a..ab5522ba 100644 --- a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx +++ b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx @@ -7,7 +7,7 @@ import { RoomWidgetUpdateRentableBotChatEvent } from '../../../../events'; import { ContextMenuView } from '../../../context-menu/ContextMenuView'; import { ContextMenuHeaderView } from '../../../context-menu/views/header/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView'; -import { BotSkillsEnum } from '../../utils/BotSkillsEnum'; +import { BotSkillsEnum } from '../../common/BotSkillsEnum'; import { AvatarInfoWidgetRentableBotViewProps } from './AvatarInfoWidgetRentableBotView.types'; const MODE_NORMAL = 0; diff --git a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx new file mode 100644 index 00000000..32ea2d7d --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx @@ -0,0 +1,83 @@ +import { IFurnitureData, RoomObjectCategory, RoomUserData } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { GetFurnitureDataForRoomObject } from '../../../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../../layout'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { FurniCategory } from '../../../../../inventory/common/FurniCategory'; +import { useRoomContext } from '../../../../context/RoomContext'; +import { RoomWidgetUseProductMessage } from '../../../../messages'; +import { AvatarInfoUseProductConfirmViewProps } from './AvatarInfoUseProductConfirmView.types'; + +const _Str_5091: number = -1; +const _Str_11906: number = 0; +const _Str_11214: number = 1; +const _Str_11733: number = 2; +const _Str_11369: number = 3; +const _Str_8759: number = 4; +const _Str_8432: number = 5; +const _Str_9653: number = 6; + +export const AvatarInfoUseProductConfirmView: FC = props => +{ + const { item = null, close = null } = props; + const [ mode, setMode ] = useState(_Str_5091); + const [ petData, setPetData ] = useState(null); + const [ furniData, setFurniData ] = useState(null); + const { roomSession = null, widgetHandler = null } = useRoomContext(); + + const useProduct = useCallback(() => + { + widgetHandler.processWidgetMessage(new RoomWidgetUseProductMessage(RoomWidgetUseProductMessage.PET_PRODUCT, item.requestRoomObjectId, petData.webID)); + }, [ widgetHandler, item, petData ]); + + useEffect(() => + { + const userData = roomSession.userDataManager.getUserDataByIndex(item.id); + + setPetData(userData); + + const furniData = GetFurnitureDataForRoomObject(roomSession.roomId, item.requestRoomObjectId, RoomObjectCategory.FLOOR); + + if(!furniData) return; + + setFurniData(furniData); + + let mode = _Str_5091; + + switch(furniData.specialType) + { + case FurniCategory._Str_7696: + mode = _Str_11906; + break; + case FurniCategory._Str_7297: + mode = _Str_11214; + break; + case FurniCategory._Str_7954: + mode = _Str_11733; + break; + case FurniCategory._Str_6096: + mode = _Str_11369; + break; + case FurniCategory._Str_6915: + mode = _Str_8759; + break; + case FurniCategory._Str_8726: + mode = _Str_8432; + break; + case FurniCategory._Str_9449: + mode = _Str_9653; + break; + } + + setMode(mode); + }, [ roomSession, item ]); + + return ( + + + + + + + ) +} diff --git a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.types.ts b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.types.ts new file mode 100644 index 00000000..8f1c3ad3 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.types.ts @@ -0,0 +1,7 @@ +import { UseProductItem } from '../../../../events'; + +export interface AvatarInfoUseProductConfirmViewProps +{ + item: UseProductItem; + close: () => void; +} diff --git a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx new file mode 100644 index 00000000..f2e66720 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx @@ -0,0 +1,138 @@ +import { RoomObjectCategory } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { GetFurnitureDataForRoomObject } from '../../../../../../api'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { FurniCategory } from '../../../../../inventory/common/FurniCategory'; +import { useRoomContext } from '../../../../context/RoomContext'; +import { ContextMenuView } from '../../../context-menu/ContextMenuView'; +import { ContextMenuHeaderView } from '../../../context-menu/views/header/ContextMenuHeaderView'; +import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView'; +import { AvatarInfoUseProductViewProps } from './AvatarInfoUseProductView.types'; + +const _Str_2906: number = 0; +const _Str_13718: number = 1; +const _Str_14146: number = 2; +const _Str_15667: number = 3; +const _Str_14658: number = 4; +const _Str_14165: number = 5; +const _Str_12577: number = 6; +const _Str_14611: number = 7; + +export const AvatarInfoUseProductView: FC = props => +{ + const { item = null, setConfirmingProduct = null, close = null } = props; + const [ mode, setMode ] = useState(0); + const { roomSession = null } = useRoomContext(); + + useEffect(() => + { + if(!item) return; + + const furniData = GetFurnitureDataForRoomObject(roomSession.roomId, item.requestRoomObjectId, RoomObjectCategory.FLOOR); + + if(!furniData) return; + + let mode = _Str_2906; + + switch(furniData.specialType) + { + case FurniCategory._Str_7696: + mode = _Str_13718; + break; + case FurniCategory._Str_7297: + mode = _Str_14146; + break; + case FurniCategory._Str_7954: + mode = _Str_15667; + break; + case FurniCategory._Str_6096: + mode = _Str_14658; + break; + case FurniCategory._Str_6915: + mode = _Str_14165; + break; + case FurniCategory._Str_8726: + mode = _Str_12577; + break; + case FurniCategory._Str_9449: + mode = _Str_14611; + break; + } + + setMode(mode); + }, [ roomSession, item ]); + + const processAction = useCallback((name: string) => + { + let hideMenu = true; + + if(name) + { + switch(name) + { + case 'use_product': + case 'use_product_shampoo': + case 'use_product_custom_part': + case 'use_product_custom_part_shampoo': + case 'use_product_saddle': + case 'replace_product_saddle': + case 'revive_monsterplant': + case 'rebreed_monsterplant': + case 'fertilize_monsterplant': + setConfirmingProduct(item); + break; + default: + break; + } + } + + if(hideMenu) close(); + }, [ item, setConfirmingProduct, close ]); + + return ( + + + { item.name } + + { (mode === _Str_2906) && + processAction('use_product') }> + { LocalizeText('infostand.button.useproduct') } + } + { (mode === _Str_13718) && + processAction('use_product_shampoo') }> + { LocalizeText('infostand.button.useproduct_shampoo') } + } + { (mode === _Str_14146) && + processAction('use_product_custom_part') }> + { LocalizeText('infostand.button.useproduct_custom_part') } + } + { (mode === _Str_15667) && + processAction('use_product_custom_part_shampoo') }> + { LocalizeText('infostand.button.useproduct_custom_part_shampoo') } + } + { (mode === _Str_14658) && + <> + { item.replace && + processAction('replace_product_saddle') }> + { LocalizeText('infostand.button.replaceproduct_saddle') } + } + { !item.replace && + processAction('use_product_saddle') }> + { LocalizeText('infostand.button.useproduct_saddle') } + } + } + { (mode === _Str_14165) && + processAction('revive_monsterplant') }> + { LocalizeText('infostand.button.revive_monsterplant') } + } + { (mode === _Str_12577) && + processAction('rebreed_monsterplant') }> + { LocalizeText('infostand.button.rebreed_monsterplant') } + } + { (mode === _Str_14611) && + processAction('fertilize_monsterplant') }> + { LocalizeText('infostand.button.fertilize_monsterplant') } + } + + ); +} diff --git a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts new file mode 100644 index 00000000..1407ee5e --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts @@ -0,0 +1,9 @@ +import { Dispatch, SetStateAction } from 'react'; +import { UseProductItem } from '../../../../events'; + +export interface AvatarInfoUseProductViewProps +{ + item: UseProductItem; + setConfirmingProduct: Dispatch>; + close: () => void; +} diff --git a/src/views/room/widgets/context-menu/ContextMenuView.tsx b/src/views/room/widgets/context-menu/ContextMenuView.tsx index 3dff75a6..c99f48b4 100644 --- a/src/views/room/widgets/context-menu/ContextMenuView.tsx +++ b/src/views/room/widgets/context-menu/ContextMenuView.tsx @@ -15,6 +15,7 @@ export const ContextMenuView: FC = props => const [ opacity, setOpacity ] = useState(1); const [ isFading, setIsFading ] = useState(false); const [ fadeTime, setFadeTime ] = useState(0); + const [ frozen, setFrozen ] = useState(false); const elementRef = useRef(); const update = useCallback((time: number) => @@ -72,13 +73,20 @@ export const ContextMenuView: FC = props => useEffect(() => { - GetTicker().add(update); + let added = false; + + if(!frozen) + { + added = true; + + GetTicker().add(update); + } return () => { - GetTicker().remove(update); + if(added) GetTicker().remove(update); } - }, [ update ]); + }, [ frozen, update ]); useEffect(() => { @@ -93,7 +101,7 @@ export const ContextMenuView: FC = props => }, [ fades ]); return ( -
+
setFrozen(true) } onMouseLeave={ event => setFrozen(false) }> { children }
); diff --git a/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx b/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx index c37a30ab..c934373b 100644 --- a/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx +++ b/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx @@ -14,7 +14,7 @@ export const InfoStandWidgetPetView: FC = props => { petData.name }
{ LocalizeText('pet.breed.' + petData.petType + '.' + petData.petBreed) } } onCloseClick={ close }>
- +
{ LocalizeText('pet.level', ['level', 'maxlevel'], [petData.level.toString(), petData.maximumLevel.toString()]) }
diff --git a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx index c4d79504..ffa24a0a 100644 --- a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx +++ b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx @@ -4,7 +4,7 @@ import { SendMessageHook } from '../../../../../../hooks/messages'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { AvatarImageView } from '../../../../../shared/avatar-image/AvatarImageView'; import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; -import { BotSkillsEnum } from '../../../avatar-info/utils/BotSkillsEnum'; +import { BotSkillsEnum } from '../../../avatar-info/common/BotSkillsEnum'; import { InfoStandBaseView } from '../base/InfoStandBaseView'; import { InfoStandWidgetRentableBotViewProps } from './InfoStandWidgetRentableBotView.types'; diff --git a/src/views/wired/WiredView.tsx b/src/views/wired/WiredView.tsx index e438dd67..b9517011 100644 --- a/src/views/wired/WiredView.tsx +++ b/src/views/wired/WiredView.tsx @@ -1,8 +1,8 @@ import { ConditionDefinition, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition } from 'nitro-renderer'; import { FC, useCallback, useMemo, useState } from 'react'; -import { GetConnection } from '../../api'; import { WiredEvent } from '../../events'; import { useUiEvent } from '../../hooks/events'; +import { SendMessageHook } from '../../hooks/messages'; import { GetWiredLayout } from './common/GetWiredLayout'; import { WiredContextProvider } from './context/WiredContext'; import { WiredMessageHandler } from './WiredMessageHandler'; @@ -27,18 +27,17 @@ export const WiredView: FC = props => if(trigger instanceof WiredActionDefinition) { - GetConnection().send(new UpdateActionMessageComposer(trigger.id, intParams, stringParam, furniIds, actionDelay, trigger.stuffTypeSelectionCode)); + SendMessageHook(new UpdateActionMessageComposer(trigger.id, intParams, stringParam, furniIds, actionDelay, trigger.stuffTypeSelectionCode)); } else if(trigger instanceof TriggerDefinition) { - console.log(intParams, stringParam); - GetConnection().send(new UpdateTriggerMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode)); + SendMessageHook(new UpdateTriggerMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode)); } else if(trigger instanceof ConditionDefinition) { - GetConnection().send(new UpdateConditionMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode)); + SendMessageHook(new UpdateConditionMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode)); } }, [ trigger, intParams, stringParam, furniIds, actionDelay ]);