mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
🆕 Added wired wf_slc_furni_bytype
This commit is contained in:
@@ -28,4 +28,5 @@ export class WiredActionLayoutCode
|
||||
public static BOT_TALK_DIRECT_TO_AVTR: number = 27;
|
||||
public static FURNI_AREA_SELECTOR: number = 28;
|
||||
public static FURNI_NEIGHBORHOOD_SELECTOR: number = 29;
|
||||
public static FURNI_BYTYPE_SELECTOR: number = 30;
|
||||
}
|
||||
|
||||
@@ -11,11 +11,12 @@ export interface WiredActionBaseViewProps
|
||||
requiresFurni: number;
|
||||
save: () => void;
|
||||
cardStyle?: CSSProperties;
|
||||
hideDelay?: boolean;
|
||||
}
|
||||
|
||||
export const WiredActionBaseView: FC<PropsWithChildren<WiredActionBaseViewProps>> = props =>
|
||||
{
|
||||
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null, cardStyle = undefined } = props;
|
||||
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, hasSpecialInput = false, children = null, cardStyle = undefined, hideDelay = false } = props;
|
||||
const { trigger = null, actionDelay = 0, setActionDelay = null } = useWired();
|
||||
|
||||
useEffect(() =>
|
||||
@@ -26,15 +27,15 @@ export const WiredActionBaseView: FC<PropsWithChildren<WiredActionBaseViewProps>
|
||||
return (
|
||||
<WiredBaseView hasSpecialInput={ hasSpecialInput } requiresFurni={ requiresFurni } save={ save } wiredType="action" cardStyle={ cardStyle }>
|
||||
{ children }
|
||||
{ !!children && <hr className="m-0 bg-dark" /> }
|
||||
<div className="flex flex-col">
|
||||
{ !hideDelay && !!children && <hr className="m-0 bg-dark" /> }
|
||||
{ !hideDelay && <div className="flex flex-col">
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.delay', [ 'seconds' ], [ GetWiredTimeLocale(actionDelay) ]) }</Text>
|
||||
<Slider
|
||||
max={ 20 }
|
||||
min={ 0 }
|
||||
value={ actionDelay }
|
||||
onChange={ event => setActionDelay(event) } />
|
||||
</div>
|
||||
</div> }
|
||||
</WiredBaseView>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import { WiredActionLayoutCode } from '../../../../api';
|
||||
import { WiredActionBotChangeFigureView } from './WiredActionBotChangeFigureView';
|
||||
import { WiredActionFurniAreaView } from '../selectors/WiredActionFurniAreaView';
|
||||
import { WiredSelectorFurniNeighborhoodView } from '../selectors/WiredSelectorFurniNeighborhoodView';
|
||||
import { WiredSelectorFurniByTypeView } from '../selectors/WiredSelectorFurniByTypeView';
|
||||
import { WiredActionBotFollowAvatarView } from './WiredActionBotFollowAvatarView';
|
||||
import { WiredActionBotGiveHandItemView } from './WiredActionBotGiveHandItemView';
|
||||
import { WiredActionBotMoveView } from './WiredActionBotMoveView';
|
||||
@@ -85,6 +86,8 @@ export const WiredActionLayoutView = (code: number) =>
|
||||
return <WiredActionFurniAreaView />;
|
||||
case WiredActionLayoutCode.FURNI_NEIGHBORHOOD_SELECTOR:
|
||||
return <WiredSelectorFurniNeighborhoodView />;
|
||||
case WiredActionLayoutCode.FURNI_BYTYPE_SELECTOR:
|
||||
return <WiredSelectorFurniByTypeView />;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
import { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { FaChevronLeft, FaChevronRight } from 'react-icons/fa';
|
||||
import { LocalizeText, WiredFurniType } from '../../../../api';
|
||||
import { Button, Text } from '../../../../common';
|
||||
import { useWired } from '../../../../hooks';
|
||||
import { WiredActionBaseView } from '../actions/WiredActionBaseView';
|
||||
|
||||
const SOURCE_FURNI_PICKED = 0;
|
||||
const SOURCE_FURNI_SIGNAL = 1;
|
||||
const SOURCE_FURNI_TRIGGER = 2;
|
||||
|
||||
const SOURCES = [
|
||||
{ value: SOURCE_FURNI_PICKED, label: 'wiredfurni.params.sources.furni.100' },
|
||||
{ value: SOURCE_FURNI_SIGNAL, label: 'wiredfurni.params.sources.furni.201' },
|
||||
{ value: SOURCE_FURNI_TRIGGER, label: 'wiredfurni.params.sources.furni.0' },
|
||||
];
|
||||
|
||||
export const WiredSelectorFurniByTypeView: FC<{}> = () =>
|
||||
{
|
||||
const [ sourceType, setSourceType ] = useState(SOURCE_FURNI_PICKED);
|
||||
const [ matchState, setMatchState ] = useState(false);
|
||||
const [ filterExisting, setFilterExisting ] = useState(false);
|
||||
const [ invert, setInvert ] = useState(false);
|
||||
|
||||
const { trigger = null, furniIds = [], setIntParams, setSelectByType, setInvertSelection } = useWired();
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
if(!trigger) return;
|
||||
|
||||
const p = trigger.intData;
|
||||
if(p.length >= 1) setSourceType(p[0]);
|
||||
if(p.length >= 2) setMatchState(p[1] === 1);
|
||||
if(p.length >= 3) setFilterExisting(p[2] === 1);
|
||||
if(p.length >= 4) setInvert(p[3] === 1);
|
||||
}, [ trigger ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setSelectByType(sourceType === SOURCE_FURNI_PICKED);
|
||||
}, [ sourceType, setSelectByType ]);
|
||||
|
||||
useEffect(() =>
|
||||
{
|
||||
setInvertSelection(invert);
|
||||
}, [ invert, setInvertSelection ]);
|
||||
|
||||
const save = useCallback(() =>
|
||||
{
|
||||
setIntParams([
|
||||
sourceType,
|
||||
matchState ? 1 : 0,
|
||||
filterExisting ? 1 : 0,
|
||||
invert ? 1 : 0,
|
||||
]);
|
||||
}, [ sourceType, matchState, filterExisting, invert, setIntParams ]);
|
||||
|
||||
const sourceIndex = SOURCES.findIndex(s => s.value === sourceType);
|
||||
|
||||
const prevSource = () =>
|
||||
setSourceType(SOURCES[(sourceIndex - 1 + SOURCES.length) % SOURCES.length].value);
|
||||
|
||||
const nextSource = () =>
|
||||
setSourceType(SOURCES[(sourceIndex + 1) % SOURCES.length].value);
|
||||
|
||||
const requiresFurni = sourceType === SOURCE_FURNI_PICKED
|
||||
? WiredFurniType.STUFF_SELECTION_OPTION_BY_ID
|
||||
: WiredFurniType.STUFF_SELECTION_OPTION_NONE;
|
||||
|
||||
const pickedCount = furniIds.length;
|
||||
const pickedLimit = trigger?.maximumItemSelectionCount ?? 20;
|
||||
|
||||
return (
|
||||
<WiredActionBaseView hasSpecialInput={ true } requiresFurni={ requiresFurni } save={ save } hideDelay={ true } cardStyle={ { width: 400 } }>
|
||||
<div className="flex flex-col gap-2">
|
||||
|
||||
<label className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
checked={ matchState }
|
||||
onChange={ e => setMatchState(e.target.checked) } />
|
||||
<Text small>{ LocalizeText('wiredfurni.params.state_match') }</Text>
|
||||
</label>
|
||||
|
||||
<hr className="m-0 bg-dark" />
|
||||
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.selector_options_selector') }</Text>
|
||||
|
||||
<label className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
checked={ filterExisting }
|
||||
onChange={ e => setFilterExisting(e.target.checked) } />
|
||||
<Text small>{ LocalizeText('wiredfurni.params.selector_option.0') }</Text>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-2">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="form-check-input"
|
||||
checked={ invert }
|
||||
onChange={ e => setInvert(e.target.checked) } />
|
||||
<Text small>{ LocalizeText('wiredfurni.params.selector_option.1') }</Text>
|
||||
</label>
|
||||
|
||||
<hr className="m-0 bg-dark" />
|
||||
|
||||
<Text bold>{ LocalizeText('wiredfurni.params.sources.furni.title') }</Text>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Button variant="primary" className="px-2 py-1" onClick={ prevSource }>
|
||||
<FaChevronLeft />
|
||||
</Button>
|
||||
<div className="flex flex-1 items-center justify-center">
|
||||
<Text small>{ LocalizeText(SOURCES[sourceIndex >= 0 ? sourceIndex : 0].label) }</Text>
|
||||
</div>
|
||||
<Button variant="primary" className="px-2 py-1" onClick={ nextSource }>
|
||||
<FaChevronRight />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</WiredActionBaseView>
|
||||
);
|
||||
};
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ConditionDefinition, OpenMessageComposer, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition, WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredOpenEvent, WiredSaveSuccessEvent } from '@nitrots/nitro-renderer';
|
||||
import { ConditionDefinition, GetRoomEngine, GetSessionDataManager, OpenMessageComposer, RoomObjectCategory, RoomObjectVariable, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition, WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredOpenEvent, WiredSaveSuccessEvent } from '@nitrots/nitro-renderer';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useBetween } from 'use-between';
|
||||
import { IsOwnerOfFloorFurniture, LocalizeText, SendMessageComposer, WiredFurniType, WiredSelectionVisualizer } from '../../api';
|
||||
import { GetRoomSession, IsOwnerOfFloorFurniture, LocalizeText, SendMessageComposer, WiredFurniType, WiredSelectionVisualizer } from '../../api';
|
||||
import { useMessageEvent } from '../events';
|
||||
import { useNotification } from '../notification';
|
||||
|
||||
@@ -13,6 +13,8 @@ const useWiredState = () =>
|
||||
const [ furniIds, setFurniIds ] = useState<number[]>([]);
|
||||
const [ actionDelay, setActionDelay ] = useState<number>(0);
|
||||
const [ allowsFurni, setAllowsFurni ] = useState<number>(WiredFurniType.STUFF_SELECTION_OPTION_NONE);
|
||||
const [ selectByType, setSelectByType ] = useState<boolean>(false);
|
||||
const [ invertSelection, setInvertSelection ] = useState<boolean>(false);
|
||||
const { showConfirm = null } = useNotification();
|
||||
|
||||
const saveWired = () =>
|
||||
@@ -56,6 +58,77 @@ const useWiredState = () =>
|
||||
|
||||
if(objectId <= 0) return;
|
||||
|
||||
if(selectByType && category === RoomObjectCategory.FLOOR)
|
||||
{
|
||||
const roomId = GetRoomSession().roomId;
|
||||
const clickedObject = GetRoomEngine().getRoomObject(roomId, objectId, RoomObjectCategory.FLOOR);
|
||||
|
||||
if(!clickedObject) return;
|
||||
|
||||
const typeId = clickedObject.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
const sourceFurniData = GetSessionDataManager().getFloorItemData(typeId);
|
||||
|
||||
if(!sourceFurniData) return;
|
||||
|
||||
const matchFurniLine = sourceFurniData.furniLine;
|
||||
const matchName = sourceFurniData.name;
|
||||
|
||||
const isSameGroup = (id: number): boolean =>
|
||||
{
|
||||
const obj = GetRoomEngine().getRoomObject(roomId, id, RoomObjectCategory.FLOOR);
|
||||
if(!obj) return false;
|
||||
|
||||
const tId = obj.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
const fd = GetSessionDataManager().getFloorItemData(tId);
|
||||
if(!fd) return false;
|
||||
|
||||
const furniLineMatch = matchFurniLine && matchFurniLine.length > 0 && fd.furniLine === matchFurniLine;
|
||||
return furniLineMatch || fd.name === matchName;
|
||||
};
|
||||
|
||||
setFurniIds(prevValue =>
|
||||
{
|
||||
// ── Click on already-selected furni: deselect the whole group ──
|
||||
if(prevValue.includes(objectId))
|
||||
{
|
||||
const toRemove = prevValue.filter(id => isSameGroup(id));
|
||||
const remaining = prevValue.filter(id => !toRemove.includes(id));
|
||||
|
||||
WiredSelectionVisualizer.clearSelectionShaderFromFurni(toRemove);
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
// ── Select a new group ──────────────────────────────────────
|
||||
if(prevValue && prevValue.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue);
|
||||
|
||||
const allFloorObjects = GetRoomEngine().getRoomObjects(roomId, RoomObjectCategory.FLOOR);
|
||||
const newIds: number[] = [];
|
||||
const limit = trigger.maximumItemSelectionCount;
|
||||
|
||||
for(const obj of allFloorObjects)
|
||||
{
|
||||
if(newIds.length >= limit) break;
|
||||
if(obj.id < 0) continue;
|
||||
|
||||
const tId = obj.model.getValue<number>(RoomObjectVariable.FURNITURE_TYPE_ID);
|
||||
const fd = GetSessionDataManager().getFloorItemData(tId);
|
||||
if(!fd) continue;
|
||||
|
||||
const furniLineMatch = matchFurniLine && matchFurniLine.length > 0 && fd.furniLine === matchFurniLine;
|
||||
const matches = furniLineMatch || fd.name === matchName;
|
||||
|
||||
if(invertSelection ? !matches : matches) newIds.push(obj.id);
|
||||
}
|
||||
|
||||
WiredSelectionVisualizer.applySelectionShaderToFurni(newIds);
|
||||
|
||||
return newIds;
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
setFurniIds(prevValue =>
|
||||
{
|
||||
const newFurniIds = [ ...prevValue ];
|
||||
@@ -131,10 +204,12 @@ const useWiredState = () =>
|
||||
return [];
|
||||
});
|
||||
setAllowsFurni(WiredFurniType.STUFF_SELECTION_OPTION_NONE);
|
||||
setSelectByType(false);
|
||||
setInvertSelection(false);
|
||||
};
|
||||
}, [ trigger ]);
|
||||
|
||||
return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired };
|
||||
return { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay, setAllowsFurni, saveWired, selectObjectForWired, setSelectByType, setInvertSelection };
|
||||
};
|
||||
|
||||
export const useWired = () => useBetween(useWiredState);
|
||||
|
||||
Reference in New Issue
Block a user