From 146f8e6b0d636ebea7490ed7449a4e2d50286c9c Mon Sep 17 00:00:00 2001 From: Lorenzune Date: Thu, 19 Mar 2026 00:01:59 +0100 Subject: [PATCH] feat(wired-ui): add upcounter clock controls and checks --- src/api/wired/WiredActionLayoutCode.ts | 2 + src/api/wired/WiredConditionLayoutCode.ts | 1 + src/api/wired/WiredTriggerLayoutCode.ts | 1 + .../actions/WiredActionAdjustClockView.tsx | 123 ++++++++++++++++++ .../actions/WiredActionControlClockView.tsx | 82 ++++++++++++ .../views/actions/WiredActionLayoutView.tsx | 6 + .../WiredConditionCounterTimeMatchesView.tsx | 123 ++++++++++++++++++ .../conditions/WiredConditionLayoutView.tsx | 3 + .../views/triggers/WiredTriggerBaseView.tsx | 7 +- .../triggers/WiredTriggerClockCounterView.tsx | 101 ++++++++++++++ .../views/triggers/WiredTriggerLayoutView.tsx | 3 + src/hooks/wired/useWired.ts | 15 ++- 12 files changed, 462 insertions(+), 5 deletions(-) create mode 100644 src/components/wired/views/actions/WiredActionAdjustClockView.tsx create mode 100644 src/components/wired/views/actions/WiredActionControlClockView.tsx create mode 100644 src/components/wired/views/conditions/WiredConditionCounterTimeMatchesView.tsx create mode 100644 src/components/wired/views/triggers/WiredTriggerClockCounterView.tsx diff --git a/src/api/wired/WiredActionLayoutCode.ts b/src/api/wired/WiredActionLayoutCode.ts index 25de806..6f98d74 100644 --- a/src/api/wired/WiredActionLayoutCode.ts +++ b/src/api/wired/WiredActionLayoutCode.ts @@ -39,4 +39,6 @@ export class WiredActionLayoutCode public static FURNI_TO_FURNI: number = 38; public static SET_ALTITUDE: number = 39; public static RELATIVE_MOVE: number = 40; + public static CONTROL_CLOCK: number = 41; + public static ADJUST_CLOCK: number = 42; } diff --git a/src/api/wired/WiredConditionLayoutCode.ts b/src/api/wired/WiredConditionLayoutCode.ts index 58cae5d..d63b3e1 100644 --- a/src/api/wired/WiredConditionLayoutCode.ts +++ b/src/api/wired/WiredConditionLayoutCode.ts @@ -26,4 +26,5 @@ export class WiredConditionlayout public static NOT_ACTOR_WEARING_EFFECT: number = 23; public static DATE_RANGE_ACTIVE: number = 24; public static ACTOR_HAS_HANDITEM: number = 25; + public static COUNTER_TIME_MATCHES: number = 27; } diff --git a/src/api/wired/WiredTriggerLayoutCode.ts b/src/api/wired/WiredTriggerLayoutCode.ts index ac80e07..6f6fbe8 100644 --- a/src/api/wired/WiredTriggerLayoutCode.ts +++ b/src/api/wired/WiredTriggerLayoutCode.ts @@ -21,4 +21,5 @@ export class WiredTriggerLayout public static CLICK_TILE: number = 19; public static CLICK_USER: number = 20; public static USER_PERFORMS_ACTION: number = 21; + public static CLOCK_COUNTER: number = 22; } diff --git a/src/components/wired/views/actions/WiredActionAdjustClockView.tsx b/src/components/wired/views/actions/WiredActionAdjustClockView.tsx new file mode 100644 index 0000000..8ae55ec --- /dev/null +++ b/src/components/wired/views/actions/WiredActionAdjustClockView.tsx @@ -0,0 +1,123 @@ +import { FC, useEffect, useMemo, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Slider, Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredSourcesSelector } from '../WiredSourcesSelector'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +const COUNTER_INTERACTION_TYPES = [ 'game_upcounter' ]; +const MINUTES_MIN = 0; +const MINUTES_MAX = 99; +const HALF_SECONDS_MIN = 0; +const HALF_SECONDS_MAX = 119; + +const OPERATOR_OPTIONS = [ + { value: 0, label: 'wiredfurni.params.operator.0' }, + { value: 1, label: 'wiredfurni.params.operator.1' }, + { value: 2, label: 'wiredfurni.params.operator.2' } +]; + +const normalizeOperator = (value: number) => +{ + if(value < 0 || value > 2) return 2; + + return value; +}; + +const normalizeMinutes = (value: number) => Math.max(MINUTES_MIN, Math.min(MINUTES_MAX, value)); +const normalizeHalfSeconds = (value: number) => Math.max(HALF_SECONDS_MIN, Math.min(HALF_SECONDS_MAX, value)); + +const formatSeconds = (halfSeconds: number) => +{ + const value = normalizeHalfSeconds(halfSeconds) / 2; + const text = value.toFixed(1); + + return text.endsWith('.0') ? text.slice(0, -2) : text; +}; + +export const WiredActionAdjustClockView: FC<{}> = () => +{ + const { trigger = null, setIntParams = null, setAllowedInteractionTypes = null, setAllowedInteractionErrorKey = null } = useWired(); + const [ operator, setOperator ] = useState(2); + const [ furniSource, setFurniSource ] = useState(() => + { + if(trigger?.intData?.length > 1) return trigger.intData[1]; + return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0; + }); + const [ minutes, setMinutes ] = useState(0); + const [ halfSeconds, setHalfSeconds ] = useState(0); + + const secondsLabel = useMemo(() => formatSeconds(halfSeconds), [ halfSeconds ]); + + useEffect(() => + { + if(!trigger) return; + + setOperator((trigger.intData.length > 0) ? normalizeOperator(trigger.intData[0]) : 2); + setFurniSource((trigger.intData.length > 1) ? trigger.intData[1] : ((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0)); + setMinutes((trigger.intData.length > 2) ? normalizeMinutes(trigger.intData[2]) : 0); + setHalfSeconds((trigger.intData.length > 3) ? normalizeHalfSeconds(trigger.intData[3]) : 0); + }, [ trigger ]); + + useEffect(() => + { + setAllowedInteractionTypes(COUNTER_INTERACTION_TYPES); + setAllowedInteractionErrorKey('wiredfurni.error.require_counter_furni'); + + return () => + { + setAllowedInteractionTypes(null); + setAllowedInteractionErrorKey(null); + }; + }, [ setAllowedInteractionErrorKey, setAllowedInteractionTypes ]); + + const save = () => + { + setIntParams([ + operator, + furniSource, + normalizeMinutes(minutes), + normalizeHalfSeconds(halfSeconds) + ]); + }; + + return ( + }> +
+ { OPERATOR_OPTIONS.map(option => + { + return ( +
+ setOperator(option.value) } /> + { LocalizeText(option.label) } +
+ ); + }) } +
+
+ { LocalizeText('wiredfurni.params.time.minute_selection') } + setMinutes(normalizeMinutes(event as number)) } /> + { minutes } +
+
+ { LocalizeText('wiredfurni.params.time.second_selection') } + setHalfSeconds(normalizeHalfSeconds(event as number)) } /> + { secondsLabel } +
+
+ ); +}; diff --git a/src/components/wired/views/actions/WiredActionControlClockView.tsx b/src/components/wired/views/actions/WiredActionControlClockView.tsx new file mode 100644 index 0000000..cba4691 --- /dev/null +++ b/src/components/wired/views/actions/WiredActionControlClockView.tsx @@ -0,0 +1,82 @@ +import { FC, useEffect, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredSourcesSelector } from '../WiredSourcesSelector'; +import { WiredActionBaseView } from './WiredActionBaseView'; + +const COUNTER_INTERACTION_TYPES = [ 'game_upcounter' ]; + +const CONTROL_OPTIONS = [ + { value: 0, label: 'wiredfurni.params.clock_control.0' }, + { value: 1, label: 'wiredfurni.params.clock_control.1' }, + { value: 2, label: 'wiredfurni.params.clock_control.2' }, + { value: 3, label: 'wiredfurni.params.clock_control.3' }, + { value: 4, label: 'wiredfurni.params.clock_control.4' } +]; + +const normalizeControl = (value: number) => +{ + if(value < 0 || value > 4) return 0; + + return value; +}; + +export const WiredActionControlClockView: FC<{}> = () => +{ + const { trigger = null, setIntParams = null, setAllowedInteractionTypes = null, setAllowedInteractionErrorKey = null } = useWired(); + const [ control, setControl ] = useState(0); + const [ furniSource, setFurniSource ] = useState(() => + { + if(trigger?.intData?.length > 1) return trigger.intData[1]; + return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0; + }); + + const save = () => + { + setIntParams([ + control, + furniSource + ]); + }; + + useEffect(() => + { + if(!trigger) return; + + setControl((trigger.intData.length > 0) ? normalizeControl(trigger.intData[0]) : 0); + setFurniSource((trigger.intData.length > 1) ? trigger.intData[1] : ((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0)); + }, [ trigger ]); + + useEffect(() => + { + setAllowedInteractionTypes(COUNTER_INTERACTION_TYPES); + setAllowedInteractionErrorKey('wiredfurni.error.require_counter_furni'); + + return () => + { + setAllowedInteractionTypes(null); + setAllowedInteractionErrorKey(null); + }; + }, [ setAllowedInteractionErrorKey, setAllowedInteractionTypes ]); + + return ( + }> +
+ { CONTROL_OPTIONS.map(option => + { + return ( +
+ setControl(option.value) } /> + { LocalizeText(option.label) } +
+ ); + }) } +
+
+ ); +}; diff --git a/src/components/wired/views/actions/WiredActionLayoutView.tsx b/src/components/wired/views/actions/WiredActionLayoutView.tsx index f515b63..c445dbb 100644 --- a/src/components/wired/views/actions/WiredActionLayoutView.tsx +++ b/src/components/wired/views/actions/WiredActionLayoutView.tsx @@ -1,6 +1,8 @@ import { WiredActionLayoutCode } from '../../../../api'; import { WiredActionBotChangeFigureView } from './WiredActionBotChangeFigureView'; +import { WiredActionAdjustClockView } from './WiredActionAdjustClockView'; import { WiredActionFreezeView } from './WiredActionFreezeView'; +import { WiredActionControlClockView } from './WiredActionControlClockView'; import { WiredActionFurniToFurniView } from './WiredActionFurniToFurniView'; import { WiredActionSetAltitudeView } from './WiredActionSetAltitudeView'; import { WiredActionSendSignalView } from './WiredActionSendSignalView'; @@ -42,6 +44,8 @@ export const WiredActionLayoutView = (code: number) => { case WiredActionLayoutCode.BOT_CHANGE_FIGURE: return ; + case WiredActionLayoutCode.ADJUST_CLOCK: + return ; case WiredActionLayoutCode.BOT_FOLLOW_AVATAR: return ; case WiredActionLayoutCode.BOT_GIVE_HAND_ITEM: @@ -64,6 +68,8 @@ export const WiredActionLayoutView = (code: number) => return ; case WiredActionLayoutCode.FREEZE: return ; + case WiredActionLayoutCode.CONTROL_CLOCK: + return ; case WiredActionLayoutCode.FURNI_TO_USER: return ; case WiredActionLayoutCode.FURNI_TO_FURNI: diff --git a/src/components/wired/views/conditions/WiredConditionCounterTimeMatchesView.tsx b/src/components/wired/views/conditions/WiredConditionCounterTimeMatchesView.tsx new file mode 100644 index 0000000..fb68c4e --- /dev/null +++ b/src/components/wired/views/conditions/WiredConditionCounterTimeMatchesView.tsx @@ -0,0 +1,123 @@ +import { FC, useEffect, useMemo, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Slider, Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredSourcesSelector } from '../WiredSourcesSelector'; +import { WiredConditionBaseView } from './WiredConditionBaseView'; + +const COUNTER_INTERACTION_TYPES = [ 'game_upcounter' ]; +const MINUTES_MIN = 0; +const MINUTES_MAX = 99; +const HALF_SECONDS_MIN = 0; +const HALF_SECONDS_MAX = 119; + +const COMPARISON_OPTIONS = [ + { value: 0, label: 'wiredfurni.params.comparison.0' }, + { value: 1, label: 'wiredfurni.params.comparison.1' }, + { value: 2, label: 'wiredfurni.params.comparison.2' } +]; + +const normalizeComparison = (value: number) => +{ + if(value < 0 || value > 2) return 1; + + return value; +}; + +const normalizeMinutes = (value: number) => Math.max(MINUTES_MIN, Math.min(MINUTES_MAX, value)); +const normalizeHalfSeconds = (value: number) => Math.max(HALF_SECONDS_MIN, Math.min(HALF_SECONDS_MAX, value)); + +const formatSeconds = (halfSeconds: number) => +{ + const value = normalizeHalfSeconds(halfSeconds) / 2; + const text = value.toFixed(1); + + return text.endsWith('.0') ? text.slice(0, -2) : text; +}; + +export const WiredConditionCounterTimeMatchesView: FC<{}> = () => +{ + const { trigger = null, setIntParams = null, setAllowedInteractionTypes = null, setAllowedInteractionErrorKey = null } = useWired(); + const [ comparison, setComparison ] = useState(1); + const [ furniSource, setFurniSource ] = useState(() => + { + if(trigger?.intData?.length > 3) return trigger.intData[3]; + return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0; + }); + const [ minutes, setMinutes ] = useState(0); + const [ halfSeconds, setHalfSeconds ] = useState(0); + + const secondsLabel = useMemo(() => formatSeconds(halfSeconds), [ halfSeconds ]); + + const save = () => + { + setIntParams([ + normalizeComparison(comparison), + normalizeMinutes(minutes), + normalizeHalfSeconds(halfSeconds), + furniSource + ]); + }; + + useEffect(() => + { + if(!trigger) return; + + setComparison((trigger.intData.length > 0) ? normalizeComparison(trigger.intData[0]) : 1); + setMinutes((trigger.intData.length > 1) ? normalizeMinutes(trigger.intData[1]) : 0); + setHalfSeconds((trigger.intData.length > 2) ? normalizeHalfSeconds(trigger.intData[2]) : 0); + setFurniSource((trigger.intData.length > 3) ? trigger.intData[3] : ((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0)); + }, [ trigger ]); + + useEffect(() => + { + setAllowedInteractionTypes(COUNTER_INTERACTION_TYPES); + setAllowedInteractionErrorKey('wiredfurni.error.require_counter_furni'); + + return () => + { + setAllowedInteractionTypes(null); + setAllowedInteractionErrorKey(null); + }; + }, [ setAllowedInteractionErrorKey, setAllowedInteractionTypes ]); + + return ( + }> +
+ { COMPARISON_OPTIONS.map(option => + { + return ( +
+ setComparison(option.value) } /> + { LocalizeText(option.label) } +
+ ); + }) } +
+
+ { LocalizeText('wiredfurni.params.clock_minutes_elapsed', [ 'minutes' ], [ minutes.toString() ]) } + setMinutes(normalizeMinutes(event as number)) } /> + { minutes } +
+
+ { LocalizeText('wiredfurni.params.clock_seconds_elapsed', [ 'seconds' ], [ secondsLabel ]) } + setHalfSeconds(normalizeHalfSeconds(event as number)) } /> + { secondsLabel } +
+
+ ); +}; diff --git a/src/components/wired/views/conditions/WiredConditionLayoutView.tsx b/src/components/wired/views/conditions/WiredConditionLayoutView.tsx index a1a88c2..11c2a30 100644 --- a/src/components/wired/views/conditions/WiredConditionLayoutView.tsx +++ b/src/components/wired/views/conditions/WiredConditionLayoutView.tsx @@ -5,6 +5,7 @@ import { WiredConditionActorIsOnFurniView } from './WiredConditionActorIsOnFurni import { WiredConditionActorIsTeamMemberView } from './WiredConditionActorIsTeamMemberView'; import { WiredConditionActorIsWearingBadgeView } from './WiredConditionActorIsWearingBadgeView'; import { WiredConditionActorIsWearingEffectView } from './WiredConditionActorIsWearingEffectView'; +import { WiredConditionCounterTimeMatchesView } from './WiredConditionCounterTimeMatchesView'; import { WiredConditionDateRangeView } from './WiredConditionDateRangeView'; import { WiredConditionFurniHasAvatarOnView } from './WiredConditionFurniHasAvatarOnView'; import { WiredConditionFurniHasFurniOnView } from './WiredConditionFurniHasFurniOnView'; @@ -58,6 +59,8 @@ export const WiredConditionLayoutView = (code: number) => case WiredConditionlayout.USER_COUNT_IN: case WiredConditionlayout.NOT_USER_COUNT_IN: return ; + case WiredConditionlayout.COUNTER_TIME_MATCHES: + return ; } return null; diff --git a/src/components/wired/views/triggers/WiredTriggerBaseView.tsx b/src/components/wired/views/triggers/WiredTriggerBaseView.tsx index 7590d9a..2c51980 100644 --- a/src/components/wired/views/triggers/WiredTriggerBaseView.tsx +++ b/src/components/wired/views/triggers/WiredTriggerBaseView.tsx @@ -1,4 +1,4 @@ -import { FC, PropsWithChildren } from 'react'; +import { FC, PropsWithChildren, ReactNode } from 'react'; import { WiredFurniType } from '../../../../api'; import { WiredBaseView } from '../WiredBaseView'; @@ -7,16 +7,17 @@ export interface WiredTriggerBaseViewProps hasSpecialInput: boolean; requiresFurni: number; save: () => void; + footer?: ReactNode; } export const WiredTriggerBaseView: FC> = props => { - const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null } = props; + const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null, footer = null } = props; const onSave = () => (save && save()); return ( - + { children } ); diff --git a/src/components/wired/views/triggers/WiredTriggerClockCounterView.tsx b/src/components/wired/views/triggers/WiredTriggerClockCounterView.tsx new file mode 100644 index 0000000..5b6240c --- /dev/null +++ b/src/components/wired/views/triggers/WiredTriggerClockCounterView.tsx @@ -0,0 +1,101 @@ +import { FC, useEffect, useMemo, useState } from 'react'; +import { LocalizeText, WiredFurniType } from '../../../../api'; +import { Slider, Text } from '../../../../common'; +import { useWired } from '../../../../hooks'; +import { WiredSourcesSelector, WiredSourceOption } from '../WiredSourcesSelector'; +import { WiredTriggerBaseView } from './WiredTriggerBaseView'; + +const COUNTER_INTERACTION_TYPES = [ 'game_upcounter' ]; +const MINUTES_MIN = 0; +const MINUTES_MAX = 99; +const HALF_SECONDS_MIN = 0; +const HALF_SECONDS_MAX = 119; +const TRIGGER_FURNI_SOURCES: WiredSourceOption[] = [ + { value: 0, label: 'wiredfurni.params.sources.furni.0' }, + { value: 100, label: 'wiredfurni.params.sources.furni.100' } +]; + +const normalizeMinutes = (value: number) => Math.max(MINUTES_MIN, Math.min(MINUTES_MAX, value)); +const normalizeHalfSeconds = (value: number) => Math.max(HALF_SECONDS_MIN, Math.min(HALF_SECONDS_MAX, value)); +const normalizeFurniSource = (value: number) => (value === 100 ? 100 : 0); + +const formatSeconds = (halfSeconds: number) => +{ + const value = normalizeHalfSeconds(halfSeconds) / 2; + const text = value.toFixed(1); + + return text.endsWith('.0') ? text.slice(0, -2) : text; +}; + +export const WiredTriggerClockCounterView: FC<{}> = () => +{ + const { trigger = null, setIntParams = null, setAllowedInteractionTypes = null, setAllowedInteractionErrorKey = null } = useWired(); + const [ furniSource, setFurniSource ] = useState(() => + { + if(trigger?.intData?.length > 2) return normalizeFurniSource(trigger.intData[2]); + return (trigger?.selectedItems?.length ?? 0) > 0 ? 100 : 0; + }); + const [ minutes, setMinutes ] = useState(0); + const [ halfSeconds, setHalfSeconds ] = useState(0); + + const secondsLabel = useMemo(() => formatSeconds(halfSeconds), [ halfSeconds ]); + + const save = () => + { + setIntParams([ + normalizeMinutes(minutes), + normalizeHalfSeconds(halfSeconds), + normalizeFurniSource(furniSource) + ]); + }; + + useEffect(() => + { + if(!trigger) return; + + setMinutes((trigger.intData.length > 0) ? normalizeMinutes(trigger.intData[0]) : 0); + setHalfSeconds((trigger.intData.length > 1) ? normalizeHalfSeconds(trigger.intData[1]) : 0); + setFurniSource((trigger.intData.length > 2) ? normalizeFurniSource(trigger.intData[2]) : ((trigger.selectedItems?.length ?? 0) > 0 ? 100 : 0)); + }, [ trigger ]); + + useEffect(() => + { + setAllowedInteractionTypes(COUNTER_INTERACTION_TYPES); + setAllowedInteractionErrorKey('wiredfurni.error.require_counter_furni'); + + return () => + { + setAllowedInteractionTypes(null); + setAllowedInteractionErrorKey(null); + }; + }, [ setAllowedInteractionErrorKey, setAllowedInteractionTypes ]); + + return ( + }> +
+ { LocalizeText('wiredfurni.params.clock_minutes_elapsed', [ 'minutes' ], [ minutes.toString() ]) } + setMinutes(normalizeMinutes(event as number)) } /> + { minutes } +
+
+ { LocalizeText('wiredfurni.params.clock_seconds_elapsed', [ 'seconds' ], [ secondsLabel ]) } + setHalfSeconds(normalizeHalfSeconds(event as number)) } /> + { secondsLabel } +
+
+ ); +}; diff --git a/src/components/wired/views/triggers/WiredTriggerLayoutView.tsx b/src/components/wired/views/triggers/WiredTriggerLayoutView.tsx index 3b152fb..409bdf0 100644 --- a/src/components/wired/views/triggers/WiredTriggerLayoutView.tsx +++ b/src/components/wired/views/triggers/WiredTriggerLayoutView.tsx @@ -9,6 +9,7 @@ import { WiredTriggerBotReachedStuffView } from './WiredTriggerBotReachedStuffVi import { WiredTriggerClickFurniView } from './WiredTriggerClickFurniView'; import { WiredTriggerClickTileView } from './WiredTriggerClickTileView'; import { WiredTriggerClickUserView } from './WiredTriggerClickUserView'; +import { WiredTriggerClockCounterView } from './WiredTriggerClockCounterView'; import { WiredTriggerCollisionView } from './WiredTriggerCollisionView'; import { WiredTriggerUserPerformsActionView } from './WiredTriggerUserPerformsActionView'; import { WiredTriggeExecuteOnceView } from './WiredTriggerExecuteOnceView'; @@ -45,6 +46,8 @@ export const WiredTriggerLayoutView = (code: number) => return ; case WiredTriggerLayout.CLICK_USER: return ; + case WiredTriggerLayout.CLOCK_COUNTER: + return ; case WiredTriggerLayout.USER_PERFORMS_ACTION: return ; case WiredTriggerLayout.COLLISION: diff --git a/src/hooks/wired/useWired.ts b/src/hooks/wired/useWired.ts index 19e6ed8..884137f 100644 --- a/src/hooks/wired/useWired.ts +++ b/src/hooks/wired/useWired.ts @@ -17,6 +17,7 @@ const useWiredState = () => const [ neighborhoodTiles, setNeighborhoodTiles ] = useState<{ x: number; y: number }[] | null>(null); const [ neighborhoodInvert, setNeighborhoodInvert ] = useState(false); const [ allowedInteractionTypes, setAllowedInteractionTypes ] = useState(null); + const [ allowedInteractionErrorKey, setAllowedInteractionErrorKey ] = useState(null); const { showConfirm = null, simpleAlert = null } = useNotification(); const saveWired = () => @@ -84,6 +85,11 @@ const useWiredState = () => return allowedInteractionTypes.some(type => (type && type.toLowerCase() === interactionType)); }; + const handleDisallowedInteraction = () => + { + if(allowedInteractionErrorKey) simpleAlert(LocalizeText(allowedInteractionErrorKey), null, null, null, LocalizeText('wiredfurni.title')); + }; + if(selectByType && category === RoomObjectCategory.FLOOR) { const roomId = GetRoomSession().roomId; @@ -97,6 +103,7 @@ const useWiredState = () => if(!sourceFurniData) return; if(!isAllowedInteraction(sourceFurniData)) { + handleDisallowedInteraction(); setFurniIds(prevValue => { if(!prevValue.includes(objectId)) return prevValue; @@ -185,6 +192,7 @@ const useWiredState = () => if(!sourceFurniData) return; if(!isAllowedInteraction(sourceFurniData)) { + handleDisallowedInteraction(); setFurniIds(prevValue => { if(!prevValue.includes(objectId)) return prevValue; @@ -245,7 +253,9 @@ const useWiredState = () => if(parser.info && parser.info.length) { - simpleAlert(parser.info, null, null, null, LocalizeText('wiredfurni.title')); + const message = (/^[a-z0-9_.]+$/i.test(parser.info) ? LocalizeText(parser.info) : parser.info); + + simpleAlert(message, null, null, null, LocalizeText('wiredfurni.title')); } }); @@ -291,10 +301,11 @@ const useWiredState = () => setNeighborhoodTiles(null); setNeighborhoodInvert(false); setAllowedInteractionTypes(null); + setAllowedInteractionErrorKey(null); }; }, [ trigger ]); - return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired, setSelectByType, setNeighborhoodTiles, setNeighborhoodInvert, setAllowedInteractionTypes }; + return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired, setSelectByType, setNeighborhoodTiles, setNeighborhoodInvert, setAllowedInteractionTypes, setAllowedInteractionErrorKey }; }; export const useWired = () => useBetween(useWiredState);