This commit is contained in:
Layne 2021-06-22 03:08:49 -04:00
commit 9110315621
18 changed files with 446 additions and 512 deletions

View File

@ -1,70 +0,0 @@
import { RoomAdsUpdateComposer, RoomObjectOperationType, SecurityLevel } from 'nitro-renderer';
import { GetConnection } from '../GetConnection';
import { GetRoomEngine } from '../room';
import { GetSessionDataManager } from './GetSessionDataManager';
export class FurniAction
{
public static ROTATE: string = 'FA_ROTATE';
public static MOVE: string = 'FA_MOVE';
public static PICKUP: string = 'FA_PICKUP';
public static EJECT: string = 'FA_EJECT';
public static USE: string = 'FA_USE';
public static OPEN_WELCOME_GIFT: string = 'FA_OPEN_WELCOME_GIFT';
public static SAVE_STUFF_DATA: string = 'FA_SAVE_STUFF_DATA';
}
export function ProcessFurniAction(type: string, objectId: number, category: number, offerId = -1, objectData: string = null): void
{
switch(type)
{
case FurniAction.ROTATE:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE);
return;
case FurniAction.MOVE:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_MOVE);
return;
case FurniAction.PICKUP:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_PICKUP);
return;
case FurniAction.EJECT:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_EJECT);
return;
case FurniAction.USE:
GetRoomEngine().useRoomObject(objectId, category);
return;
case FurniAction.SAVE_STUFF_DATA: {
if(objectData)
{
const mapData = new Map<string, string>();
const dataParts = objectData.split('\t');
if(dataParts)
{
for(const part of dataParts)
{
const partPieces = part.split('=', 2);
if(partPieces && partPieces.length === 2)
{
const piece1 = partPieces[0];
const piece2 = partPieces[1];
mapData.set(piece1, piece2);
}
}
}
GetRoomEngine().processRoomObjectWallOperation(objectId, category, RoomObjectOperationType.OBJECT_SAVE_STUFF_DATA, mapData);
if(GetSessionDataManager().hasSecurity(SecurityLevel.MODERATOR))
{
GetConnection().send(new RoomAdsUpdateComposer(this._widget.furniData.id, mapData));
}
mapData.clear();
}
return;
}
}
}

View File

@ -1,194 +0,0 @@
import { RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUserData } from 'nitro-renderer';
import { GetConnection } from '../GetConnection';
import { GetRoomSession } from './GetRoomSession';
import { GetSessionDataManager } from './GetSessionDataManager';
export class UserAction
{
public static WHISPER_USER: string = 'UA_WHISPER_USER';
public static IGNORE_USER: string = 'UA_IGNORE_USER';
public static IGNORE_USER_BUBBLE: string = 'UA_IGNORE_USER_BUBBLE';
public static UNIGNORE_USER: string = 'UA_UNIGNORE_USER';
public static KICK_USER: string = 'UA_KICK_USER';
public static BAN_USER_HOUR: string = 'UA_BAN_USER_HOUR';
public static BAN_USER_DAY: string = 'UA_BAN_USER_DAY';
public static BAN_USER_PERM: string = 'UA_BAN_USER_PERM';
public static MUTE_USER_2MIN: string = 'UA_MUTE_USER_2MIN';
public static MUTE_USER_5MIN: string = 'UA_MUTE_USER_5MIN';
public static MUTE_USER_10MIN: string = 'UA_MUTE_USER_10MIN';
public static SEND_FRIEND_REQUEST: string = 'UA_SEND_FRIEND_REQUEST';
public static RESPECT_USER: string = 'UA_RESPECT_USER';
public static GIVE_RIGHTS: string = 'UA_GIVE_RIGHTS';
public static TAKE_RIGHTS: string = 'UA_TAKE_RIGHTS';
public static START_TRADING: string = 'UA_START_TRADING';
public static OPEN_HOME_PAGE: string = 'UA_OPEN_HOME_PAGE';
public static REPORT: string = 'UA_REPORT';
public static PICKUP_PET: string = 'UA_PICKUP_PET';
public static MOUNT_PET: string = 'UA_MOUNT_PET';
public static TOGGLE_PET_RIDING_PERMISSION: string = 'UA_TOGGLE_PET_RIDING_PERMISSION';
public static TOGGLE_PET_BREEDING_PERMISSION: string = 'UA_TOGGLE_PET_BREEDING_PERMISSION';
public static DISMOUNT_PET: string = 'UA_DISMOUNT_PET';
public static SADDLE_OFF: string = 'UA_SADDLE_OFF';
public static TRAIN_PET: string = 'UA_TRAIN_PET';
public static RESPECT_PET: string = 'UA_ RESPECT_PET';
public static TREAT_PET: string = 'UA_TREAT_PET';
public static REQUEST_PET_UPDATE: string = 'UA_REQUEST_PET_UPDATE';
public static START_NAME_CHANGE: string = 'UA_START_NAME_CHANGE';
public static PASS_CARRY_ITEM: string = 'UA_PASS_CARRY_ITEM';
public static DROP_CARRY_ITEM: string = 'UA_DROP_CARRY_ITEM';
public static GIVE_CARRY_ITEM_TO_PET: string = 'UA_GIVE_CARRY_ITEM_TO_PET';
public static GIVE_WATER_TO_PET: string = 'UA_GIVE_WATER_TO_PET';
public static GIVE_LIGHT_TO_PET: string = 'UA_GIVE_LIGHT_TO_PET';
public static REQUEST_BREED_PET: string = 'UA_REQUEST_BREED_PET';
public static HARVEST_PET: string = 'UA_HARVEST_PET';
public static REVIVE_PET: string = 'UA_REVIVE_PET';
public static COMPOST_PLANT: string = 'UA_COMPOST_PLANT';
public static GET_BOT_INFO: string = 'UA_GET_BOT_INFO';
public static REPORT_CFH_OTHER: string = 'UA_REPORT_CFH_OTHER';
public static AMBASSADOR_ALERT_USER: string = 'UA_AMBASSADOR_ALERT_USER';
public static AMBASSADOR_KICK_USER: string = 'UA_AMBASSADOR_KICK_USER';
public static AMBASSADOR_MUTE_USER_2MIN: string = 'UA_AMBASSADOR_MUTE_2MIN';
public static AMBASSADOR_MUTE_USER_10MIN: string = 'UA_AMBASSADOR_MUTE_10MIN';
public static AMBASSADOR_MUTE_USER_60MIN: string = 'UA_AMBASSADOR_MUTE_60MIN';
public static AMBASSADOR_MUTE_USER_18HOUR: string = 'UA_AMBASSADOR_MUTE_18HOUR';
}
export function ProcessUserAction(userId: number, type: string): void
{
let userData: RoomUserData = null;
const petMessages = [
UserAction.REQUEST_PET_UPDATE,
UserAction.RESPECT_PET,
UserAction.PICKUP_PET,
UserAction.MOUNT_PET,
UserAction.TOGGLE_PET_RIDING_PERMISSION,
UserAction.TOGGLE_PET_BREEDING_PERMISSION,
UserAction.DISMOUNT_PET,
UserAction.SADDLE_OFF,
UserAction.GIVE_CARRY_ITEM_TO_PET,
UserAction.GIVE_WATER_TO_PET,
UserAction.GIVE_LIGHT_TO_PET,
UserAction.TREAT_PET
];
if(petMessages.indexOf(type) >= 0)
{
userData = GetRoomSession().userDataManager.getPetData(userId);
}
else
{
userData = GetRoomSession().userDataManager.getUserData(userId);
}
if(!userData) return
switch(type)
{
case UserAction.RESPECT_USER:
GetSessionDataManager().giveRespect(userId);
return;
case UserAction.RESPECT_PET:
GetSessionDataManager().givePetRespect(userId);
return;
// case UserAction.WHISPER_USER:
// this._container.events.dispatchEvent(new RoomWidgetChatInputContentUpdateEvent(RoomWidgetChatInputContentUpdateEvent.WHISPER, userData.name));
// return;
case UserAction.IGNORE_USER:
GetSessionDataManager().ignoreUser(userData.name);
return;
case UserAction.UNIGNORE_USER:
GetSessionDataManager().unignoreUser(userData.name);
return;
case UserAction.KICK_USER:
GetRoomSession().sendKickMessage(userId);
return;
case UserAction.BAN_USER_DAY:
case UserAction.BAN_USER_HOUR:
case UserAction.BAN_USER_PERM:
GetRoomSession().sendBanMessage(userId, type);
return;
case UserAction.MUTE_USER_2MIN:
GetRoomSession().sendMuteMessage(userId, 2);
return;
case UserAction.MUTE_USER_5MIN:
GetRoomSession().sendMuteMessage(userId, 5);
return;
case UserAction.MUTE_USER_10MIN:
GetRoomSession().sendMuteMessage(userId, 10);
return;
case UserAction.GIVE_RIGHTS:
GetRoomSession().sendGiveRightsMessage(userId);
return;
case UserAction.TAKE_RIGHTS:
GetRoomSession().sendTakeRightsMessage(userId);
return;
// case UserAction.START_TRADING:
// if(userData) this._widget.inventoryTrading.startTrade(userData.roomIndex, userData.name);
// return;
// case UserAction.OPEN_HOME_PAGE:
// GetSessionDataManager()._Str_21275(userId, _local_3.name);
// return;
// case UserAction.PICKUP_PET:
// GetRoomSession()._Str_13781(_local_2);
// return;
// case UserAction.MOUNT_PET:
// GetRoomSession()._Str_21066(_local_2);
// return;
// case UserAction.TOGGLE_PET_RIDING_PERMISSION:
// GetRoomSession()._Str_21025(_local_2);
// return;
// case UserAction.TOGGLE_PET_BREEDING_PERMISSION:
// GetRoomSession()._Str_21562(_local_2);
// return;
// case UserAction.DISMOUNT_PET:
// GetRoomSession()._Str_19075(_local_2);
// return;
// case UserAction.SADDLE_OFF:
// GetRoomSession()._Str_21635(_local_2);
// return;
case UserAction.PASS_CARRY_ITEM:
GetConnection().send(new RoomUnitGiveHandItemComposer(userId));
return;
// case UserAction.GIVE_CARRY_ITEM_TO_PET:
// GetConnection().send(new RoomUnitGiveHandItemPetComposer(userId));
// return;
// case UserAction.GIVE_WATER_TO_PET:
// GetConnection().send(new _Str_7251(_local_2, PetSupplementEnum._Str_9473));
// return;
// case UserAction.GIVE_LIGHT_TO_PET:
// GetConnection().send(new _Str_7251(_local_2, PetSupplementEnum._Str_8421));
// return;
// case UserAction.TREAT_PET:
// GetConnection().send(new _Str_8184(_local_2));
// return;
case UserAction.DROP_CARRY_ITEM:
GetConnection().send(new RoomUnitDropHandItemComposer());
return;
case UserAction.REQUEST_PET_UPDATE:
GetRoomSession().userDataManager.requestPetInfo(userId);
return;
case UserAction.REPORT:
return;
case UserAction.REPORT_CFH_OTHER:
return;
case UserAction.AMBASSADOR_ALERT_USER:
GetRoomSession().sendAmbassadorAlertMessage(userId);
return;
case UserAction.AMBASSADOR_KICK_USER:
GetRoomSession().sendKickMessage(userId);
return;
case UserAction.AMBASSADOR_MUTE_USER_2MIN:
GetRoomSession().sendMuteMessage(userId, 2);
return;
case UserAction.AMBASSADOR_MUTE_USER_10MIN:
GetRoomSession().sendMuteMessage(userId, 10);
return;
case UserAction.AMBASSADOR_MUTE_USER_60MIN:
GetRoomSession().sendMuteMessage(userId, 60);
return;
case UserAction.AMBASSADOR_MUTE_USER_18HOUR:
GetRoomSession().sendMuteMessage(userId, 1080);
return;
}
}

