From 927e8da62e26b6c4cd199f1d5a0186a37d98570c Mon Sep 17 00:00:00 2001 From: duckietm Date: Thu, 5 Mar 2026 14:27:56 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=86=99=20Small=20fixes=20for=20the=20Area?= =?UTF-8?q?=20and=20Neighborhood=20Wired?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../selectors/WiredActionFurniAreaView.tsx | 55 ++++++++++++++++-- .../WiredSelectorFurniNeighborhoodView.tsx | 57 ++++++++++++++++--- src/hooks/wired/useWired.ts | 6 +- 3 files changed, 105 insertions(+), 13 deletions(-) diff --git a/src/components/wired/views/selectors/WiredActionFurniAreaView.tsx b/src/components/wired/views/selectors/WiredActionFurniAreaView.tsx index b54eff0..1c51178 100644 --- a/src/components/wired/views/selectors/WiredActionFurniAreaView.tsx +++ b/src/components/wired/views/selectors/WiredActionFurniAreaView.tsx @@ -1,4 +1,4 @@ -import { GetRoomEngine, RoomAreaSelectionManager } from '@nitrots/nitro-renderer'; +import { GetRoomEngine, RoomAreaSelectionManager, RoomObjectCategory } from '@nitrots/nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { LocalizeText } from '../../../../api'; import { Button, Text } from '../../../../common'; @@ -11,13 +11,16 @@ export const WiredActionFurniAreaView: FC<{}> = props => const [ rootY, setRootY ] = useState(0); const [ areaWidth, setAreaWidth ] = useState(0); const [ areaHeight, setAreaHeight ] = useState(0); + const [ filterExisting, setFilterExisting ] = useState(false); + const [ invert, setInvert ] = useState(false); const { trigger = null, setIntParams } = useWired(); const save = useCallback(() => { - setIntParams([ rootX, rootY, areaWidth, areaHeight ]); - }, [ rootX, rootY, areaWidth, areaHeight, setIntParams ]); + setIntParams([ rootX, rootY, areaWidth, areaHeight, filterExisting ? 1 : 0, invert ? 1 : 0 ]); + }, [ rootX, rootY, areaWidth, areaHeight, filterExisting, invert, setIntParams ]); + // Activate the area selection manager when dialog opens, deactivate on close useEffect(() => { if(!trigger) return; @@ -34,6 +37,7 @@ export const WiredActionFurniAreaView: FC<{}> = props => if(activated) { + // Restore previously saved area highlight when re-opening dialog if(trigger.intData.length >= 4 && trigger.intData[2] > 0 && trigger.intData[3] > 0) { GetRoomEngine().areaSelectionManager.setHighlight( @@ -69,19 +73,38 @@ export const WiredActionFurniAreaView: FC<{}> = props => setAreaWidth(0); setAreaHeight(0); } + + setFilterExisting(trigger.intData.length >= 5 && trigger.intData[4] === 1); + setInvert(trigger.intData.length >= 6 && trigger.intData[5] === 1); }, [ trigger ]); const hasArea = areaWidth > 0 && areaHeight > 0; + const pickedLimit = trigger?.maximumItemSelectionCount ?? 20; + const pickedCount = hasArea + ? GetRoomEngine().getRoomObjects(GetRoomEngine().activeRoomId, RoomObjectCategory.FLOOR) + .filter(obj => + { + const loc = obj.location; + const inArea = loc.x >= rootX && loc.x < rootX + areaWidth && loc.y >= rootY && loc.y < rootY + areaHeight; + return invert ? !inArea : inArea; + }).length + : 0; + return ( - +
{ LocalizeText('wiredfurni.params.area_selection') } { LocalizeText('wiredfurni.params.area_selection.info') } { hasArea && - { LocalizeText('wiredfurni.params.area_selection.selected', [ 'x', 'y', 'w', 'h' ], [ rootX.toString(), rootY.toString(), areaWidth.toString(), areaHeight.toString() ]) } + { LocalizeText('wiredfurni.params.area_selection:', [ 'x', 'y', 'w', 'h' ], [ rootX.toString(), rootY.toString(), areaWidth.toString(), areaHeight.toString() ]) } + } + + { hasArea && + + { LocalizeText('wiredfurni.pickfurnis.caption', [ 'count', 'limit' ], [ pickedCount.toString(), pickedLimit.toString() ]) } }
@@ -92,6 +115,28 @@ export const WiredActionFurniAreaView: FC<{}> = props => { LocalizeText('wiredfurni.params.area_selection.clear') }
+ +
+ + { LocalizeText('wiredfurni.params.selector_options_selector') } + + + +
); diff --git a/src/components/wired/views/selectors/WiredSelectorFurniNeighborhoodView.tsx b/src/components/wired/views/selectors/WiredSelectorFurniNeighborhoodView.tsx index 0185f09..27bf7d6 100644 --- a/src/components/wired/views/selectors/WiredSelectorFurniNeighborhoodView.tsx +++ b/src/components/wired/views/selectors/WiredSelectorFurniNeighborhoodView.tsx @@ -1,7 +1,8 @@ +import { GetRoomEngine, RoomObjectCategory } from '@nitrots/nitro-renderer'; import { CSSProperties, FC, useCallback, useEffect, useState } from 'react'; import { FaMinus, FaPlus, FaTimes } from 'react-icons/fa'; import { MdGridOn } from 'react-icons/md'; -import { LocalizeText, WiredFurniType } from '../../../../api'; +import { GetRoomSession, LocalizeText, WiredFurniType, WiredSelectionVisualizer } from '../../../../api'; import { Button, Text } from '../../../../common'; import { useWired } from '../../../../hooks'; import { WiredActionBaseView } from '../actions/WiredActionBaseView'; @@ -46,10 +47,11 @@ const tileTop = (rx: number, ry: number) => interface GridProps { selectedTiles: Tile[]; + invert: boolean; onToggle: (x: number, y: number) => void; } -const NeighborhoodGrid: FC = ({ selectedTiles, onToggle }) => +const NeighborhoodGrid: FC = ({ selectedTiles, invert, onToggle }) => { const tiles: JSX.Element[] = []; @@ -59,19 +61,20 @@ const NeighborhoodGrid: FC = ({ selectedTiles, onToggle }) => { const isCenter = rx === 0 && ry === 0; const isSelected = tileIncluded(selectedTiles, rx, ry); + const isActive = invert ? !isSelected : isSelected; const left = tileLeft(rx, ry); const top_ = tileTop(rx, ry); const zIdx = rx + ry + GRID_RANGE * 2 + 10; const bgColor = isCenter ? '#ff9500' - : isSelected + : isActive ? '#3399ff' : '#2a3042'; const borderColor = isCenter ? '#cc6600' - : isSelected + : isActive ? '#1166cc' : '#1a2032'; @@ -127,7 +130,7 @@ export const WiredSelectorFurniNeighborhoodView: FC<{}> = () => const [ curX, setCurX ] = useState(0); const [ curY, setCurY ] = useState(0); - const { trigger = null, furniIds = [], setIntParams } = useWired(); + const { trigger = null, furniIds = [], setIntParams, setFurniIds } = useWired(); useEffect(() => { @@ -157,6 +160,46 @@ export const WiredSelectorFurniNeighborhoodView: FC<{}> = () => } }, [ trigger ]); + useEffect(() => + { + if(sourceType !== SOURCE_FURNI_PICKED || !trigger) return; + + const roomId = GetRoomSession().roomId; + const wiredObj = GetRoomEngine().getRoomObject(roomId, trigger.id, RoomObjectCategory.FLOOR); + + if(!wiredObj) return; + + const wiredPos = wiredObj.getLocation(); + const tileSet = new Set(selectedTiles.map(t => `${ t.x },${ t.y }`)); + const limit = trigger.maximumItemSelectionCount; + + const allFloorObjects = GetRoomEngine().getRoomObjects(roomId, RoomObjectCategory.FLOOR); + const newIds: number[] = []; + + for(const obj of allFloorObjects) + { + if(newIds.length >= limit) break; + if(obj.id < 0 || obj.id === trigger.id) continue; + + const pos = obj.getLocation(); + const relX = Math.round(pos.x - wiredPos.x); + const relY = Math.round(pos.y - wiredPos.y); + + const isInTiles = tileSet.has(`${ relX },${ relY }`); + + if(invert ? !isInTiles : isInTiles) newIds.push(obj.id); + } + + setFurniIds(prevValue => + { + if(prevValue && prevValue.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue); + + WiredSelectionVisualizer.applySelectionShaderToFurni(newIds); + + return newIds; + }); + }, [ sourceType, selectedTiles, invert, trigger, setFurniIds ]); + const save = useCallback(() => { const params: number[] = [ @@ -235,7 +278,7 @@ export const WiredSelectorFurniNeighborhoodView: FC<{}> = () => const pickedLimit = trigger?.maximumItemSelectionCount ?? 20; return ( - +
{ LocalizeText('wiredfurni.params.neighborhood_selection') } @@ -256,7 +299,7 @@ export const WiredSelectorFurniNeighborhoodView: FC<{}> = () =>
- +
diff --git a/src/hooks/wired/useWired.ts b/src/hooks/wired/useWired.ts index f25235f..df746b5 100644 --- a/src/hooks/wired/useWired.ts +++ b/src/hooks/wired/useWired.ts @@ -15,6 +15,8 @@ const useWiredState = () => const [ allowsFurni, setAllowsFurni ] = useState(WiredFurniType.STUFF_SELECTION_OPTION_NONE); const [ selectByType, setSelectByType ] = useState(false); const [ invertSelection, setInvertSelection ] = useState(false); + const [ neighborhoodTiles, setNeighborhoodTiles ] = useState<{ x: number; y: number }[] | null>(null); + const [ neighborhoodInvert, setNeighborhoodInvert ] = useState(false); const { showConfirm = null } = useNotification(); const saveWired = () => @@ -206,10 +208,12 @@ const useWiredState = () => setAllowsFurni(WiredFurniType.STUFF_SELECTION_OPTION_NONE); setSelectByType(false); setInvertSelection(false); + setNeighborhoodTiles(null); + setNeighborhoodInvert(false); }; }, [ trigger ]); - return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired, setSelectByType, setInvertSelection }; + return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired, setSelectByType, setInvertSelection, setNeighborhoodTiles, setNeighborhoodInvert }; }; export const useWired = () => useBetween(useWiredState);