Start context menu

This commit is contained in:
Bill 2021-06-24 03:58:43 -04:00
parent 41889f970c
commit ee324edea0
59 changed files with 1090 additions and 285 deletions

View File

@ -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<string[]>('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)
{

View File

@ -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;
}

View File

@ -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';

View File

@ -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<string>(RoomObjectVariable.FIGURE_CAN_STAND_UP);
}

View File

@ -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<number>(RoomObjectVariable.FIGURE_EFFECT);
return ((effectId === 29) || (effectId === 30) || (effectId === 185));
}

View File

@ -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<string>(RoomObjectVariable.FIGURE_POSTURE);
}

View File

@ -0,0 +1,7 @@
import { HabboClubLevelEnum } from 'nitro-renderer';
import { GetSessionDataManager } from './GetSessionDataManager';
export function HasHabboClub(): boolean
{
return (GetSessionDataManager().clubLevel >= HabboClubLevelEnum.CLUB);
}

View File

@ -0,0 +1,7 @@
import { HabboClubLevelEnum } from 'nitro-renderer';
import { GetSessionDataManager } from './GetSessionDataManager';
export function HasHabboVip(): boolean
{
return (GetSessionDataManager().clubLevel >= HabboClubLevelEnum.VIP);
}

View File

@ -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<number>(RoomObjectVariable.FIGURE_EFFECT);
return (effectId === 77);
}

View File

@ -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';

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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<RoomViewProps> = props =>
const widgetHandlerManager = new RoomWidgetHandlerManager(roomSession, new EventDispatcher());
widgetHandlerManager.registerHandler(new RoomWidgetAvatarInfoHandler());
widgetHandlerManager.registerHandler(new RoomWidgetInfostandHandler());
setWidgetHandler(widgetHandlerManager);

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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';

View File

@ -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
];
}
}

View File

@ -1,5 +1,6 @@
export * from './IRoomWidgetHandler';
export * from './IRoomWidgetHandlerManager';
export * from './RoomWidgetAvatarInfoHandler';
export * from './RoomWidgetHandler';
export * from './RoomWidgetHandlerManager';
export * from './RoomWidgetInfostandHandler';

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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';

View File

@ -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';

View File

@ -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<AvatarInfoWidgetViewProps> = props =>
{
@ -13,121 +20,213 @@ export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
const [ name, setName ] = useState<RoomWidgetObjectNameEvent>(null);
const [ infoStandEvent, setInfoStandEvent ] = useState<RoomWidgetUpdateInfostandEvent>(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 <AvatarInfoWidgetDecorateView userId={ userId } userName={ userName } roomIndex={ roomIndex } />;
}, [ isDecorating ]);
const clearInfoStandEvent = useCallback(() =>
{
setInfoStandEvent(null);
}, []);
const currentView = useMemo(() =>
{
if(isGameMode) return null;
if(decorateView) return decorateView;
if(name) return <AvatarInfoWidgetNameView event={ name } />;
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 <AvatarInfoWidgetOwnAvatarView userData={ event } isDancing={ isDancing } close={ clearInfoStandEvent } />;
}
return <AvatarInfoWidgetAvatarView userData={ event } close={ clearInfoStandEvent } />;
}
case RoomWidgetUpdateInfostandPetEvent.PET_INFO: {
const event = (infoStandEvent as RoomWidgetUpdateInfostandPetEvent);
if(event.isOwner)
{
return <AvatarInfoWidgetOwnPetView petData={ event } close={ clearInfoStandEvent } />;
}
return <AvatarInfoWidgetPetView petData={ event } close={ clearInfoStandEvent } />;
}
case RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT: {
return <AvatarInfoWidgetRentableBotView rentableBotData={ (infoStandEvent as RoomWidgetUpdateInfostandRentableBotEvent) } close={ clearInfoStandEvent } />
}
case RoomWidgetUpdateInfostandFurniEvent.FURNI: {
return null;
}
}
}
return null;
}, [ isGameMode, decorateView, name, infoStandEvent ]);
return (
<>
{ name && <AvatarInfoWidgetNameView event={ name } /> }
{ currentView }
</>
)
}

View File