View File

@ -5,7 +5,5 @@ export * from './GetRoomSession';
export * from './GetRoomSessionManager'; export * from './GetRoomSessionManager';
export * from './GetSessionDataManager'; export * from './GetSessionDataManager';
export * from './IsOwnerOfFurniture'; export * from './IsOwnerOfFurniture';
export * from './ProcessFurniAction';
export * from './ProcessUserAction';
export * from './SendChatTypingMessage'; export * from './SendChatTypingMessage';
export * from './StartRoomSession'; export * from './StartRoomSession';

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 257 B

View File

@ -526,9 +526,9 @@ $blockquote-footer-color: $gray-600 !default;
$blockquote-footer-font-size: $small-font-size !default; $blockquote-footer-font-size: $small-font-size !default;
$hr-margin-y: $spacer !default; $hr-margin-y: $spacer !default;
$hr-color: inherit !default; $hr-color: rgba($white, 0.1) !default;
$hr-height: $border-width !default; $hr-height: $border-width !default;
$hr-opacity: .25 !default; $hr-opacity: 0.5 !default;
$legend-margin-bottom: .5rem !default; $legend-margin-bottom: .5rem !default;
$legend-font-size: 1.5rem !default; $legend-font-size: 1.5rem !default;

View File

@ -458,6 +458,16 @@ i {
height: 14px; height: 14px;
} }
&.icon-user-profile {
background: url('../images/icons/user-profile.png');
width: 13px;
height: 11px;
&:hover {
background: url('../images/icons/user-profile-hover.png');
}
}
&.spin { &.spin {
animation: rotating 1s linear infinite; animation: rotating 1s linear infinite;
} }

View File

