From 56a0be64d91ee50e75777efff2d038aa873ee73f Mon Sep 17 00:00:00 2001 From: Lorenzune Date: Wed, 25 Mar 2026 03:26:27 +0100 Subject: [PATCH] Polish wired editor UI and source selection flows --- public/UITexts.example | 5 +- ...er-config.example => renderer-config.json} | 47 +- public/{ui-config.example => ui-config.json} | 0 src/api/wired/WiredActionLayoutCode.ts | 2 + src/common/Slider.tsx | 6 +- src/components/wired/views/WiredBaseView.tsx | 68 +- .../views/WiredFurniSelectionSourceRow.tsx | 66 + .../wired/views/WiredFurniSelectorView.tsx | 6 +- .../wired/views/WiredSourcesSelector.tsx | 222 +- .../views/actions/WiredActionBaseView.tsx | 10 +- .../WiredActionBotGiveHandItemView.tsx | 6 +- .../actions/WiredActionFurniToFurniView.tsx | 77 +- .../views/actions/WiredActionLayoutView.tsx | 6 + .../actions/WiredActionSendSignalView.tsx | 80 +- .../conditions/WiredConditionActorDirView.tsx | 1 + .../conditions/WiredConditionBaseView.tsx | 6 +- .../WiredConditionFurniIsOfTypeView.tsx | 75 +- .../WiredConditionHasAltitudeView.tsx | 1 + .../WiredConditionSelectionQuantityView.tsx | 12 +- .../WiredConditionTeamHasRankView.tsx | 1 + .../WiredConditionTeamHasScoreView.tsx | 1 + .../WiredConditionTriggererMatchView.tsx | 1 + .../WiredConditionUserPerformsActionView.tsx | 1 + .../wired/views/extras/WiredExtraBaseView.tsx | 6 +- .../extras/WiredExtraExecuteInOrderView.tsx | 17 + .../extras/WiredExtraExecutionLimitView.tsx | 84 + .../extras/WiredExtraMoveCarryUsersView.tsx | 2 +- .../extras/WiredExtraMovePhysicsView.tsx | 1 + .../views/selectors/WiredSelectorBaseView.tsx | 6 +- .../WiredSelectorFurniNeighborhoodView.tsx | 9 +- .../WiredSelectorUsersNeighborhoodView.tsx | 9 +- .../views/triggers/WiredTriggerBaseView.tsx | 6 +- src/css/index.css | 268 +- vite.config.mjs | 47 +- yarn.lock | 3238 +++++++++++++++++ 35 files changed, 4137 insertions(+), 256 deletions(-) rename public/{renderer-config.example => renderer-config.json} (88%) rename public/{ui-config.example => ui-config.json} (100%) create mode 100644 src/components/wired/views/WiredFurniSelectionSourceRow.tsx create mode 100644 src/components/wired/views/extras/WiredExtraExecuteInOrderView.tsx create mode 100644 src/components/wired/views/extras/WiredExtraExecutionLimitView.tsx create mode 100644 yarn.lock diff --git a/public/UITexts.example b/public/UITexts.example index fe20439..25c2cfa 100644 --- a/public/UITexts.example +++ b/public/UITexts.example @@ -20,5 +20,8 @@ "widget.room.chat.clear_history": "leeg geschiedenis", "widget.room.youtube.shared": "YouTube word gedeeld", "widget.room.youtube.open_video": "Open de video", - "wiredfurni.params.area_selection.selected": "Geselecteerd gebied: Lengte=%x%, Breedte=%y%, breedte=%w%, hoogte=%h%" + "wiredfurni.params.area_selection.selected": "Geselecteerd gebied: Lengte=%x%, Breedte=%y%, breedte=%w%, hoogte=%h%", + "wiredfurni.params.sources.users.11": "L'utente cliccato", + "wiredfurni.params.setexecutions": "Quantità di esecuzioni: %amount%", + "wiredfurni.params.settimewindow": "Tempo massimo consentito: %timewindow% secondi" } diff --git a/public/renderer-config.example b/public/renderer-config.json similarity index 88% rename from public/renderer-config.example rename to public/renderer-config.json index 62dc183..b0beddf 100644 --- a/public/renderer-config.example +++ b/public/renderer-config.json @@ -1,28 +1,28 @@ { - "socket.url": "ws:localhost:2097", - "asset.url": "http://localhost:3000/public\nitro-assets\gamedata", - "image.library.url": "http://localhost:3000/swf/gamedata/c_images/", - "hof.furni.url": "http://localhost:3000/", - "images.url": "${asset.url}/images", - "gamedata.url": "${asset.url}", + "socket.url": "ws://192.168.1.52:2096", + "asset.url": "https://client.paxxo.online/nitro/bundled", + "image.library.url": "https://client.paxxo.online/c_images/", + "hof.furni.url": "https://client.paxxo.online/c_images/dcr/hof_furni", + "images.url": "https://client.paxxo.online/nitro/images", + "gamedata.url": "https://client.paxxo.online/nitro/gamedata", "sounds.url": "${asset.url}/sounds/%sample%.mp3", "external.texts.url": [ - "${gamedata.url}/config/ExternalTexts.json", - "${gamedata.url}//config/UITexts.json" + "${gamedata.url}/ExternalTexts.json", + "${gamedata.url}/UITexts.json" ], - "external.samples.url": "${hof.furni.url}/gamedata/sounds/sound_machine_sample_%sample%.mp3", - "furnidata.url": "${gamedata.url}/config/FurnitureData.json?v=1", - "productdata.url": "${gamedata.url}/config/ProductData.json?v=1", - "avatar.actions.url": "${gamedata.url}/config/HabboAvatarActions.json?v=1", - "avatar.figuredata.url": "${gamedata.url}/config/FigureData.json?v=1", - "avatar.figuremap.url": "${gamedata.url}/config/FigureMap.json?v=1", - "avatar.effectmap.url": "${gamedata.url}/config/EffectMap.json?v=1", - "avatar.asset.url": "${asset.url}/clothes/%libname%.nitro", + "external.samples.url": "${hof.furni.url}/mp3/sound_machine_sample_%sample%.mp3", + "furnidata.url": "${gamedata.url}/FurnitureData.json?v=1", + "productdata.url": "${gamedata.url}/ProductData.json?v=1", + "avatar.actions.url": "${gamedata.url}/HabboAvatarActions.json?v=1", + "avatar.figuredata.url": "${gamedata.url}/FigureData.json?v=1", + "avatar.figuremap.url": "${gamedata.url}/FigureMap.json?v=1", + "avatar.effectmap.url": "${gamedata.url}/EffectMap.json?v=1", + "avatar.asset.url": "${asset.url}/figure/%libname%.nitro", "avatar.asset.effect.url": "${asset.url}/effect/%libname%.nitro", "furni.asset.url": "${asset.url}/furniture/%libname%.nitro", - "furni.asset.icon.url": "${gamedata.url}/icons/%libname%%param%_icon.png", - "generic.asset.url": "${asset.url}/generic_custom/%libname%.nitro", + "furni.asset.icon.url": "${hof.furni.url}/icons/%libname%%param%_icon.png", "pet.asset.url": "${asset.url}/pets/%libname%.nitro", + "generic.asset.url": "${asset.url}/generic/%libname%.nitro", "badge.asset.url": "${image.library.url}album1584/%badgename%.gif", "furni.rotation.bounce.steps": 20, "furni.rotation.bounce.height": 0.0625, @@ -31,7 +31,7 @@ "system.log.warn": true, "system.log.error": true, "system.log.events": false, - "system.log.packets": false, + "system.log.packets": true, "system.fps.animation": 24, "system.fps.max": 60, "system.pong.manually": true, @@ -39,7 +39,6 @@ "room.color.skip.transition": true, "room.landscapes.enabled": true, "room.zoom.enabled": true, - "timezone.settings": "America/Los_Angeles", "avatar.mandatory.libraries": [ "bd:1", "li:0" @@ -578,11 +577,11 @@ "elephants" ], "preload.assets.urls": [ - "${asset.url}/bundled/generic/avatar_additions.nitro", - "${asset.url}/bundled/generic/group_badge.nitro", - "${asset.url}/bundled/generic/floor_editor.nitro", + "${asset.url}/generic/avatar_additions.nitro", + "${asset.url}/generic/group_badge.nitro", + "${asset.url}/generic/floor_editor.nitro", "${images.url}/loading_icon.png", "${images.url}/clear_icon.png", "${images.url}/big_arrow.png" ] -} +} \ No newline at end of file diff --git a/public/ui-config.example b/public/ui-config.json similarity index 100% rename from public/ui-config.example rename to public/ui-config.json diff --git a/src/api/wired/WiredActionLayoutCode.ts b/src/api/wired/WiredActionLayoutCode.ts index 0e38692..d3f1f5e 100644 --- a/src/api/wired/WiredActionLayoutCode.ts +++ b/src/api/wired/WiredActionLayoutCode.ts @@ -62,4 +62,6 @@ export class WiredActionLayoutCode public static MOVE_PHYSICS_EXTRA: number = 61; public static UNSEEN_EXTRA: number = 62; public static RANDOM_EXTRA: number = 63; + public static EXEC_IN_ORDER_EXTRA: number = 64; + public static EXECUTION_LIMIT_EXTRA: number = 65; } diff --git a/src/common/Slider.tsx b/src/common/Slider.tsx index 206c0a5..72fb74c 100644 --- a/src/common/Slider.tsx +++ b/src/common/Slider.tsx @@ -27,9 +27,9 @@ export const Slider: FC = props => return parseFloat(nextValue.toFixed(precision)); }; - return - { !disabledButton && } + return + { !disabledButton && } - { !disabledButton && } + { !disabledButton && } ; } diff --git a/src/components/wired/views/WiredBaseView.tsx b/src/components/wired/views/WiredBaseView.tsx index 96f302a..d55e5fc 100644 --- a/src/components/wired/views/WiredBaseView.tsx +++ b/src/components/wired/views/WiredBaseView.tsx @@ -14,14 +14,16 @@ export interface WiredBaseViewProps validate?: () => boolean; cardStyle?: CSSProperties; footer?: ReactNode; + footerCollapsible?: boolean; + selectionPreview?: ReactNode; } export const WiredBaseView: FC> = props => { - const { wiredType = '', requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, children = null, hasSpecialInput = false, cardStyle = undefined, footer = null } = props; + const { wiredType = '', requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, children = null, hasSpecialInput = false, cardStyle = undefined, footer = null, footerCollapsible = true, selectionPreview = null } = props; const [ wiredName, setWiredName ] = useState(null); - const [ wiredDescription, setWiredDescription ] = useState(null); const [ needsSave, setNeedsSave ] = useState(false); + const [ showFooter, setShowFooter ] = useState(false); const { trigger = null, setTrigger = null, setIntParams = null, setStringParam = null, setFurniIds = null, setAllowsFurni = null, saveWired = null } = useWired(); const clearRoomAreaSelection = () => @@ -59,6 +61,8 @@ export const WiredBaseView: FC> = props => { if(!trigger) return; + setShowFooter(false); + WiredSelectionVisualizer.clearAllSelectionShaders(); const spriteId = (trigger.spriteId || -1); @@ -67,12 +71,10 @@ export const WiredBaseView: FC> = props => if(!furniData) { setWiredName(('NAME: ' + spriteId)); - setWiredDescription(('NAME: ' + spriteId)); } else { setWiredName(furniData.name); - setWiredDescription(furniData.description); } if(hasSpecialInput) @@ -115,36 +117,62 @@ export const WiredBaseView: FC> = props => if(resolvedCardStyle.width !== undefined) { - resolvedCardStyle.minWidth = resolvedCardStyle.width; + if(typeof resolvedCardStyle.width === 'number') + { + resolvedCardStyle.maxWidth = Math.min(resolvedCardStyle.width, 324); + } + else if(typeof resolvedCardStyle.width === 'string') + { + const match = resolvedCardStyle.width.trim().match(/^(\d+(?:\.\d+)?)px$/i); + + resolvedCardStyle.maxWidth = match ? `${ Math.min(parseFloat(match[1]), 324) }px` : resolvedCardStyle.width; + } + delete resolvedCardStyle.width; } + if(resolvedCardStyle.minWidth === undefined) resolvedCardStyle.minWidth = 216; + if(resolvedCardStyle.maxWidth === undefined) resolvedCardStyle.maxWidth = 'min(90vw, 324px)'; + return ( - - -
-
+ + +
+
- { wiredName } + { wiredName }
- { wiredDescription }
- { !!children &&
} - { children } + { !!children &&
} + { !!children &&
{ children }
} { (requiresFurni > WiredFurniType.STUFF_SELECTION_OPTION_NONE) && <> -
- +
+
+ { selectionPreview || } +
} { footer && <> -
- { footer } +
+
+ { footerCollapsible + ? ( + <> + + { showFooter &&
{ footer }
} + + ) + : footer } +
} -
- - +
+
+ +
diff --git a/src/components/wired/views/WiredFurniSelectionSourceRow.tsx b/src/components/wired/views/WiredFurniSelectionSourceRow.tsx new file mode 100644 index 0000000..b064d80 --- /dev/null +++ b/src/components/wired/views/WiredFurniSelectionSourceRow.tsx @@ -0,0 +1,66 @@ +import { FC } from 'react'; +import { FaChevronLeft, FaChevronRight, FaMousePointer } from 'react-icons/fa'; +import { LocalizeText } from '../../../api'; +import { Button, Text } from '../../../common'; +import { WiredSourceOption } from './WiredSourcesSelector'; + +interface WiredFurniSelectionSourceRowProps +{ + title: string; + titleIsLiteral?: boolean; + options: WiredSourceOption[]; + value: number; + selectionKind: 'primary' | 'secondary'; + selectionActive: boolean; + selectionCount: number; + selectionLimit: number; + selectionEnabledValues: number[]; + showSelectionToggle?: boolean; + onChange: (value: number) => void; + onSelectionActivate?: () => void; +} + +export const WiredFurniSelectionSourceRow: FC = props => +{ + const { title = '', titleIsLiteral = false, options = [], value = 0, selectionKind = 'primary', selectionActive = false, selectionCount = 0, selectionLimit = 0, selectionEnabledValues = [], showSelectionToggle = true, onChange = null, onSelectionActivate = null } = props; + const currentIndex = Math.max(0, options.findIndex(option => (option.value === value))); + const currentOption = options[currentIndex] ?? options[0]; + const canActivateSelection = !!onSelectionActivate && selectionEnabledValues.includes(currentOption?.value); + const shouldShowCount = selectionEnabledValues.includes(currentOption?.value); + const countText = selectionLimit ? `[${ selectionCount }/${ selectionLimit }]` : `[${ selectionCount }]`; + const labelText = currentOption ? LocalizeText(currentOption.label) : ''; + const displayText = shouldShowCount ? `${ labelText } ${ countText }` : labelText; + const resolvedTitle = titleIsLiteral ? title : LocalizeText(title); + + const cycleValue = (direction: -1 | 1) => + { + if(!options.length || !onChange) return; + + const nextIndex = (currentIndex + direction + options.length) % options.length; + + onChange(options[nextIndex].value); + }; + + return ( +
+
+ { resolvedTitle } + { showSelectionToggle && + } +
+
+ +
+ { displayText } +
+ +
+
+ ); +}; diff --git a/src/components/wired/views/WiredFurniSelectorView.tsx b/src/components/wired/views/WiredFurniSelectorView.tsx index 1363326..528f303 100644 --- a/src/components/wired/views/WiredFurniSelectorView.tsx +++ b/src/components/wired/views/WiredFurniSelectorView.tsx @@ -8,9 +8,9 @@ export const WiredFurniSelectorView: FC<{}> = props => const { trigger = null, furniIds = [] } = useWired(); return ( -
- { LocalizeText('wiredfurni.pickfurnis.caption', [ 'count', 'limit' ], [ furniIds.length.toString(), trigger.maximumItemSelectionCount.toString() ]) } - { LocalizeText('wiredfurni.pickfurnis.desc') } +
+ { LocalizeText('wiredfurni.pickfurnis.caption', [ 'count', 'limit' ], [ furniIds.length.toString(), trigger.maximumItemSelectionCount.toString() ]) } + { LocalizeText('wiredfurni.pickfurnis.desc') }
); }; diff --git a/src/components/wired/views/WiredSourcesSelector.tsx b/src/components/wired/views/WiredSourcesSelector.tsx index ab1288e..8a38be7 100644 --- a/src/components/wired/views/WiredSourcesSelector.tsx +++ b/src/components/wired/views/WiredSourcesSelector.tsx @@ -1,13 +1,15 @@ -import { FC } from 'react'; +import { FurnitureFloorUpdateEvent, GetRoomEngine, GetSessionDataManager, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectVariable, Triggerable } from '@nitrots/nitro-renderer'; +import { FC, ReactNode, useCallback, useEffect, useMemo, useState } from 'react'; import { FaChevronLeft, FaChevronRight } from 'react-icons/fa'; -import { LocalizeText } from '../../../api'; +import { GetRoomSession, LocalizeText } from '../../../api'; import { Button, Text } from '../../../common'; +import { useMessageEvent, useNitroEvent, useWired } from '../../../hooks'; export const FURNI_SOURCES = [ - { value: 0, label: 'wiredfurni.params.sources.furni.0' }, { value: 100, label: 'wiredfurni.params.sources.furni.100' }, { value: 200, label: 'wiredfurni.params.sources.furni.200' }, - { value: 201, label: 'wiredfurni.params.sources.furni.201' } + { value: 201, label: 'wiredfurni.params.sources.furni.201' }, + { value: 0, label: 'wiredfurni.params.sources.furni.0' } ]; export const USER_SOURCES = [ @@ -16,6 +18,9 @@ export const USER_SOURCES = [ { value: 201, label: 'wiredfurni.params.sources.users.201' } ]; +export const CLICKED_USER_SOURCE_VALUE = 11; +export const CLICKED_USER_SOURCE = { value: CLICKED_USER_SOURCE_VALUE, label: 'wiredfurni.params.sources.users.11' }; + export const BOT_SOURCES = [ { value: 0, label: 'wiredfurni.params.sources.users.0' }, { value: 100, label: 'wiredfurni.params.sources.users.100' }, @@ -29,6 +34,45 @@ export interface WiredSourceOption label: string; } +const FURNI_SOURCE_LABEL_ORDER = [ + 'wiredfurni.params.sources.furni.100', + 'wiredfurni.params.sources.furni.101', + 'wiredfurni.params.sources.furni.200', + 'wiredfurni.params.sources.furni.201', + 'wiredfurni.params.sources.furni.0', + 'wiredfurni.params.sources.furni.900' +]; + +const USER_SOURCE_LABEL_ORDER = [ + 'wiredfurni.params.sources.users.0', + 'wiredfurni.params.sources.users.11', + 'wiredfurni.params.sources.users.100', + 'wiredfurni.params.sources.users.101', + 'wiredfurni.params.sources.users.200', + 'wiredfurni.params.sources.users.201', + 'wiredfurni.params.sources.users.900' +]; + +const getSourceSortIndex = (label: string, category: 'furni' | 'users') => +{ + const order = (category === 'furni') ? FURNI_SOURCE_LABEL_ORDER : USER_SOURCE_LABEL_ORDER; + const index = order.indexOf(label); + + return (index >= 0) ? index : (order.length + 1); +}; + +export const sortWiredSourceOptions = (options: WiredSourceOption[], category: 'furni' | 'users') => +{ + return [ ...options ].sort((left, right) => + { + const orderDifference = getSourceSortIndex(left.label, category) - getSourceSortIndex(right.label, category); + + if(orderDifference !== 0) return orderDifference; + + return left.value - right.value; + }); +}; + interface WiredSourcesSelectorProps { showFurni?: boolean; @@ -39,10 +83,122 @@ interface WiredSourcesSelectorProps usersTitle?: string; furniSources?: WiredSourceOption[]; userSources?: WiredSourceOption[]; + allowClickedUserSource?: boolean; + furniDetail?: ReactNode; + userDetail?: ReactNode; onChangeFurni?: (source: number) => void; onChangeUsers?: (source: number) => void; } +const BOT_SOURCE_TITLE = 'wiredfurni.params.sources.users.title.bots'; + +const CLICK_USER_TRIGGER_NAME = 'wf_trg_click_user'; +const isClickUserTriggerName = (value?: string) => +{ + if(!value) return false; + + return value.toLowerCase().startsWith(CLICK_USER_TRIGGER_NAME); +}; + +const hasClickUserTriggerInStack = (trigger: Triggerable) => +{ + if(!trigger) return false; + + const roomSession = GetRoomSession(); + const roomId = roomSession?.roomId ?? GetRoomEngine().activeRoomId; + + if(roomId == null || roomId < 0) return false; + + const triggerObject = GetRoomEngine().getRoomObject(roomId, trigger.id, RoomObjectCategory.FLOOR); + + if(!triggerObject) return false; + + const triggerLocation = triggerObject.getLocation(); + const roomObjects = GetRoomEngine().getRoomObjects(roomId, RoomObjectCategory.FLOOR) || []; + + for(const roomObject of roomObjects) + { + if(!roomObject) continue; + + const location = roomObject.getLocation(); + + if(!location || location.x !== triggerLocation.x || location.y !== triggerLocation.y) continue; + + const typeId = roomObject.model.getValue(RoomObjectVariable.FURNITURE_TYPE_ID); + const furniData = GetSessionDataManager().getFloorItemData(typeId); + + if(isClickUserTriggerName(furniData?.className) || isClickUserTriggerName(furniData?.fullName) || isClickUserTriggerName(furniData?.name)) return true; + } + + return false; +}; + +export const getAvailableUserSources = (trigger: Triggerable, userSources: WiredSourceOption[], currentUserSource: number, usersTitle = 'wiredfurni.params.sources.users.title', allowClickedUserSource = true) => +{ + if(!allowClickedUserSource || usersTitle === BOT_SOURCE_TITLE) return userSources; + if(userSources.some(option => option.value === CLICKED_USER_SOURCE_VALUE)) return userSources; + + if(!hasClickUserTriggerInStack(trigger)) return userSources; + + const triggerIndex = userSources.findIndex(option => option.value === 0); + + if(triggerIndex === -1) return [ ...userSources, CLICKED_USER_SOURCE ]; + + return [ + ...userSources.slice(0, triggerIndex + 1), + CLICKED_USER_SOURCE, + ...userSources.slice(triggerIndex + 1) + ]; +}; + +export const useAvailableUserSources = (trigger: Triggerable, userSources: WiredSourceOption[] = USER_SOURCES, usersTitle = 'wiredfurni.params.sources.users.title', allowClickedUserSource = true) => +{ + const [ hasClickUserTrigger, setHasClickUserTrigger ] = useState(false); + + const refreshStackSources = useCallback(() => + { + setHasClickUserTrigger(hasClickUserTriggerInStack(trigger)); + }, [ trigger ]); + + useEffect(() => + { + refreshStackSources(); + + if(!trigger) return; + + const intervalId = window.setInterval(refreshStackSources, 100); + + return () => window.clearInterval(intervalId); + }, [ refreshStackSources, trigger ]); + + useNitroEvent([ + RoomEngineObjectEvent.ADDED, + RoomEngineObjectEvent.REMOVED, + RoomEngineObjectEvent.PLACED, + RoomEngineObjectEvent.CONTENT_UPDATED + ], event => + { + if(!trigger) return; + if(event.category !== RoomObjectCategory.FLOOR) return; + + const roomSession = GetRoomSession(); + const roomId = roomSession?.roomId ?? GetRoomEngine().activeRoomId; + + if(event.roomId !== roomId) return; + + refreshStackSources(); + }, !!trigger); + + useMessageEvent(FurnitureFloorUpdateEvent, () => + { + if(!trigger) return; + + refreshStackSources(); + }); + + return useMemo(() => getAvailableUserSources(trigger, userSources, 0, usersTitle, allowClickedUserSource && hasClickUserTrigger), [ allowClickedUserSource, hasClickUserTrigger, trigger, userSources, usersTitle ]); +}; + export const WiredSourcesSelector: FC = props => { const { @@ -54,35 +210,51 @@ export const WiredSourcesSelector: FC = props => usersTitle = 'wiredfurni.params.sources.users.title', furniSources = FURNI_SOURCES, userSources = USER_SOURCES, + allowClickedUserSource = true, + furniDetail = null, + userDetail = null, onChangeFurni = null, onChangeUsers = null } = props; + const { trigger = null } = useWired(); + const availableUserSources = useAvailableUserSources(trigger, userSources, usersTitle, allowClickedUserSource); + const orderedFurniSources = useMemo(() => sortWiredSourceOptions(furniSources, 'furni'), [ furniSources ]); + const orderedUserSources = useMemo(() => sortWiredSourceOptions(availableUserSources, 'users'), [ availableUserSources ]); - const furniIndex = Math.max(0, furniSources.findIndex(s => s.value === furniSource)); - const userIndex = Math.max(0, userSources.findIndex(s => s.value === userSource)); + useEffect(() => + { + if(!showUsers || !onChangeUsers) return; + if(userSource !== CLICKED_USER_SOURCE_VALUE) return; + if(availableUserSources.some(source => source.value === CLICKED_USER_SOURCE_VALUE)) return; + + onChangeUsers(0); + }, [ availableUserSources, onChangeUsers, showUsers, userSource ]); + + const furniIndex = Math.max(0, orderedFurniSources.findIndex(s => s.value === furniSource)); + const userIndex = Math.max(0, orderedUserSources.findIndex(s => s.value === userSource)); const prevFurni = () => { - const next = (furniIndex - 1 + furniSources.length) % furniSources.length; - onChangeFurni && onChangeFurni(furniSources[next].value); + const next = (furniIndex - 1 + orderedFurniSources.length) % orderedFurniSources.length; + onChangeFurni && onChangeFurni(orderedFurniSources[next].value); }; const nextFurni = () => { - const next = (furniIndex + 1) % furniSources.length; - onChangeFurni && onChangeFurni(furniSources[next].value); + const next = (furniIndex + 1) % orderedFurniSources.length; + onChangeFurni && onChangeFurni(orderedFurniSources[next].value); }; const prevUsers = () => { - const next = (userIndex - 1 + userSources.length) % userSources.length; - onChangeUsers && onChangeUsers(userSources[next].value); + const next = (userIndex - 1 + orderedUserSources.length) % orderedUserSources.length; + onChangeUsers && onChangeUsers(orderedUserSources[next].value); }; const nextUsers = () => { - const next = (userIndex + 1) % userSources.length; - onChangeUsers && onChangeUsers(userSources[next].value); + const next = (userIndex + 1) % orderedUserSources.length; + onChangeUsers && onChangeUsers(orderedUserSources[next].value); }; if(!showFurni && !showUsers) return null; @@ -92,13 +264,14 @@ export const WiredSourcesSelector: FC = props => { showFurni && <> { LocalizeText(furniTitle) } -
- -
- { LocalizeText(furniSources[furniIndex].label) } +
+ +
+ { LocalizeText(orderedFurniSources[furniIndex].label) }
- +
+ { furniDetail &&
{ furniDetail }
} } { showFurni && showUsers &&
} @@ -106,13 +279,14 @@ export const WiredSourcesSelector: FC = props => { showUsers && <> { LocalizeText(usersTitle) } -
- -
- { LocalizeText(userSources[userIndex].label) } +
+ +
+ { LocalizeText(orderedUserSources[userIndex].label) }
- +
+ { userDetail &&
{ userDetail }
} }
); diff --git a/src/components/wired/views/actions/WiredActionBaseView.tsx b/src/components/wired/views/actions/WiredActionBaseView.tsx index eaa30fc..3e4075b 100644 --- a/src/components/wired/views/actions/WiredActionBaseView.tsx +++ b/src/components/wired/views/actions/WiredActionBaseView.tsx @@ -14,11 +14,13 @@ export interface WiredActionBaseViewProps cardStyle?: CSSProperties; hideDelay?: boolean; footer?: ReactNode; + footerCollapsible?: boolean; + selectionPreview?: ReactNode; } export const WiredActionBaseView: FC> = props => { - const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, hasSpecialInput = false, children = null, cardStyle = undefined, hideDelay = false, footer = null } = props; + const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, validate = null, hasSpecialInput = false, children = null, cardStyle = undefined, hideDelay = false, footer = null, footerCollapsible = true, selectionPreview = null } = props; const { trigger = null, actionDelay = 0, setActionDelay = null } = useWired(); useEffect(() => @@ -27,10 +29,10 @@ export const WiredActionBaseView: FC }, [ trigger, setActionDelay ]); return ( - + { children } - { !hideDelay && !!children &&
} - { !hideDelay &&
+ { !hideDelay && !!children &&
} + { !hideDelay &&
{ LocalizeText('wiredfurni.params.delay', [ 'seconds' ], [ GetWiredTimeLocale(actionDelay) ]) } (USER_SOURCE_OPTIONS.some(option => (option.value === value)) ? value : 0); +const normalizeUserSource = (value: number) => ((value === CLICKED_USER_SOURCE_VALUE) || USER_SOURCE_OPTIONS.some(option => (option.value === value)) ? value : 0); const normalizeBotSource = (value: number, hasBotName = false) => (BOT_SOURCE_OPTIONS.some(option => (option.value === value)) ? value : (hasBotName ? 100 : 0)); export const WiredActionBotGiveHandItemView: FC<{}> = props => @@ -56,7 +56,7 @@ export const WiredActionBotGiveHandItemView: FC<{}> = props =>

- setBotSource(normalizeBotSource(value, (botName.length > 0))) } /> + setBotSource(normalizeBotSource(value, (botName.length > 0))) } />
}>
diff --git a/src/components/wired/views/actions/WiredActionFurniToFurniView.tsx b/src/components/wired/views/actions/WiredActionFurniToFurniView.tsx index dff73b0..a997fa9 100644 --- a/src/components/wired/views/actions/WiredActionFurniToFurniView.tsx +++ b/src/components/wired/views/actions/WiredActionFurniToFurniView.tsx @@ -1,8 +1,8 @@ import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { LocalizeText, WiredFurniType, WiredSelectionVisualizer } from '../../../../api'; -import { Button, Text } from '../../../../common'; +import { WiredFurniType, WiredSelectionVisualizer } from '../../../../api'; import { useWired } from '../../../../hooks'; -import { WiredSourcesSelector, FURNI_SOURCES, WiredSourceOption } from '../WiredSourcesSelector'; +import { WiredFurniSelectionSourceRow } from '../WiredFurniSelectionSourceRow'; +import { FURNI_SOURCES, sortWiredSourceOptions, WiredSourceOption } from '../WiredSourcesSelector'; import { WiredActionBaseView } from './WiredActionBaseView'; const SOURCE_TRIGGER = 0; @@ -10,12 +10,12 @@ const SOURCE_SELECTED = 100; const SOURCE_SECONDARY_SELECTED = 101; const FURNI_DELIMITER = ';'; -const TARGET_FURNI_SOURCES: WiredSourceOption[] = [ +const TARGET_FURNI_SOURCES: WiredSourceOption[] = sortWiredSourceOptions([ { value: 0, label: 'wiredfurni.params.sources.furni.0' }, { value: SOURCE_SECONDARY_SELECTED, label: 'wiredfurni.params.sources.furni.101' }, { value: 200, label: 'wiredfurni.params.sources.furni.200' }, { value: 201, label: 'wiredfurni.params.sources.furni.201' } -]; +], 'furni'); type SelectionMode = 'move' | 'target'; @@ -185,49 +185,32 @@ export const WiredActionFurniToFurniView: FC<{}> = () => hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save } - footer={ + selectionPreview={
- -
- setTargetSource((value === SOURCE_SELECTED) ? SOURCE_SECONDARY_SELECTED : value) } /> + switchSelection('move') } /> + setTargetSource((value === SOURCE_SELECTED) ? SOURCE_SECONDARY_SELECTED : value) } + onSelectionActivate={ () => switchSelection('target') } />
- }> -
-
- { LocalizeText('wiredfurni.params.sources.furni.title.mv.0') } -
- - { selectionLimit ? `${ moveFurniIds.length }/${ selectionLimit }` : moveFurniIds.length } -
-
-
- { LocalizeText('wiredfurni.params.sources.furni.title.mv.1') } -
- - { selectionLimit ? `${ targetFurniIds.length }/${ selectionLimit }` : targetFurniIds.length } -
-
-
- + } + /> ); }; diff --git a/src/components/wired/views/actions/WiredActionLayoutView.tsx b/src/components/wired/views/actions/WiredActionLayoutView.tsx index e218f6d..051ae58 100644 --- a/src/components/wired/views/actions/WiredActionLayoutView.tsx +++ b/src/components/wired/views/actions/WiredActionLayoutView.tsx @@ -54,6 +54,8 @@ import { WiredExtraFilterFurniView } from '../extras/WiredExtraFilterFurniView'; import { WiredExtraFilterUserView } from '../extras/WiredExtraFilterUserView'; import { WiredExtraAnimationTimeView } from '../extras/WiredExtraAnimationTimeView'; import { WiredExtraMoveCarryUsersView } from '../extras/WiredExtraMoveCarryUsersView'; +import { WiredExtraExecuteInOrderView } from '../extras/WiredExtraExecuteInOrderView'; +import { WiredExtraExecutionLimitView } from '../extras/WiredExtraExecutionLimitView'; import { WiredExtraMoveNoAnimationView } from '../extras/WiredExtraMoveNoAnimationView'; import { WiredExtraMovePhysicsView } from '../extras/WiredExtraMovePhysicsView'; import { WiredExtraRandomView } from '../extras/WiredExtraRandomView'; @@ -183,6 +185,10 @@ export const WiredActionLayoutView = (code: number) => return ; case WiredActionLayoutCode.RANDOM_EXTRA: return ; + case WiredActionLayoutCode.EXEC_IN_ORDER_EXTRA: + return ; + case WiredActionLayoutCode.EXECUTION_LIMIT_EXTRA: + return ; case WiredActionLayoutCode.SEND_SIGNAL: return ; } diff --git a/src/components/wired/views/actions/WiredActionSendSignalView.tsx b/src/components/wired/views/actions/WiredActionSendSignalView.tsx index 77509e5..c3f080a 100644 --- a/src/components/wired/views/actions/WiredActionSendSignalView.tsx +++ b/src/components/wired/views/actions/WiredActionSendSignalView.tsx @@ -1,8 +1,9 @@ import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { LocalizeText, WiredFurniType, WiredSelectionVisualizer } from '../../../../api'; -import { Button, Text } from '../../../../common'; +import { Text } from '../../../../common'; import { useWired } from '../../../../hooks'; -import { WiredSourcesSelector } from '../WiredSourcesSelector'; +import { WiredFurniSelectionSourceRow } from '../WiredFurniSelectionSourceRow'; +import { FURNI_SOURCES, USER_SOURCES } from '../WiredSourcesSelector'; import { WiredActionBaseView } from './WiredActionBaseView'; const ANTENNA_INTERACTION_TYPES = [ 'antenna' ]; @@ -184,7 +185,6 @@ export const WiredActionSendSignalView: FC<{}> = () => }, []); const selectionLimit = trigger?.maximumItemSelectionCount ?? 0; - const forwardSelectionEnabled = (furniSource === SOURCE_SELECTED); return ( = () => requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } cardStyle={ { width: '400px' } } save={ save } - footer={ ( - - ) }> + selectionPreview={ +
+ {} } + onSelectionActivate={ () => switchSelection('antenna') } /> + switchSelection('furni') } /> + +
+ } + >
-
- Antenne selezionate -
- - { selectionLimit ? `${ antennaIds.length }/${ selectionLimit }` : antennaIds.length } -
-
-
- Furni selezionati -
- - { selectionLimit ? `${ forwardFurniIds.length }/${ selectionLimit }` : forwardFurniIds.length } -
-
- { LocalizeText('wiredfurni.params.signal.options') }
= () => hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save } + footerCollapsible={ false } footer={
- }> + } + >
{ LocalizeText('wiredfurni.params.quantifier_selection') } { [ 0, 1 ].map(value => ( @@ -220,32 +231,6 @@ export const WiredConditionFurniIsOfTypeView: FC )) }
-
-
- { LocalizeText('wiredfurni.params.sources.furni.title.match.0') } -
- - { selectionLimit ? `${ primaryFurniIds.length }/${ selectionLimit }` : primaryFurniIds.length } -
-
-
- { LocalizeText('wiredfurni.params.sources.furni.title.match.1') } -
- - { selectionLimit ? `${ secondaryFurniIds.length }/${ selectionLimit }` : secondaryFurniIds.length } -
-
-
); }; diff --git a/src/components/wired/views/conditions/WiredConditionHasAltitudeView.tsx b/src/components/wired/views/conditions/WiredConditionHasAltitudeView.tsx index 91a6a82..75f4b79 100644 --- a/src/components/wired/views/conditions/WiredConditionHasAltitudeView.tsx +++ b/src/components/wired/views/conditions/WiredConditionHasAltitudeView.tsx @@ -127,6 +127,7 @@ export const WiredConditionHasAltitudeView: FC<{}> = () => hasSpecialInput={ true } requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ save } + footerCollapsible={ false } footer={