@ -0,0 +1,9 @@
import { FC } from 'react';
import { AvatarInfoWidgetAvatarViewProps } from './AvatarInfoWidgetAvatarView.types';
export const AvatarInfoWidgetAvatarView: FC<AvatarInfoWidgetAvatarViewProps> = props =>
{
const { userData = null } = props;
return null;
}

View File

@ -0,0 +1,7 @@
import { RoomWidgetUpdateInfostandUserEvent } from '../../../../events';
export interface AvatarInfoWidgetAvatarViewProps
{
userData: RoomWidgetUpdateInfostandUserEvent;
close: () => void;
}

View File

@ -0,0 +1,9 @@
import { FC } from 'react';
import { AvatarInfoWidgetDecorateViewProps } from './AvatarInfoWidgetDecorateView.types';
export const AvatarInfoWidgetDecorateView: FC<AvatarInfoWidgetDecorateViewProps> = props =>
{
const { userId = -1, userName = '', roomIndex = -1 } = props;
return null;
}

View File

@ -0,0 +1,6 @@
export interface AvatarInfoWidgetDecorateViewProps
{
userId: number;
userName: string;
roomIndex: number;
}

View File

@ -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<AvatarInfoWidgetOwnAvatarViewProps> = 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 (
<ContextMenuView objectId={ userData.roomIndex } category={ RoomObjectCategory.UNIT } onClose={ close }>
<ContextMenuHeaderView>
{ userData.name }
</ContextMenuHeaderView>
<ContextMenuListView>
{ (mode === MODE_NORMAL) &&
<>
<ContextMenuListItemView onClick={ event => processAction('decorate') }>
{ LocalizeText('widget.avatar.decorate') }
</ContextMenuListItemView>
<ContextMenuListItemView onClick={ event => processAction('change_looks') }>
{ LocalizeText('widget.memenu.myclothes') }
</ContextMenuListItemView>
{ (HasHabboClub() && !isRidingHorse) &&
<ContextMenuListItemView onClick={ event => processAction('dance_menu') }>
{ LocalizeText('widget.memenu.dance') }
</ContextMenuListItemView> }
{ (!isDancing && !HasHabboClub() && !isRidingHorse) &&
<ContextMenuListItemView onClick={ event => processAction('dance') }>
{ LocalizeText('widget.memenu.dance') }
</ContextMenuListItemView> }
{ (isDancing && !HasHabboClub() && !isRidingHorse) &&
<ContextMenuListItemView onClick={ event => processAction('dance_stop') }>
{ LocalizeText('widget.memenu.dance.stop') }
</ContextMenuListItemView> }
<ContextMenuListItemView onClick={ event => processAction('expressions') }>
{ LocalizeText('infostand.link.expressions') }
</ContextMenuListItemView>
<ContextMenuListItemView onClick={ event => processAction('signs') }>
{ LocalizeText('infostand.show.signs') }
</ContextMenuListItemView>
{ (userData.carryItem > 0) &&
<ContextMenuListItemView onClick={ event => processAction('drop_carry_item') }>
{ LocalizeText('avatar.widget.drop_hand_item') }
</ContextMenuListItemView> }
</> }
{ (mode === MODE_CLUB_DANCES) &&
<>
{ isDancing &&
<ContextMenuListItemView onClick={ event => processAction('dance_stop') }>
{ LocalizeText('widget.memenu.dance.stop') }
</ContextMenuListItemView> }
<ContextMenuListItemView onClick={ event => processAction('dance_1') }>
{ LocalizeText('widget.memenu.dance1') }
</ContextMenuListItemView>
<ContextMenuListItemView onClick={ event => processAction('dance_2') }>
{ LocalizeText('widget.memenu.dance2') }
</ContextMenuListItemView>
<ContextMenuListItemView onClick={ event => processAction('dance_3') }>
{ LocalizeText('widget.memenu.dance3') }
</ContextMenuListItemView>
<ContextMenuListItemView onClick={ event => processAction('dance_4') }>
{ LocalizeText('widget.memenu.dance4') }
</ContextMenuListItemView>
<ContextMenuListItemView onClick={ event => processAction('back') }>
{ LocalizeText('generic.back') }
</ContextMenuListItemView>
</> }
{ (mode === MODE_EXPRESSIONS) &&
<>
{ (GetOwnPosture() === AvatarAction.POSTURE_STAND) &&
<ContextMenuListItemView onClick={ event => processAction('sit') }>
{ LocalizeText('widget.memenu.sit') }
</ContextMenuListItemView> }
{ GetCanStandUp() &&
<ContextMenuListItemView onClick={ event => processAction('stand') }>
{ LocalizeText('widget.memenu.stand') }
</ContextMenuListItemView> }
{ GetCanUseExpression() &&
<ContextMenuListItemView onClick={ event => processAction('wave') }>
{ LocalizeText('widget.memenu.wave') }
</ContextMenuListItemView> }
{ (GetCanUseExpression() && HasHabboVip()) &&
<ContextMenuListItemView onClick={ event => processAction('laugh') }>
{ LocalizeText('widget.memenu.laugh') }
</ContextMenuListItemView> }
{ (GetCanUseExpression() && HasHabboVip()) &&
<ContextMenuListItemView onClick={ event => processAction('blow') }>
{ LocalizeText('widget.memenu.blow') }
</ContextMenuListItemView> }
<ContextMenuListItemView onClick={ event => processAction('idle') }>
{ LocalizeText('widget.memenu.idle') }
</ContextMenuListItemView>
<ContextMenuListItemView onClick={ event => processAction('back') }>
{ LocalizeText('generic.back') }
</ContextMenuListItemView>
</> }
</ContextMenuListView>
</ContextMenuView>
);
}