@ -14,7 +14,7 @@ export const NitroCardHeaderView: FC<NitroCardHeaderViewProps> = props =>
<div className="h4 m-0 text-white text-shadow">{ headerText }</div> <div className="h4 m-0 text-white text-shadow">{ headerText }</div>
</div> </div>
<div className="nitro-card-close-parent"> <div className="nitro-card-close-parent">
<div className="nitro-card-close" onClick={ onCloseClick }> <div className="nitro-card-close cursor-pointer" onMouseDown={ event => event.stopPropagation() } onClick={ onCloseClick }>
<i className="fas fa-times"></i> <i className="fas fa-times"></i>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetType, RoomControllerLevel, RoomModerationParser, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomTradingLevelEnum, RoomUserData, RoomWidgetEnumItemExtradataParameter, Vector3d } from 'nitro-renderer'; import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationParser, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer';
import { GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; import { GetConnection, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api';
import { LocalizeText } from '../../../utils/LocalizeText'; import { LocalizeText } from '../../../utils/LocalizeText';
import { RoomWidgetObjectNameEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events'; import { RoomWidgetObjectNameEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events';
import { RoomWidgetChangeMottoMessage, RoomWidgetFurniActionMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages'; import { RoomWidgetChangeMottoMessage, RoomWidgetFurniActionMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages';
@ -14,7 +14,9 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
case RoomSessionPetInfoUpdateEvent.PET_INFO: case RoomSessionPetInfoUpdateEvent.PET_INFO:
this.processPetInfoEvent((event as RoomSessionPetInfoUpdateEvent)); this.processPetInfoEvent((event as RoomSessionPetInfoUpdateEvent));
return; return;
case RoomSessionUserBadgesEvent.RSUBE_BADGES:
this.eventDispatcher.dispatchEvent(event);
return;
} }
} }
@ -68,6 +70,162 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
return this.processObjectNameMessage((message as RoomWidgetRoomObjectMessage)); return this.processObjectNameMessage((message as RoomWidgetRoomObjectMessage));
case RoomWidgetRoomObjectMessage.GET_OBJECT_INFO: case RoomWidgetRoomObjectMessage.GET_OBJECT_INFO:
return this.processObjectInfoMessage((message as RoomWidgetRoomObjectMessage)); return this.processObjectInfoMessage((message as RoomWidgetRoomObjectMessage));
case RoomWidgetUserActionMessage.SEND_FRIEND_REQUEST:
//this._container.friendService.sendFriendRequest(userId, userData.name);
break;
case RoomWidgetUserActionMessage.RESPECT_USER:
GetSessionDataManager().giveRespect(userId);
break;
case RoomWidgetUserActionMessage.RESPECT_PET:
GetSessionDataManager().givePetRespect(userId);
break;
case RoomWidgetUserActionMessage.WHISPER_USER:
//this.eventDispatcher.dispatchEvent(new RoomWidgetChatInputContentUpdateEvent(RoomWidgetChatInputContentUpdateEvent.WHISPER, userData.name));
break;
case RoomWidgetUserActionMessage.IGNORE_USER:
GetSessionDataManager().ignoreUser(userData.name);
break;
case RoomWidgetUserActionMessage.UNIGNORE_USER:
GetSessionDataManager().unignoreUser(userData.name);
break;
case RoomWidgetUserActionMessage.KICK_USER:
this.roomSession.sendKickMessage((message as RoomWidgetUserActionMessage).userId);
break;
case RoomWidgetUserActionMessage.BAN_USER_DAY:
case RoomWidgetUserActionMessage.BAN_USER_HOUR:
case RoomWidgetUserActionMessage.BAN_USER_PERM:
this.roomSession.sendBanMessage((message as RoomWidgetUserActionMessage).userId, message.type);
break;
case RoomWidgetUserActionMessage.MUTE_USER_2MIN:
this.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 2);
break;
case RoomWidgetUserActionMessage.MUTE_USER_5MIN:
this.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 5);
break;
case RoomWidgetUserActionMessage.MUTE_USER_10MIN:
this.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 10);
break;
case RoomWidgetUserActionMessage.GIVE_RIGHTS:
this.roomSession.sendGiveRightsMessage((message as RoomWidgetUserActionMessage).userId);
break;
case RoomWidgetUserActionMessage.TAKE_RIGHTS:
this.roomSession.sendTakeRightsMessage((message as RoomWidgetUserActionMessage).userId);
break;
case RoomWidgetUserActionMessage.START_TRADING:
//if(userData) this._widget.inventoryTrading.startTrade(userData.roomIndex, userData.name);
break;
// case RoomWidgetUserActionMessage.RWUAM_OPEN_HOME_PAGE:
// this._container.sessionDataManager._Str_21275((message as RoomWidgetUserActionMessage).userId, _local_3.name);
// break;
// case RoomWidgetUserActionMessage.RWUAM_PICKUP_PET:
// this._container.roomSession._Str_13781(_local_2);
// break;
// case RoomWidgetUserActionMessage.RWUAM_MOUNT_PET:
// this._container.roomSession._Str_21066(_local_2);
// break;
// case RoomWidgetUserActionMessage.RWUAM_TOGGLE_PET_RIDING_PERMISSION:
// this._container.roomSession._Str_21025(_local_2);
// break;
// case RoomWidgetUserActionMessage.RWUAM_TOGGLE_PET_BREEDING_PERMISSION:
// this._container.roomSession._Str_21562(_local_2);
// break;
// case RoomWidgetUserActionMessage.RWUAM_DISMOUNT_PET:
// this._container.roomSession._Str_19075(_local_2);
// break;
// case RoomWidgetUserActionMessage.RWUAM_SADDLE_OFF:
// this._container.roomSession._Str_21635(_local_2);
// break;
case RoomWidgetUserActionMessage.PASS_CARRY_ITEM:
GetConnection().send(new RoomUnitGiveHandItemComposer(userId));
break;
case RoomWidgetUserActionMessage.GIVE_CARRY_ITEM_TO_PET:
GetConnection().send(new RoomUnitGiveHandItemPetComposer(userId));
break;
case RoomWidgetUserActionMessage.GIVE_WATER_TO_PET:
//this._container.connection.send(new _Str_7251(_local_2, PetSupplementEnum._Str_9473));
break;
case RoomWidgetUserActionMessage.GIVE_LIGHT_TO_PET:
//this._container.connection.send(new _Str_7251(_local_2, PetSupplementEnum._Str_8421));
break;
case RoomWidgetUserActionMessage.TREAT_PET:
//this._container.connection.send(new _Str_8184(_local_2));
break;
case RoomWidgetUserActionMessage.DROP_CARRY_ITEM:
GetConnection().send(new RoomUnitDropHandItemComposer());
break;
case RoomWidgetUserActionMessage.REQUEST_PET_UPDATE:
this.roomSession.userDataManager.requestPetInfo(userId);
return;
case RoomWidgetUserActionMessage.REPORT:
return;
case RoomWidgetUserActionMessage.REPORT_CFH_OTHER:
return;
case RoomWidgetUserActionMessage.AMBASSADOR_ALERT_USER:
this.roomSession.sendAmbassadorAlertMessage(userId);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_KICK_USER:
this.roomSession.sendKickMessage(userId);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_MUTE_USER_2MIN:
this.roomSession.sendMuteMessage(userId, 2);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_MUTE_USER_10MIN:
this.roomSession.sendMuteMessage(userId, 10);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_MUTE_USER_60MIN:
this.roomSession.sendMuteMessage(userId, 60);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_MUTE_USER_18HOUR:
this.roomSession.sendMuteMessage(userId, 1080);
return;
case RoomWidgetFurniActionMessage.ROTATE:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE);
return;
case RoomWidgetFurniActionMessage.MOVE:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_MOVE);
return;
case RoomWidgetFurniActionMessage.PICKUP:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_PICKUP);
return;
case RoomWidgetFurniActionMessage.EJECT:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_EJECT);
return;
case RoomWidgetFurniActionMessage.USE:
GetRoomEngine().useRoomObject(objectId, category);
return;
case RoomWidgetFurniActionMessage.SAVE_STUFF_DATA: {
const furniMessage = (message as RoomWidgetFurniActionMessage);
if(!furniMessage.objectData) return;
const mapData = new Map<string, string>();
const dataParts = furniMessage.objectData.split('\t');
if(dataParts)
{
for(const part of dataParts)
{
const partPieces = part.split('=', 2);
if(partPieces && partPieces.length === 2)
{
const piece1 = partPieces[0];
const piece2 = partPieces[1];
mapData.set(piece1, piece2);
}
}
}
GetRoomEngine().processRoomObjectWallOperation(objectId, category, RoomObjectOperationType.OBJECT_SAVE_STUFF_DATA, mapData);
if(GetSessionDataManager().hasSecurity(SecurityLevel.MODERATOR)) GetConnection().send(new RoomAdsUpdateComposer(objectId, mapData));
return;
}
case RoomWidgetChangeMottoMessage.CHANGE_MOTTO:
this.roomSession.sendMottoMessage((message as RoomWidgetChangeMottoMessage).motto);
return;
} }
return null; return null;
@ -604,7 +762,8 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
public get eventTypes(): string[] public get eventTypes(): string[]
{ {
return [ return [
RoomSessionPetInfoUpdateEvent.PET_INFO RoomSessionPetInfoUpdateEvent.PET_INFO,
RoomSessionUserBadgesEvent.RSUBE_BADGES
]; ];
} }

