diff --git a/src/App.tsx b/src/App.tsx index e929a7dd..4b530739 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,5 +1,5 @@ import { ConfigurationEvent, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, RoomEngineEvent, WebGL } from 'nitro-renderer'; -import { FC, useCallback, useMemo, useState } from 'react'; +import { FC, useCallback, useState } from 'react'; import { GetConfiguration } from './api'; import { useConfigurationEvent } from './hooks/events/core/configuration/configuration-event'; import { useLocalizationEvent } from './hooks/events/nitro/localization/localization-event'; @@ -21,7 +21,7 @@ export const App: FC<{}> = props => if(!Nitro.instance) Nitro.bootstrap(); - const getPreloadAssetUrls = useMemo(() => + const getPreloadAssetUrls = useCallback(() => { const urls: string[] = []; const assetUrls = GetConfiguration('preload.assets.urls'); @@ -91,7 +91,7 @@ export const App: FC<{}> = props => setIsReady(true); return; case NitroLocalizationEvent.LOADED: - Nitro.instance.core.asset.downloadAssets(getPreloadAssetUrls, (status: boolean) => + Nitro.instance.core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) => { if(status) { diff --git a/src/api/nitro/room/GetOwnRoomObject.ts b/src/api/nitro/room/GetOwnRoomObject.ts new file mode 100644 index 00000000..81890c16 --- /dev/null +++ b/src/api/nitro/room/GetOwnRoomObject.ts @@ -0,0 +1,32 @@ +import { IRoomObjectController, RoomObjectCategory } from 'nitro-renderer'; +import { GetRoomSession, GetSessionDataManager } from '../session'; +import { GetRoomEngine } from './GetRoomEngine'; + +export function GetOwnRoomObject(): IRoomObjectController +{ + const userId = GetSessionDataManager().userId; + const roomId = GetRoomEngine().activeRoomId; + const category = RoomObjectCategory.UNIT; + const totalObjects = GetRoomEngine().getTotalObjectsForManager(roomId, category); + + let i = 0; + + while(i < totalObjects) + { + const roomObject = GetRoomEngine().getRoomObjectByIndex(roomId, i, category); + + if(roomObject) + { + const userData = GetRoomSession().userDataManager.getUserDataByIndex(roomObject.id); + + if(userData) + { + if(userData.webID === userId) return roomObject; + } + } + + i++; + } + + return null; +} diff --git a/src/api/nitro/room/index.ts b/src/api/nitro/room/index.ts index a3b38b42..6a06237f 100644 --- a/src/api/nitro/room/index.ts +++ b/src/api/nitro/room/index.ts @@ -1,6 +1,7 @@ export * from './DispatchMouseEvent'; export * from './DispatchResizeEvent'; export * from './DispatchTouchEvent'; +export * from './GetOwnRoomObject'; export * from './GetRoomEngine'; export * from './GetRoomObjectBounds'; export * from './InitializeRoomInstanceRenderingCanvas'; diff --git a/src/api/nitro/session/GetCanStandUp.ts b/src/api/nitro/session/GetCanStandUp.ts new file mode 100644 index 00000000..ce114506 --- /dev/null +++ b/src/api/nitro/session/GetCanStandUp.ts @@ -0,0 +1,13 @@ +import { AvatarAction, RoomObjectVariable } from 'nitro-renderer'; +import { GetOwnRoomObject } from '../room'; + +export function GetCanStandUp(): string +{ + const roomObject = GetOwnRoomObject(); + + if(!roomObject) return AvatarAction.POSTURE_STAND; + + const model = roomObject.model; + + return model.getValue(RoomObjectVariable.FIGURE_CAN_STAND_UP); +} diff --git a/src/api/nitro/session/GetCanUseExpression.ts b/src/api/nitro/session/GetCanUseExpression.ts new file mode 100644 index 00000000..933f64c8 --- /dev/null +++ b/src/api/nitro/session/GetCanUseExpression.ts @@ -0,0 +1,14 @@ +import { RoomObjectVariable } from 'nitro-renderer'; +import { GetOwnRoomObject } from '../room'; + +export function GetCanUseExpression(): boolean +{ + const roomObject = GetOwnRoomObject(); + + if(!roomObject) return false; + + const model = roomObject.model; + const effectId = model.getValue(RoomObjectVariable.FIGURE_EFFECT); + + return ((effectId === 29) || (effectId === 30) || (effectId === 185)); +} diff --git a/src/api/nitro/session/GetOwnPosture.ts b/src/api/nitro/session/GetOwnPosture.ts new file mode 100644 index 00000000..7cc554d4 --- /dev/null +++ b/src/api/nitro/session/GetOwnPosture.ts @@ -0,0 +1,13 @@ +import { AvatarAction, RoomObjectVariable } from 'nitro-renderer'; +import { GetOwnRoomObject } from '../room'; + +export function GetOwnPosture(): string +{ + const roomObject = GetOwnRoomObject(); + + if(!roomObject) return AvatarAction.POSTURE_STAND; + + const model = roomObject.model; + + return model.getValue(RoomObjectVariable.FIGURE_POSTURE); +} diff --git a/src/api/nitro/session/HasHabboClub.ts b/src/api/nitro/session/HasHabboClub.ts new file mode 100644 index 00000000..213d3daa --- /dev/null +++ b/src/api/nitro/session/HasHabboClub.ts @@ -0,0 +1,7 @@ +import { HabboClubLevelEnum } from 'nitro-renderer'; +import { GetSessionDataManager } from './GetSessionDataManager'; + +export function HasHabboClub(): boolean +{ + return (GetSessionDataManager().clubLevel >= HabboClubLevelEnum.CLUB); +} diff --git a/src/api/nitro/session/HasHabboVip.ts b/src/api/nitro/session/HasHabboVip.ts new file mode 100644 index 00000000..5c84150a --- /dev/null +++ b/src/api/nitro/session/HasHabboVip.ts @@ -0,0 +1,7 @@ +import { HabboClubLevelEnum } from 'nitro-renderer'; +import { GetSessionDataManager } from './GetSessionDataManager'; + +export function HasHabboVip(): boolean +{ + return (GetSessionDataManager().clubLevel >= HabboClubLevelEnum.VIP); +} diff --git a/src/api/nitro/session/IsRidingHorse.ts b/src/api/nitro/session/IsRidingHorse.ts new file mode 100644 index 00000000..ff4c5d02 --- /dev/null +++ b/src/api/nitro/session/IsRidingHorse.ts @@ -0,0 +1,14 @@ +import { RoomObjectVariable } from 'nitro-renderer'; +import { GetOwnRoomObject } from '../room'; + +export function IsRidingHorse(): boolean +{ + const roomObject = GetOwnRoomObject(); + + if(!roomObject) return false; + + const model = roomObject.model; + const effectId = model.getValue(RoomObjectVariable.FIGURE_EFFECT); + + return (effectId === 77); +} diff --git a/src/api/nitro/session/index.ts b/src/api/nitro/session/index.ts index 2c35db50..cdf07f2a 100644 --- a/src/api/nitro/session/index.ts +++ b/src/api/nitro/session/index.ts @@ -1,9 +1,15 @@ export * from './CanManipulateFurniture'; +export * from './GetCanStandUp'; +export * from './GetCanUseExpression'; export * from './GetFurnitureDataForProductOffer'; +export * from './GetOwnPosture'; export * from './GetProductDataForLocalization'; export * from './GetRoomSession'; export * from './GetRoomSessionManager'; export * from './GetSessionDataManager'; +export * from './HasHabboClub'; +export * from './HasHabboVip'; export * from './IsOwnerOfFurniture'; +export * from './IsRidingHorse'; export * from './SendChatTypingMessage'; export * from './StartRoomSession'; diff --git a/src/assets/styles/bootstrap/_variables.scss b/src/assets/styles/bootstrap/_variables.scss index 91d6a902..245cb056 100644 --- a/src/assets/styles/bootstrap/_variables.scss +++ b/src/assets/styles/bootstrap/_variables.scss @@ -81,7 +81,7 @@ $warning: $yellow !default; $danger: $red !default; $light: #DFDFDF !default; -$dark: #12191c !default; +$dark: rgba(28,28,32,.9803921568627451) !default; $light-dark: $gray-800 !default; // scss-docs-end theme-color-variables diff --git a/src/layout/card/NitroCardView.scss b/src/layout/card/NitroCardView.scss index 50cb0fe3..de37a762 100644 --- a/src/layout/card/NitroCardView.scss +++ b/src/layout/card/NitroCardView.scss @@ -39,23 +39,3 @@ $nitro-card-tabs-height: 33px; } } } - -.header-close { - right: 6px; - border-radius: $border-radius; - box-shadow: inset 0 0 0 1.5px #921911, inset 0 2px rgba($white, .2); - border: 1px solid $white; - background: rgb(245,80,65); - background: linear-gradient(180deg, rgba(245,80,65,1) 0%, rgba(245,80,65,1) 50%, rgba(194,48,39,1) 50%, rgba(194,48,39,1) 100%); - cursor: pointer; - line-height: 1; - padding: 4px 6px; - - &:hover { - filter: brightness(1.2); - } - - &:active { - filter: brightness(0.8); - } -} diff --git a/src/layout/card/header/NitroCardHeaderView.scss b/src/layout/card/header/NitroCardHeaderView.scss index 02cae864..f3ff8d96 100644 --- a/src/layout/card/header/NitroCardHeaderView.scss +++ b/src/layout/card/header/NitroCardHeaderView.scss @@ -8,9 +8,39 @@ } .bg-tertiary-split { + position: relative; border: 2px solid darken($quaternary, 4); box-shadow: 0 0 0 2px $white; width: 100%; margin: 0 25px; + + &:before { + position: absolute; + content: ' '; + top: 0; + left: 0; + width: 100%; + height: 2px; + background-color: rgba($white, 0.3); + } + } + + .header-close { + right: 6px; + border-radius: $border-radius; + box-shadow: 0 0 0 1.5px $white; + border: 2px solid #921911; + background: repeating-linear-gradient(rgba(245,80,65,1), rgba(245,80,65,1) 50%, rgba(194,48,39,1) 50%, rgba(194,48,39,1) 100%); + cursor: pointer; + line-height: 1; + padding: 1px 3px; + + &:hover { + filter: brightness(1.2); + } + + &:active { + filter: brightness(0.8); + } } } diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index 19500aff..f0afb252 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -9,7 +9,7 @@ import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; import { useRoomEngineEvent } from '../../hooks/events'; import { RoomContextProvider } from './context/RoomContext'; import { RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent } from './events'; -import { IRoomWidgetHandlerManager, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; +import { IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; import { RoomViewProps } from './RoomView.types'; import { RoomWidgetsView } from './widgets/RoomWidgetsView'; @@ -33,6 +33,7 @@ export const RoomView: FC = props => const widgetHandlerManager = new RoomWidgetHandlerManager(roomSession, new EventDispatcher()); + widgetHandlerManager.registerHandler(new RoomWidgetAvatarInfoHandler()); widgetHandlerManager.registerHandler(new RoomWidgetInfostandHandler()); setWidgetHandler(widgetHandlerManager); diff --git a/src/views/room/events/RoomWidgetAvatarInfoEvent.ts b/src/views/room/events/RoomWidgetAvatarInfoEvent.ts new file mode 100644 index 00000000..c9d068f9 --- /dev/null +++ b/src/views/room/events/RoomWidgetAvatarInfoEvent.ts @@ -0,0 +1,48 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; + +export class RoomWidgetAvatarInfoEvent extends RoomWidgetUpdateEvent +{ + public static AVATAR_INFO: string = 'RWAIE_AVATAR_INFO'; + + private _userId: number; + private _userName: string; + private _userType: number; + private _roomIndex: number; + private _allowNameChange: boolean; + + constructor(userId: number, userName: string, userType: number, roomIndex: number, allowNameChange: boolean) + { + super(RoomWidgetAvatarInfoEvent.AVATAR_INFO); + + this._userId = userId; + this._userName = userName; + this._userType = userType; + this._roomIndex = roomIndex; + this._allowNameChange = allowNameChange; + } + + public get userId(): number + { + return this._userId; + } + + public get userName(): string + { + return this._userName; + } + + public get userType(): number + { + return this._userType; + } + + public get roomIndex(): number + { + return this._roomIndex; + } + + public get allowNameChange(): boolean + { + return this._allowNameChange; + } +} diff --git a/src/views/room/events/RoomWidgetUpdateDanceStatusEvent.ts b/src/views/room/events/RoomWidgetUpdateDanceStatusEvent.ts new file mode 100644 index 00000000..a1c0d206 --- /dev/null +++ b/src/views/room/events/RoomWidgetUpdateDanceStatusEvent.ts @@ -0,0 +1,20 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; + +export class RoomWidgetUpdateDanceStatusEvent extends RoomWidgetUpdateEvent +{ + public static UPDATE_DANCE: string = 'RWUDSE_UPDATE_DANCE'; + + private _isDancing: boolean; + + constructor(isDancing: boolean) + { + super(RoomWidgetUpdateDanceStatusEvent.UPDATE_DANCE); + + this._isDancing = isDancing; + } + + public get isDancing(): boolean + { + return this._isDancing; + } +} diff --git a/src/views/room/events/RoomWidgetUpdateInfostandUserEvent.ts b/src/views/room/events/RoomWidgetUpdateInfostandUserEvent.ts index 6171b20a..f54ecc9a 100644 --- a/src/views/room/events/RoomWidgetUpdateInfostandUserEvent.ts +++ b/src/views/room/events/RoomWidgetUpdateInfostandUserEvent.ts @@ -41,4 +41,9 @@ export class RoomWidgetUpdateInfostandUserEvent extends RoomWidgetUpdateInfostan public targetRoomControllerLevel: number = 0; public isFriend: boolean = false; public isAmbassador: boolean = false; + + public get isOwnUser(): boolean + { + return (this.type === RoomWidgetUpdateInfostandUserEvent.OWN_USER); + } } diff --git a/src/views/room/events/RoomWidgetUserDataUpdateEvent.ts b/src/views/room/events/RoomWidgetUserDataUpdateEvent.ts new file mode 100644 index 00000000..62a747b6 --- /dev/null +++ b/src/views/room/events/RoomWidgetUserDataUpdateEvent.ts @@ -0,0 +1,11 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; + +export class RoomWidgetUserDataUpdateEvent extends RoomWidgetUpdateEvent +{ + public static USER_DATA_UPDATED: string = 'RWUDUE_USER_DATA_UPDATED'; + + constructor() + { + super(RoomWidgetUserDataUpdateEvent.USER_DATA_UPDATED); + } +} diff --git a/src/views/room/events/index.ts b/src/views/room/events/index.ts index f55e5067..8691caae 100644 --- a/src/views/room/events/index.ts +++ b/src/views/room/events/index.ts @@ -1,9 +1,12 @@ +export * from './RoomWidgetAvatarInfoEvent'; export * from './RoomWidgetObjectNameEvent'; export * from './RoomWidgetRoomEngineUpdateEvent'; export * from './RoomWidgetRoomObjectUpdateEvent'; +export * from './RoomWidgetUpdateDanceStatusEvent'; export * from './RoomWidgetUpdateEvent'; export * from './RoomWidgetUpdateInfostandEvent'; export * from './RoomWidgetUpdateInfostandFurniEvent'; export * from './RoomWidgetUpdateInfostandPetEvent'; export * from './RoomWidgetUpdateInfostandRentableBotEvent'; export * from './RoomWidgetUpdateInfostandUserEvent'; +export * from './RoomWidgetUserDataUpdateEvent'; diff --git a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts new file mode 100644 index 00000000..207a37d4 --- /dev/null +++ b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts @@ -0,0 +1,91 @@ +import { NitroEvent, RoomSessionDanceEvent, RoomSessionUserDataUpdateEvent } from 'nitro-renderer'; +import { GetRoomSession, GetSessionDataManager } from '../../../api'; +import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUserDataUpdateEvent } from '../events'; +import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages'; +import { RoomWidgetHandler } from './RoomWidgetHandler'; + +export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler +{ + public processEvent(event: NitroEvent): void + { + switch(event.type) + { + case RoomSessionUserDataUpdateEvent.USER_DATA_UPDATED: + this.eventDispatcher.dispatchEvent(new RoomWidgetUserDataUpdateEvent()); + return; + case RoomSessionDanceEvent.RSDE_DANCE: + const danceEvent = (event as RoomSessionDanceEvent); + + let isDancing = false; + + const userData = GetRoomSession().userDataManager.getUserData(GetSessionDataManager().userId); + + if(userData && (userData.roomIndex === danceEvent.roomIndex)) isDancing = (danceEvent.danceId !== 0); + + this.eventDispatcher.dispatchEvent(new RoomWidgetUpdateDanceStatusEvent(isDancing)); + return; + } + } + + public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent + { + let userId = 0; + + if(message instanceof RoomWidgetUserActionMessage) userId = message.userId; + + switch(message.type) + { + case RoomWidgetRoomObjectMessage.GET_OWN_CHARACTER_INFO: + this.processOwnCharacterInfo(); + break; + case RoomWidgetDanceMessage.DANCE: { + const danceMessage = (message as RoomWidgetDanceMessage); + + GetRoomSession().sendDanceMessage(danceMessage.style); + break; + } + case RoomWidgetAvatarExpressionMessage.AVATAR_EXPRESSION: { + const expressionMessage = (message as RoomWidgetAvatarExpressionMessage); + + GetRoomSession().sendExpressionMessage(expressionMessage.animation.ordinal) + break; + } + case RoomWidgetChangePostureMessage.CHANGE_POSTURE: { + const postureMessage = (message as RoomWidgetChangePostureMessage); + + GetRoomSession().sendPostureMessage(postureMessage.posture); + break; + } + } + + return null; + } + + private processOwnCharacterInfo(): void + { + const userId = GetSessionDataManager().userId; + const userName = GetSessionDataManager().userName; + const allowNameChange = GetSessionDataManager().canChangeName; + const userData = GetRoomSession().userDataManager.getUserData(userId); + + if(userData) this.eventDispatcher.dispatchEvent(new RoomWidgetAvatarInfoEvent(userId, userName, userData.type, userData.roomIndex, allowNameChange)); + } + + public get eventTypes(): string[] + { + return [ + RoomSessionUserDataUpdateEvent.USER_DATA_UPDATED, + RoomSessionDanceEvent.RSDE_DANCE + ]; + } + + public get messageTypes(): string[] + { + return [ + RoomWidgetRoomObjectMessage.GET_OWN_CHARACTER_INFO, + RoomWidgetDanceMessage.DANCE, + RoomWidgetAvatarExpressionMessage.AVATAR_EXPRESSION, + RoomWidgetChangePostureMessage.CHANGE_POSTURE + ]; + } +} diff --git a/src/views/room/handlers/index.ts b/src/views/room/handlers/index.ts index 14a8f6f5..d9a3656c 100644 --- a/src/views/room/handlers/index.ts +++ b/src/views/room/handlers/index.ts @@ -1,5 +1,6 @@ export * from './IRoomWidgetHandler'; export * from './IRoomWidgetHandlerManager'; +export * from './RoomWidgetAvatarInfoHandler'; export * from './RoomWidgetHandler'; export * from './RoomWidgetHandlerManager'; export * from './RoomWidgetInfostandHandler'; diff --git a/src/views/room/messages/RoomWidgetAvatarExpressionMessage.ts b/src/views/room/messages/RoomWidgetAvatarExpressionMessage.ts new file mode 100644 index 00000000..6e7631d2 --- /dev/null +++ b/src/views/room/messages/RoomWidgetAvatarExpressionMessage.ts @@ -0,0 +1,21 @@ +import { AvatarExpressionEnum } from 'nitro-renderer'; +import { RoomWidgetMessage } from './RoomWidgetMessage'; + +export class RoomWidgetAvatarExpressionMessage extends RoomWidgetMessage +{ + public static AVATAR_EXPRESSION: string = 'RWAEM_MESSAGE_AVATAR_EXPRESSION'; + + private _animation: AvatarExpressionEnum; + + constructor(animation: AvatarExpressionEnum) + { + super(RoomWidgetAvatarExpressionMessage.AVATAR_EXPRESSION); + + this._animation = animation; + } + + public get animation(): AvatarExpressionEnum + { + return this._animation; + } +} diff --git a/src/views/room/messages/RoomWidgetChangePostureMessage.ts b/src/views/room/messages/RoomWidgetChangePostureMessage.ts new file mode 100644 index 00000000..2325ce09 --- /dev/null +++ b/src/views/room/messages/RoomWidgetChangePostureMessage.ts @@ -0,0 +1,22 @@ +import { RoomWidgetMessage } from './RoomWidgetMessage'; + +export class RoomWidgetChangePostureMessage extends RoomWidgetMessage +{ + public static CHANGE_POSTURE: string = 'RWCPM_MESSAGE_CHANGE_POSTURE'; + public static POSTURE_STAND: number = 0; + public static POSTURE_SIT: number = 1; + + private _posture: number; + + constructor(posture: number) + { + super(RoomWidgetChangePostureMessage.CHANGE_POSTURE); + + this._posture = posture; + } + + public get posture(): number + { + return this._posture; + } +} diff --git a/src/views/room/messages/RoomWidgetDanceMessage.ts b/src/views/room/messages/RoomWidgetDanceMessage.ts new file mode 100644 index 00000000..b493db13 --- /dev/null +++ b/src/views/room/messages/RoomWidgetDanceMessage.ts @@ -0,0 +1,22 @@ +import { RoomWidgetMessage } from './RoomWidgetMessage'; + +export class RoomWidgetDanceMessage extends RoomWidgetMessage +{ + public static DANCE: string = 'RWDM_MESSAGE_DANCE'; + public static NORMAL_STYLE: number = 0; + public static CLUB_STYLE: number[] = [2, 3, 4]; + + private _style: number = 0; + + constructor(style: number) + { + super(RoomWidgetDanceMessage.DANCE); + + this._style = style; + } + + public get style(): number + { + return this._style; + } +} diff --git a/src/views/room/messages/index.ts b/src/views/room/messages/index.ts index cf9d00e6..320b77c2 100644 --- a/src/views/room/messages/index.ts +++ b/src/views/room/messages/index.ts @@ -1,4 +1,7 @@ +export * from './RoomWidgetAvatarExpressionMessage'; export * from './RoomWidgetChangeMottoMessage'; +export * from './RoomWidgetChangePostureMessage'; +export * from './RoomWidgetDanceMessage'; export * from './RoomWidgetFurniActionMessage'; export * from './RoomWidgetMessage'; export * from './RoomWidgetRoomObjectMessage'; diff --git a/src/views/room/widgets/RoomWidgets.scss b/src/views/room/widgets/RoomWidgets.scss index 91ce4b4f..982c8ade 100644 --- a/src/views/room/widgets/RoomWidgets.scss +++ b/src/views/room/widgets/RoomWidgets.scss @@ -1,6 +1,7 @@ @import './camera/CameraWidgetView'; @import './chat/ChatWidgetView'; @import './chat-input/ChatInputView'; +@import './context-menu/ContextMenu'; @import './furniture/FurnitureWidgets'; @import './infostand/InfoStandWidgetView'; @import './object-location/ObjectLocationView'; diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx index 221c6c63..99afe2ea 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx @@ -1,11 +1,18 @@ -import { RoomObjectCategory } from 'nitro-renderer'; -import { FC, useCallback, useState } from 'react'; +import { RoomEnterEffect, RoomObjectCategory } from 'nitro-renderer'; +import { FC, useCallback, useMemo, useState } from 'react'; +import { GetRoomSession, GetSessionDataManager } from '../../../../api'; import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base'; import { useRoomContext } from '../../context/RoomContext'; -import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../../events'; +import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../../events'; import { RoomWidgetRoomObjectMessage } from '../../messages'; import { AvatarInfoWidgetViewProps } from './AvatarInfoWidgetView.types'; +import { AvatarInfoWidgetAvatarView } from './views/avatar/AvatarInfoWidgetAvatarView'; +import { AvatarInfoWidgetDecorateView } from './views/decorate/AvatarInfoWidgetDecorateView'; import { AvatarInfoWidgetNameView } from './views/name/AvatarInfoWidgetNameView'; +import { AvatarInfoWidgetOwnAvatarView } from './views/own-avatar/AvatarInfoWidgetOwnAvatarView'; +import { AvatarInfoWidgetOwnPetView } from './views/own-pet/AvatarInfoWidgetOwnPetView'; +import { AvatarInfoWidgetPetView } from './views/pet/AvatarInfoWidgetPetView'; +import { AvatarInfoWidgetRentableBotView } from './views/rentable-bot/AvatarInfoWidgetRentableBotView'; export const AvatarInfoWidgetView: FC = props => { @@ -13,121 +20,213 @@ export const AvatarInfoWidgetView: FC = props => const [ name, setName ] = useState(null); const [ infoStandEvent, setInfoStandEvent ] = useState(null); const [ isGameMode, setGameMode ] = useState(false); + const [ isDancing, setIsDancing ] = useState(false); + const [ isDecorating, setIsDecorating ] = useState(GetRoomSession().isDecorating); - const onRoomWidgetUpdateEvent = useCallback((event: RoomWidgetUpdateEvent) => + const onRoomWidgetRoomEngineUpdateEvent = useCallback((event: RoomWidgetRoomEngineUpdateEvent) => { switch(event.type) { case RoomWidgetRoomEngineUpdateEvent.NORMAL_MODE: { - const roomEngineEvent = (event as RoomWidgetRoomEngineUpdateEvent); - - setGameMode(false); + if(isGameMode) setGameMode(false); return; } case RoomWidgetRoomEngineUpdateEvent.GAME_MODE: { - const roomEngineEvent = (event as RoomWidgetRoomEngineUpdateEvent); - - setGameMode(true); + if(!isGameMode) setGameMode(true); return; } - case RoomWidgetRoomObjectUpdateEvent.USER_ADDED: { - const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); + } + }, [ isGameMode ]); - return; + CreateEventDispatcherHook(RoomWidgetRoomEngineUpdateEvent.NORMAL_MODE, eventDispatcher, onRoomWidgetRoomEngineUpdateEvent); + CreateEventDispatcherHook(RoomWidgetRoomEngineUpdateEvent.GAME_MODE, eventDispatcher, onRoomWidgetRoomEngineUpdateEvent); + + const onRoomObjectRemoved = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + { + if(name) + { + if(event.id === name.id) setName(null); + } + + if(infoStandEvent) + { + if(infoStandEvent instanceof RoomWidgetUpdateInfostandFurniEvent) + { + if(infoStandEvent.id === event.id) setInfoStandEvent(null); } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: - case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED: { - const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); - setName(prevValue => - { - if(!prevValue || (roomObjectEvent.id === prevValue.id)) return null; - - return prevValue; - }) - - setInfoStandEvent(prevValue => - { - if(!prevValue) return null; - - switch(event.type) - { - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: - if(prevValue instanceof RoomWidgetUpdateInfostandFurniEvent) - { - if(prevValue.id === roomObjectEvent.id) return null; - } - break; - case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED: - if(prevValue instanceof RoomWidgetUpdateInfostandUserEvent || prevValue instanceof RoomWidgetUpdateInfostandRentableBotEvent) - { - if(prevValue.roomIndex === roomObjectEvent.id) return null; - } - - else if(prevValue instanceof RoomWidgetUpdateInfostandPetEvent) - { - if(prevValue.roomIndex === roomObjectEvent.id) return null; - } - break; - } - - return prevValue; - }); - - return; + else if((infoStandEvent instanceof RoomWidgetUpdateInfostandUserEvent) || (infoStandEvent instanceof RoomWidgetUpdateInfostandRentableBotEvent)) + { + if(infoStandEvent.roomIndex === event.id) setInfoStandEvent(null); } + + else if(infoStandEvent instanceof RoomWidgetUpdateInfostandPetEvent) + { + if(infoStandEvent.roomIndex === event.id) setInfoStandEvent(null); + } + } + }, [ name, infoStandEvent ]); + + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomObjectRemoved); + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomObjectRemoved); + + const onObjectRolled = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + { + switch(event.type) + { case RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER: { const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); - + + if(infoStandEvent) return; + widgetHandler.processWidgetMessage(new RoomWidgetRoomObjectMessage(RoomWidgetRoomObjectMessage.GET_OBJECT_NAME, roomObjectEvent.id, roomObjectEvent.category)); + return; } case RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT: { const roomObjectEvent = (event as RoomWidgetRoomObjectUpdateEvent); + if(!name || (name.roomIndex !== roomObjectEvent.id)) return; + setName(null); - return; - } - case RoomWidgetObjectNameEvent.TYPE: { - const objectNameEvent = (event as RoomWidgetObjectNameEvent); - - if(objectNameEvent.category !== RoomObjectCategory.UNIT) return; - - setName(objectNameEvent); return; } - case RoomWidgetUpdateInfostandFurniEvent.FURNI: - case RoomWidgetUpdateInfostandUserEvent.OWN_USER: - case RoomWidgetUpdateInfostandUserEvent.PEER: - case RoomWidgetUpdateInfostandUserEvent.BOT: - case RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT: { - setInfoStandEvent((event as RoomWidgetUpdateInfostandFurniEvent)); - return; - } - default: - console.log(event); - return; } - }, [ widgetHandler ]); + }, [ infoStandEvent, name, widgetHandler ]); - CreateEventDispatcherHook(RoomWidgetRoomEngineUpdateEvent.NORMAL_MODE, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomEngineUpdateEvent.GAME_MODE, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_ADDED, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetObjectNameEvent.TYPE, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetUpdateInfostandFurniEvent.FURNI, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.OWN_USER, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.PEER, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.BOT, eventDispatcher, onRoomWidgetUpdateEvent); - CreateEventDispatcherHook(RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT, eventDispatcher, onRoomWidgetUpdateEvent); + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER, eventDispatcher, onObjectRolled); + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT, eventDispatcher, onObjectRolled); + + const onObjectDeselected = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + { + if(!infoStandEvent) return; + + setInfoStandEvent(null); + }, [ infoStandEvent ]); + + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onObjectDeselected); + + const onRoomWidgetObjectNameEvent = useCallback((event: RoomWidgetObjectNameEvent) => + { + if(event.category !== RoomObjectCategory.UNIT) return; + + setName(event); + }, []); + + CreateEventDispatcherHook(RoomWidgetObjectNameEvent.TYPE, eventDispatcher, onRoomWidgetObjectNameEvent); + + const onRoomWidgetUpdateInfostandEvent = useCallback((event: RoomWidgetUpdateInfostandEvent) => + { + if(name) setName(null); + setInfoStandEvent(event); + }, [ name ]); + + CreateEventDispatcherHook(RoomWidgetUpdateInfostandFurniEvent.FURNI, eventDispatcher, onRoomWidgetUpdateInfostandEvent); + CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.OWN_USER, eventDispatcher, onRoomWidgetUpdateInfostandEvent); + CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.PEER, eventDispatcher, onRoomWidgetUpdateInfostandEvent); + CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.BOT, eventDispatcher, onRoomWidgetUpdateInfostandEvent); + CreateEventDispatcherHook(RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT, eventDispatcher, onRoomWidgetUpdateInfostandEvent); + + const onRoomWidgetUpdateDanceStatusEvent = useCallback((event: RoomWidgetUpdateDanceStatusEvent) => + { + setIsDancing(event.isDancing); + }, []); + + CreateEventDispatcherHook(RoomWidgetUpdateDanceStatusEvent.UPDATE_DANCE, eventDispatcher, onRoomWidgetUpdateDanceStatusEvent); + + const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => + { + switch(event.type) + { + case RoomWidgetRoomObjectUpdateEvent.USER_ADDED: { + // bubble if friend + + return; + } + case RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED: { + // set if waiting for pet + + return; + } + } + }, []); + + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_ADDED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); + + const decorateView = useMemo(() => + { + GetRoomSession().isDecorating = isDecorating; + + if(!isDecorating) return null; + + const userId = GetSessionDataManager().userId; + const userName = GetSessionDataManager().userName; + const roomIndex = GetRoomSession().ownRoomIndex; + + return ; + }, [ isDecorating ]); + + const clearInfoStandEvent = useCallback(() => + { + setInfoStandEvent(null); + }, []); + + const currentView = useMemo(() => + { + if(isGameMode) return null; + + if(decorateView) return decorateView; + + if(name) return ; + + if(infoStandEvent) + { + switch(infoStandEvent.type) + { + case RoomWidgetUpdateInfostandUserEvent.OWN_USER: + case RoomWidgetUpdateInfostandUserEvent.PEER: { + const event = (infoStandEvent as RoomWidgetUpdateInfostandUserEvent); + + if(event.isSpectatorMode) return null; + + // if existing name bubble remove it + + if(event.isOwnUser) + { + if(RoomEnterEffect.isRunning()) return null; + + return ; + } + + return ; + } + case RoomWidgetUpdateInfostandPetEvent.PET_INFO: { + const event = (infoStandEvent as RoomWidgetUpdateInfostandPetEvent); + + if(event.isOwner) + { + return ; + } + + return ; + } + case RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT: { + return + } + case RoomWidgetUpdateInfostandFurniEvent.FURNI: { + return null; + } + } + } + + return null; + }, [ isGameMode, decorateView, name, infoStandEvent ]); return ( <> - { name && } + { currentView } ) } diff --git a/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx b/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx new file mode 100644 index 00000000..078d0d0e --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx @@ -0,0 +1,9 @@ +import { FC } from 'react'; +import { AvatarInfoWidgetAvatarViewProps } from './AvatarInfoWidgetAvatarView.types'; + +export const AvatarInfoWidgetAvatarView: FC = props => +{ + const { userData = null } = props; + + return null; +} diff --git a/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.types.ts b/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.types.ts new file mode 100644 index 00000000..ade7a285 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.types.ts @@ -0,0 +1,7 @@ +import { RoomWidgetUpdateInfostandUserEvent } from '../../../../events'; + +export interface AvatarInfoWidgetAvatarViewProps +{ + userData: RoomWidgetUpdateInfostandUserEvent; + close: () => void; +} diff --git a/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.tsx b/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.tsx new file mode 100644 index 00000000..4b53cffb --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.tsx @@ -0,0 +1,9 @@ +import { FC } from 'react'; +import { AvatarInfoWidgetDecorateViewProps } from './AvatarInfoWidgetDecorateView.types'; + +export const AvatarInfoWidgetDecorateView: FC = props => +{ + const { userId = -1, userName = '', roomIndex = -1 } = props; + + return null; +} diff --git a/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.types.ts b/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.types.ts new file mode 100644 index 00000000..ba8d0a96 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/decorate/AvatarInfoWidgetDecorateView.types.ts @@ -0,0 +1,6 @@ +export interface AvatarInfoWidgetDecorateViewProps +{ + userId: number; + userName: string; + roomIndex: number; +} diff --git a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx new file mode 100644 index 00000000..d049e21e --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx @@ -0,0 +1,202 @@ +import { AvatarAction, AvatarExpressionEnum, RoomObjectCategory } from 'nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { GetCanStandUp, GetCanUseExpression, GetOwnPosture, HasHabboClub, HasHabboVip, IsRidingHorse } from '../../../../../../api'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { useRoomContext } from '../../../../context/RoomContext'; +import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetUserActionMessage } from '../../../../messages'; +import { ContextMenuView } from '../../../context-menu/ContextMenuView'; +import { ContextMenuHeaderView } from '../../../context-menu/views/header/ContextMenuHeaderView'; +import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView'; +import { ContextMenuListView } from '../../../context-menu/views/list/ContextMenuListView'; +import { AvatarInfoWidgetOwnAvatarViewProps } from './AvatarInfoWidgetOwnAvatarView.types'; + +const MODE_NORMAL = 0; +const MODE_CLUB_DANCES = 1; +const MODE_NAME_CHANGE = 2; +const MODE_EXPRESSIONS = 3; +const MODE_SIGNS = 4; +const MODE_CHANGE_LOOKS = 5; + +export const AvatarInfoWidgetOwnAvatarView: FC = props => +{ + const { userData = null, isDancing = false, close = null } = props; + const [ mode, setMode ] = useState((isDancing && HasHabboClub()) ? MODE_CLUB_DANCES : MODE_NORMAL); + const { roomSession = null, widgetHandler = null } = useRoomContext(); + + const processAction = useCallback((name: string) => + { + let message: RoomWidgetMessage = null; + let hideMenu = true; + + if(name) + { + if(name.startsWith('sign_')) + { + const sign = parseInt(name.split('_')[1]); + + roomSession.sendSignMessage(sign); + } + else + { + switch(name) + { + case 'decorate': + // if(this.widget.hasClub) + // { + // this.widget.isDecorating = true; + // } + break; + case 'change_looks': + break; + case 'expressions': + hideMenu = false; + setMode(MODE_EXPRESSIONS); + break; + case 'sit': + message = new RoomWidgetChangePostureMessage(RoomWidgetChangePostureMessage.POSTURE_SIT); + break; + case 'stand': + message = new RoomWidgetChangePostureMessage(RoomWidgetChangePostureMessage.POSTURE_STAND); + break; + case 'wave': + message = new RoomWidgetAvatarExpressionMessage(AvatarExpressionEnum.WAVE); + break; + case 'blow': + message = new RoomWidgetAvatarExpressionMessage(AvatarExpressionEnum.BLOW); + break; + case 'laugh': + message = new RoomWidgetAvatarExpressionMessage(AvatarExpressionEnum.LAUGH); + break; + case 'idle': + message = new RoomWidgetAvatarExpressionMessage(AvatarExpressionEnum.IDLE); + break; + case 'dance_menu': + hideMenu = false; + setMode(MODE_CLUB_DANCES); + break; + case 'dance': + message = new RoomWidgetDanceMessage(1); + break; + case 'dance_stop': + message = new RoomWidgetDanceMessage(0); + break; + case 'dance_1': + case 'dance_2': + case 'dance_3': + case 'dance_4': + message = new RoomWidgetDanceMessage(parseInt(name.charAt((name.length - 1)))); + break; + case 'signs': + hideMenu = false; + setMode(MODE_SIGNS); + break; + case 'back': + hideMenu = false; + setMode(MODE_NORMAL); + break; + case 'drop_carry_item': + message = new RoomWidgetUserActionMessage(RoomWidgetUserActionMessage.DROP_CARRY_ITEM, userData.webID); + break; + } + } + + if(message) widgetHandler.processWidgetMessage(message); + } + + if(hideMenu) close(); + }, [ roomSession, userData, widgetHandler, close ]); + + const isRidingHorse = IsRidingHorse(); + + return ( + + + { userData.name } + + + { (mode === MODE_NORMAL) && + <> + processAction('decorate') }> + { LocalizeText('widget.avatar.decorate') } + + processAction('change_looks') }> + { LocalizeText('widget.memenu.myclothes') } + + { (HasHabboClub() && !isRidingHorse) && + processAction('dance_menu') }> + { LocalizeText('widget.memenu.dance') } + } + { (!isDancing && !HasHabboClub() && !isRidingHorse) && + processAction('dance') }> + { LocalizeText('widget.memenu.dance') } + } + { (isDancing && !HasHabboClub() && !isRidingHorse) && + processAction('dance_stop') }> + { LocalizeText('widget.memenu.dance.stop') } + } + processAction('expressions') }> + { LocalizeText('infostand.link.expressions') } + + processAction('signs') }> + { LocalizeText('infostand.show.signs') } + + { (userData.carryItem > 0) && + processAction('drop_carry_item') }> + { LocalizeText('avatar.widget.drop_hand_item') } + } + } + { (mode === MODE_CLUB_DANCES) && + <> + { isDancing && + processAction('dance_stop') }> + { LocalizeText('widget.memenu.dance.stop') } + } + processAction('dance_1') }> + { LocalizeText('widget.memenu.dance1') } + + processAction('dance_2') }> + { LocalizeText('widget.memenu.dance2') } + + processAction('dance_3') }> + { LocalizeText('widget.memenu.dance3') } + + processAction('dance_4') }> + { LocalizeText('widget.memenu.dance4') } + + processAction('back') }> + { LocalizeText('generic.back') } + + } + { (mode === MODE_EXPRESSIONS) && + <> + { (GetOwnPosture() === AvatarAction.POSTURE_STAND) && + processAction('sit') }> + { LocalizeText('widget.memenu.sit') } + } + { GetCanStandUp() && + processAction('stand') }> + { LocalizeText('widget.memenu.stand') } + } + { GetCanUseExpression() && + processAction('wave') }> + { LocalizeText('widget.memenu.wave') } + } + { (GetCanUseExpression() && HasHabboVip()) && + processAction('laugh') }> + { LocalizeText('widget.memenu.laugh') } + } + { (GetCanUseExpression() && HasHabboVip()) && + processAction('blow') }> + { LocalizeText('widget.memenu.blow') } + } + processAction('idle') }> + { LocalizeText('widget.memenu.idle') } + + processAction('back') }> + { LocalizeText('generic.back') } + + } + + + ); +} diff --git a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.types.ts b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.types.ts new file mode 100644 index 00000000..62709872 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.types.ts @@ -0,0 +1,8 @@ +import { RoomWidgetUpdateInfostandUserEvent } from '../../../../events'; + +export interface AvatarInfoWidgetOwnAvatarViewProps +{ + userData: RoomWidgetUpdateInfostandUserEvent; + isDancing: boolean; + close: () => void; +} 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 new file mode 100644 index 00000000..b95e6c30 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx @@ -0,0 +1,9 @@ +import { FC } from 'react'; +import { AvatarInfoWidgetOwnPetViewProps } from './AvatarInfoWidgetOwnPetView.types'; + +export const AvatarInfoWidgetOwnPetView: FC = props => +{ + const { petData = null } = props; + + return null; +} diff --git a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.types.ts b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.types.ts new file mode 100644 index 00000000..cd9cf18e --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.types.ts @@ -0,0 +1,7 @@ +import { RoomWidgetUpdateInfostandPetEvent } from '../../../../events'; + +export interface AvatarInfoWidgetOwnPetViewProps +{ + petData: RoomWidgetUpdateInfostandPetEvent; + close: () => void; +} diff --git a/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx b/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx new file mode 100644 index 00000000..59eac211 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx @@ -0,0 +1,9 @@ +import { FC } from 'react'; +import { AvatarInfoWidgetPetViewProps } from './AvatarInfoWidgetPetView.types'; + +export const AvatarInfoWidgetPetView: FC = props => +{ + const { petData = null } = props; + + return null; +} diff --git a/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.types.ts b/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.types.ts new file mode 100644 index 00000000..c07ecf15 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.types.ts @@ -0,0 +1,7 @@ +import { RoomWidgetUpdateInfostandPetEvent } from '../../../../events'; + +export interface AvatarInfoWidgetPetViewProps +{ + petData: RoomWidgetUpdateInfostandPetEvent; + close: () => void; +} 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 new file mode 100644 index 00000000..8fcfd5e1 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx @@ -0,0 +1,9 @@ +import { FC } from 'react'; +import { AvatarInfoWidgetRentableBotViewProps } from './AvatarInfoWidgetRentableBotView.types'; + +export const AvatarInfoWidgetRentableBotView: FC = props => +{ + const { rentableBotData = null } = props; + + return null; +} diff --git a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.types.ts b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.types.ts new file mode 100644 index 00000000..d7b8912d --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.types.ts @@ -0,0 +1,7 @@ +import { RoomWidgetUpdateInfostandRentableBotEvent } from '../../../../events'; + +export interface AvatarInfoWidgetRentableBotViewProps +{ + rentableBotData: RoomWidgetUpdateInfostandRentableBotEvent; + close: () => void; +} diff --git a/src/views/room/widgets/context-menu/ContextMenu.scss b/src/views/room/widgets/context-menu/ContextMenu.scss index 3c393d9b..50e9f149 100644 --- a/src/views/room/widgets/context-menu/ContextMenu.scss +++ b/src/views/room/widgets/context-menu/ContextMenu.scss @@ -1,3 +1,6 @@ .nitro-context-menu { + @import './views/header/ContextMenuHeaderView'; + @import './views/list/ContextMenuListView'; + @import './views/list-item/ContextMenuListItemView'; } diff --git a/src/views/room/widgets/context-menu/views/header/ContextMenuHeaderView.scss b/src/views/room/widgets/context-menu/views/header/ContextMenuHeaderView.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/views/room/widgets/context-menu/views/header/ContextMenuHeaderView.tsx b/src/views/room/widgets/context-menu/views/header/ContextMenuHeaderView.tsx new file mode 100644 index 00000000..e7a73dad --- /dev/null +++ b/src/views/room/widgets/context-menu/views/header/ContextMenuHeaderView.tsx @@ -0,0 +1,13 @@ +import { FC } from 'react'; +import { ContextMenuHeaderViewProps } from './ContextMenuHeaderView.types'; + +export const ContextMenuHeaderView: FC = props => +{ + const { children = null } = props; + + return ( +
+ { children } +
+ ); +} diff --git a/src/views/room/widgets/context-menu/views/header/ContextMenuHeaderView.types.ts b/src/views/room/widgets/context-menu/views/header/ContextMenuHeaderView.types.ts new file mode 100644 index 00000000..65bfa25e --- /dev/null +++ b/src/views/room/widgets/context-menu/views/header/ContextMenuHeaderView.types.ts @@ -0,0 +1,4 @@ +export interface ContextMenuHeaderViewProps +{ + +} diff --git a/src/views/room/widgets/context-menu/views/list-item/ContextMenuListItemView.scss b/src/views/room/widgets/context-menu/views/list-item/ContextMenuListItemView.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/views/room/widgets/context-menu/views/list-item/ContextMenuListItemView.tsx b/src/views/room/widgets/context-menu/views/list-item/ContextMenuListItemView.tsx new file mode 100644 index 00000000..1bc955a6 --- /dev/null +++ b/src/views/room/widgets/context-menu/views/list-item/ContextMenuListItemView.tsx @@ -0,0 +1,13 @@ +import { FC } from 'react'; +import { ContextMenuListItemViewProps } from './ContextMenuListItemView.types'; + +export const ContextMenuListItemView: FC = props => +{ + const { onClick = null, children = null } = props; + + return ( +
+ { children } +
+ ) +} diff --git a/src/views/room/widgets/context-menu/views/list-item/ContextMenuListItemView.types.ts b/src/views/room/widgets/context-menu/views/list-item/ContextMenuListItemView.types.ts new file mode 100644 index 00000000..21878f3a --- /dev/null +++ b/src/views/room/widgets/context-menu/views/list-item/ContextMenuListItemView.types.ts @@ -0,0 +1,6 @@ +import { MouseEvent } from 'react'; + +export interface ContextMenuListItemViewProps +{ + onClick: (event: MouseEvent) => void; +} diff --git a/src/views/room/widgets/context-menu/views/list/ContextMenuListView.scss b/src/views/room/widgets/context-menu/views/list/ContextMenuListView.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/views/room/widgets/context-menu/views/list/ContextMenuListView.tsx b/src/views/room/widgets/context-menu/views/list/ContextMenuListView.tsx new file mode 100644 index 00000000..7046bf5f --- /dev/null +++ b/src/views/room/widgets/context-menu/views/list/ContextMenuListView.tsx @@ -0,0 +1,13 @@ +import { FC } from 'react'; +import { ContextMenuListViewProps } from './ContextMenuListView.types'; + +export const ContextMenuListView: FC = props => +{ + const { children = null } = props; + + return ( +
+ { children } +
+ ); +} diff --git a/src/views/room/widgets/context-menu/views/list/ContextMenuListView.types.ts b/src/views/room/widgets/context-menu/views/list/ContextMenuListView.types.ts new file mode 100644 index 00000000..185d9e71 --- /dev/null +++ b/src/views/room/widgets/context-menu/views/list/ContextMenuListView.types.ts @@ -0,0 +1,4 @@ +export interface ContextMenuListViewProps +{ + +} diff --git a/src/views/room/widgets/infostand/InfoStandWidgetView.scss b/src/views/room/widgets/infostand/InfoStandWidgetView.scss index 8394c58b..404b6a93 100644 --- a/src/views/room/widgets/infostand/InfoStandWidgetView.scss +++ b/src/views/room/widgets/infostand/InfoStandWidgetView.scss @@ -7,12 +7,12 @@ .nitro-infostand { position: relative; - min-width: 200px; - max-width: 200px; + min-width: 190px; + max-width: 190px; z-index: $infostand-zindex; pointer-events: auto; - box-shadow: inset 0 2px 0 rgba($white, .15), inset 0 -2px rgba($black, .1), 0 1px rgba($black, .1); - border: 1px solid rgba($black, 0.1); + background: rgba($dark,.95); + box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); .form-control-sm { height: 25px; diff --git a/src/views/room/widgets/infostand/views/base/InfoStandBaseView.tsx b/src/views/room/widgets/infostand/views/base/InfoStandBaseView.tsx new file mode 100644 index 00000000..7e5049ab --- /dev/null +++ b/src/views/room/widgets/infostand/views/base/InfoStandBaseView.tsx @@ -0,0 +1,20 @@ +import { FC } from 'react'; +import { InfoStandBaseViewProps } from './InfoStandBaseView.types'; + +export const InfoStandBaseView: FC = props => +{ + const { headerText = null, onCloseClick = null, children = null } = props; + + return ( +
+
+
+
{ headerText }
+ +
+
+ { children } +
+
+ ); +} diff --git a/src/views/room/widgets/infostand/views/base/InfoStandBaseView.types.ts b/src/views/room/widgets/infostand/views/base/InfoStandBaseView.types.ts new file mode 100644 index 00000000..bb775875 --- /dev/null +++ b/src/views/room/widgets/infostand/views/base/InfoStandBaseView.types.ts @@ -0,0 +1,7 @@ +import { MouseEvent, ReactNode } from 'react'; + +export interface InfoStandBaseViewProps +{ + headerText: ReactNode; + onCloseClick: (event: MouseEvent) => void; +} diff --git a/src/views/room/widgets/infostand/views/bot/InfoStandWidgetBotView.tsx b/src/views/room/widgets/infostand/views/bot/InfoStandWidgetBotView.tsx index 0e683936..45c2eb20 100644 --- a/src/views/room/widgets/infostand/views/bot/InfoStandWidgetBotView.tsx +++ b/src/views/room/widgets/infostand/views/bot/InfoStandWidgetBotView.tsx @@ -2,6 +2,7 @@ import { FC, useCallback } from 'react'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { AvatarImageView } from '../../../../../shared/avatar-image/AvatarImageView'; import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; +import { InfoStandBaseView } from '../base/InfoStandBaseView'; import { InfoStandWidgetBotViewProps } from './InfoStandWidgetBotView.types'; export const InfoStandWidgetBotView: FC = props => @@ -17,34 +18,27 @@ export const InfoStandWidgetBotView: FC = props => if(!botData) return null; return ( -
-
-
-
{ botData.name }
- + +
+
+
-
-
-
- -
-
- { (botData.badges.length > 0) && botData.badges.map((result, index) => - { - return ; - }) } -
+
+ { (botData.badges.length > 0) && botData.badges.map((result, index) => + { + return ; + }) }
-
-
{ botData.motto }
- { (botData.carryItem > 0) && - <> -
-
- { LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + botData.carryItem) ]) } -
- }
-
+
+
{ botData.motto }
+ { (botData.carryItem > 0) && + <> +
+
+ { LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + botData.carryItem) ]) } +
+ } +
); } diff --git a/src/views/room/widgets/infostand/views/furni/InfoStandWidgetFurniView.tsx b/src/views/room/widgets/infostand/views/furni/InfoStandWidgetFurniView.tsx index b2413aba..0415db5f 100644 --- a/src/views/room/widgets/infostand/views/furni/InfoStandWidgetFurniView.tsx +++ b/src/views/room/widgets/infostand/views/furni/InfoStandWidgetFurniView.tsx @@ -5,6 +5,7 @@ import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView import { LimitedEditionCompactPlateView } from '../../../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView'; import { useRoomContext } from '../../../../context/RoomContext'; import { RoomWidgetFurniActionMessage } from '../../../../messages'; +import { InfoStandBaseView } from '../base/InfoStandBaseView'; import { InfoStandWidgetFurniViewProps } from './InfoStandWidgetFurniView.types'; const PICKUP_MODE_NONE: number = 0; @@ -176,83 +177,71 @@ export const InfoStandWidgetFurniView: FC = props return ( <> -
-
-
-
{ furniData.name }
- -
-
-
- { furniData.stuffData.isUnique && -
- -
} - { furniData.image.src.length && - } -
-
-
{ furniData.description }
-
-
- -
{ LocalizeText('furni.owner', [ 'name' ], [ furniData.ownerName ]) }
-
- { isCrackable && - <> -
-
{ LocalizeText('infostand.crackable_furni.hits_remaining', [ 'hits', 'target' ], [ crackableHits.toString(), crackableTarget.toString() ]) }
- } - { (furniData.groupId > 0) && - <> -
-
- -
- } - { godMode && - <> -
-
ID: { furniData.id }
- { (furniSettingsKeys.length > 0) && - <> -
- { furniSettingsKeys.map((key, index) => - { - return ( -
-
{ key }
- onFurniSettingChange(index, event.target.value) }/> -
); - }) } - } - } + +
+ { furniData.stuffData.isUnique && +
+ +
} + { furniData.image.src.length && + }
-
+
+
{ furniData.description }
+
+
+ +
{ LocalizeText('furni.owner', [ 'name' ], [ furniData.ownerName ]) }
+
+ { isCrackable && + <> +
+
{ LocalizeText('infostand.crackable_furni.hits_remaining', [ 'hits', 'target' ], [ crackableHits.toString(), crackableTarget.toString() ]) }
+ } + { (furniData.groupId > 0) && + <> +
+
+ +
+ } + { godMode && + <> +
+
ID: { furniData.id }
+ { (furniSettingsKeys.length > 0) && + <> +
+ { furniSettingsKeys.map((key, index) => + { + return ( +
+
{ key }
+ onFurniSettingChange(index, event.target.value) }/> +
); + }) } + } + } +
{ canMove && - } { canRotate && - } { canUse && - } { (pickupMode !== PICKUP_MODE_NONE) && - } { ((furniSettingsKeys.length > 0 && furniSettingsValues.length > 0) && (furniSettingsKeys.length === furniSettingsValues.length)) && - }
diff --git a/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx b/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx index afb62410..c37a30ab 100644 --- a/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx +++ b/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx @@ -1,6 +1,7 @@ import { FC } from 'react'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { PetImageView } from '../../../../../shared/pet-image/PetImageView'; +import { InfoStandBaseView } from '../base/InfoStandBaseView'; import { InfoStandWidgetPetViewProps } from './InfoStandWidgetPetView.types'; export const InfoStandWidgetPetView: FC = props => @@ -9,54 +10,45 @@ export const InfoStandWidgetPetView: FC = props => if(!petData) return null; - return (<> -
-
-
-
- { petData.name }
- { LocalizeText('pet.breed.' + petData.petType + '.' + petData.petBreed) }
- + return ( + { petData.name }
{ LocalizeText('pet.breed.' + petData.petType + '.' + petData.petBreed) } } onCloseClick={ close }> +
+
+
-
-
-
- -
-
-
{ LocalizeText('pet.level', ['level', 'maxlevel'], [petData.level.toString(), petData.maximumLevel.toString()]) }
-
-
{ LocalizeText('infostand.pet.text.happiness') }
-
-
{ petData.happyness + '/' + petData.maximumHappyness }
-
-
-
-
-
{ LocalizeText('infostand.pet.text.experience') }
-
-
{ petData.experience + '/' + petData.levelExperienceGoal }
-
-
-
-
-
{ LocalizeText('infostand.pet.text.energy') }
-
-
{ petData.energy + '/' + petData.maximumEnergy }
-
-
+
+
{ LocalizeText('pet.level', ['level', 'maxlevel'], [petData.level.toString(), petData.maximumLevel.toString()]) }
+
+
{ LocalizeText('infostand.pet.text.happiness') }
+
+
{ petData.happyness + '/' + petData.maximumHappyness }
+
+
+
+
+
{ LocalizeText('infostand.pet.text.experience') }
+
+
{ petData.experience + '/' + petData.levelExperienceGoal }
+
+
+
+
+
{ LocalizeText('infostand.pet.text.energy') }
+
+
{ petData.energy + '/' + petData.maximumEnergy }
+
-
-
-
{ LocalizeText('infostand.text.petrespect', ['count'], [petData.respect.toString()]) }
-
{ LocalizeText('pet.age', ['age'], [petData.age.toString()]) }
-
-
- -
{ LocalizeText('infostand.text.petowner', ['name'], [petData.ownerName]) }
-
- ); +
+
{ LocalizeText('infostand.text.petrespect', ['count'], [petData.respect.toString()]) }
+
{ LocalizeText('pet.age', ['age'], [petData.age.toString()]) }
+
+
+ +
{ LocalizeText('infostand.text.petowner', ['name'], [petData.ownerName]) }
+
+ + ); } 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 4b3230b7..258840ef 100644 --- a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx +++ b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx @@ -5,6 +5,7 @@ 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 { InfoStandBaseView } from '../base/InfoStandBaseView'; import { InfoStandWidgetRentableBotViewProps } from './InfoStandWidgetRentableBotView.types'; export const InfoStandWidgetRentableBotView: FC = props => @@ -29,40 +30,33 @@ export const InfoStandWidgetRentableBotView: FC -
-
-
-
{ rentableBotData.name }
- + +
+
+
-
-
-
- -
-
- { (rentableBotData.badges.length > 0) && rentableBotData.badges.map((result, index) => - { - return ; - }) } -
+
+ { (rentableBotData.badges.length > 0) && rentableBotData.badges.map((result, index) => + { + return ; + }) }
-
-
{ rentableBotData.motto }
-
-
- -
{ LocalizeText('infostand.text.botowner', [ 'name' ], [ rentableBotData.ownerName ]) }
-
- { (rentableBotData.carryItem > 0) && - <> -
-
- { LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + rentableBotData.carryItem) ]) } -
- }
-
+
+
{ rentableBotData.motto }
+
+
+ +
{ LocalizeText('infostand.text.botowner', [ 'name' ], [ rentableBotData.ownerName ]) }
+
+ { (rentableBotData.carryItem > 0) && + <> +
+
+ { LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + rentableBotData.carryItem) ]) } +
+ } +
{ canPickup &&