View File

@ -0,0 +1,8 @@
import { RoomWidgetUpdateInfostandUserEvent } from '../../../../events';
export interface AvatarInfoWidgetOwnAvatarViewProps
{
userData: RoomWidgetUpdateInfostandUserEvent;
isDancing: boolean;
close: () => void;
}

View File

@ -0,0 +1,9 @@
import { FC } from 'react';
import { AvatarInfoWidgetOwnPetViewProps } from './AvatarInfoWidgetOwnPetView.types';
export const AvatarInfoWidgetOwnPetView: FC<AvatarInfoWidgetOwnPetViewProps> = props =>
{
const { petData = null } = props;
return null;
}

View File

@ -0,0 +1,7 @@
import { RoomWidgetUpdateInfostandPetEvent } from '../../../../events';
export interface AvatarInfoWidgetOwnPetViewProps
{
petData: RoomWidgetUpdateInfostandPetEvent;
close: () => void;
}

View File

@ -0,0 +1,9 @@
import { FC } from 'react';
import { AvatarInfoWidgetPetViewProps } from './AvatarInfoWidgetPetView.types';
export const AvatarInfoWidgetPetView: FC<AvatarInfoWidgetPetViewProps> = props =>
{
const { petData = null } = props;
return null;
}

View File

@ -0,0 +1,7 @@
import { RoomWidgetUpdateInfostandPetEvent } from '../../../../events';
export interface AvatarInfoWidgetPetViewProps
{
petData: RoomWidgetUpdateInfostandPetEvent;
close: () => void;
}

View File

@ -0,0 +1,9 @@
import { FC } from 'react';
import { AvatarInfoWidgetRentableBotViewProps } from './AvatarInfoWidgetRentableBotView.types';
export const AvatarInfoWidgetRentableBotView: FC<AvatarInfoWidgetRentableBotViewProps> = props =>
{
const { rentableBotData = null } = props;
return null;
}

View File

@ -0,0 +1,7 @@
import { RoomWidgetUpdateInfostandRentableBotEvent } from '../../../../events';
export interface AvatarInfoWidgetRentableBotViewProps
{
rentableBotData: RoomWidgetUpdateInfostandRentableBotEvent;
close: () => void;
}

View File

@ -1,3 +1,6 @@
.nitro-context-menu {
@import './views/header/ContextMenuHeaderView';
@import './views/list/ContextMenuListView';
@import './views/list-item/ContextMenuListItemView';
}

View File