View File

@ -6,9 +6,9 @@ export class RoomWidgetChangeMottoMessage extends RoomWidgetMessage
private _motto: string; private _motto: string;
constructor(type: string, motto: string) constructor(motto: string)
{ {
super(type); super(RoomWidgetChangeMottoMessage.CHANGE_MOTTO);
this._motto = motto; this._motto = motto;
} }

View File

@ -61,12 +61,12 @@ export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED: case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED:
if(prevValue instanceof RoomWidgetUpdateInfostandUserEvent || prevValue instanceof RoomWidgetUpdateInfostandRentableBotEvent) if(prevValue instanceof RoomWidgetUpdateInfostandUserEvent || prevValue instanceof RoomWidgetUpdateInfostandRentableBotEvent)
{ {
if(prevValue.webID === roomObjectEvent.id) return null; if(prevValue.roomIndex === roomObjectEvent.id) return null;
} }
else if(prevValue instanceof RoomWidgetUpdateInfostandPetEvent) else if(prevValue instanceof RoomWidgetUpdateInfostandPetEvent)
{ {
// room index if(prevValue.roomIndex === roomObjectEvent.id) return null;
} }
break; break;
} }
@ -102,9 +102,7 @@ export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
case RoomWidgetUpdateInfostandUserEvent.PEER: case RoomWidgetUpdateInfostandUserEvent.PEER:
case RoomWidgetUpdateInfostandUserEvent.BOT: case RoomWidgetUpdateInfostandUserEvent.BOT:
case RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT: { case RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT: {
const infostandEvent = (event as RoomWidgetUpdateInfostandFurniEvent); setInfoStandEvent((event as RoomWidgetUpdateInfostandFurniEvent));
setInfoStandEvent(infostandEvent);
return; return;
} }
default: default:

View File

@ -0,0 +1,18 @@
export class BotSkillsEnum
{
public static _Str_19584: number = 0;
public static DRESS_UP: number = 1;
public static SETUP_CHAT: number = 2;
public static RANDOM_WALK: number = 3;
public static DANCE: number = 4;
public static CHANGE_BOT_NAME: number = 5;
public static _Str_20280: number = 6;
public static _Str_18934: number = 7;
public static _Str_14917: number = 8;
public static CHANGE_BOT_MOTTO: number = 9;
public static NUX_TAKE_TOUR: number = 10;
public static NO_PICK_UP: number = 12;
public static NAVIGATOR_SEARCH: number = 14;
public static DONATE_TO_USER: number = 24;
public static DONATE_TO_ALL: number = 25;
}

View File

