From 86233806f29616505dceb46dc7528a6b78e7be26 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 5 Jul 2021 02:46:47 -0400 Subject: [PATCH] Trade updates --- src/assets/styles/utils.scss | 4 + .../inventory/InventoryTradeRequestEvent.ts | 27 ++++ .../inventory/InventoryTradeStartEvent.ts | 28 ++++ src/events/inventory/index.ts | 2 + .../inventory/InventoryMessageHandler.tsx | 117 ++++++++++++++- src/views/inventory/InventoryView.scss | 2 +- src/views/inventory/InventoryView.tsx | 31 +++- src/views/inventory/common/FurnitureItem.ts | 42 +++--- .../inventory/common/FurnitureUtilities.ts | 2 +- src/views/inventory/common/GroupItem.ts | 56 +++++-- src/views/inventory/common/TradeState.ts | 10 ++ src/views/inventory/common/TradeUserData.ts | 15 ++ .../inventory/common/TradingUtilities.ts | 73 +++++++++ .../reducers/InventoryFurnitureReducer.tsx | 139 +++++++++++++++++- .../furniture/InventoryFurnitureView.tsx | 125 ++++++++++++++-- .../item/InventoryFurnitureItemView.tsx | 3 +- .../results/InventoryFurnitureResultsView.tsx | 2 +- .../views/trade/InventoryTradeView.tsx | 37 +++++ .../views/trade/InventoryTradeView.types.ts | 4 + .../trade/item/InventoryTradeItemView.tsx | 37 +++++ .../item/InventoryTradeItemView.types.ts | 6 + src/views/purse/PurseView.tsx | 4 +- .../handlers/RoomWidgetInfostandHandler.ts | 4 +- 23 files changed, 709 insertions(+), 61 deletions(-) create mode 100644 src/events/inventory/InventoryTradeRequestEvent.ts create mode 100644 src/events/inventory/InventoryTradeStartEvent.ts create mode 100644 src/views/inventory/common/TradeState.ts create mode 100644 src/views/inventory/common/TradeUserData.ts create mode 100644 src/views/inventory/common/TradingUtilities.ts create mode 100644 src/views/inventory/views/trade/InventoryTradeView.tsx create mode 100644 src/views/inventory/views/trade/InventoryTradeView.types.ts create mode 100644 src/views/inventory/views/trade/item/InventoryTradeItemView.tsx create mode 100644 src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts diff --git a/src/assets/styles/utils.scss b/src/assets/styles/utils.scss index 69ce07fc..c2a43bac 100644 --- a/src/assets/styles/utils.scss +++ b/src/assets/styles/utils.scss @@ -14,6 +14,10 @@ transform: scale(2) translateZ(0); } +.opacity-0-5 { + opacity: 0.5; +} + .text-shadow { text-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); } diff --git a/src/events/inventory/InventoryTradeRequestEvent.ts b/src/events/inventory/InventoryTradeRequestEvent.ts new file mode 100644 index 00000000..8cc0ee9f --- /dev/null +++ b/src/events/inventory/InventoryTradeRequestEvent.ts @@ -0,0 +1,27 @@ +import { InventoryEvent } from './InventoryEvent'; + +export class InventoryTradeRequestEvent extends InventoryEvent +{ + public static REQUEST_TRADE: string = 'ITSE_REQUEST_TRADE'; + + private _objectId: number; + private _username: string; + + constructor(objectId: number, username: string) + { + super(InventoryTradeRequestEvent.REQUEST_TRADE); + + this._objectId = objectId; + this._username = username; + } + + public get objectId(): number + { + return this._objectId; + } + + public get username(): string + { + return this._username; + } +} diff --git a/src/events/inventory/InventoryTradeStartEvent.ts b/src/events/inventory/InventoryTradeStartEvent.ts new file mode 100644 index 00000000..1724979d --- /dev/null +++ b/src/events/inventory/InventoryTradeStartEvent.ts @@ -0,0 +1,28 @@ +import { TradeUserData } from '../../views/inventory/common/TradeUserData'; +import { InventoryEvent } from './InventoryEvent'; + +export class InventoryTradeStartEvent extends InventoryEvent +{ + public static START_TRADE: string = 'ITSE_START_TRADE'; + + private _ownUserTradeData: TradeUserData; + private _otherUserTradeData: TradeUserData; + + constructor(ownUserTradeData: TradeUserData, otherUserTradeData: TradeUserData) + { + super(InventoryTradeStartEvent.START_TRADE); + + this._ownUserTradeData = ownUserTradeData; + this._otherUserTradeData = otherUserTradeData; + } + + public get ownUserTradeData(): TradeUserData + { + return this._ownUserTradeData; + } + + public get otherUserTradeData(): TradeUserData + { + return this._otherUserTradeData; + } +} diff --git a/src/events/inventory/index.ts b/src/events/inventory/index.ts index 6b5cf8e6..e795837f 100644 --- a/src/events/inventory/index.ts +++ b/src/events/inventory/index.ts @@ -1 +1,3 @@ export * from './InventoryEvent'; +export * from './InventoryTradeRequestEvent'; +export * from './InventoryTradeStartEvent'; diff --git a/src/views/inventory/InventoryMessageHandler.tsx b/src/views/inventory/InventoryMessageHandler.tsx index af4e8eba..d28f0edf 100644 --- a/src/views/inventory/InventoryMessageHandler.tsx +++ b/src/views/inventory/InventoryMessageHandler.tsx @@ -1,15 +1,17 @@ -import { BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory } from 'nitro-renderer'; +import { AdvancedMap, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingOpenEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; +import { GetRoomSession, GetSessionDataManager } from '../../api'; import { CreateMessageHook } from '../../hooks/messages/message-event'; import { mergeFurniFragments } from './common/FurnitureUtilities'; import { mergePetFragments } from './common/PetUtilities'; +import { TradeState } from './common/TradeState'; +import { TradeUserData } from './common/TradeUserData'; import { useInventoryContext } from './context/InventoryContext'; import { InventoryMessageHandlerProps } from './InventoryMessageHandler.types'; import { InventoryBadgeActions } from './reducers/InventoryBadgeReducer'; import { InventoryBotActions } from './reducers/InventoryBotReducer'; import { InventoryFurnitureActions } from './reducers/InventoryFurnitureReducer'; import { InventoryPetActions } from './reducers/InventoryPetReducer'; - let furniMsgFragments: Map[] = null; let petMsgFragments: Map[] = null; @@ -161,6 +163,111 @@ export const InventoryMessageHandler: FC = props = }); }, [ dispatchBadgeState ]); + const onTradingAcceptEvent = useCallback((event: TradingAcceptEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_ACCEPTANCE, + payload: { + userId: parser.userID, + flag: parser.userAccepts + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingOpenEvent = useCallback((event: TradingOpenEvent) => + { + const parser = event.getParser(); + + const ownUser = new TradeUserData(); + const otherUser = new TradeUserData(); + + ownUser.userItems = new AdvancedMap(); + otherUser.userItems = new AdvancedMap(); + + const userDataOne = GetRoomSession().userDataManager.getUserData(parser.userID); + const userDataTwo = GetRoomSession().userDataManager.getUserData(parser.otherUserID); + + if(userDataOne.webID === GetSessionDataManager().userId) + { + ownUser.userId = userDataOne.webID; + ownUser.userName = userDataOne.name; + ownUser.canTrade = parser.userCanTrade; + + otherUser.userId = userDataTwo.webID; + otherUser.userName = userDataTwo.name; + otherUser.canTrade = parser.otherUserCanTrade; + } + + else if(userDataTwo.webID === GetSessionDataManager().userId) + { + ownUser.userId = userDataTwo.webID; + ownUser.userName = userDataTwo.name; + ownUser.canTrade = parser.otherUserCanTrade; + + otherUser.userId = userDataOne.webID; + otherUser.userName = userDataOne.name; + otherUser.canTrade = parser.userCanTrade; + } + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_DATA, + payload: { + ownTradeUser: ownUser, + otherTradeUser: otherUser + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingCloseEvent = useCallback((event: TradingCloseEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.CLOSE_TRADE, + payload: {} + }); + }, [ dispatchFurnitureState ]); + + const onTradingCompletedEvent = useCallback((event: TradingCompletedEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_STATE, + payload: { + tradeState: TradeState.TRADING_STATE_COMPLETED + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingConfirmationEvent = useCallback((event: TradingConfirmationEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_STATE, + payload: { + tradeState: TradeState.TRADING_STATE_CONFIRMED + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingListItemEvent = useCallback((event: TradingListItemEvent) => + { + const parser = event.getParser(); + + console.log(parser); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.UPDATE_TRADE, + payload: { + tradeParser: event.getParser() + } + }); + }, [ dispatchFurnitureState ]); + CreateMessageHook(FurnitureListAddOrUpdateEvent, onFurnitureListAddOrUpdateEvent); CreateMessageHook(FurnitureListEvent, onFurnitureListEvent); CreateMessageHook(FurnitureListInvalidateEvent, onFurnitureListInvalidateEvent); @@ -173,6 +280,12 @@ export const InventoryMessageHandler: FC = props = CreateMessageHook(PetRemovedFromInventory, onPetRemovedFromInventory); CreateMessageHook(PetAddedToInventoryEvent, onPetAddedToInventoryEvent); CreateMessageHook(BadgesEvent, onBadgesEvent); + CreateMessageHook(TradingAcceptEvent, onTradingAcceptEvent); + CreateMessageHook(TradingOpenEvent, onTradingOpenEvent); + CreateMessageHook(TradingCloseEvent, onTradingCloseEvent); + CreateMessageHook(TradingCompletedEvent, onTradingCompletedEvent); + CreateMessageHook(TradingConfirmationEvent, onTradingConfirmationEvent); + CreateMessageHook(TradingListItemEvent, onTradingListItemEvent); return null; } diff --git a/src/views/inventory/InventoryView.scss b/src/views/inventory/InventoryView.scss index 66c21ce4..4363c1d0 100644 --- a/src/views/inventory/InventoryView.scss +++ b/src/views/inventory/InventoryView.scss @@ -6,7 +6,7 @@ height: 240px; max-height: 430px; resize: vertical; - overflow:auto; + overflow: auto; } .empty-image { diff --git a/src/views/inventory/InventoryView.tsx b/src/views/inventory/InventoryView.tsx index a1ba407e..04f65231 100644 --- a/src/views/inventory/InventoryView.tsx +++ b/src/views/inventory/InventoryView.tsx @@ -1,7 +1,7 @@ -import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent } from 'nitro-renderer'; +import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent, TradingOpenComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; -import { GetRoomEngine } from '../../api'; -import { InventoryEvent } from '../../events'; +import { GetConnection, GetRoomEngine } from '../../api'; +import { InventoryEvent, InventoryTradeRequestEvent } from '../../events'; import { useRoomEngineEvent } from '../../hooks/events/nitro/room/room-engine-event'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; @@ -19,11 +19,12 @@ import { InventoryBadgeView } from './views/badge/InventoryBadgeView'; import { InventoryBotView } from './views/bot/InventoryBotView'; import { InventoryFurnitureView } from './views/furniture/InventoryFurnitureView'; import { InventoryPetView } from './views/pet/InventoryPetView'; +import { InventoryTradeView } from './views/trade/InventoryTradeView'; + +const tabs = [ InventoryTabs.FURNITURE, InventoryTabs.BOTS, InventoryTabs.PETS, InventoryTabs.BADGES ]; export const InventoryView: FC = props => { - const tabs = [ InventoryTabs.FURNITURE, InventoryTabs.BOTS, InventoryTabs.PETS, InventoryTabs.BADGES ]; - const [ isVisible, setIsVisible ] = useState(false); const [ currentTab, setCurrentTab ] = useState(tabs[0]); const [ roomSession, setRoomSession ] = useState(null); @@ -46,12 +47,18 @@ export const InventoryView: FC = props => case InventoryEvent.TOGGLE_INVENTORY: setIsVisible(value => !value); return; + case InventoryTradeRequestEvent.REQUEST_TRADE: { + const tradeEvent = (event as InventoryTradeRequestEvent); + + GetConnection().send(new TradingOpenComposer(tradeEvent.objectId)); + } } }, []); useUiEvent(InventoryEvent.SHOW_INVENTORY, onInventoryEvent); useUiEvent(InventoryEvent.HIDE_INVENTORY, onInventoryEvent); useUiEvent(InventoryEvent.TOGGLE_INVENTORY, onInventoryEvent); + useUiEvent(InventoryTradeRequestEvent.REQUEST_TRADE, onInventoryEvent); const onRoomEngineObjectPlacedEvent = useCallback((event: RoomEngineObjectPlacedEvent) => { @@ -96,6 +103,19 @@ export const InventoryView: FC = props => } }, []); + useEffect(() => + { + if(!isVisible) + { + if(furnitureState.tradeData) + { + setIsVisible(true); + + if(currentTab !== InventoryTabs.FURNITURE) setCurrentTab(InventoryTabs.FURNITURE); + } + } + }, [ furnitureState.tradeData, isVisible, currentTab ]); + return ( @@ -121,6 +141,7 @@ export const InventoryView: FC = props => } { (currentTab === InventoryTabs.BADGES ) && } + { furnitureState.tradeData && } } diff --git a/src/views/inventory/common/FurnitureItem.ts b/src/views/inventory/common/FurnitureItem.ts index 702b46c3..e063c9f0 100644 --- a/src/views/inventory/common/FurnitureItem.ts +++ b/src/views/inventory/common/FurnitureItem.ts @@ -28,6 +28,8 @@ export class FurnitureItem implements IFurnitureItem constructor(parser: IFurnitureItemData) { + if(!parser) return; + this._locked = false; this._id = parser.itemId; this._type = parser.spriteId; @@ -189,26 +191,26 @@ export class FurnitureItem implements IFurnitureItem public update(parser: IFurnitureItemData): void { - this._type = parser.spriteId; - this._ref = parser.ref; - this._category = parser.category; - this._groupable = (parser.isGroupable && !parser.rentable); - this._tradeable = parser.tradable; - this._recyclable = parser.isRecycleable; - this._sellable = parser.sellable; - this._stuffData = parser.stuffData; - this._extra = parser.extra; - this._secondsToExpiration = parser.secondsToExpiration; - this._expirationTimeStamp = parser.expirationTimeStamp; - this._hasRentPeriodStarted = parser.hasRentPeriodStarted; - this._creationDay = parser.creationDay; - this._creationMonth = parser.creationMonth; - this._creationYear = parser.creationYear; - this._slotId = parser.slotId; - this._songId = parser.songId; - this._flatId = parser.flatId; - this._isRented = parser.rentable; - this._isWallItem = parser.isWallItem; + this._type = parser.spriteId; + this._ref = parser.ref; + this._category = parser.category; + this._groupable = (parser.isGroupable && !parser.rentable); + this._tradeable = parser.tradable; + this._recyclable = parser.isRecycleable; + this._sellable = parser.sellable; + this._stuffData = parser.stuffData; + this._extra = parser.extra; + this._secondsToExpiration = parser.secondsToExpiration; + this._expirationTimeStamp = parser.expirationTimeStamp; + this._hasRentPeriodStarted = parser.hasRentPeriodStarted; + this._creationDay = parser.creationDay; + this._creationMonth = parser.creationMonth; + this._creationYear = parser.creationYear; + this._slotId = parser.slotId; + this._songId = parser.songId; + this._flatId = parser.flatId; + this._isRented = parser.rentable; + this._isWallItem = parser.isWallItem; } public clone(): FurnitureItem diff --git a/src/views/inventory/common/FurnitureUtilities.ts b/src/views/inventory/common/FurnitureUtilities.ts index dc2052d7..06b13a84 100644 --- a/src/views/inventory/common/FurnitureUtilities.ts +++ b/src/views/inventory/common/FurnitureUtilities.ts @@ -310,7 +310,7 @@ function addGroupableFurnitureItem(set: GroupItem[], item: FurnitureItem, unseen return existingGroup; } -function createGroupItem(type: number, category: number, stuffData: IObjectData, extra: number = NaN, flag: boolean = false): GroupItem +export function createGroupItem(type: number, category: number, stuffData: IObjectData, extra: number = NaN, flag: boolean = false): GroupItem { // const iconImage: HTMLImageElement = null; diff --git a/src/views/inventory/common/GroupItem.ts b/src/views/inventory/common/GroupItem.ts index a5f53234..80d081fa 100644 --- a/src/views/inventory/common/GroupItem.ts +++ b/src/views/inventory/common/GroupItem.ts @@ -20,21 +20,42 @@ export class GroupItem private _hasUnseenItems: boolean; private _items: FurnitureItem[]; - constructor(type: number, category: number, roomEngine: IRoomEngine, stuffData: IObjectData, extra: number) + constructor(type: number = -1, category: number = -1, roomEngine: IRoomEngine = null, stuffData: IObjectData = null, extra: number = -1) { - this._type = type; - this._category = category; - this._roomEngine = roomEngine; - this._stuffData = stuffData; - this._extra = extra; - this._isWallItem = false; - this._iconUrl = null; - this._name = null; - this._description = null; - this._locked = false; - this._selected = false; - this._hasUnseenItems = false; - this._items = []; + this._type = type; + this._category = category; + this._roomEngine = roomEngine; + this._stuffData = stuffData; + this._extra = extra; + this._isWallItem = false; + this._iconUrl = null; + this._name = null; + this._description = null; + this._locked = false; + this._selected = false; + this._hasUnseenItems = false; + this._items = []; + } + + public clone(): GroupItem + { + const groupItem = new GroupItem(); + + groupItem._type = this._type; + groupItem._category = this._category; + groupItem._roomEngine = this._roomEngine; + groupItem._stuffData = this._stuffData; + groupItem._extra = this._extra; + groupItem._isWallItem = this._isWallItem; + groupItem._iconUrl = this._iconUrl; + groupItem._name = this._name; + groupItem._description = this._description; + groupItem._locked = this._locked; + groupItem._selected = this._selected; + groupItem._hasUnseenItems = this._hasUnseenItems; + groupItem._items = this._items; + + return groupItem; } public prepareGroup(): void @@ -251,11 +272,12 @@ export class GroupItem this._items = items; } - public lockItemIds(itemIds: number[]): void + public lockItemIds(itemIds: number[]): boolean { const items = [ ...this._items ]; let index = 0; + let updated = false; while(index < items.length) { @@ -264,6 +286,8 @@ export class GroupItem if(item.locked !== locked) { + updated = true; + const newItem = item.clone(); newItem.locked = locked; @@ -275,6 +299,8 @@ export class GroupItem } this._items = items; + + return updated; } private setName(): void diff --git a/src/views/inventory/common/TradeState.ts b/src/views/inventory/common/TradeState.ts new file mode 100644 index 00000000..68253e87 --- /dev/null +++ b/src/views/inventory/common/TradeState.ts @@ -0,0 +1,10 @@ +export class TradeState +{ + public static TRADING_STATE_READY: number = 0; + public static TRADING_STATE_RUNNING: number = 1; + public static TRADING_STATE_COUNTDOWN: number = 2; + public static TRADING_STATE_CONFIRMING: number = 3; + public static TRADING_STATE_CONFIRMED: number = 4; + public static TRADING_STATE_COMPLETED: number = 5; + public static TRADING_STATE_CANCELLED: number = 6; +} diff --git a/src/views/inventory/common/TradeUserData.ts b/src/views/inventory/common/TradeUserData.ts new file mode 100644 index 00000000..5df557fb --- /dev/null +++ b/src/views/inventory/common/TradeUserData.ts @@ -0,0 +1,15 @@ +import { AdvancedMap } from 'nitro-renderer'; +import { GroupItem } from './GroupItem'; + +export class TradeUserData +{ + constructor( + public userId: number = -1, + public userName: string = '', + public userItems: AdvancedMap = null, + public itemCount: number = 0, + public creditsCount: number = 0, + public accepts: boolean = false, + public canTrade: boolean = false, + public items: AdvancedMap = new AdvancedMap()) {} +} diff --git a/src/views/inventory/common/TradingUtilities.ts b/src/views/inventory/common/TradingUtilities.ts new file mode 100644 index 00000000..be7fc72d --- /dev/null +++ b/src/views/inventory/common/TradingUtilities.ts @@ -0,0 +1,73 @@ +import { AdvancedMap, IObjectData, ItemDataStructure, StringDataType } from 'nitro-renderer'; +import { GetSessionDataManager } from '../../../api'; +import { FurniCategory } from './FurniCategory'; +import { FurnitureItem } from './FurnitureItem'; +import { createGroupItem } from './FurnitureUtilities'; +import { GroupItem } from './GroupItem'; + +function isExternalImage(spriteId: number): boolean +{ + const furnitureData = GetSessionDataManager().getWallItemData(spriteId); + + return (furnitureData && furnitureData.isExternalImage); +} + +export function parseTradeItems(items: ItemDataStructure[], _arg_2: AdvancedMap): void +{ + const totalItems = items.length; + + if(!totalItems) return; + + for(const item of items) + { + const spriteId = item.spriteId; + const category = item.category; + + let name = (item.furniType + spriteId); + + if(!item.isGroupable || isExternalImage(spriteId)) + { + name = ('itemid' + item.itemId); + } + + if(item.category === FurniCategory._Str_5186) + { + name = (item.itemId + 'poster' + item.stuffData.getLegacyString()); + } + + else if(item.category === FurniCategory._Str_12454) + { + name = ''; + } + + let groupItem = ((item.isGroupable && !isExternalImage(item.spriteId)) ? _arg_2.getValue(name) : null); + + if(!groupItem) + { + groupItem = createGroupItem(spriteId, category, item.stuffData); + + _arg_2.add(name, groupItem); + } + + groupItem.push(new FurnitureItem(item)); + } +} + +export function _Str_16998(spriteId: number, stuffData: IObjectData): string +{ + let type = spriteId.toString(); + const _local_4 = (stuffData as StringDataType); + + if(!(stuffData instanceof StringDataType)) return type; + + let _local_5 = 1; + + while(_local_5 < 5) + { + type = (type + (',' + _local_4.getValue(_local_5))); + + _local_5++; + } + + return type; +} diff --git a/src/views/inventory/reducers/InventoryFurnitureReducer.tsx b/src/views/inventory/reducers/InventoryFurnitureReducer.tsx index 865b9207..51b380c6 100644 --- a/src/views/inventory/reducers/InventoryFurnitureReducer.tsx +++ b/src/views/inventory/reducers/InventoryFurnitureReducer.tsx @@ -1,14 +1,22 @@ -import { FurnitureListItemParser } from 'nitro-renderer'; +import { AdvancedMap, FurnitureListItemParser, TradingListItemParser } from 'nitro-renderer'; import { Reducer } from 'react'; import { FurnitureItem } from '../common/FurnitureItem'; import { addFurnitureItem, processFurniFragment, removeFurniItemById } from '../common/FurnitureUtilities'; import { GroupItem } from '../common/GroupItem'; +import { TradeState } from '../common/TradeState'; +import { TradeUserData } from '../common/TradeUserData'; +import { parseTradeItems } from '../common/TradingUtilities'; export interface IInventoryFurnitureState { needsFurniUpdate: boolean; groupItem: GroupItem; groupItems: GroupItem[]; + tradeData: { + ownUser: TradeUserData; + otherUser: TradeUserData; + state: number; + } } export interface IInventoryFurnitureAction @@ -20,6 +28,11 @@ export interface IInventoryFurnitureAction parsers?: FurnitureListItemParser[]; itemId?: number; fragment?: Map; + ownTradeUser?: TradeUserData; + otherTradeUser?: TradeUserData; + tradeState?: number; + userId?: number; + tradeParser?: TradingListItemParser; } } @@ -30,12 +43,18 @@ export class InventoryFurnitureActions public static PROCESS_FRAGMENT: string = 'IFA_PROCESS_FRAGMENT'; public static ADD_OR_UPDATE_FURNITURE: string = 'IFA_ADD_OR_UPDATE_FURNITURE'; public static REMOVE_FURNITURE: string = 'IFA_REMOVE_FURNITURE'; + public static SET_TRADE_DATA: string = 'IFA_SET_TRADE_DATA'; + public static SET_TRADE_STATE: string = 'IFA_SET_TRADE_STATE'; + public static SET_TRADE_ACCEPTANCE: string = 'FA_SET_TRADE_ACCEPTANCE'; + public static CLOSE_TRADE: string = 'IFA_CLOSE_STRING'; + public static UPDATE_TRADE: string = 'IFA_UPDATE_TRADE'; } export const initialInventoryFurniture: IInventoryFurnitureState = { needsFurniUpdate: true, groupItem: null, - groupItems: [] + groupItems: [], + tradeData: null } export const InventoryFurnitureReducer: Reducer = (state, action) => @@ -131,6 +150,122 @@ export const InventoryFurnitureReducer: Reducer = new AdvancedMap(); + const secondUserItems: AdvancedMap = new AdvancedMap(); + + parseTradeItems(parser.firstUserItemArray, firstUserItems); + parseTradeItems(parser.secondUserItemArray, secondUserItems); + + const ownUserData = Object.assign({}, tradeData.ownUser); + const otherUserData = Object.assign({}, tradeData.otherUser); + + if(tradeData.ownUser.userId === parser.firstUserID) + { + ownUserData.creditsCount = parser.firstUserNumCredits; + ownUserData.itemCount = parser.firstUserNumItems; + ownUserData.items = firstUserItems; + } + + else if(tradeData.ownUser.userId === parser.secondUserID) + { + ownUserData.creditsCount = parser.secondUserNumCredits; + ownUserData.itemCount = parser.secondUserNumItems; + ownUserData.items = secondUserItems; + } + + if(tradeData.otherUser.userId === parser.firstUserID) + { + otherUserData.creditsCount = parser.firstUserNumCredits; + otherUserData.itemCount = parser.firstUserNumItems; + otherUserData.items = firstUserItems; + } + + else if(tradeData.otherUser.userId === parser.secondUserID) + { + otherUserData.creditsCount = parser.secondUserNumCredits; + otherUserData.itemCount = parser.secondUserNumItems; + otherUserData.items = secondUserItems; + } + + tradeData.ownUser = ownUserData; + tradeData.otherUser = otherUserData; + + const tradeIds: number[] = []; + + for(const groupItem of ownUserData.items.getValues()) + { + let i = 0; + + while(i < groupItem.getTotalCount()) + { + const item = groupItem.getItemByIndex(i); + + if(item) tradeIds.push(item.ref); + + i++; + } + } + + for(const groupItem of groupItems) groupItem.lockItemIds(tradeIds); + + } + + return { ...state, groupItems, tradeData }; + } default: return state; } diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx index 644af8a1..89cb22ac 100644 --- a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx +++ b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx @@ -1,6 +1,6 @@ -import { FurnitureListComposer, RoomObjectVariable, Vector3d } from 'nitro-renderer'; -import { FC, useEffect, useState } from 'react'; -import { GetRoomEngine } from '../../../../api'; +import { FurnitureListComposer, IObjectData, RoomObjectVariable, TradingListAddItemComposer, TradingListAddItemsComposer, Vector3d } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { GetConnection, GetRoomEngine } from '../../../../api'; import { SendMessageHook } from '../../../../hooks/messages/message-event'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { LimitedEditionCompactPlateView } from '../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView'; @@ -8,19 +8,122 @@ import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerV import { FurniCategory } from '../../common/FurniCategory'; import { attemptItemPlacement } from '../../common/FurnitureUtilities'; import { GroupItem } from '../../common/GroupItem'; +import { IFurnitureItem } from '../../common/IFurnitureItem'; +import { TradeState } from '../../common/TradeState'; +import { _Str_16998 } from '../../common/TradingUtilities'; import { useInventoryContext } from '../../context/InventoryContext'; import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer'; import { InventoryFurnitureViewProps } from './InventoryFurnitureView.types'; import { InventoryFurnitureResultsView } from './results/InventoryFurnitureResultsView'; import { InventoryFurnitureSearchView } from './search/InventoryFurnitureSearchView'; +const MAX_ITEMS_TO_TRADE: number = 3; + export const InventoryFurnitureView: FC = props => { const { roomSession = null, roomPreviewer = null } = props; const { furnitureState = null, dispatchFurnitureState = null } = useInventoryContext(); - const { needsFurniUpdate = false, groupItem = null, groupItems = [] } = furnitureState; + const { needsFurniUpdate = false, groupItem = null, groupItems = [], tradeData = null } = furnitureState; const [ filteredGroupItems, setFilteredGroupItems ] = useState(groupItems); + const isTrading = useMemo(() => + { + if(!tradeData) return false; + + return (tradeData.state >= TradeState.TRADING_STATE_RUNNING); + }, [ tradeData ]); + + const canTradeItem = useCallback((isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) => + { + if(!tradeData || !tradeData.ownUser || tradeData.ownUser.accepts || !tradeData.ownUser.items) return false; + + if(tradeData.ownUser.items.length < MAX_ITEMS_TO_TRADE) return true; + + if(!groupable) return false; + + let type = spriteId.toString(); + + if(category === FurniCategory._Str_5186) + { + type = ((type + 'poster') + stuffData.getLegacyString()); + } + else + { + if(category === FurniCategory._Str_12454) + { + type = _Str_16998(spriteId, stuffData); + } + else + { + type = (((isWallItem) ? 'I' : 'S') + type); + } + } + + return !!tradeData.ownUser.items.getValue(type); + }, [ tradeData ]); + + const attemptItemOffer = useCallback((count: number) => + { + if(!tradeData || !groupItem || !isTrading) return; + + const tradeItems = groupItem.getTradeItems(count); + + if(!tradeItems || !tradeItems.length) return; + + let coreItem: IFurnitureItem = null; + const itemIds: number[] = []; + + for(const item of tradeItems) + { + itemIds.push(item.id); + + if(!coreItem) coreItem = item; + } + + const tradedIds: number[] = []; + + if(isTrading) + { + const ownItemCount = tradeData.ownUser.items.length; + + if((ownItemCount + itemIds.length) <= 1500) + { + if(!coreItem.isGroupable && (itemIds.length)) + { + GetConnection().send(new TradingListAddItemComposer(itemIds.pop())); + } + else + { + const tradeIds: number[] = []; + + for(const itemId of itemIds) + { + if(canTradeItem(coreItem.isWallItem, coreItem.type, coreItem.category, coreItem.isGroupable, coreItem.stuffData)) + { + tradedIds.push(itemId); + } + } + + if(tradedIds.length) + { + if(tradedIds.length === 1) + { + GetConnection().send(new TradingListAddItemComposer(tradedIds.pop())); + } + else + { + GetConnection().send(new TradingListAddItemsComposer(...tradedIds)); + } + } + } + } + else + { + //this._notificationService.alert('${trading.items.too_many_items.desc}', '${trading.items.too_many_items.title}'); + } + } + }, [ canTradeItem, groupItem, isTrading, tradeData ]); + useEffect(() => { if(needsFurniUpdate) @@ -123,14 +226,18 @@ export const InventoryFurnitureView: FC = props =>
- { groupItem && groupItem.stuffData.isUnique && + { groupItem &&groupItem.stuffData.isUnique &&
} - { groupItem &&
-

{ groupItem.name }

- { !!roomSession && } -
} + { groupItem && +
+

{ groupItem.name }

+ { !!roomSession && !isTrading && + } + { isTrading && + } +
}
); diff --git a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx index 97d174c6..5079f367 100644 --- a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx +++ b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx @@ -10,6 +10,7 @@ export const InventoryFurnitureItemView: FC = p { const { groupItem } = props; const { furnitureState, dispatchFurnitureState } = useInventoryContext(); + const { tradeData = null } = furnitureState; const [ isMouseDown, setMouseDown ] = useState(false); const isActive = (furnitureState.groupItem === groupItem); @@ -40,7 +41,7 @@ export const InventoryFurnitureItemView: FC = p return (
-
+
{groupItem.getUnlockedCount() > 1 && {groupItem.getUnlockedCount()} } { groupItem.stuffData.isUnique && diff --git a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx index 4b3ae59b..9df3889c 100644 --- a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx +++ b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx @@ -9,7 +9,7 @@ export const InventoryFurnitureResultsView: FC
- { groupItems && (groupItems.length > 0) && groupItems.map((item, index) => + { groupItems && (groupItems.length > 0) && groupItems.map((item, index) => { return }) } diff --git a/src/views/inventory/views/trade/InventoryTradeView.tsx b/src/views/inventory/views/trade/InventoryTradeView.tsx new file mode 100644 index 00000000..88fe8f7f --- /dev/null +++ b/src/views/inventory/views/trade/InventoryTradeView.tsx @@ -0,0 +1,37 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { useInventoryContext } from '../../context/InventoryContext'; +import { InventoryTradeViewProps } from './InventoryTradeView.types'; +import { InventoryTradeItemView } from './item/InventoryTradeItemView'; + +const MAX_ITEMS_COUNT: number = 9; + +export const InventoryTradeView: FC = props => +{ + const { isInFurnitureView = false } = props; + const { furnitureState = null } = useInventoryContext(); + const { tradeData = null } = furnitureState; + + return ( +
+
+
{ LocalizeText('inventory.trading.you') }
+
+ { Array.from(Array(MAX_ITEMS_COUNT), (e, i) => + { + return ; + }) } +
+
+
+
{ tradeData.otherUser.userName }
+
+ { Array.from(Array(MAX_ITEMS_COUNT), (e, i) => + { + return ; + }) } +
+
+
+ ); +} diff --git a/src/views/inventory/views/trade/InventoryTradeView.types.ts b/src/views/inventory/views/trade/InventoryTradeView.types.ts new file mode 100644 index 00000000..aa863e89 --- /dev/null +++ b/src/views/inventory/views/trade/InventoryTradeView.types.ts @@ -0,0 +1,4 @@ +export interface InventoryTradeViewProps +{ + isInFurnitureView: boolean; +} diff --git a/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx b/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx new file mode 100644 index 00000000..75627b04 --- /dev/null +++ b/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx @@ -0,0 +1,37 @@ +import { FC, useCallback } from 'react'; +import { LimitedEditionStyledNumberView } from '../../../../shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; +import { InventoryTradeItemViewProps } from './InventoryTradeItemView.types'; + +export const InventoryTradeItemView: FC = props => +{ + const { groupItem = null } = props; + + const onClick = useCallback(() => + { + + }, []); + + if(!groupItem) + { + return ( +
+
+
+ ); + } + + const imageUrl = `url(${ groupItem.iconUrl })`; + + return ( +
+
+ { groupItem.getUnlockedCount() > 1 && + { groupItem.getUnlockedCount() } } + { groupItem.stuffData.isUnique && +
+ +
} +
+
+ ); +} diff --git a/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts b/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts new file mode 100644 index 00000000..29740d21 --- /dev/null +++ b/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts @@ -0,0 +1,6 @@ +import { GroupItem } from '../../../common/GroupItem'; + +export interface InventoryTradeItemViewProps +{ + groupItem: GroupItem; +} diff --git a/src/views/purse/PurseView.tsx b/src/views/purse/PurseView.tsx index 15932d13..8ab722ca 100644 --- a/src/views/purse/PurseView.tsx +++ b/src/views/purse/PurseView.tsx @@ -37,11 +37,11 @@ export const PurseView: FC = props =>
- { currencies && currencies.map((currency, index) => + { currencies && currencies.map(currency => { if(displayedCurrencies.indexOf(currency.type) === -1) return null; - return ; + return ; }) }
diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 868911a7..9ad903bf 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -1,6 +1,6 @@ import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; import { GetConnection, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; -import { WiredSelectObjectEvent } from '../../../events'; +import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../events'; import { dispatchUiEvent } from '../../../hooks/events'; import { LocalizeText } from '../../../utils/LocalizeText'; import { RoomWidgetObjectNameEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events'; @@ -114,7 +114,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler this.container.roomSession.sendTakeRightsMessage((message as RoomWidgetUserActionMessage).userId); break; case RoomWidgetUserActionMessage.START_TRADING: - //if(userData) this._widget.inventoryTrading.startTrade(userData.roomIndex, userData.name); + dispatchUiEvent(new InventoryTradeRequestEvent(userData.roomIndex, userData.name)); break; // case RoomWidgetUserActionMessage.RWUAM_OPEN_HOME_PAGE: // this._container.sessionDataManager._Str_21275((message as RoomWidgetUserActionMessage).userId, _local_3.name);