@ -0,0 +1,13 @@
import { FC } from 'react';
import { ContextMenuHeaderViewProps } from './ContextMenuHeaderView.types';
export const ContextMenuHeaderView: FC<ContextMenuHeaderViewProps> = props =>
{
const { children = null } = props;
return (
<div>
{ children }
</div>
);
}

View File

@ -0,0 +1,4 @@
export interface ContextMenuHeaderViewProps
{
}

View File

@ -0,0 +1,13 @@
import { FC } from 'react';
import { ContextMenuListItemViewProps } from './ContextMenuListItemView.types';
export const ContextMenuListItemView: FC<ContextMenuListItemViewProps> = props =>
{
const { onClick = null, children = null } = props;
return (
<div className="" onClick={ onClick }>
{ children }
</div>
)
}

View File

@ -0,0 +1,6 @@
import { MouseEvent } from 'react';
export interface ContextMenuListItemViewProps
{
onClick: (event: MouseEvent) => void;
}

View File

@ -0,0 +1,13 @@
import { FC } from 'react';
import { ContextMenuListViewProps } from './ContextMenuListView.types';
export const ContextMenuListView: FC<ContextMenuListViewProps> = props =>
{
const { children = null } = props;
return (
<div>
{ children }
</div>
);
}

View File

@ -0,0 +1,4 @@
export interface ContextMenuListViewProps
{
}

View File

@ -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;

View File

@ -0,0 +1,20 @@
import { FC } from 'react';
import { InfoStandBaseViewProps } from './InfoStandBaseView.types';
export const InfoStandBaseView: FC<InfoStandBaseViewProps> = props =>
{
const { headerText = null, onCloseClick = null, children = null } = props;
return (
<div className="d-flex flex-column nitro-card nitro-infostand rounded">
<div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center">
<div className="small text-wrap">{ headerText }</div>
<i className="fas fa-times cursor-pointer" onClick={ onCloseClick }></i>
</div>
<hr className="m-0 my-1" />
{ children }
</div>
</div>
);
}

View File

@ -0,0 +1,7 @@
import { MouseEvent, ReactNode } from 'react';
export interface InfoStandBaseViewProps
{
headerText: ReactNode;
onCloseClick: (event: MouseEvent) => void;
}

View File

@ -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<InfoStandWidgetBotViewProps> = props =>
@ -17,34 +18,27 @@ export const InfoStandWidgetBotView: FC<InfoStandWidgetBotViewProps> = props =>
if(!botData) return null;
return (
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center">
<div className="small text-wrap">{ botData.name }</div>
<i className="fas fa-times cursor-pointer" onClick={ close }></i>
<InfoStandBaseView headerText={ botData.name } onCloseClick={ close }>
<div className="d-flex">
<div className="body-image bot w-100">
<AvatarImageView figure={ botData.figure } direction={ 4 } />
</div>
<hr className="m-0 my-1" />
<div className="d-flex">
<div className="body-image bot w-100">
<AvatarImageView figure={ botData.figure } direction={ 4 } />
</div>
<div className="w-100 d-flex justify-content-center align-items-center">
{ (botData.badges.length > 0) && botData.badges.map((result, index) =>
{
return <BadgeImageView key={ index } badgeCode={ result } />;
}) }
</div>
<div className="w-100 d-flex justify-content-center align-items-center">
{ (botData.badges.length > 0) && botData.badges.map((result, index) =>
{
return <BadgeImageView key={ index } badgeCode={ result } />;
}) }
</div>
<hr className="m-0 my-1" />
<div className="motto-content small">{ botData.motto }</div>
{ (botData.carryItem > 0) &&
<>
<hr className="m-0 my-1" />
<div className="small text-wrap">
{ LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + botData.carryItem) ]) }
</div>
</> }
</div>
</div>
<hr className="m-0 my-1" />
<div className="motto-content small">{ botData.motto }</div>
{ (botData.carryItem > 0) &&
<>
<hr className="m-0 my-1" />
<div className="small text-wrap">
{ LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + botData.carryItem) ]) }
</div>
</> }
</InfoStandBaseView>
);
}

View File