@ -7,14 +7,16 @@
.nitro-infostand { .nitro-infostand {
position: relative; position: relative;
min-width: 170px; min-width: 190px;
max-width: 170px; max-width: 190px;
z-index: $infostand-zindex; z-index: $infostand-zindex;
pointer-events: auto; pointer-events: auto;
box-shadow: inset 0 2px 0 rgba($white, .15), 0 1px 1px rgba($black, .1); box-shadow: inset 0 2px 0 rgba($white, .15), 0 1px 1px rgba($black, .1);
&.nitro-infostand-user { .form-control-sm {
max-width: 180px; height: 25px;
min-height: 25px;
padding: 0.1rem 0.25rem;
} }
.pet-image { .pet-image {

View File

@ -53,12 +53,12 @@ export const InfoStandWidgetView: FC<InfoStandWidgetViewProps> = props =>
case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED: case RoomWidgetRoomObjectUpdateEvent.USER_REMOVED:
if(prevValue instanceof RoomWidgetUpdateInfostandUserEvent || prevValue instanceof RoomWidgetUpdateInfostandRentableBotEvent) if(prevValue instanceof RoomWidgetUpdateInfostandUserEvent || prevValue instanceof RoomWidgetUpdateInfostandRentableBotEvent)
{ {
if(prevValue.webID === roomObjectEvent.id) return null; if(prevValue.roomIndex === roomObjectEvent.id) return null;
} }
else if(prevValue instanceof RoomWidgetUpdateInfostandPetEvent) else if(prevValue instanceof RoomWidgetUpdateInfostandPetEvent)
{ {
// room index if(prevValue.roomIndex === roomObjectEvent.id) return null;
} }
break; break;
} }
@ -73,11 +73,7 @@ export const InfoStandWidgetView: FC<InfoStandWidgetViewProps> = props =>
case RoomWidgetUpdateInfostandUserEvent.BOT: case RoomWidgetUpdateInfostandUserEvent.BOT:
case RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT: case RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT:
case RoomWidgetUpdateInfostandPetEvent.PET_INFO: { case RoomWidgetUpdateInfostandPetEvent.PET_INFO: {
const infostandEvent = (event as RoomWidgetUpdateInfostandEvent); setInfoStandEvent((event as RoomWidgetUpdateInfostandEvent));
console.log(infostandEvent);
setInfoStandEvent(infostandEvent);
return; return;
} }
default: default:

View File

@ -1,5 +1,4 @@
import { RoomControllerLevel } from 'nitro-renderer'; import { FC, useCallback } from 'react';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../../../avatar-image/AvatarImageView'; import { AvatarImageView } from '../../../../../avatar-image/AvatarImageView';
import { BadgeImageView } from '../../../../../badge-image/BadgeImageView'; import { BadgeImageView } from '../../../../../badge-image/BadgeImageView';
@ -9,17 +8,6 @@ export const InfoStandWidgetBotView: FC<InfoStandWidgetBotViewProps> = props =>
{ {
const { botData = null, close = null } = props; const { botData = null, close = null } = props;
const [ canPickup, setCanPickup ] = useState(false);
useEffect(() =>
{
setCanPickup(false);
if(botData.amIOwner || botData.amIAnyRoomController || botData.roomControllerLevel >= RoomControllerLevel.MODERATOR)
setCanPickup(true);
}, [ botData ]);
const processButtonAction = useCallback((action: string) => const processButtonAction = useCallback((action: string) =>
{ {
if(!action || (action === '')) return; if(!action || (action === '')) return;
@ -29,34 +17,34 @@ export const InfoStandWidgetBotView: FC<InfoStandWidgetBotViewProps> = props =>
if(!botData) return null; if(!botData) return null;
return ( return (
<> <div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded nitro-infostand-user">
<div className="container-fluid content-area"> <div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center"> <div className="d-flex justify-content-between align-items-center">
<div>{ botData.name }</div> <div className="small text-wrap">{ botData.name }</div>
<i className="fas fa-times cursor-pointer" onClick={ close }></i> <i className="fas fa-times cursor-pointer" onClick={ close }></i>
</div> </div>
<hr className="m-0 my-1"/> <hr className="m-0 my-1" />
<div className="d-flex"> <div className="d-flex">
<div className="body-image bot w-100"> <div className="body-image bot w-100">
<AvatarImageView figure={ botData.figure } direction={ 4 } /> <AvatarImageView figure={ botData.figure } direction={ 4 } />
</div> </div>
<div className="w-100 d-flex justify-content-center align-items-center"> <div className="w-100 d-flex justify-content-center align-items-center">
<BadgeImageView badgeCode="BOT" /> { (botData.badges.length > 0) && botData.badges.map((result, index) =>
{
return <BadgeImageView key={ index } badgeCode={ result } />;
}) }
</div> </div>
</div> </div>
<hr className="m-0 my-1"/> <hr className="m-0 my-1" />
<div className="bg-secondary rounded py-1 px-2 small"> <div className="motto-content small">{ botData.motto }</div>
<div className="motto-content">{ 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>
</div> </div>
</div>
{ canPickup && <div className="button-container mt-2">
<button type="button" className="btn btn-sm btn-danger ms-1" onClick={event => processButtonAction('pickup')}>
<i className="me-1 fas fa-eject"></i>
{LocalizeText('infostand.button.pickup')}
</button>
</div> }
</>
); );
} }

View File

@ -1,9 +1,10 @@
import { CrackableDataType, RoomControllerLevel, RoomWidgetEnumItemExtradataParameter, RoomWidgetFurniInfoUsagePolicyEnum, StringDataType } from 'nitro-renderer'; import { CrackableDataType, RoomControllerLevel, RoomWidgetEnumItemExtradataParameter, RoomWidgetFurniInfoUsagePolicyEnum, StringDataType } from 'nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react'; import { FC, useCallback, useEffect, useState } from 'react';
import { FurniAction, ProcessFurniAction } from '../../../../../../api';
import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { BadgeImageView } from '../../../../../badge-image/BadgeImageView'; import { BadgeImageView } from '../../../../../badge-image/BadgeImageView';
import { LimitedEditionCompactPlateView } from '../../../../../limited-edition/compact-plate/LimitedEditionCompactPlateView'; import { LimitedEditionCompactPlateView } from '../../../../../limited-edition/compact-plate/LimitedEditionCompactPlateView';
import { useRoomContext } from '../../../../context/RoomContext';
import { RoomWidgetFurniActionMessage } from '../../../../messages';
import { InfoStandWidgetFurniViewProps } from './InfoStandWidgetFurniView.types'; import { InfoStandWidgetFurniViewProps } from './InfoStandWidgetFurniView.types';
const PICKUP_MODE_NONE: number = 0; const PICKUP_MODE_NONE: number = 0;
@ -13,6 +14,7 @@ const PICKUP_MODE_FULL: number = 2;
export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props => export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props =>
{ {
const { furniData = null, close = null } = props; const { furniData = null, close = null } = props;
const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
const [ pickupMode, setPickupMode ] = useState(0); const [ pickupMode, setPickupMode ] = useState(0);
const [ canMove, setCanMove ] = useState(false); const [ canMove, setCanMove ] = useState(false);
@ -27,29 +29,28 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
useEffect(() => useEffect(() =>
{ {
setPickupMode(0); let pickupMode = PICKUP_MODE_NONE;
setCanMove(false); let canMove = false;
setCanRotate(false); let canRotate = false;
setCanUse(false); let canUse = false;
setFurniSettingsKeys([]); let furniSettings: string[] = [];
setFurniSettingsValues([]); let furniValues: string[] = [];
setIsCrackable(false); let isCrackable = false;
setCrackableHits(0); let crackableHits = 0;
setCrackableTarget(0); let crackableTarget = 0;
setGodMode(false); let godMode = false;
const isValidController = (furniData.roomControllerLevel >= RoomControllerLevel.GUEST); const isValidController = (furniData.roomControllerLevel >= RoomControllerLevel.GUEST);
if(isValidController || furniData.isOwner || furniData.isRoomOwner || furniData.isAnyRoomController) if(isValidController || furniData.isOwner || furniData.isRoomOwner || furniData.isAnyRoomController)
{ {
setCanMove(true); canMove = true;
setCanRotate(!furniData.isWallItem); canRotate = !furniData.isWallItem;
if(furniData.roomControllerLevel >= RoomControllerLevel.MODERATOR) setGodMode(true); if(furniData.roomControllerLevel >= RoomControllerLevel.MODERATOR) godMode = true;
} }
else
if((((furniData.usagePolicy === RoomWidgetFurniInfoUsagePolicyEnum.EVERYBODY) || ((furniData.usagePolicy === RoomWidgetFurniInfoUsagePolicyEnum.CONTROLLER) && isValidController)) || ((furniData.extraParam === RoomWidgetEnumItemExtradataParameter.JUKEBOX) && isValidController)) || ((furniData.extraParam === RoomWidgetEnumItemExtradataParameter.USABLE_PRODUCT) && isValidController)) setCanUse(true); if((((furniData.usagePolicy === RoomWidgetFurniInfoUsagePolicyEnum.EVERYBODY) || ((furniData.usagePolicy === RoomWidgetFurniInfoUsagePolicyEnum.CONTROLLER) && isValidController)) || ((furniData.extraParam === RoomWidgetEnumItemExtradataParameter.JUKEBOX) && isValidController)) || ((furniData.extraParam === RoomWidgetEnumItemExtradataParameter.USABLE_PRODUCT) && isValidController)) canUse = true;
if(furniData.extraParam) if(furniData.extraParam)
{ {
@ -57,10 +58,10 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
{ {
const stuffData = (furniData.stuffData as CrackableDataType); const stuffData = (furniData.stuffData as CrackableDataType);
setCanUse(true); canUse = true;
setIsCrackable(true); isCrackable = true;
setCrackableHits(stuffData.hits); crackableHits = stuffData.hits;
setCrackableTarget(stuffData.target); crackableTarget = stuffData.target;
} }
if(godMode) if(godMode)
@ -71,39 +72,36 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
{ {
const parts = extraParam.split('\t'); const parts = extraParam.split('\t');
let keys: string[] = [];
let values: string[] = [];
for(const part of parts) for(const part of parts)
{ {
const value = part.split('='); const value = part.split('=');
if(value && (value.length === 2)) if(value && (value.length === 2))
{ {
keys.push(value[0]); furniSettings.push(value[0]);
values.push(value[1]); furniValues.push(value[1]);
}
}
}
} }
} }
setFurniSettingsKeys(keys); if(furniData.isOwner || furniData.isAnyRoomController) pickupMode = PICKUP_MODE_FULL;
setFurniSettingsValues(values);
}
}
}
setPickupMode(PICKUP_MODE_NONE); else if(furniData.isRoomOwner || (furniData.roomControllerLevel >= RoomControllerLevel.GUILD_ADMIN)) pickupMode = PICKUP_MODE_EJECT;
if(furniData.isOwner || furniData.isAnyRoomController) if(furniData.isStickie) pickupMode = PICKUP_MODE_NONE;
{
setPickupMode(PICKUP_MODE_FULL);
}
else if(furniData.isRoomOwner || (furniData.roomControllerLevel >= RoomControllerLevel.GUILD_ADMIN)) setPickupMode(pickupMode);
{ setCanMove(canMove);
setPickupMode(PICKUP_MODE_EJECT); setCanRotate(canRotate);
} setCanUse(canUse);
setFurniSettingsKeys(furniSettings);
else if(furniData.isStickie) setPickupMode(PICKUP_MODE_NONE); setFurniSettingsValues(furniValues);
setIsCrackable(isCrackable);
setCrackableHits(crackableHits);
setCrackableTarget(crackableTarget);
setGodMode(godMode);
}, [ furniData ]); }, [ furniData ]);
const openFurniGroupInfo = useCallback(() => const openFurniGroupInfo = useCallback(() =>
@ -151,28 +149,28 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
switch(action) switch(action)
{ {
case 'move': case 'move':
messageType = FurniAction.MOVE; messageType = RoomWidgetFurniActionMessage.MOVE;
break; break;
case 'rotate': case 'rotate':
messageType = FurniAction.ROTATE; messageType = RoomWidgetFurniActionMessage.ROTATE;
break; break;
case 'pickup': case 'pickup':
if(pickupMode === PICKUP_MODE_FULL) messageType = FurniAction.PICKUP; if(pickupMode === PICKUP_MODE_FULL) messageType = RoomWidgetFurniActionMessage.PICKUP;
else messageType = FurniAction.EJECT; else messageType = RoomWidgetFurniActionMessage.EJECT;
break; break;
case 'use': case 'use':
messageType = FurniAction.USE; messageType = RoomWidgetFurniActionMessage.USE;
break; break;
case 'save_branding_configuration': case 'save_branding_configuration':
messageType = FurniAction.SAVE_STUFF_DATA; messageType = RoomWidgetFurniActionMessage.SAVE_STUFF_DATA;
objectData = getFurniSettingsAsString(); objectData = getFurniSettingsAsString();
break; break;
} }
if(!messageType) return; if(!messageType) return;
ProcessFurniAction(messageType, furniData.id, furniData.category, furniData.purchaseOfferId, objectData); widgetHandler.processWidgetMessage(new RoomWidgetFurniActionMessage(messageType, furniData.id, furniData.category, furniData.purchaseOfferId, objectData));
}, [ furniData, pickupMode ]); }, [ furniData, pickupMode, widgetHandler, getFurniSettingsAsString ]);
if(!furniData) return null; if(!furniData) return null;
@ -181,41 +179,51 @@ export const InfoStandWidgetFurniView: FC<InfoStandWidgetFurniViewProps> = props
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded"> <div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="container-fluid content-area"> <div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center"> <div className="d-flex justify-content-between align-items-center">
<div>{ furniData.name }</div> <div className="small text-wrap">{ furniData.name }</div>
<i className="fas fa-times cursor-pointer" onClick={ close }></i> <i className="fas fa-times cursor-pointer" onClick={ close }></i>
</div> </div>
<hr className="m-0 my-1"/> <hr className="m-0 my-1" />
<div className="w-100"> <div className="position-relative w-100">
{ furniData.stuffData.isUnique && { furniData.stuffData.isUnique &&
<LimitedEditionCompactPlateView uniqueNumber={ furniData.stuffData.uniqueNumber } uniqueSeries={ furniData.stuffData.uniqueSeries } /> } <div className="position-absolute r-0">
<LimitedEditionCompactPlateView uniqueNumber={ furniData.stuffData.uniqueNumber } uniqueSeries={ furniData.stuffData.uniqueSeries } />
</div> }
{ furniData.image.src.length && { furniData.image.src.length &&
<img className="d-block mx-auto" src={ furniData.image.src } alt="" /> } <img className="d-block mx-auto" src={ furniData.image.src } alt="" /> }
</div> </div>
<hr className="m-0 my-1"/> <hr className="m-0 my-1" />
<div className="d-flex flex-column"> <div className="small text-wrap">{ furniData.description }</div>
<div className="small text-center text-wrap">{furniData.description}</div> <hr className="m-0 my-1" />
<hr className="m-0 my-1"/> <div className="d-flex align-items-center">
<div className="small text-center text-wrap">{ LocalizeText('furni.owner', [ 'name' ], [ furniData.ownerName ]) }</div> <i className="icon icon-user-profile me-1 cursor-pointer" />
{isCrackable && <div> <div className="small text-wrap">{ LocalizeText('furni.owner', [ 'name' ], [ furniData.ownerName ]) }</div>
<hr className="m-0 my-1"/> </div>
<p className="badge badge-secondary mb-0 text-wrap">{LocalizeText('infostand.crackable_furni.hits_remaining', ['hits', 'target'], [crackableHits.toString(), crackableTarget.toString()])}</p> { isCrackable &&
</div>} <>
<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) && { (furniData.groupId > 0) &&
<>
<hr className="m-0 my-1" />
<div className="badge badge-secondary mb-0" onClick={ openFurniGroupInfo }> <div className="badge badge-secondary mb-0" onClick={ openFurniGroupInfo }>
<BadgeImageView badgeCode={ (furniData.stuffData as StringDataType).getValue(2) } /> <BadgeImageView badgeCode={ (furniData.stuffData as StringDataType).getValue(2) } />
</div> }
</div> </div>
{ godMode && <> </> }
<hr className="m-0 my-1"/> { godMode &&
<div className="small text-center text-wrap">ID: { furniData.id }</div> <>
{furniSettingsKeys.length > 0 && <> <hr className="m-0 my-1" />
<div className="small text-wrap">ID: { furniData.id }</div>
{ (furniSettingsKeys.length > 0) &&
<>
<hr className="m-0 my-1"/> <hr className="m-0 my-1"/>
{ furniSettingsKeys.map((key, index) => { furniSettingsKeys.map((key, index) =>
{ {
return <div key={ index } className="mb-1"> return (
<div>{ key }</div> <div key={ index } className="mb-1">
<input type="text" className="form-control form-control-sm" value={ furniSettingsValues[index] } onChange={ (event) => onFurniSettingChange(index, event.target.value) }/> <div className="small text-wrap">{ key }</div>
</div>; <input type="text" className="form-control form-control-sm" value={ furniSettingsValues[index] } onChange={ event => onFurniSettingChange(index, event.target.value) }/>
</div>);
}) } }) }
</> } </> }
</> } </> }

View File

@ -1,60 +1,73 @@
import { RoomControllerLevel } from 'nitro-renderer'; import { BotRemoveComposer } from 'nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react'; import { FC, useCallback, useMemo } from 'react';
import { GetConnection } from '../../../../../../api';
import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../../../avatar-image/AvatarImageView'; import { AvatarImageView } from '../../../../../avatar-image/AvatarImageView';
import { BadgeImageView } from '../../../../../badge-image/BadgeImageView'; import { BadgeImageView } from '../../../../../badge-image/BadgeImageView';
import { BotSkillsEnum } from '../../../avatar-info/utils/BotSkillsEnum';
import { InfoStandWidgetRentableBotViewProps } from './InfoStandWidgetRentableBotView.types'; import { InfoStandWidgetRentableBotViewProps } from './InfoStandWidgetRentableBotView.types';
export const InfoStandWidgetRentableBotView: FC<InfoStandWidgetRentableBotViewProps> = props => export const InfoStandWidgetRentableBotView: FC<InfoStandWidgetRentableBotViewProps> = props =>
{ {
const { rentableBotData = null, close = null } = props; const { rentableBotData = null, close = null } = props;
const [ canPickup, setCanPickup ] = useState(false); const canPickup = useMemo(() =>
useEffect(() =>
{ {
setCanPickup(false); if(rentableBotData.botSkills.indexOf(BotSkillsEnum.NO_PICK_UP) >= 0) return false;
if(rentableBotData.amIOwner || rentableBotData.amIAnyRoomController || rentableBotData.roomControllerLevel >= RoomControllerLevel.MODERATOR) if(!rentableBotData.amIOwner && !rentableBotData.amIAnyRoomController) return false;
setCanPickup(true);
return true;
}, [ rentableBotData ]); }, [ rentableBotData ]);
const processButtonAction = useCallback((action: string) => const pickupBot = useCallback(() =>
{ {
if(!action || (action === '')) return; GetConnection().send(new BotRemoveComposer(rentableBotData.webID));
}, [ rentableBotData ]);
}, []);
if(!rentableBotData) return; if(!rentableBotData) return;
return ( return (
<> <>
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded nitro-infostand-user"> <div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="container-fluid content-area"> <div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center"> <div className="d-flex justify-content-between align-items-center">
<div>{ rentableBotData.name }</div> <div className="small text-wrap">{ rentableBotData.name }</div>
<i className="fas fa-times cursor-pointer" onClick={ close }></i> <i className="fas fa-times cursor-pointer" onClick={ close }></i>
</div> </div>
<hr className="m-0 my-1"/> <hr className="m-0 my-1" />
<div className="d-flex"> <div className="d-flex">
<div className="body-image bot w-100"> <div className="body-image bot w-100">
<AvatarImageView figure={ rentableBotData.figure } direction={ 4 } /> <AvatarImageView figure={ rentableBotData.figure } direction={ 4 } />
</div> </div>
<div className="w-100 d-flex justify-content-center align-items-center"> <div className="w-100 d-flex justify-content-center align-items-center">
<BadgeImageView badgeCode="BOT" /> { (rentableBotData.badges.length > 0) && rentableBotData.badges.map((result, index) =>
{
return <BadgeImageView key={ index } badgeCode={ result } />;
}) }
</div> </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"/> <hr className="m-0 my-1"/>
<div className="w-100 text-center">{ rentableBotData.motto }</div> <div className="small text-wrap">
<hr className="m-0 my-1"/> { LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + rentableBotData.carryItem) ]) }
<div className="w-100 text-center">{ LocalizeText('infostand.text.botowner', ['name'], [ rentableBotData.ownerName ]) }</div> </div>
</> }
</div> </div>
</div> </div>
{ canPickup && <div className="button-container mt-2"> { canPickup &&
<button type="button" className="btn btn-sm btn-danger ms-1" onClick={event => processButtonAction('pickup')}> <div className="button-container mt-2">
<button type="button" className="btn btn-sm btn-danger ms-1" onClick={ pickupBot }>
<i className="me-1 fas fa-eject"></i> <i className="me-1 fas fa-eject"></i>
{LocalizeText('infostand.button.pickup')} { LocalizeText('infostand.button.pickup') }
</button> </button>
</div> } </div> }
</> </>

View File

@ -1,67 +1,72 @@
import classNames from 'classnames'; import { RoomSessionUserBadgesEvent } from 'nitro-renderer';
import { FC, KeyboardEvent, useCallback, useEffect, useRef, useState } from 'react'; import { FC, FocusEvent, KeyboardEvent, useCallback, useEffect, useState } from 'react';
import { CreateEventDispatcherHook } from '../../../../../../hooks/events';
import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../../../avatar-image/AvatarImageView'; import { AvatarImageView } from '../../../../../avatar-image/AvatarImageView';
import { BadgeImageView } from '../../../../../badge-image/BadgeImageView'; import { BadgeImageView } from '../../../../../badge-image/BadgeImageView';
import { useRoomContext } from '../../../../context/RoomContext';
import { RoomWidgetUpdateInfostandUserEvent } from '../../../../events/RoomWidgetUpdateInfostandUserEvent'; import { RoomWidgetUpdateInfostandUserEvent } from '../../../../events/RoomWidgetUpdateInfostandUserEvent';
import { RoomWidgetChangeMottoMessage } from '../../../../messages';
import { InfoStandWidgetUserViewProps } from './InfoStandWidgetUserView.types'; import { InfoStandWidgetUserViewProps } from './InfoStandWidgetUserView.types';
export const InfoStandWidgetUserView: FC<InfoStandWidgetUserViewProps> = props => export const InfoStandWidgetUserView: FC<InfoStandWidgetUserViewProps> = props =>
{ {
const { userData = null, close = null } = props; const { userData = null, close = null } = props;
const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
const [ badges, setBadges ] = useState<string[]>([]);
const [ motto, setMotto ] = useState(null); const [ motto, setMotto ] = useState(null);
const [ isEditingMotto, setIsEditingMotto ] = useState(false); const [ isEditingMotto, setIsEditingMotto ] = useState(false);
const inputRef = useRef<HTMLInputElement>(); const saveMotto = useCallback((motto: string) =>
useEffect(() =>
{ {
if(motto.length > 38) return;
widgetHandler.processWidgetMessage(new RoomWidgetChangeMottoMessage(motto));
setIsEditingMotto(false); setIsEditingMotto(false);
setMotto(null); }, [ widgetHandler ]);
if(!motto) setMotto(userData.motto); const onMottoBlur = useCallback((event: FocusEvent<HTMLInputElement>) =>
}, [ userData ]);
const saveMotto = useCallback(() =>
{ {
setIsEditingMotto(false); saveMotto(event.target.value);
}, [ motto ]); }, [ saveMotto ]);
const editMotto = useCallback(() => const onMottoKeyDown = useCallback((event: KeyboardEvent<HTMLInputElement>) =>
{
setIsEditingMotto(true);
setTimeout(() =>
{
if(inputRef.current) inputRef.current.focus();
}, 100);
}, [ inputRef ]);
const onKeyDownEvent = useCallback((event: KeyboardEvent<HTMLInputElement>) =>
{ {
switch(event.key) switch(event.key)
{ {
case 'Enter': case 'Enter':
saveMotto(); saveMotto((event.target as HTMLInputElement).value);
const target = (event.target as HTMLInputElement);
target.blur();
return; return;
} }
}, [ saveMotto ]);
}, []); const onRoomSessionUserBadgesEvent = useCallback((event: RoomSessionUserBadgesEvent) =>
{
if(!userData || (userData.webID !== event.userId)) return;
setBadges(event.badges);
}, [ userData ]);
CreateEventDispatcherHook(RoomSessionUserBadgesEvent.RSUBE_BADGES, eventDispatcher, onRoomSessionUserBadgesEvent);
useEffect(() =>
{
setBadges(userData.badges);
setIsEditingMotto(false);
setMotto(userData.motto);
}, [ userData ]);
if(!userData) return null; if(!userData) return null;
return ( return (
<> <div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded">
<div className="d-flex flex-column bg-dark nitro-card nitro-infostand rounded nitro-infostand-user">
<div className="container-fluid content-area"> <div className="container-fluid content-area">
<div className="d-flex justify-content-between align-items-center"> <div className="d-flex justify-content-between align-items-center">
<div>{ userData.name }</div> <div className="small text-wrap">{ userData.name }</div>
<i className="fas fa-times cursor-pointer" onClick={ close }></i> <i className="fas fa-times cursor-pointer" onClick={ close }></i>
</div> </div>
<hr className="m-0 my-1"/> <hr className="m-0 my-1" />
<div className="d-flex"> <div className="d-flex">
<div className="body-image w-100"> <div className="body-image w-100">
<AvatarImageView figure={ userData.figure } direction={ 4 } /> <AvatarImageView figure={ userData.figure } direction={ 4 } />
@ -69,7 +74,7 @@ export const InfoStandWidgetUserView: FC<InfoStandWidgetUserViewProps> = props =
<div> <div>
<div className="d-flex justify-content-between"> <div className="d-flex justify-content-between">
<div className="badge-image"> <div className="badge-image">
{ userData.badges[0] && <BadgeImageView badgeCode={ userData.badges[0] } /> } { badges[0] && <BadgeImageView badgeCode={ badges[0] } /> }
</div> </div>
<div className="badge-image"> <div className="badge-image">
{ userData.groupId > 0 && <BadgeImageView badgeCode={ userData.groupBadgeId } isGroup={ true } /> } { userData.groupId > 0 && <BadgeImageView badgeCode={ userData.groupBadgeId } isGroup={ true } /> }
@ -77,44 +82,47 @@ export const InfoStandWidgetUserView: FC<InfoStandWidgetUserViewProps> = props =
</div> </div>
<div className="d-flex justify-content-between"> <div className="d-flex justify-content-between">
<div className="badge-image"> <div className="badge-image">
{ userData.badges[1] && <BadgeImageView badgeCode={ userData.badges[1] } /> } { badges[1] && <BadgeImageView badgeCode={ badges[1] } /> }
</div> </div>
<div className="badge-image"> <div className="badge-image">
{ userData.badges[2] && <BadgeImageView badgeCode={ userData.badges[2] } /> } { badges[2] && <BadgeImageView badgeCode={ badges[2] } /> }
</div> </div>
</div> </div>
<div className="d-flex justify-content-between"> <div className="d-flex justify-content-between">
<div className="badge-image"> <div className="badge-image">
{ userData.badges[3] && <BadgeImageView badgeCode={ userData.badges[3] } /> } { badges[3] && <BadgeImageView badgeCode={ badges[3] } /> }
</div> </div>
<div className="badge-image"> <div className="badge-image">
{ userData.badges[4] && <BadgeImageView badgeCode={ userData.badges[4] } /> } { badges[4] && <BadgeImageView badgeCode={ badges[4] } /> }
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<hr className="m-0 my-1"/> <hr className="m-0 my-1" />
<div className="bg-light-dark rounded py-1 px-2 small"> <div className="bg-light-dark rounded py-1 px-2 small">
{ userData.type !== RoomWidgetUpdateInfostandUserEvent.OWN_USER && <div className="motto-content">{ motto }</div> } { userData.type !== RoomWidgetUpdateInfostandUserEvent.OWN_USER && <div className="motto-content">{ motto }</div> }
{ userData.type === RoomWidgetUpdateInfostandUserEvent.OWN_USER && <div className="d-flex justify-content-between align-items-center"> { userData.type === RoomWidgetUpdateInfostandUserEvent.OWN_USER &&
<div className="me-2"> <div className="d-flex justify-content-between align-items-center">
<i className="fas fa-pencil-alt"></i> <i className="small fas fa-pencil-alt me-2"></i>
</div>
<div className="h-100 w-100"> <div className="h-100 w-100">
{ !isEditingMotto && <div className="motto-content cursor-pointer w-100 text-wrap text-break" onClick={ () => editMotto() }>{ motto }</div> } { !isEditingMotto &&
<input ref={ inputRef } type="text" className={ "motto-input" + classNames({ ' d-none': !isEditingMotto }) } maxLength={ 38 } value={ motto } onChange={ event => setMotto(event.target.value) } onBlur={ () => saveMotto() } onKeyDown={ event => onKeyDownEvent(event) }/> <div className="motto-content cursor-pointer w-100 text-wrap text-break" onClick={ event => setIsEditingMotto(true) }>{ motto }</div> }
{ isEditingMotto &&
<input type="text" className="motto-input" maxLength={ 38 } value={ motto } onChange={ event => setMotto(event.target.value) } onBlur={ onMottoBlur } onKeyDown={ onMottoKeyDown } autoFocus={ true } /> }
</div> </div>
</div> } </div> }
</div> </div>
<hr className="m-0 my-1"/> <hr className="m-0 my-1" />
<div> <div className="small text-wrap">
{ LocalizeText('infostand.text.achievement_score') + ' ' + userData.achievementScore } { LocalizeText('infostand.text.achievement_score') + ' ' + userData.achievementScore }
</div> </div>
{ userData.carryItem > 0 && <> { (userData.carryItem > 0) &&
<hr className="m-0 my-1"/> <>
{ LocalizeText('infostand.text.handitem', ['item'], [LocalizeText('handitem' + userData.carryItem)]) } <hr className="m-0 my-1" />
<div className="small text-wrap">
{ LocalizeText('infostand.text.handitem', [ 'item' ], [ LocalizeText('handitem' + userData.carryItem) ]) }
</div>
</> } </> }
</div> </div>
</div> </div>);
</>);
} }