@ -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<InfoStandWidgetFurniViewProps> = props
return (
<>
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center">
<div className="small text-wrap">{ furniData.name }</div>
<i className="fas fa-times cursor-pointer" onClick={ close }></i>
</div>
<hr className="m-0 my-1" />
<div className="position-relative w-100">
{ furniData.stuffData.isUnique &&
<div className="position-absolute r-0">
<LimitedEditionCompactPlateView uniqueNumber={ furniData.stuffData.uniqueNumber } uniqueSeries={ furniData.stuffData.uniqueSeries } />
</div> }
{ furniData.image.src.length &&
<img className="d-block mx-auto" src={ furniData.image.src } alt="" /> }
</div>
<hr className="m-0 my-1" />
<div className="small text-wrap">{ furniData.description }</div>
<hr className="m-0 my-1" />
<div className="d-flex align-items-center">
<i className="icon icon-user-profile me-1 cursor-pointer" />
<div className="small text-wrap">{ LocalizeText('furni.owner', [ 'name' ], [ furniData.ownerName ]) }</div>
</div>
{ isCrackable &&
<>
<hr className="m-0 my-1" />
<div className="small text-wrap">{ LocalizeText('infostand.crackable_furni.hits_remaining', [ 'hits', 'target' ], [ crackableHits.toString(), crackableTarget.toString() ]) }</div>
</> }
{ (furniData.groupId > 0) &&
<>
<hr className="m-0 my-1" />
<div className="badge badge-secondary mb-0" onClick={ openFurniGroupInfo }>
<BadgeImageView badgeCode={ (furniData.stuffData as StringDataType).getValue(2) } />
</div>
</> }
{ godMode &&
<>
<hr className="m-0 my-1" />
<div className="small text-wrap">ID: { furniData.id }</div>
{ (furniSettingsKeys.length > 0) &&
<>
<hr className="m-0 my-1"/>
{ furniSettingsKeys.map((key, index) =>
{
return (
<div key={ index } className="mb-1">
<div className="small text-wrap">{ key }</div>
<input type="text" className="form-control form-control-sm" value={ furniSettingsValues[index] } onChange={ event => onFurniSettingChange(index, event.target.value) }/>
</div>);
}) }
</> }
</> }
<InfoStandBaseView headerText={ furniData.name } onCloseClick={ close }>
<div className="position-relative w-100">
{ furniData.stuffData.isUnique &&
<div className="position-absolute r-0">
<LimitedEditionCompactPlateView uniqueNumber={ furniData.stuffData.uniqueNumber } uniqueSeries={ furniData.stuffData.uniqueSeries } />
</div> }
{ furniData.image.src.length &&
<img className="d-block mx-auto" src={ furniData.image.src } alt="" /> }
</div>
</div>
<hr className="m-0 my-1" />
<div className="small text-wrap">{ furniData.description }</div>
<hr className="m-0 my-1" />
<div className="d-flex align-items-center">
<i className="icon icon-user-profile me-1 cursor-pointer" />
<div className="small text-wrap">{ LocalizeText('furni.owner', [ 'name' ], [ furniData.ownerName ]) }</div>
</div>
{ isCrackable &&
<>
<hr className="m-0 my-1" />
<div className="small text-wrap">{ LocalizeText('infostand.crackable_furni.hits_remaining', [ 'hits', 'target' ], [ crackableHits.toString(), crackableTarget.toString() ]) }</div>
</> }
{ (furniData.groupId > 0) &&
<>
<hr className="m-0 my-1" />
<div className="badge badge-secondary mb-0" onClick={ openFurniGroupInfo }>
<BadgeImageView badgeCode={ (furniData.stuffData as StringDataType).getValue(2) } />
</div>
</> }
{ godMode &&
<>
<hr className="m-0 my-1" />
<div className="small text-wrap">ID: { furniData.id }</div>
{ (furniSettingsKeys.length > 0) &&
<>
<hr className="m-0 my-1"/>
{ furniSettingsKeys.map((key, index) =>
{
return (
<div key={ index } className="mb-1">
<div className="small text-wrap">{ key }</div>
<input type="text" className="form-control form-control-sm" value={ furniSettingsValues[index] } onChange={ event => onFurniSettingChange(index, event.target.value) }/>
</div>);
}) }
</> }
</> }
</InfoStandBaseView>
<div className="button-container mt-2">
{ canMove &&
<button type="button" className="btn btn-sm btn-secondary" onClick={event => processButtonAction('move')}>
<i className="fas fa-arrows-alt me-1"></i>
<button type="button" className="btn btn-sm btn-dark" onClick={event => processButtonAction('move')}>
{ LocalizeText('infostand.button.move') }
</button> }
{ canRotate &&
<button type="button" className="btn btn-sm btn-secondary ms-1" onClick={event => processButtonAction('rotate')}>
<i className="fas fa-sync-alt me-1"></i>
<button type="button" className="btn btn-sm btn-dark ms-1" onClick={event => processButtonAction('rotate')}>
{ LocalizeText('infostand.button.rotate') }
</button> }
{ canUse &&
<button type="button" className="btn btn-sm btn-success ms-1" onClick={event => processButtonAction('use')}>
<i className="fas fa-mouse me-1"></i>
{LocalizeText('infostand.button.use')}
<button type="button" className="btn btn-sm btn-dark ms-1" onClick={event => processButtonAction('use')}>
{ LocalizeText('infostand.button.use') }
</button>}
{ (pickupMode !== PICKUP_MODE_NONE) &&
<button type="button" className="btn btn-sm btn-danger ms-1" onClick={event => processButtonAction('pickup')}>
<i className={ "me-1 " + (pickupMode === PICKUP_MODE_EJECT ? "fas fa-eject" : "fas fa-box-open") }></i>
<button type="button" className="btn btn-sm btn-dark ms-1" onClick={event => processButtonAction('pickup')}>
{ LocalizeText((pickupMode === PICKUP_MODE_EJECT) ? 'infostand.button.eject' : 'infostand.button.pickup') }
</button> }
{ ((furniSettingsKeys.length > 0 && furniSettingsValues.length > 0) && (furniSettingsKeys.length === furniSettingsValues.length)) &&
<button className="btn btn-sm btn-success ms-1" onClick={ () => processButtonAction('save_branding_configuration') }>
<i className="fas fa-save me-1"></i>
<button className="btn btn-sm btn-dark ms-1" onClick={ () => processButtonAction('save_branding_configuration') }>
{ LocalizeText('save') }
</button> }
</div>

View File

@ -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<InfoStandWidgetPetViewProps> = props =>
@ -9,54 +10,45 @@ export const InfoStandWidgetPetView: FC<InfoStandWidgetPetViewProps> = props =>
if(!petData) return null;
return (<>
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center">
<div className="small text-wrap">
{ petData.name }<br />
{ LocalizeText('pet.breed.' + petData.petType + '.' + petData.petBreed) }</div>
<i className="fas fa-times cursor-pointer" onClick={ close }></i>
return (
<InfoStandBaseView headerText={ <>{ petData.name }<br />{ LocalizeText('pet.breed.' + petData.petType + '.' + petData.petBreed) }</> } onCloseClick={ close }>
<div className="d-flex">
<div className="body-image pet w-100">
<PetImageView typeId={ petData.petType } paletteId={ petData.petBreed } color={ petData.petFigure.color } posture={ petData.posture } direction={ 4 } />
</div>
<hr className="m-0 my-1" />
<div className="d-flex">
<div className="body-image pet w-100">
<PetImageView typeId={ petData.petType } paletteId={ petData.petBreed } color={ petData.petFigure.color } posture={ petData.posture } direction={ 4 } />
</div>
<div className="w-100 d-flex flex-column align-items-center">
<div className="small text-center mb-1">{ LocalizeText('pet.level', ['level', 'maxlevel'], [petData.level.toString(), petData.maximumLevel.toString()]) }</div>
<div className="text-center mb-1 w-100">
<div className="small text-wrap mb-1">{ LocalizeText('infostand.pet.text.happiness') }</div>
<div className="bg-light-dark rounded position-relative overflow-hidden">
<div className="d-flex justify-content-center align-items-center w-100 h-100 position-absolute small top-0">{ petData.happyness + '/' + petData.maximumHappyness }</div>
<div className="bg-info rounded pet-stats" style={{ width: (petData.happyness / petData.maximumHappyness) * 100 + '%' }} />
</div>
</div>
<div className="text-center mb-1 w-100">
<div className="small text-wrap mb-1">{ LocalizeText('infostand.pet.text.experience') }</div>
<div className="bg-light-dark rounded position-relative overflow-hidden">
<div className="d-flex justify-content-center align-items-center w-100 h-100 position-absolute small top-0">{ petData.experience + '/' + petData.levelExperienceGoal }</div>
<div className="small bg-purple rounded pet-stats" style={{ width: ((petData.experience / petData.levelExperienceGoal) * 100 + '%') }} />
</div>
</div>
<div className="text-center w-100">
<div className="small text-wrap mb-1">{ LocalizeText('infostand.pet.text.energy') }</div>
<div className="bg-light-dark rounded position-relative overflow-hidden">
<div className="d-flex justify-content-center align-items-center w-100 h-100 position-absolute small top-0">{ petData.energy + '/' + petData.maximumEnergy }</div>
<div className="small bg-success rounded pet-stats" style={{ width: (petData.energy/petData.maximumEnergy)*100 +'%' }}></div>
</div>
<div className="w-100 d-flex flex-column align-items-center">
<div className="small text-center mb-1">{ LocalizeText('pet.level', ['level', 'maxlevel'], [petData.level.toString(), petData.maximumLevel.toString()]) }</div>
<div className="text-center mb-1 w-100">
<div className="small text-wrap mb-1">{ LocalizeText('infostand.pet.text.happiness') }</div>
<div className="bg-light-dark rounded position-relative overflow-hidden">
<div className="d-flex justify-content-center align-items-center w-100 h-100 position-absolute small top-0">{ petData.happyness + '/' + petData.maximumHappyness }</div>
<div className="bg-info rounded pet-stats" style={{ width: (petData.happyness / petData.maximumHappyness) * 100 + '%' }} />
</div>
</div>
<div className="text-center mb-1 w-100">
<div className="small text-wrap mb-1">{ LocalizeText('infostand.pet.text.experience') }</div>
<div className="bg-light-dark rounded position-relative overflow-hidden">
<div className="d-flex justify-content-center align-items-center w-100 h-100 position-absolute small top-0">{ petData.experience + '/' + petData.levelExperienceGoal }</div>
<div className="small bg-purple rounded pet-stats" style={{ width: ((petData.experience / petData.levelExperienceGoal) * 100 + '%') }} />
</div>
</div>
<div className="text-center w-100">
<div className="small text-wrap mb-1">{ LocalizeText('infostand.pet.text.energy') }</div>
<div className="bg-light-dark rounded position-relative overflow-hidden">
<div className="d-flex justify-content-center align-items-center w-100 h-100 position-absolute small top-0">{ petData.energy + '/' + petData.maximumEnergy }</div>
<div className="small bg-success rounded pet-stats" style={{ width: (petData.energy/petData.maximumEnergy)*100 +'%' }}></div>
</div>
</div>
</div>
<hr className="m-0 my-1" />
<div className="small text-wrap">{ LocalizeText('infostand.text.petrespect', ['count'], [petData.respect.toString()]) }</div>
<div className="small text-wrap">{ LocalizeText('pet.age', ['age'], [petData.age.toString()]) }</div>
<hr className="m-0 my-1" />
<div className="d-flex align-items-center">
<i className="icon icon-user-profile me-1 cursor-pointer" />
<div className="small text-wrap">{ LocalizeText('infostand.text.petowner', ['name'], [petData.ownerName]) }</div>
</div>
</div>
</div>
</>);
<hr className="m-0 my-1" />
<div className="small text-wrap">{ LocalizeText('infostand.text.petrespect', ['count'], [petData.respect.toString()]) }</div>
<div className="small text-wrap">{ LocalizeText('pet.age', ['age'], [petData.age.toString()]) }</div>
<hr className="m-0 my-1" />
<div className="d-flex align-items-center">
<i className="icon icon-user-profile me-1 cursor-pointer" />
<div className="small text-wrap">{ LocalizeText('infostand.text.petowner', ['name'], [petData.ownerName]) }</div>
</div>
</InfoStandBaseView>
);
}

View File

@ -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<InfoStandWidgetRentableBotViewProps> = props =>
@ -29,40 +30,33 @@ export const InfoStandWidgetRentableBotView: FC<InfoStandWidgetRentableBotViewPr
return (
<>
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center">
<div className="small text-wrap">{ rentableBotData.name }</div>
<i className="fas fa-times cursor-pointer" onClick={ close }></i>
<InfoStandBaseView headerText={ rentableBotData.name } onCloseClick={ close }>
<div className="d-flex">
<div className="body-image bot w-100">
<AvatarImageView figure={ rentableBotData.figure } direction={ 4 } />
</div>
<hr className="m-0 my-1" />
<div className="d-flex">
<div className="body-image bot w-100">
<AvatarImageView figure={ rentableBotData.figure } direction={ 4 } />
</div>
<div className="w-100 d-flex justify-content-center align-items-center">
{ (rentableBotData.badges.length > 0) && rentableBotData.badges.map((result, index) =>
{
return <BadgeImageView key={ index } badgeCode={ result } />;
}) }
</div>
<div className="w-100 d-flex justify-content-center align-items-center">
{ (rentableBotData.badges.length > 0) && rentableBotData.badges.map((result, index) =>
{
return <BadgeImageView key={ index } badgeCode={ result } />;
}) }
</div>
<hr className="m-0 my-1" />
<div className="motto-content small">{ rentableBotData.motto }</div>
<hr className="m-0 my-1" />
<div className="d-flex align-items-center">
<i className="icon icon-user-profile me-1 cursor-pointer" />
<div className="small text-wrap">{ LocalizeText('infostand.text.botowner', [ 'name' ], [ rentableBotData.ownerName ]) }</div>
</div>
{ (rentableBotData.carryItem > 0) &&
<>
<hr className="m-0 my-1"/>
<div className="small text-wrap">
{ LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + rentableBotData.carryItem) ]) }
</div>
</> }
</div>
</div>
<hr className="m-0 my-1" />
<div className="motto-content small">{ rentableBotData.motto }</div>
<hr className="m-0 my-1" />
<div className="d-flex align-items-center">
<i className="icon icon-user-profile me-1 cursor-pointer" />
<div className="small text-wrap">{ LocalizeText('infostand.text.botowner', [ 'name' ], [ rentableBotData.ownerName ]) }</div>
</div>
{ (rentableBotData.carryItem > 0) &&
<>
<hr className="m-0 my-1"/>
<div className="small text-wrap">
{ LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + rentableBotData.carryItem) ]) }
</div>
</> }
</InfoStandBaseView>
{ canPickup &&
<div className="button-container mt-2">
<button type="button" className="btn btn-sm btn-danger ms-1" onClick={ pickupBot }>

View File

@ -60,7 +60,7 @@ export const InfoStandWidgetUserView: FC<InfoStandWidgetUserViewProps> = props =
if(!userData) return null;
return (
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="d-flex flex-column nitro-card nitro-infostand rounded">
<div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center">
<div className="small text-wrap">{ userData.name }</div>

View File

@ -10,7 +10,6 @@
height: 100%;
pointer-events: all;
background: rgba($dark,.95);
border-top: 2px solid lighten($dark,8.3);
box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4);
#toolbar-chat-input-container {

View File

@ -61,8 +61,8 @@ export const ToolbarView: FC<ToolbarViewProps> = props =>
<TransitionAnimation type={ TransitionAnimationTypes.FADE_IN } inProp={ isMeExpanded } timeout={ 300 }>
<ToolbarMeView setMeExpanded={ setMeExpanded } handleToolbarItemClick={ handleToolbarItemClick } />
</TransitionAnimation>
<div className="d-flex justify-content-between nitro-toolbar py-1 px-3">
<div className="d-flex toolbar-left-side">
<div className="d-flex justify-content-between align-items-center nitro-toolbar py-1 px-3">
<div className="d-flex align-items-center toolbar-left-side">
<div className="navigation-items navigation-avatar pe-1 me-2">
<div className="navigation-item">
<div className={ 'toolbar-avatar ' + (isMeExpanded ? 'active ' : '') } onClick={ event => setMeExpanded(!isMeExpanded) }>