Merge branch '@feature/wired' into dev

This commit is contained in:
Bill 2021-06-30 02:07:19 -04:00
commit dfaf239052
102 changed files with 3200 additions and 26 deletions

View File

@ -12,5 +12,6 @@
"git.ignoreLimitWarning": true, "git.ignoreLimitWarning": true,
"files.eol": "\n", "files.eol": "\n",
"files.insertFinalNewline": true, "files.insertFinalNewline": true,
"files.trimFinalNewlines": true "files.trimFinalNewlines": true,
"editor.wordWrap": "on"
} }

89
package-lock.json generated
View File

@ -2376,6 +2376,15 @@
"redux": "^4.0.0" "redux": "^4.0.0"
} }
}, },
"@types/react-slider": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/@types/react-slider/-/react-slider-1.3.0.tgz",
"integrity": "sha512-Hr+P8wiqYAjeFTlf+NWPVGWW79npC8V7KkZdbPlMqo+iblcopPzE/z0m8503j2YmfxoKJKaPnrJe0a6spXacYQ==",
"dev": true,
"requires": {
"@types/react": "*"
}
},
"@types/react-transition-group": { "@types/react-transition-group": {
"version": "4.4.1", "version": "4.4.1",
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz",
@ -5268,6 +5277,11 @@
"resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz",
"integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==" "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ=="
}, },
"dom-align": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/dom-align/-/dom-align-1.12.2.tgz",
"integrity": "sha512-pHuazgqrsTFrGU2WLDdXxCFabkdQDx72ddkraZNih1KsMcN5qsRSTR9O4VJRlwTPCPb5COYg3LOfiMHHcPInHg=="
},
"dom-converter": { "dom-converter": {
"version": "0.2.0", "version": "0.2.0",
"resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz", "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
@ -14739,6 +14753,71 @@
} }
} }
}, },
"rc-align": {
"version": "4.0.9",
"resolved": "https://registry.npmjs.org/rc-align/-/rc-align-4.0.9.tgz",
"integrity": "sha512-myAM2R4qoB6LqBul0leaqY8gFaiECDJ3MtQDmzDo9xM9NRT/04TvWOYd2YHU9zvGzqk9QXF6S9/MifzSKDZeMw==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"dom-align": "^1.7.0",
"rc-util": "^5.3.0",
"resize-observer-polyfill": "^1.5.1"
}
},
"rc-motion": {
"version": "2.4.4",
"resolved": "https://registry.npmjs.org/rc-motion/-/rc-motion-2.4.4.tgz",
"integrity": "sha512-ms7n1+/TZQBS0Ydd2Q5P4+wJTSOrhIrwNxLXCZpR7Fa3/oac7Yi803HDALc2hLAKaCTQtw9LmQeB58zcwOsqlQ==",
"requires": {
"@babel/runtime": "^7.11.1",
"classnames": "^2.2.1",
"rc-util": "^5.2.1"
}
},
"rc-slider": {
"version": "9.7.2",
"resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-9.7.2.tgz",
"integrity": "sha512-mVaLRpDo6otasBs6yVnG02ykI3K6hIrLTNfT5eyaqduFv95UODI9PDS6fWuVVehVpdS4ENgOSwsTjrPVun+k9g==",
"requires": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
"rc-tooltip": "^5.0.1",
"rc-util": "^5.0.0",
"shallowequal": "^1.1.0"
}
},
"rc-tooltip": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-5.1.1.tgz",
"integrity": "sha512-alt8eGMJulio6+4/uDm7nvV+rJq9bsfxFDCI0ljPdbuoygUscbsMYb6EQgwib/uqsXQUvzk+S7A59uYHmEgmDA==",
"requires": {
"@babel/runtime": "^7.11.2",
"rc-trigger": "^5.0.0"
}
},
"rc-trigger": {
"version": "5.2.9",
"resolved": "https://registry.npmjs.org/rc-trigger/-/rc-trigger-5.2.9.tgz",
"integrity": "sha512-0Bxsh2Xe+etejMn73am+jZBcOpsueAZiEKLiGoDfA0fvm/JHLNOiiww3zJ0qgyPOTmbYxhsxFcGOZu+VcbaZhQ==",
"requires": {
"@babel/runtime": "^7.11.2",
"classnames": "^2.2.6",
"rc-align": "^4.0.0",
"rc-motion": "^2.0.0",
"rc-util": "^5.5.0"
}
},
"rc-util": {
"version": "5.13.1",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.13.1.tgz",
"integrity": "sha512-Dws2tjXBBihfjVQFlG5JzZ/5O3Wutctm0W94Wb1+M7GD2roWJPrQdSa4AkWm2pn0Ms32zoVPPkWodFeAYZPLfA==",
"requires": {
"@babel/runtime": "^7.12.5",
"react-is": "^16.12.0",
"shallowequal": "^1.1.0"
}
},
"react": { "react": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
@ -15430,6 +15509,11 @@
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
"integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
}, },
"resize-observer-polyfill": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz",
"integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg=="
},
"resolve": { "resolve": {
"version": "1.18.1", "version": "1.18.1",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.18.1.tgz",
@ -16220,6 +16304,11 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"shallowequal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz",
"integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="
},
"shebang-command": { "shebang-command": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",

View File

@ -15,6 +15,7 @@
"immutable": "^4.0.0-rc.12", "immutable": "^4.0.0-rc.12",
"nitro-renderer": "file:../nitro-renderer", "nitro-renderer": "file:../nitro-renderer",
"node-sass": "^5.0.0", "node-sass": "^5.0.0",
"rc-slider": "^9.7.2",
"react": "^17.0.2", "react": "^17.0.2",
"react-bootstrap": "^2.0.0-alpha.2", "react-bootstrap": "^2.0.0-alpha.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
@ -58,6 +59,7 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@types/react-slider": "^1.3.0",
"@types/react-transition-group": "^4.4.1" "@types/react-transition-group": "^4.4.1"
} }
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 B

After

Width:  |  Height:  |  Size: 197 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 172 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 B

After

Width:  |  Height:  |  Size: 157 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 187 B

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 B

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 B

After

Width:  |  Height:  |  Size: 171 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 B

After

Width:  |  Height:  |  Size: 169 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 198 B

After

Width:  |  Height:  |  Size: 153 B

View File

@ -5,3 +5,4 @@ export * from './inventory';
export * from './navigator'; export * from './navigator';
export * from './notification-center'; export * from './notification-center';
export * from './room-widgets'; export * from './room-widgets';
export * from './wired';

View File

@ -0,0 +1,6 @@
import { NitroEvent } from 'nitro-renderer';
export class WiredEvent extends NitroEvent
{
public static SAVE_WIRED: string = 'WE_SAVE_WIRED';
}

View File

@ -0,0 +1,27 @@
import { WiredEvent } from './WiredEvent';
export class WiredSelectObjectEvent extends WiredEvent
{
public static SELECT_OBJECT: string = 'WE_SELECT_OBJECT';
private _objectId: number;
private _category: number;
constructor(objectId = -1, category = -1)
{
super(WiredSelectObjectEvent.SELECT_OBJECT);
this._objectId = objectId;
this._category = category;
}
public get objectId(): number
{
return this._objectId;
}
public get category(): number
{
return this._category;
}
}

View File

@ -0,0 +1,2 @@
export * from './WiredEvent';
export * from './WiredSelectObjectEvent';

View File

@ -1,5 +1,6 @@
@import url('https://fonts.googleapis.com/css2?family=Ubuntu+Condensed:wght@300;400;500&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Ubuntu+Condensed:wght@300;400;500&display=swap');
@import '../node_modules/animate.css/animate.css'; @import '../node_modules/animate.css/animate.css';
@import '../node_modules/rc-slider/assets/index.css';
@import './assets/styles'; @import './assets/styles';
html, html,

View File

@ -14,3 +14,4 @@
@import './room/RoomView'; @import './room/RoomView';
@import './room-host/RoomHostView'; @import './room-host/RoomHostView';
@import './toolbar/ToolbarView'; @import './toolbar/ToolbarView';
@import './wired/WiredView';

View File

@ -11,6 +11,7 @@ import { NotificationCenterView } from '../notification-center/NotificationCente
import { RightSideView } from '../right-side/RightSideView'; import { RightSideView } from '../right-side/RightSideView';
import { RoomHostView } from '../room-host/RoomHostView'; import { RoomHostView } from '../room-host/RoomHostView';
import { ToolbarView } from '../toolbar/ToolbarView'; import { ToolbarView } from '../toolbar/ToolbarView';
import { WiredView } from '../wired/WiredView';
import { MainViewProps } from './MainView.types'; import { MainViewProps } from './MainView.types';
export const MainView: FC<MainViewProps> = props => export const MainView: FC<MainViewProps> = props =>
@ -46,6 +47,7 @@ export const MainView: FC<MainViewProps> = props =>
{ landingViewVisible && <HotelView /> } { landingViewVisible && <HotelView /> }
<ToolbarView isInRoom={ !landingViewVisible } /> <ToolbarView isInRoom={ !landingViewVisible } />
<RoomHostView /> <RoomHostView />
<WiredView />
<AvatarEditorView /> <AvatarEditorView />
<NavigatorView /> <NavigatorView />
<InventoryView /> <InventoryView />

View File

@ -1,5 +1,7 @@
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 { 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 { GetConnection, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api';
import { WiredSelectObjectEvent } from '../../../events';
import { dispatchUiEvent } from '../../../hooks/events';
import { LocalizeText } from '../../../utils/LocalizeText'; import { LocalizeText } from '../../../utils/LocalizeText';
import { RoomWidgetObjectNameEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events'; import { RoomWidgetObjectNameEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events';
import { RoomWidgetChangeMottoMessage, RoomWidgetFurniActionMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages'; import { RoomWidgetChangeMottoMessage, RoomWidgetFurniActionMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages';
@ -386,10 +388,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
event.rentCouldBeUsedForBuyout = furnitureData.rentCouldBeUsedForBuyout; event.rentCouldBeUsedForBuyout = furnitureData.rentCouldBeUsedForBuyout;
event.availableForBuildersClub = furnitureData.availableForBuildersClub; event.availableForBuildersClub = furnitureData.availableForBuildersClub;
// if(this._container.wiredService && (k.category === RoomObjectCategory.FLOOR)) dispatchUiEvent(new WiredSelectObjectEvent(event.id, event.category));
// {
// this._container.wiredService.selectFurniture(roomObject.id, furnitureData.name);
// }
} }
} }

View File

@ -1,5 +1,5 @@
import { AvatarScaleType, AvatarSetType } from 'nitro-renderer'; import { AvatarScaleType, AvatarSetType } from 'nitro-renderer';
import { FC, useCallback, useEffect, useState } from 'react'; import { FC, useEffect, useState } from 'react';
import { GetAvatarRenderManager } from '../../../api'; import { GetAvatarRenderManager } from '../../../api';
import { AvatarImageViewProps } from './AvatarImageView.types'; import { AvatarImageViewProps } from './AvatarImageView.types';
@ -8,39 +8,32 @@ export const AvatarImageView: FC<AvatarImageViewProps> = props =>
const { figure = '', gender = 'M', headOnly = false, direction = 0, scale = 1 } = props; const { figure = '', gender = 'M', headOnly = false, direction = 0, scale = 1 } = props;
const [ avatarUrl, setAvatarUrl ] = useState<string>(null); const [ avatarUrl, setAvatarUrl ] = useState<string>(null);
const [ randomValue, setRandomValue ] = useState(-1);
const getUserImageUrl = useCallback(() => useEffect(() =>
{ {
let url = null; if(randomValue) {}
const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, gender, { const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, gender, {
resetFigure: (figure) => setAvatarUrl(getUserImageUrl()), resetFigure: figure => setRandomValue(Math.random()),
dispose: () => {}, dispose: () => {},
disposed: false disposed: false
}, null); }, null);
if(avatarImage) if(!avatarImage) return;
{
let setType = AvatarSetType.FULL;
if(headOnly) setType = AvatarSetType.HEAD; let setType = AvatarSetType.FULL;
avatarImage.setDirection(setType, direction); if(headOnly) setType = AvatarSetType.HEAD;
const image = avatarImage.getCroppedImage(setType); avatarImage.setDirection(setType, direction);
if(image) url = image.src; const image = avatarImage.getCroppedImage(setType);
avatarImage.dispose(); if(image) setAvatarUrl(image.src);
}
return url; avatarImage.dispose();
}, [ figure, gender, direction, headOnly ]); }, [ figure, gender, direction, headOnly, randomValue ]);
useEffect(() =>
{
setAvatarUrl(getUserImageUrl());
}, [ getUserImageUrl ]);
const url = `url('${ avatarUrl }')`; const url = `url('${ avatarUrl }')`;

View File

@ -0,0 +1,62 @@
import { WiredFurniActionEvent, WiredFurniConditionEvent, WiredFurniTriggerEvent, WiredOpenEvent, WiredRewardResultMessageEvent, WiredSaveSuccessEvent, WiredValidationErrorEvent } from 'nitro-renderer';
import { FC, useCallback } from 'react';
import { CreateMessageHook } from '../../hooks/messages';
import { useWiredContext } from './context/WiredContext';
export const WiredMessageHandler: FC<{}> = props =>
{
const { setTrigger = null } = useWiredContext();
const onWiredFurniActionEvent = useCallback((event: WiredFurniActionEvent) =>
{
const parser = event.getParser();
setTrigger(parser.definition);
}, [ setTrigger ]);
const onWiredFurniConditionEvent = useCallback((event: WiredFurniConditionEvent) =>
{
const parser = event.getParser();
setTrigger(parser.definition);
}, [ setTrigger ]);
const onWiredFurniTriggerEvent = useCallback((event: WiredFurniTriggerEvent) =>
{
const parser = event.getParser();
setTrigger(parser.definition);
}, [ setTrigger ]);
const onWiredOpenEvent = useCallback((event: WiredOpenEvent) =>
{
const parser = event.getParser();
}, []);
const onWiredRewardResultMessageEvent = useCallback((event: WiredRewardResultMessageEvent) =>
{
const parser = event.getParser();
}, []);
const onWiredSaveSuccessEvent = useCallback((event: WiredSaveSuccessEvent) =>
{
const parser = event.getParser();
setTrigger(null);
}, [ setTrigger ]);
const onWiredValidationErrorEvent = useCallback((event: WiredValidationErrorEvent) =>
{
const parser = event.getParser();
}, []);
CreateMessageHook(WiredFurniActionEvent, onWiredFurniActionEvent);
CreateMessageHook(WiredFurniConditionEvent, onWiredFurniConditionEvent);
CreateMessageHook(WiredFurniTriggerEvent, onWiredFurniTriggerEvent);
CreateMessageHook(WiredOpenEvent, onWiredOpenEvent);
CreateMessageHook(WiredRewardResultMessageEvent, onWiredRewardResultMessageEvent);
CreateMessageHook(WiredSaveSuccessEvent, onWiredSaveSuccessEvent);
CreateMessageHook(WiredValidationErrorEvent, onWiredValidationErrorEvent);
return null;
};

View File

@ -0,0 +1,160 @@
.nitro-wired {
width: 300px;
padding:7px;
.icon {
width: 16px;
height: 9px;
background-repeat: no-repeat;
background-position: center;
&.icon-mv-1 {
background-image: url('../../assets/images/wired/icon_wired_around.png');
}
&.icon-mv-2 {
background-image: url('../../assets/images/wired/icon_wired_up_down.png');
}
&.icon-mv-3 {
background-image: url('../../assets/images/wired/icon_wired_left_right.png');
}
&.icon-ne {
background-image: url('../../assets/images/wired/icon_wired_north_east.png');
}
&.icon-se {
background-image: url('../../assets/images/wired/icon_wired_south_east.png');
}
&.icon-sw {
background-image: url('../../assets/images/wired/icon_wired_south_west.png');
}
&.icon-nw {
background-image: url('../../assets/images/wired/icon_wired_north_west.png');
}
&.icon-rot-1 {
background-image: url('../../assets/images/wired/icon_wired_rotate_clockwise.png');
}
&.icon-rot-2 {
background-image: url('../../assets/images/wired/icon_wired_rotate_counter_clockwise.png');
}
}
.nitro-wired-header {
color: #000;
margin-bottom:3px;
.nitro-wired-title, .nitro-wired-close {
border:1px solid rgba($black,.8);
background-image: linear-gradient(45deg, #00d9cb 25%, #00bdb0 25%, #00bdb0 50%, #00d9cb 50%, #00d9cb 75%, #00bdb0 75%, #00bdb0 100%);
background-size: 197.99px 197.99px;
animation: wiredSlider 3s linear infinite;
text-align: center;
box-shadow:inset 0 0 0 2px rgba($white,.6), 0 2px rgba($black,.4);
}
.nitro-wired-title {
margin-right:3px;
}
.nitro-wired-close {
min-width: 23px;
}
}
&.nitro-wired-trigger {
background-color: #3b2516 !important;
border: 1px solid #000 !important;
box-shadow: inset 0px -2px #50321f,
inset 0px -3px #86583b,
inset 0 0 0 1px #86583b,
inset 0 0 0 3px #644029,
inset 0 0 0 4px rgba($black,.4) !important;
.bg-light,.bg-primary {
background-color: transparent !important;
}
.bg-dark {
background-color: #000 !important;
}
}
&.nitro-wired-action {
background-color: #686868 !important;
border: 1px solid #000 !important;
box-shadow: inset 0px -2px #9d9d9d,
inset 0px -3px #c5c5c5,
inset 0 0 0 1px #c5c5c5,
inset 0 0 0 3px #9d9d9d,
inset 0 0 0 4px rgba($black,.4) !important;
.bg-light,.bg-primary {
background-color: transparent !important;
}
.bg-dark {
background-color: #000 !important;
}
&::before,
&::after,
.content-area::before,
.content-area::after {
content: '';
height: 6px;
width: 6px;
position: absolute;
background-image: url('../../assets/images/wired/card-action-corners.png');
}
&::before {
background-position: 0 0;
top: 0;
left: 0;
}
&::after {
background-position: 6px 0;
top: 0;
right: 0;
}
.content-area {
&::before {
background-position: 0 6px;
bottom: 0;
left: 0;
}
&::after {
background-position: 6px 6px;
bottom: 0;
right: 0;
}
}
}
&.nitro-wired-condition {
background-color: #cfd2dd !important;
border: 1px solid #000 !important;
box-shadow: inset 0 0 0 3px #efefef, inset 4px 4px #abaeb9 !important;
color: #000;
.bg-light,.bg-primary {
background-color: transparent !important;
}
.bg-dark {
background-color: #000 !important;
}
}
}
@keyframes wiredSlider {
0% {
background-position: 0 0;
}
100% {
background-position: 0 -197.99px;
}
}

View File

@ -0,0 +1,53 @@
import { ConditionDefinition, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition } from 'nitro-renderer';
import { FC, useCallback, useMemo, useState } from 'react';
import { GetConnection } from '../../api';
import { WiredEvent } from '../../events';
import { useUiEvent } from '../../hooks/events';
import { GetWiredLayout } from './common/GetWiredLayout';
import { WiredContextProvider } from './context/WiredContext';
import { WiredMessageHandler } from './WiredMessageHandler';
import { WiredFurniSelectorViewProps } from './WiredView.types';
export const WiredView: FC<WiredFurniSelectorViewProps> = props =>
{
const [ trigger, setTrigger ] = useState<Triggerable>(null);
const [ intParams, setIntParams ] = useState<number[]>(null);
const [ stringParam, setStringParam ] = useState<string>(null);
const [ furniIds, setFurniIds ] = useState<number[]>([]);
const [ actionDelay, setActionDelay ] = useState<number>(null);
const wiredLayout = useMemo(() =>
{
return GetWiredLayout(trigger);
}, [ trigger ]);
const onWiredEvent = useCallback((event: WiredEvent) =>
{
// check if owner & warn with confirm
if(trigger instanceof WiredActionDefinition)
{
GetConnection().send(new UpdateActionMessageComposer(trigger.id, intParams, stringParam, furniIds, actionDelay, trigger.stuffTypeSelectionCode));
}
else if(trigger instanceof TriggerDefinition)
{
console.log(intParams, stringParam);
GetConnection().send(new UpdateTriggerMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode));
}
else if(trigger instanceof ConditionDefinition)
{
GetConnection().send(new UpdateConditionMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode));
}
}, [ trigger, intParams, stringParam, furniIds, actionDelay ]);
useUiEvent(WiredEvent.SAVE_WIRED, onWiredEvent);
return (
<WiredContextProvider value={ { trigger, setTrigger, intParams, setIntParams, stringParam, setStringParam, furniIds, setFurniIds, actionDelay, setActionDelay }}>
<WiredMessageHandler />
{ wiredLayout }
</WiredContextProvider>
);
};

View File

@ -0,0 +1,12 @@
export class WiredFurniSelectorViewProps
{}
export class WiredFurniType
{
public static STUFF_SELECTION_OPTION_NONE: number = 0;
public static STUFF_SELECTION_OPTION_BY_ID: number = 1;
public static STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE: number = 2;
public static STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT: number = 3;
}
export const WIRED_STRING_DELIMETER: string = '\t';

View File

@ -0,0 +1,85 @@
import { WiredActionBotChangeFigureView } from '../views/actions/bot-change-figure/WiredActionBotChangeFigureView';
import { WiredActionBotFollowAvatarView } from '../views/actions/bot-follow-avatar/WiredActionBotFollowAvatarView';
import { WiredActionBotGiveHandItemView } from '../views/actions/bot-give-hand-item/WiredActionBotGiveHandItemView';
import { WiredActionBotMoveView } from '../views/actions/bot-move/WiredActionBotMoveView';
import { WiredActionBotTalkToAvatarView } from '../views/actions/bot-talk-to-avatar/WiredActionBotTalkToAvatarView';
import { WiredActionBotTalkView } from '../views/actions/bot-talk/WiredActionBotTalkView';
import { WiredActionBotTeleportView } from '../views/actions/bot-teleport/WiredActionBotTeleportView';
import { WiredActionCallAnotherStackView } from '../views/actions/call-another-stack/WiredActionCallAnotherStackView';
import { WiredActionChaseView } from '../views/actions/chase/WiredActionChaseView';
import { WiredActionChatView } from '../views/actions/chat/WiredActionChatView';
import { WiredActionFleeView } from '../views/actions/flee/WiredActionFleeView';
import { WiredActionGiveRewardView } from '../views/actions/give-reward/WiredActionGiveRewardView';
import { WiredActionGiveScoreToPredefinedTeamView } from '../views/actions/give-score-to-predefined-team/WiredActionGiveScoreToPredefinedTeamView';
import { WiredActionGiveScoreView } from '../views/actions/give-score/WiredActionGiveScoreView';
import { WiredActionJoinTeamView } from '../views/actions/join-team/WiredActionJoinTeamView';
import { WiredActionKickFromRoomView } from '../views/actions/kick-from-room/WiredActionKickFromRoomView';
import { WiredActionLeaveTeamView } from '../views/actions/leave-team/WiredActionLeaveTeamView';
import { WiredActionMoveAndRotateFurniView } from '../views/actions/move-and-rotate-furni/WiredActionMoveAndRotateFurniView';
import { WiredActionMoveFurniToView } from '../views/actions/move-furni-to/WiredActionMoveFurniToView';
import { WiredActionMoveFurniView } from '../views/actions/move-furni/WiredActionMoveFurniView';
import { WiredActionMuteUserView } from '../views/actions/mute-user/WiredActionMuteUserView';
import { WiredActionResetView } from '../views/actions/reset/WiredActionResetView';
import { WiredActionSetFurniStateToView } from '../views/actions/set-furni-state-to/WiredActionSetFurniStateToView';
import { WiredActionTeleportView } from '../views/actions/teleport/WiredActionTeleportView';
import { WiredActionToggleFurniStateView } from '../views/actions/toggle-furni-state/WiredActionToggleFurniStateView';
import { WiredActionLayout } from './WiredActionLayoutCode';
export function GetWiredActionLayout(code: number): JSX.Element
{
switch(code)
{
case WiredActionLayout.BOT_CHANGE_FIGURE:
return <WiredActionBotChangeFigureView />;
case WiredActionLayout.BOT_FOLLOW_AVATAR:
return <WiredActionBotFollowAvatarView />;
case WiredActionLayout.BOT_GIVE_HAND_ITEM:
return <WiredActionBotGiveHandItemView />;
case WiredActionLayout.BOT_MOVE:
return <WiredActionBotMoveView />;
case WiredActionLayout.BOT_TALK:
return <WiredActionBotTalkView />;
case WiredActionLayout.BOT_TALK_DIRECT_TO_AVTR:
return <WiredActionBotTalkToAvatarView />;
case WiredActionLayout.BOT_TELEPORT:
return <WiredActionBotTeleportView />;
case WiredActionLayout.CALL_ANOTHER_STACK:
return <WiredActionCallAnotherStackView />;
case WiredActionLayout.CHASE:
return <WiredActionChaseView />;
case WiredActionLayout.CHAT:
return <WiredActionChatView />;
case WiredActionLayout.FLEE:
return <WiredActionFleeView />;
case WiredActionLayout.GIVE_REWARD:
return <WiredActionGiveRewardView />;
case WiredActionLayout.GIVE_SCORE:
return <WiredActionGiveScoreView />;
case WiredActionLayout.GIVE_SCORE_TO_PREDEFINED_TEAM:
return <WiredActionGiveScoreToPredefinedTeamView />;
case WiredActionLayout.JOIN_TEAM:
return <WiredActionJoinTeamView />;
case WiredActionLayout.KICK_FROM_ROOM:
return <WiredActionKickFromRoomView />;
case WiredActionLayout.LEAVE_TEAM:
return <WiredActionLeaveTeamView />;
case WiredActionLayout.MOVE_FURNI:
return <WiredActionMoveFurniView />;
case WiredActionLayout.MOVE_AND_ROTATE_FURNI:
return <WiredActionMoveAndRotateFurniView />;
case WiredActionLayout.MOVE_FURNI_TO:
return <WiredActionMoveFurniToView />;
case WiredActionLayout.MUTE_USER:
return <WiredActionMuteUserView />;
case WiredActionLayout.RESET:
return <WiredActionResetView />;
case WiredActionLayout.SET_FURNI_STATE:
return <WiredActionSetFurniStateToView />;
case WiredActionLayout.TELEPORT:
return <WiredActionTeleportView />;
case WiredActionLayout.TOGGLE_FURNI_STATE:
return <WiredActionToggleFurniStateView />;
}
return null;
}

View File

@ -0,0 +1,64 @@
import { WiredConditionActorHasHandItemView } from '../views/conditions/actor-has-hand-item/WiredConditionActorHasHandItem';
import { WiredConditionActorIsGroupMemberView } from '../views/conditions/actor-is-group-member/WiredConditionActorIsGroupMemberView';
import { WiredConditionActorIsOnFurniView } from '../views/conditions/actor-is-on-furni/WiredConditionActorIsOnFurniView';
import { WiredConditionActorIsTeamMemberView } from '../views/conditions/actor-is-team-member/WiredConditionActorIsTeamMemberView';
import { WiredConditionActorIsWearingBadgeView } from '../views/conditions/actor-is-wearing-badge/WiredConditionActorIsWearingBadgeView';
import { WiredConditionActorIsWearingEffectView } from '../views/conditions/actor-is-wearing-effect/WiredConditionActorIsWearingEffectView';
import { WiredConditionDateRangeView } from '../views/conditions/date-range/WiredConditionDateRangeView';
import { WiredConditionFurniHasAvatarOnView } from '../views/conditions/furni-has-avatar-on/WiredConditionFurniHasAvatarOnView';
import { WiredConditionFurniHasFurniOnView } from '../views/conditions/furni-has-furni-on/WiredConditionFurniHasFurniOnView';
import { WiredConditionFurniHasNotFurniOnView } from '../views/conditions/furni-has-not-furni-on/WiredConditionFurniHasNotFurniOnView';
import { WiredConditionFurniIsOfTypeView } from '../views/conditions/furni-is-of-type/WiredConditionFurniIsOfTypeView';
import { WiredConditionFurniMatchesSnapshotView } from '../views/conditions/furni-matches-snapshot/WiredConditionFurniMatchesSnapshotView';
import { WiredConditionTimeElapsedLessView } from '../views/conditions/time-elapsed-less/WiredConditionTimeElapsedLessView';
import { WiredConditionTimeElapsedMoreView } from '../views/conditions/time-elapsed-more/WiredConditionTimeElapsedMoreView';
import { WiredConditionUserCountInRoomView } from '../views/conditions/user-count-in-room/WiredConditionUserCountInRoomView';
import { WiredConditionlayout } from './WiredConditionLayoutCode';
export function GetWiredConditionLayout(code: number): JSX.Element
{
switch(code)
{
case WiredConditionlayout.ACTOR_HAS_HANDITEM:
return <WiredConditionActorHasHandItemView />;
case WiredConditionlayout.ACTOR_IS_GROUP_MEMBER:
case WiredConditionlayout.NOT_ACTOR_IN_GROUP:
return <WiredConditionActorIsGroupMemberView />;
case WiredConditionlayout.ACTOR_IS_ON_FURNI:
case WiredConditionlayout.NOT_ACTOR_ON_FURNI:
return <WiredConditionActorIsOnFurniView />;
case WiredConditionlayout.ACTOR_IS_IN_TEAM:
case WiredConditionlayout.NOT_ACTOR_IN_TEAM:
return <WiredConditionActorIsTeamMemberView />;
case WiredConditionlayout.ACTOR_IS_WEARING_BADGE:
case WiredConditionlayout.NOT_ACTOR_WEARS_BADGE:
return <WiredConditionActorIsWearingBadgeView />;
case WiredConditionlayout.ACTOR_IS_WEARING_EFFECT:
case WiredConditionlayout.NOT_ACTOR_WEARING_EFFECT:
return <WiredConditionActorIsWearingEffectView />;
case WiredConditionlayout.DATE_RANGE_ACTIVE:
return <WiredConditionDateRangeView />;
case WiredConditionlayout.FURNIS_HAVE_AVATARS:
case WiredConditionlayout.FURNI_NOT_HAVE_HABBO:
return <WiredConditionFurniHasAvatarOnView />;
case WiredConditionlayout.HAS_STACKED_FURNIS:
return <WiredConditionFurniHasFurniOnView />;
case WiredConditionlayout.NOT_HAS_STACKED_FURNIS:
return <WiredConditionFurniHasNotFurniOnView />;
case WiredConditionlayout.STUFF_TYPE_MATCHES:
case WiredConditionlayout.NOT_FURNI_IS_OF_TYPE:
return <WiredConditionFurniIsOfTypeView />;
case WiredConditionlayout.STATES_MATCH:
case WiredConditionlayout.NOT_STATES_MATCH:
return <WiredConditionFurniMatchesSnapshotView />;
case WiredConditionlayout.TIME_ELAPSED_LESS:
return <WiredConditionTimeElapsedLessView />;
case WiredConditionlayout.TIME_ELAPSED_MORE:
return <WiredConditionTimeElapsedMoreView />;
case WiredConditionlayout.USER_COUNT_IN:
case WiredConditionlayout.NOT_USER_COUNT_IN:
return <WiredConditionUserCountInRoomView />;
}
return null;
}

View File

@ -0,0 +1,15 @@
import { ConditionDefinition, Triggerable, TriggerDefinition, WiredActionDefinition } from 'nitro-renderer';
import { GetWiredActionLayout } from './GetWiredActionLayout';
import { GetWiredConditionLayout } from './GetWiredConditionLayout';
import { GetWiredTriggerLayout } from './GetWiredTriggerLayout';
export function GetWiredLayout(trigger: Triggerable): JSX.Element
{
if(trigger instanceof WiredActionDefinition) return GetWiredActionLayout(trigger.code);
if(trigger instanceof TriggerDefinition) return GetWiredTriggerLayout(trigger.code);
if(trigger instanceof ConditionDefinition) return GetWiredConditionLayout(trigger.code);
return null;
}

View File

@ -0,0 +1,8 @@
export function GetWiredTimeLocale(value: number): string
{
const time = Math.floor((value / 2));
if(!(value % 2)) return time.toString();
return (time + 0.5).toString();
}

View File

@ -0,0 +1,52 @@
import { WiredTriggerAvatarEnterRoomView } from '../views/triggers/avatar-enter-room/WiredTriggerAvatarEnterRoomView';
import { WiredTriggerAvatarSaysSomethingView } from '../views/triggers/avatar-says-something/WiredTriggerAvatarSaysSomethingView';
import { WiredTriggerAvatarWalksOffFurniView } from '../views/triggers/avatar-walks-off-furni/WiredTriggerAvatarWalksOffFurniView';
import { WiredTriggerAvatarWalksOnFurniView } from '../views/triggers/avatar-walks-on-furni/WiredTriggerAvatarWalksOnFurni';
import { WiredTriggerBotReachedAvatarView } from '../views/triggers/bot-reached-avatar/WiredTriggerBotReachedAvatarView';
import { WiredTriggerBotReachedStuffView } from '../views/triggers/bot-reached-stuff/WiredTriggerBotReachedStuffView';
import { WiredTriggerCollisionView } from '../views/triggers/collision/WiredTriggerCollisionView';
import { WiredTriggeExecuteOnceView } from '../views/triggers/execute-once/WiredTriggerExecuteOnceView';
import { WiredTriggeExecutePeriodicallyLongView } from '../views/triggers/execute-periodically-long/WiredTriggerExecutePeriodicallyLongView';
import { WiredTriggeExecutePeriodicallyView } from '../views/triggers/execute-periodically/WiredTriggerExecutePeriodicallyView';
import { WiredTriggerGameEndsView } from '../views/triggers/game-ends/WiredTriggerGameEndsView';
import { WiredTriggerGameStartsView } from '../views/triggers/game-starts/WiredTriggerGameStartsView';
import { WiredTriggeScoreAchievedView } from '../views/triggers/score-achieved/WiredTriggerScoreAchievedView';
import { WiredTriggerToggleFurniView } from '../views/triggers/toggle-furni/WiredTriggerToggleFurniView';
import { WiredTriggerLayout } from './WiredTriggerLayoutCode';
export function GetWiredTriggerLayout(code: number): JSX.Element
{
switch(code)
{
case WiredTriggerLayout.AVATAR_ENTERS_ROOM:
return <WiredTriggerAvatarEnterRoomView />;
case WiredTriggerLayout.AVATAR_SAYS_SOMETHING:
return <WiredTriggerAvatarSaysSomethingView />;
case WiredTriggerLayout.AVATAR_WALKS_OFF_FURNI:
return <WiredTriggerAvatarWalksOffFurniView />;
case WiredTriggerLayout.AVATAR_WALKS_ON_FURNI:
return <WiredTriggerAvatarWalksOnFurniView />;
case WiredTriggerLayout.BOT_REACHED_AVATAR:
return <WiredTriggerBotReachedAvatarView />;
case WiredTriggerLayout.BOT_REACHED_STUFF:
return <WiredTriggerBotReachedStuffView />;
case WiredTriggerLayout.COLLISION:
return <WiredTriggerCollisionView />;
case WiredTriggerLayout.EXECUTE_ONCE:
return <WiredTriggeExecuteOnceView />;
case WiredTriggerLayout.EXECUTE_PERIODICALLY:
return <WiredTriggeExecutePeriodicallyView />;
case WiredTriggerLayout.EXECUTE_PERIODICALLY_LONG:
return <WiredTriggeExecutePeriodicallyLongView />;
case WiredTriggerLayout.GAME_ENDS:
return <WiredTriggerGameEndsView />;
case WiredTriggerLayout.GAME_STARTS:
return <WiredTriggerGameStartsView />;
case WiredTriggerLayout.SCORE_ACHIEVED:
return <WiredTriggeScoreAchievedView />;
case WiredTriggerLayout.TOGGLE_FURNI:
return <WiredTriggerToggleFurniView />;
}
return null;
}

View File

@ -0,0 +1,29 @@
export class WiredActionLayout
{
public static TOGGLE_FURNI_STATE: number = 0;
public static RESET: number = 1;
public static SET_FURNI_STATE: number = 3;
public static MOVE_FURNI: number = 4;
public static GIVE_SCORE: number = 6;
public static CHAT: number = 7;
public static TELEPORT: number = 8;
public static JOIN_TEAM: number = 9;
public static LEAVE_TEAM: number = 10;
public static CHASE: number = 11;
public static FLEE: number = 12;
public static MOVE_AND_ROTATE_FURNI: number = 13;
public static GIVE_SCORE_TO_PREDEFINED_TEAM: number = 14;
public static TOGGLE_TO_RANDOM_STATE: number = 15;
public static MOVE_FURNI_TO: number = 16;
public static GIVE_REWARD: number = 17;
public static CALL_ANOTHER_STACK: number = 18;
public static KICK_FROM_ROOM: number = 19;
public static MUTE_USER: number = 20;
public static BOT_TELEPORT: number = 21;
public static BOT_MOVE: number = 22;
public static BOT_TALK: number = 23;
public static BOT_GIVE_HAND_ITEM: number = 24;
public static BOT_FOLLOW_AVATAR: number = 25;
public static BOT_CHANGE_FIGURE: number = 26;
public static BOT_TALK_DIRECT_TO_AVTR: number = 27;
}

View File

@ -0,0 +1,29 @@
export class WiredConditionlayout
{
public static STATES_MATCH: number = 0;
public static FURNIS_HAVE_AVATARS: number = 1;
public static ACTOR_IS_ON_FURNI: number = 2;
public static TIME_ELAPSED_MORE: number = 3;
public static TIME_ELAPSED_LESS: number = 4;
public static USER_COUNT_IN: number = 5;
public static ACTOR_IS_IN_TEAM: number = 6;
public static HAS_STACKED_FURNIS: number = 7;
public static STUFF_TYPE_MATCHES: number = 8;
public static STUFFS_IN_FORMATION: number = 9;
public static ACTOR_IS_GROUP_MEMBER: number = 10;
public static ACTOR_IS_WEARING_BADGE: number = 11;
public static ACTOR_IS_WEARING_EFFECT: number = 12;
public static NOT_STATES_MATCH: number = 13;
public static FURNI_NOT_HAVE_HABBO: number = 14;
public static NOT_ACTOR_ON_FURNI: number = 15;
public static NOT_USER_COUNT_IN: number = 16;
public static NOT_ACTOR_IN_TEAM: number = 17;
public static NOT_HAS_STACKED_FURNIS: number = 18;
public static NOT_FURNI_IS_OF_TYPE: number = 19;
public static NOT_STUFFS_IN_FORMATION: number = 20;
public static NOT_ACTOR_IN_GROUP: number = 21;
public static NOT_ACTOR_WEARS_BADGE: number = 22;
public static NOT_ACTOR_WEARING_EFFECT: number = 23;
public static DATE_RANGE_ACTIVE: number = 24;
public static ACTOR_HAS_HANDITEM: number = 25;
}

View File

@ -0,0 +1,95 @@
import { ColorConverter, NitroFilter } from 'nitro-renderer';
const vertex = `
attribute vec2 aVertexPosition;
attribute vec2 aTextureCoord;
uniform mat3 projectionMatrix;
varying vec2 vTextureCoord;
void main(void)
{
gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
vTextureCoord = aTextureCoord;
}`;
const fragment = `
varying vec2 vTextureCoord;
uniform sampler2D uSampler;
uniform vec3 lineColor;
uniform vec3 color;
void main(void) {
vec4 currentColor = texture2D(uSampler, vTextureCoord);
vec3 colorLine = lineColor * currentColor.a;
vec3 colorOverlay = color * currentColor.a;
if(currentColor.r == 0.0 && currentColor.g == 0.0 && currentColor.b == 0.0 && currentColor.a > 0.0) {
gl_FragColor = vec4(colorLine.r, colorLine.g, colorLine.b, currentColor.a);
} else if(currentColor.a > 0.0) {
gl_FragColor = vec4(colorOverlay.r, colorOverlay.g, colorOverlay.b, currentColor.a);
}
}`;
export class WiredSelectionFilter extends NitroFilter
{
private _lineColor: number;
private _color: number;
constructor(lineColor: number | number[], color: number | number[])
{
super(vertex, fragment);
this.uniforms.lineColor = new Float32Array(3);
this.uniforms.color = new Float32Array(3);
this.lineColor = lineColor;
this.color = color;
}
public get lineColor(): number | number[]
{
return this._lineColor;
}
public set lineColor(value: number | number[])
{
const arr = this.uniforms.lineColor;
if(typeof value === 'number')
{
ColorConverter.hex2rgb(value, arr);
this._lineColor = value;
}
else
{
arr[0] = value[0];
arr[1] = value[1];
arr[2] = value[2];
this._lineColor = ColorConverter.rgb2hex(arr);
}
}
public get color(): number | number[]
{
return this._color;
}
public set color(value: number | number[])
{
const arr = this.uniforms.color;
if(typeof value === 'number')
{
ColorConverter.hex2rgb(value, arr);
this._color = value;
}
else
{
arr[0] = value[0];
arr[1] = value[1];
arr[2] = value[2];
this._color = ColorConverter.rgb2hex(arr);
}
}
}

View File

@ -0,0 +1,68 @@
import { IRoomObject, IRoomObjectSpriteVisualization, NitroFilter, RoomObjectCategory } from 'nitro-renderer';
import { GetRoomEngine } from '../../../api';
import { WiredSelectionFilter } from './WiredSelectionFilter';
export class WiredSelectionVisualizer
{
private static _selectionShader: NitroFilter = new WiredSelectionFilter([ 1, 1, 1 ], [ 0.6, 0.6, 0.6 ]);
public static show(furniId: number): void
{
WiredSelectionVisualizer.applySelectionShader(WiredSelectionVisualizer.getRoomObject(furniId));
}
public static hide(furniId: number): void
{
WiredSelectionVisualizer.clearSelectionShader(WiredSelectionVisualizer.getRoomObject(furniId));
}
public static clearSelectionShaderFromFurni(furniIds: number[]): void
{
for(const furniId of furniIds)
{
WiredSelectionVisualizer.clearSelectionShader(WiredSelectionVisualizer.getRoomObject(furniId));
}
}
public static applySelectionShaderToFurni(furniIds: number[]): void
{
for(const furniId of furniIds)
{
WiredSelectionVisualizer.applySelectionShader(WiredSelectionVisualizer.getRoomObject(furniId));
}
}
private static getRoomObject(objectId: number): IRoomObject
{
const roomEngine = GetRoomEngine();
return roomEngine.getRoomObject(roomEngine.activeRoomId, objectId, RoomObjectCategory.FLOOR);
}
private static applySelectionShader(roomObject: IRoomObject): void
{
if(!roomObject) return;
const visualization = (roomObject.visualization as IRoomObjectSpriteVisualization);
if(!visualization) return;
for(const sprite of visualization.sprites)
{
if(sprite.blendMode === 1) continue; // BLEND_MODE: ADD
sprite.filters = [ WiredSelectionVisualizer._selectionShader ];
}
}
private static clearSelectionShader(roomObject: IRoomObject): void
{
if(!roomObject) return;
const visualization = (roomObject.visualization as IRoomObjectSpriteVisualization);
if(!visualization) return;
for(const sprite of visualization.sprites) sprite.filters = [];
}
}

View File

@ -0,0 +1,17 @@
export class WiredTriggerLayout
{
public static AVATAR_SAYS_SOMETHING: number = 0;
public static AVATAR_WALKS_ON_FURNI: number = 1;
public static AVATAR_WALKS_OFF_FURNI: number = 2;
public static EXECUTE_ONCE: number = 3;
public static TOGGLE_FURNI: number = 4;
public static EXECUTE_PERIODICALLY: number = 6;
public static AVATAR_ENTERS_ROOM: number = 7;
public static GAME_STARTS: number = 8;
public static GAME_ENDS: number = 9;
public static SCORE_ACHIEVED: number = 10;
public static COLLISION: number = 11;
public static EXECUTE_PERIODICALLY_LONG: number = 12;
public static BOT_REACHED_STUFF: number = 13;
public static BOT_REACHED_AVATAR: number = 14;
}

View File

@ -0,0 +1,22 @@
import { createContext, FC, useContext } from 'react';
import { IWiredContext, WiredContextProps } from './WiredContext.types';
const WiredContext = createContext<IWiredContext>({
trigger: null,
setTrigger: null,
intParams: null,
setIntParams: null,
stringParam: null,
setStringParam: null,
furniIds: null,
setFurniIds: null,
actionDelay: null,
setActionDelay: null
});
export const WiredContextProvider: FC<WiredContextProps> = props =>
{
return <WiredContext.Provider value={ props.value }>{ props.children }</WiredContext.Provider>
}
export const useWiredContext = () => useContext(WiredContext);

View File

@ -0,0 +1,21 @@
import { Triggerable } from 'nitro-renderer';
import { Dispatch, ProviderProps, SetStateAction } from 'react';
export interface IWiredContext
{
trigger: Triggerable;
setTrigger: Dispatch<SetStateAction<Triggerable>>;
intParams: number[],
setIntParams: Dispatch<SetStateAction<number[]>>;
stringParam: string;
setStringParam: Dispatch<SetStateAction<string>>;
furniIds: number[];
setFurniIds: Dispatch<SetStateAction<number[]>>;
actionDelay: number;
setActionDelay: Dispatch<SetStateAction<number>>;
}
export interface WiredContextProps extends ProviderProps<IWiredContext>
{
}

View File

@ -0,0 +1,45 @@
import { WiredActionDefinition } from 'nitro-renderer';
import Slider from 'rc-slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { GetWiredTimeLocale } from '../../../common/GetWiredTimeLocale';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredBaseView } from '../../base/WiredBaseView';
import { WiredActionBaseViewProps } from './WiredActionBaseView.types';
export const WiredActionBaseView: FC<WiredActionBaseViewProps> = props =>
{
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, children = null } = props;
const [ delay, setDelay ] = useState(-1);
const { trigger = null, setActionDelay = null } = useWiredContext();
useEffect(() =>
{
setDelay((trigger as WiredActionDefinition).delayInPulses);
}, [ trigger ]);
const onSave = useCallback(() =>
{
if(save) save();
setActionDelay(delay);
}, [ delay, save, setActionDelay ]);
return (
<WiredBaseView wiredType="action" requiresFurni={ requiresFurni } save={ onSave }>
{ !children ? null : <>
{ children }
<hr className="my-1 mb-2 bg-dark" />
</> }
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.delay', [ 'seconds' ], [ GetWiredTimeLocale(delay) ]) }</label>
<Slider
value={ delay }
min={ 0 }
max={ 20 }
onChange={ event => setDelay(event) } />
</div>
</WiredBaseView>
);
}

View File

@ -0,0 +1,5 @@
export interface WiredActionBaseViewProps
{
requiresFurni: number;
save: () => void;
}

View File

@ -0,0 +1,47 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { GetSessionDataManager } from '../../../../../api';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType, WIRED_STRING_DELIMETER } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
const DEFAULT_FIGURE: string = 'hd-180-1.ch-210-66.lg-270-82.sh-290-81';
export const WiredActionBotChangeFigureView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const [ figure, setFigure ] = useState('');
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
const data = trigger.stringData.split(WIRED_STRING_DELIMETER);
if(data.length > 0) setBotName(data[0]);
if(data.length > 1) setFigure(data[1].length > 0 ? data[1] : DEFAULT_FIGURE);
}, [ trigger ]);
const copyLooks = useCallback(() =>
{
setFigure(GetSessionDataManager().figure);
}, []);
const save = useCallback(() =>
{
setStringParam((botName + WIRED_STRING_DELIMETER + figure));
}, [ botName, figure, setStringParam ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
<div className="d-flex align-items-center justify-content-center">
<AvatarImageView figure={ figure } direction={ 4 } />
<button type="button" className="btn btn-primary" onClick={ copyLooks }>{ LocalizeText('wiredfurni.params.capture.figure') }</button>
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,47 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionBotFollowAvatarView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const [ followMode, setFollowMode ] = useState(-1);
const { trigger = null, setStringParam = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setBotName(trigger.stringData);
setFollowMode((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(botName);
setIntParams([followMode]);
}, [ followMode, botName, setStringParam, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
<div className="form-group">
<div className="form-check">
<input className="form-check-input" type="radio" name="followMode" id="followMode1" checked={ (followMode === 1) } onChange={ event => setFollowMode(1) } />
<label className="form-check-label" htmlFor="followMode1">
{ LocalizeText('wiredfurni.params.start.following') }
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" name="followMode" id="followMode2" checked={ (followMode === 0) } onChange={ event => setFollowMode(0) } />
<label className="form-check-label" htmlFor="followMode2">
{ LocalizeText('wiredfurni.params.stop.following') }
</label>
</div>
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,45 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
const allowedHanditemIds: number[] = [2, 5, 7, 8, 9, 10, 27];
export const WiredActionBotGiveHandItemView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const [ handItemId, setHandItemId ] = useState(-1);
const { trigger = null, setStringParam = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setBotName(trigger.stringData);
setHandItemId((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(botName);
setIntParams([ handItemId ]);
}, [ handItemId, botName, setStringParam, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.handitem') }</label>
<select className="form-select form-select-sm" value={ handItemId } onChange={ event => setHandItemId(parseInt(event.target.value)) }>
<option value="0">------</option>
{ allowedHanditemIds.map(value =>
{
return <option key={ value } value={ value }>{ LocalizeText(`handitem${ value }`) }</option>
}) }
</select>
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,30 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionBotMoveView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setBotName(trigger.stringData);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(botName);
}, [ botName, setStringParam ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,52 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType, WIRED_STRING_DELIMETER } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionBotTalkToAvatarView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const [ message, setMessage ] = useState('');
const [ talkMode, setTalkMode ] = useState(-1);
const { trigger = null, setStringParam = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
const data = trigger.stringData.split(WIRED_STRING_DELIMETER);
if(data.length > 0) setBotName(data[0]);
if(data.length > 1) setMessage(data[1].length > 0 ? data[1] : '');
setTalkMode((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(botName + WIRED_STRING_DELIMETER + message);
setIntParams([ talkMode ]);
}, [ botName, message, talkMode, setStringParam, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.message') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 64 } value={ message } onChange={ event => setMessage(event.target.value) } />
</div>
<div className="form-group">
<div className="form-check">
<input className="form-check-input" type="radio" name="talkMode" id="talkMode1" checked={ (talkMode === 0) } onChange={ event => setTalkMode(0) } />
<label className="form-check-label" htmlFor="talkMode1">{ LocalizeText('wiredfurni.params.talk') }</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" name="talkMode" id="talkMode2" checked={ (talkMode === 1) } onChange={ event => setTalkMode(1) } />
<label className="form-check-label" htmlFor="talkMode2">{ LocalizeText('wiredfurni.params.whisper') }</label>
</div>
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,52 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType, WIRED_STRING_DELIMETER } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionBotTalkView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const [ message, setMessage ] = useState('');
const [ talkMode, setTalkMode ] = useState(-1);
const { trigger = null, setStringParam = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
const data = trigger.stringData.split(WIRED_STRING_DELIMETER);
if(data.length > 0) setBotName(data[0]);
if(data.length > 1) setMessage(data[1].length > 0 ? data[1] : '');
setTalkMode((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(botName + WIRED_STRING_DELIMETER + message);
setIntParams([ talkMode ]);
}, [ botName, message, talkMode, setStringParam, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.message') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 64 } value={ message } onChange={ event => setMessage(event.target.value) } />
</div>
<div className="form-group">
<div className="form-check">
<input className="form-check-input" type="radio" name="talkMode" id="talkMode1" checked={ (talkMode === 0) } onChange={ event => setTalkMode(0) } />
<label className="form-check-label" htmlFor="talkMode1">{ LocalizeText('wiredfurni.params.talk') }</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" name="talkMode" id="talkMode2" checked={ (talkMode === 1) } onChange={ event => setTalkMode(1) } />
<label className="form-check-label" htmlFor="talkMode2">{ LocalizeText('wiredfurni.params.shout') }</label>
</div>
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,30 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionBotTeleportView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setBotName(trigger.stringData);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(botName);
}, [ botName, setStringParam ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionCallAnotherStackView: FC<{}> = props =>
{
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionChaseView: FC<{}> = props =>
{
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
}

View File

@ -0,0 +1,30 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionChatView: FC<{}> = props =>
{
const [ message, setMessage ] = useState('');
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setMessage(trigger.stringData);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(message);
}, [ message, setStringParam ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.message') }</label>
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } />
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionFleeView: FC<{}> = props =>
{
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
}

View File

@ -0,0 +1,173 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionGiveRewardView: FC<{}> = props =>
{
const [ limitEnabled, setLimitEnabled ] = useState(false);
const [ rewardTime, setRewardTime ] = useState(1);
const [ uniqueRewards, setUniqueRewards ] = useState(false);
const [ rewardsLimit, setRewardsLimit ] = useState(1);
const [ limitationInterval, setLimitationInterval ] = useState(1);
const [ rewards, setRewards ] = useState<{ isBadge: boolean, itemCode: string, probability: number }[]>([]);
const { trigger = null, setIntParams = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setRewardTime(trigger.intData.length > 0 ? trigger.intData[0] : 0);
setUniqueRewards(trigger.intData.length > 1 ? trigger.intData[1] === 1 : false);
setRewardsLimit(trigger.intData.length > 2 ? trigger.intData[2] : 0);
setLimitationInterval(trigger.intData.length > 3 ? trigger.intData[3] : 0);
setLimitEnabled(trigger.intData.length > 3 ? trigger.intData[3] > 0 : false);
const readRewards: { isBadge: boolean, itemCode: string, probability: number }[] = [];
if(trigger.stringData.length > 0 && trigger.stringData.includes(';'))
{
const splittedRewards = trigger.stringData.split(';');
for(const rawReward of splittedRewards)
{
const reward = rawReward.split(',');
if(reward.length !== 3) continue;
readRewards.push({ isBadge: reward[0] === '0', itemCode: reward[1], probability: Number(reward[2]) });
}
}
if(readRewards.length === 0)
{
readRewards.push({ isBadge: false, itemCode: '', probability: null });
}
setRewards(readRewards);
}, [ trigger ]);
const addReward = useCallback(() =>
{
setRewards(rewards => [...rewards, { isBadge: false, itemCode: '', probability: null }]);
}, [ setRewards ]);
const removeReward = useCallback((index: number) =>
{
const rewardsClone = Array.from(rewards);
rewardsClone.splice(index, 1);
setRewards(rewardsClone);
}, [ rewards, setRewards ]);
const updateReward = useCallback((index: number, isBadge: boolean, itemCode: string, probability: number) =>
{
const rewardsClone = Array.from(rewards);
const reward = rewardsClone[index];
if(!reward) return;
reward.isBadge = isBadge;
reward.itemCode = itemCode;
reward.probability = probability;
setRewards(rewardsClone);
}, [ rewards, setRewards ]);
const save = useCallback(() =>
{
let stringRewards = [];
for(const reward of rewards)
{
if(!reward.itemCode) continue;
const rewardsString = [reward.isBadge ? '0' : '1', reward.itemCode, reward.probability.toString()];
stringRewards.push(rewardsString.join(','));
}
if(stringRewards.length > 0)
{
setStringParam(stringRewards.join(';'));
setIntParams([rewardTime, uniqueRewards ? 1 : 0, rewardsLimit, limitationInterval]);
}
}, [ rewardTime, uniqueRewards, rewardsLimit, limitationInterval, rewards, setIntParams, setStringParam ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-check">
<input className="form-check-input" type="checkbox" id="limitEnabled" onChange={(e) => setLimitEnabled(e.target.checked)} />
<label className="form-check-label" htmlFor="uniqueRewards">
{ LocalizeText('wiredfurni.params.prizelimit', ['amount'], [limitEnabled ? rewardsLimit.toString() : '']) }
</label>
</div>
{ !limitEnabled && <div className="bg-muted rounded small text-black p-1 text-center">
Reward limit not set. Make sure rewards are badges or non-tradeable items.
</div> }
{ limitEnabled && <Slider
defaultValue={ rewardsLimit }
dots={ true }
min={ 1 }
max={ 1000 }
step={ 1 }
onChange={ event => setRewardsLimit(event) }
/> }
<hr className="my-1 mb-2 bg-dark" />
<div className="fw-bold">How ofter can a user be rewarded?</div>
<div className="d-flex">
<select className="form-select form-select-sm w-100" value={ rewardTime } onChange={ (e) => setRewardTime(Number(e.target.value)) }>
<option value="0">Once</option>
<option value="3">Once every { limitationInterval } minutes</option>
<option value="2">Once every { limitationInterval } hours</option>
<option value="1">Once every { limitationInterval } days</option>
</select>
{ rewardTime > 0 && <input type="number" className="ms-2 form-control form-control-sm" value={ limitationInterval } onChange={ event => setLimitationInterval(Number(event.target.value)) } /> }
</div>
<hr className="my-1 mb-2 bg-dark" />
<div className="form-check">
<input className="form-check-input" type="checkbox" id="uniqueRewards" checked={ uniqueRewards } onChange={(e) => setUniqueRewards(e.target.checked)} />
<label className="form-check-label" htmlFor="uniqueRewards">
Unique rewards
</label>
</div>
<div className="bg-muted rounded small text-black p-1 text-center">If checked each reward will be given once to each user. This will disable the probabilities option.</div>
<hr className="my-1 mb-2 bg-dark" />
<div className="d-flex justify-content-between align-items-center">
<div className="fw-bold">Rewards</div>
<div className="btn btn-sm btn-success" onClick={ addReward }><i className="fas fa-plus" /></div>
</div>
<table className="table-sm">
<thead>
<tr>
<td>Badge?</td>
<td>Item Code</td>
<td>Probability</td>
<td></td>
</tr>
</thead>
<tbody>
{ rewards && rewards.map((reward, index) =>
{
return (
<tr key={ index }>
<td className="d-flex align-items-center justify-content-center">
<input className="form-check-input" type="checkbox" checked={ reward.isBadge } onChange={(e) => updateReward(index, e.target.checked, reward.itemCode, reward.probability)} />
</td>
<td>
<input type="text" className="form-control form-control-sm" value={ reward.itemCode } onChange={ e => updateReward(index, reward.isBadge, e.target.value, reward.probability) } />
</td>
<td>
<input type="number" className="form-control form-control-sm" value={ reward.probability } onChange={ e => updateReward(index, reward.isBadge, reward.itemCode, Number(e.target.value)) } />
</td>
<td>
{ index > 0 && <button className="btn btn-sm btn-danger" onClick={() => removeReward(index) }><i className="fas fa-trash" /></button> }
</td>
</tr>
)
}) }
</tbody>
</table>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,70 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionGiveScoreToPredefinedTeamView: FC<{}> = props =>
{
const [ points, setPoints ] = useState(1);
const [ time, setTime ] = useState(1);
const [ selectedTeam, setSelectedTeam ] = useState(1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
if(trigger.intData.length >= 2)
{
setPoints(trigger.intData[0]);
setTime(trigger.intData[1]);
setSelectedTeam(trigger.intData[2]);
}
else
{
setPoints(1);
setTime(1);
setSelectedTeam(1);
}
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ points, time, selectedTeam ]);
}, [ points, time, selectedTeam, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) }</label>
<Slider
value={ points }
min={ 1 }
max={ 100 }
onChange={ event => setPoints(event) } />
</div>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.settimesingame', [ 'times' ], [ time.toString() ]) }</label>
<Slider
value={ time }
min={ 1 }
max={ 10 }
onChange={ event => setTime(event) } />
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.team') }</label>
{ [1, 2, 3, 4].map(value =>
{
return (
<div key={ value } className="form-check">
<input className="form-check-input" type="radio" name="selectedTeam" id={ `selectedTeam${ value }` } checked={ (selectedTeam === value) } onChange={ event => setSelectedTeam(value) } />
<label className="form-check-label" htmlFor={'selectedTeam' + value}>
{ LocalizeText('wiredfurni.params.team.' + value) }
</label>
</div>
);
}) }
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,53 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionGiveScoreView: FC<{}> = props =>
{
const [ points, setPoints ] = useState(1);
const [ time, setTime ] = useState(1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
if(trigger.intData.length >= 2)
{
setPoints(trigger.intData[0]);
setTime(trigger.intData[1]);
}
else
{
setPoints(1);
setTime(1);
}
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ points, time ]);
}, [ points, time, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.setpoints', [ 'points' ], [ points.toString() ]) }</label>
<Slider
value={ points }
min={ 1 }
max={ 100 }
onChange={ event => setPoints(event) } />
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.settimesingame', [ 'times' ], [ time.toString() ]) }</label>
<Slider
value={ time }
min={ 1 }
max={ 10 }
onChange={ event => setTime(event) } />
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,40 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionJoinTeamView: FC<{}> = props =>
{
const [ selectedTeam, setSelectedTeam ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setSelectedTeam((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ selectedTeam ]);
}, [ selectedTeam, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.team') }</label>
{ [1, 2, 3, 4].map(team =>
{
return (
<div key={ team } className="form-check">
<input className="form-check-input" type="radio" name="selectedTeam" id={ `selectedTeam${ team }` } checked={ (selectedTeam === team) } onChange={ event => setSelectedTeam(team) } />
<label className="form-check-label" htmlFor={ `selectedTeam${ team }` }>
{ LocalizeText(`wiredfurni.params.team.${ team }`) }
</label>
</div>
)
}) }
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,30 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionKickFromRoomView: FC<{}> = props =>
{
const [ message, setMessage ] = useState('');
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setMessage(trigger.stringData);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(message);
}, [ message, setStringParam ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.message') }</label>
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } />
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionLeaveTeamView: FC<{}> = props =>
{
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />;
}

View File

@ -0,0 +1,89 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
const directionOptions: { value: number, icon: string }[] = [
{
value: 0,
icon: 'ne'
},
{
value: 2,
icon: 'se'
},
{
value: 4,
icon: 'sw'
},
{
value: 6,
icon: 'nw'
}
];
const rotationOptions: number[] = [0, 1, 2, 3, 4, 5, 6];
export const WiredActionMoveAndRotateFurniView: FC<{}> = props =>
{
const [ movement, setMovement ] = useState(-1);
const [ rotation, setRotation ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
if(trigger.intData.length >= 2)
{
setMovement(trigger.intData[0]);
setRotation(trigger.intData[1]);
}
else
{
setMovement(-1);
setRotation(-1);
}
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ movement, rotation ]);
}, [ movement, rotation, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.startdir') }</label>
<div className="row row-col-4">
{ directionOptions.map(option =>
{
return (
<div key={ option.value } className="col">
<div className="form-check">
<input className="form-check-input" type="radio" name="movement" id={ `movement${ option.value }` } checked={ (movement === option.value) } onChange={ event => setMovement(option.value) } />
<label className="form-check-label" htmlFor={ `movement${ option.value }` }>
<i className={ `icon icon-${ option.icon }` } />
</label>
</div>
</div>
)
}) }
</div>
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.turn') }</label>
{ rotationOptions.map(option =>
{
return (
<div key={ option } className="form-check">
<input className="form-check-input" type="radio" name="rotation" id={ `rotation${ option }` } checked={ (rotation === option) } onChange={ event => setRotation(option) } />
<label className="form-check-label" htmlFor={ `rotation${ option }` }>
{ LocalizeText(`wiredfurni.params.turn.${ option }`) }
</label>
</div>
)
}) }
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,82 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
const directionOptions: { value: number, icon: string }[] = [
{
value: 0,
icon: 'ne'
},
{
value: 2,
icon: 'se'
},
{
value: 4,
icon: 'sw'
},
{
value: 6,
icon: 'nw'
}
];
export const WiredActionMoveFurniToView: FC<{}> = props =>
{
const [ spacing, setSpacing ] = useState(-1);
const [ movement, setMovement ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
if(trigger.intData.length >= 2)
{
setSpacing(trigger.intData[1]);
setMovement(trigger.intData[0]);
}
else
{
setSpacing(-1);
setMovement(-1);
}
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ movement, spacing ]);
}, [ movement, spacing, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.emptytiles', [ 'tiles' ], [ spacing.toString() ]) }</label>
<Slider
value={ spacing }
min={ 1 }
max={ 5 }
onChange={ event => setSpacing(event) } />
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.startdir') }</label>
<div className="row row-cold-4">
{ directionOptions.map(value =>
{
return (
<div key={ value.value } className="col">
<div className="form-check">
<input className="form-check-input" type="radio" name="movement" id={ `movement${ value.value }` } checked={ (movement === value.value) } onChange={ event => setMovement(value.value) } />
<label className="form-check-label" htmlFor={ `movement${ value.value }` }>
<i className={ `icon icon-${ value.icon }` } />
</label>
</div>
</div>
)
}) }
</div>
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,109 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
const directionOptions: { value: number, icon: string }[] = [
{
value: 4,
icon: 'ne'
},
{
value: 5,
icon: 'se'
},
{
value: 6,
icon: 'sw'
},
{
value: 7,
icon: 'nw'
},
{
value: 2,
icon: 'mv-2'
},
{
value: 3,
icon: 'mv-3'
},
{
value: 1,
icon: 'mv-1'
}
];
const rotationOptions: number[] = [0, 1, 2, 3];
export const WiredActionMoveFurniView: FC<{}> = props =>
{
const [ movement, setMovement ] = useState(-1);
const [ rotation, setRotation ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
if(trigger.intData.length >= 2)
{
setMovement(trigger.intData[0]);
setRotation(trigger.intData[1]);
}
else
{
setMovement(-1);
setRotation(-1);
}
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ movement, rotation ]);
}, [ movement, rotation, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.movefurni') }</label>
<div className="form-check">
<input className="form-check-input" type="radio" name="selectedTeam" id="movement0" checked={ (movement === 0) } onChange={ event => setMovement(0) } />
<label className="form-check-label" htmlFor="movement0">
{ LocalizeText('wiredfurni.params.movefurni.0') }
</label>
</div>
<div className="row row-col-4">
{ directionOptions.map(option =>
{
return (
<div key={ option.value } className="col">
<div className="form-check">
<input className="form-check-input" type="radio" name="movement" id={ `movement${ option.value }` } checked={ (movement === option.value) } onChange={ event => setMovement(option.value) } />
<label className="form-check-label" htmlFor={ `movement${ option.value }` }>
<i className={ `icon icon-${ option.icon }` } />
</label>
</div>
</div>
)
}) }
<div className="col" />
</div>
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.rotatefurni') }</label>
{ rotationOptions.map(option =>
{
return (
<div key={ option } className="form-check">
<input className="form-check-input" type="radio" name="rotation" id={ `rotation${ option }` } checked={ (rotation === option) } onChange={ event => setRotation(option) } />
<label className="form-check-label" htmlFor={'rotation' + option}>
{ [1, 2].includes(option) && <i className={ `icon icon-rot-${ option }` } /> }
{ LocalizeText(`wiredfurni.params.rotatefurni.${ option }`) }
</label>
</div>
)
}) }
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,42 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionMuteUserView: FC<{}> = props =>
{
const [ time, setTime ] = useState(-1);
const [ message, setMessage ] = useState('');
const { trigger = null, setIntParams = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0);
setMessage(trigger.stringData);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ time ]);
setStringParam(message);
}, [ time, message, setIntParams, setStringParam ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.length.minutes', ['minutes'], [ time.toString() ]) }</label>
<Slider
value={ time }
min={ 1 }
max={ 10 }
onChange={ event => setTime(event) } />
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.message') }</label>
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } />
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionResetView: FC<{}> = props =>
{
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />;
}

View File

@ -0,0 +1,51 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionSetFurniStateToView: FC<{}> = props =>
{
const [ stateFlag, setStateFlag ] = useState(-1);
const [ directionFlag, setDirectionFlag ] = useState(-1);
const [ positionFlag, setPositionFlag ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setStateFlag(trigger.getBoolean(0) ? 1 : 0);
setDirectionFlag(trigger.getBoolean(1) ? 1 : 0);
setPositionFlag(trigger.getBoolean(2) ? 1 : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ stateFlag, directionFlag, positionFlag ]);
}, [ directionFlag, positionFlag, stateFlag, setIntParams ]);
return (
<WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.conditions') }</label>
<div className="form-check">
<input className="form-check-input" type="checkbox" id="stateFlag" onChange={ event => setStateFlag(event.target.checked ? 1 : 0) } />
<label className="form-check-label" htmlFor="stateFlag">
{ LocalizeText('wiredfurni.params.condition.state') }
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="checkbox" id="directionFlag" onChange={ event => setDirectionFlag(event.target.checked ? 1 : 0) } />
<label className="form-check-label" htmlFor="directionFlag">
{ LocalizeText('wiredfurni.params.condition.direction') }
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="checkbox" id="positionFlag" onChange={ event => setPositionFlag(event.target.checked ? 1 : 0) } />
<label className="form-check-label" htmlFor="positionFlag">
{ LocalizeText('wiredfurni.params.condition.position') }
</label>
</div>
</div>
</WiredActionBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionTeleportView: FC<{}> = props =>
{
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredActionBaseView } from '../base/WiredActionBaseView';
export const WiredActionToggleFurniStateView: FC<{}> = props =>
{
return <WiredActionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_BY_TYPE_OR_FROM_CONTEXT } save={ null } />;
}

View File

@ -0,0 +1,100 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { GetSessionDataManager } from '../../../../api';
import { WiredEvent } from '../../../../events';
import { dispatchUiEvent } from '../../../../hooks/events';
import { NitroCardContentView, NitroCardView } from '../../../../layout';
import { LocalizeText } from '../../../../utils/LocalizeText';
import { WiredSelectionVisualizer } from '../../common/WiredSelectionVisualizer';
import { useWiredContext } from '../../context/WiredContext';
import { WiredFurniType } from '../../WiredView.types';
import { WiredFurniSelectorView } from '../furni-selector/WiredFurniSelectorView';
import { WiredBaseViewProps } from './WiredBaseView.types';
export const WiredBaseView: FC<WiredBaseViewProps> = props =>
{
const { wiredType = '', requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, children = null } = props;
const [ wiredName, setWiredName ] = useState<string>(null);
const [ wiredDescription, setWiredDescription ] = useState<string>(null);
const { trigger = null, setTrigger = null, setIntParams = null, setStringParam = null, setFurniIds = null } = useWiredContext();
useEffect(() =>
{
if(!trigger) return;
const spriteId = (trigger.spriteId || -1);
const furniData = GetSessionDataManager().getFloorItemData(spriteId);
if(!furniData)
{
setWiredName(('NAME: ' + spriteId));
setWiredDescription(('NAME: ' + spriteId));
}
else
{
setWiredName(furniData.name);
setWiredDescription(furniData.description);
}
setIntParams(trigger.intData);
setStringParam(trigger.stringData);
setFurniIds(prevValue =>
{
if(prevValue && prevValue.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue);
if(trigger.selectedItems && trigger.selectedItems.length)
{
WiredSelectionVisualizer.applySelectionShaderToFurni(trigger.selectedItems);
return trigger.selectedItems;
}
return [];
});
}, [ trigger, setIntParams, setStringParam, setFurniIds ]);
const onSave = useCallback(() =>
{
if(save) save();
setTimeout(() => dispatchUiEvent(new WiredEvent(WiredEvent.SAVE_WIRED)), 1);
}, [ save ]);
const close = useCallback(() =>
{
setTrigger(null);
}, [ setTrigger ]);
return (
<NitroCardView className={`nitro-wired nitro-wired-${wiredType} ` + (wiredType === 'trigger' ? 'rounded-0' : 'rounded-2')}>
<div className="nitro-wired-header d-flex">
<div className="nitro-wired-title rounded-start w-100 drag-handler">{ LocalizeText('wiredfurni.title') }</div>
<div className="nitro-wired-close rounded-end flex-shrink-0" onClick={ close }>
<i className="fas fa-times" />
</div>
</div>
<NitroCardContentView>
<div className="d-flex align-items-center">
<i className={ `me-2 icon icon-wired-${ wiredType }` } />
<div className="fw-bold">{ wiredName }</div>
</div>
<div>{ wiredDescription }</div>
<div>
{ !children ? null : <>
<hr className="my-1 mb-2 bg-dark" />
{ children }
</> }
</div>
{ (requiresFurni > WiredFurniType.STUFF_SELECTION_OPTION_NONE) &&
<>
<hr className="my-1 mb-2 bg-dark" />
<WiredFurniSelectorView />
</> }
<div className="d-flex mt-3">
<button className="btn btn-sm btn-success me-2 w-100" onClick={ onSave }>{ LocalizeText('wiredfurni.ready') }</button>
<button className="btn btn-sm btn-secondary w-100" onClick={ close }>{ LocalizeText('cancel') }</button>
</div>
</NitroCardContentView>
</NitroCardView>
);
}

View File

@ -0,0 +1,6 @@
export interface WiredBaseViewProps
{
wiredType: string;
requiresFurni: number;
save: () => void;
}

View File

@ -0,0 +1,37 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
const allowedHanditemIds: number[] = [ 2, 5, 7, 8, 9, 10, 27 ];
export const WiredConditionActorHasHandItemView: FC<{}> = props =>
{
const [ handItemId, setHandItemId ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setHandItemId((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ handItemId ]);
}, [ handItemId, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.handitem') }</label>
<select className="form-select form-select-sm" value={ handItemId } onChange={ event => setHandItemId(parseInt(event.target.value)) }>
{ allowedHanditemIds.map((value, index) =>
{
return <option key={ index } value={ value }>{ LocalizeText(`handitem${ value }`) }</option>
}) }
</select>
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionActorIsGroupMemberView: FC<{}> = props =>
{
return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />;
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionActorIsOnFurniView: FC<{}> = props =>
{
return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ null } />;
}

View File

@ -0,0 +1,42 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
const teamIds: number[] = [ 1, 2, 3, 4 ];
export const WiredConditionActorIsTeamMemberView: FC<{}> = props =>
{
const [ selectedTeam, setSelectedTeam ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setSelectedTeam((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ selectedTeam ]);
}, [ selectedTeam, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.team') }</label>
{ teamIds.map((value, index) =>
{
return (
<div key={ index } className="form-check">
<input className="form-check-input" type="radio" name="selectedTeam" id={ `selectedTeam${ value }` } checked={ (selectedTeam === value) } onChange={ event => setSelectedTeam(value) } />
<label className="form-check-label" htmlFor={ `selectedTeam${ value }` }>
{ LocalizeText(`wiredfurni.params.team.${ value }`) }
</label>
</div>
)
}) }
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,30 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionActorIsWearingBadgeView: FC<{}> = props =>
{
const [ badge, setBadge ] = useState('');
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setBadge(trigger.stringData);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(badge);
}, [ badge, setStringParam ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.badgecode') }</label>
<input type="text" className="form-control form-control-sm" value={ badge } onChange={ event => setBadge(event.target.value) } />
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,30 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionActorIsWearingEffectView: FC<{}> = props =>
{
const [ effect, setEffect ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setEffect((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ effect ]);
}, [ effect, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.effectid') }</label>
<input type="number" className="form-control form-control-sm" value={ effect } onChange={ event => setEffect(parseInt(event.target.value)) } />
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,20 @@
import { FC, useCallback } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredBaseView } from '../../base/WiredBaseView';
import { WiredConditionBaseViewProps } from './WiredConditionBaseView.types';
export const WiredConditionBaseView: FC<WiredConditionBaseViewProps> = props =>
{
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, children = null } = props;
const onSave = useCallback(() =>
{
if(save) save();
}, [ save ]);
return (
<WiredBaseView wiredType="condition" requiresFurni={ requiresFurni } save={ onSave }>
{ children }
</WiredBaseView>
);
}

View File

@ -0,0 +1,5 @@
export interface WiredConditionBaseViewProps
{
requiresFurni: number;
save: () => void;
}

View File

@ -0,0 +1,62 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionDateRangeView: FC<{}> = props =>
{
const [ startDate, setStartDate ] = useState('');
const [ endDate, setEndDate ] = useState('');
const { trigger = null, setIntParams = null } = useWiredContext();
const dateToString = useCallback((date: Date) =>
{
return `${date.getFullYear()}/${('0' + (date.getMonth() + 1)).slice(-2)}/${('0' + date.getDate()).slice(-2)} ` + `${('0' + date.getHours()).slice(-2)}:${('0' + date.getMinutes()).slice(-2)}`;
}, []);
useEffect(() =>
{
if(trigger.intData.length >= 2)
{
let startDate = new Date();
let endDate = new Date();
if(trigger.intData[0] > 0)
startDate = new Date((trigger.intData[0] * 1000));
if(trigger.intData[1] > 0)
endDate = new Date((trigger.intData[1] * 1000));
setStartDate(dateToString(startDate));
setEndDate(dateToString(endDate));
}
}, [ trigger ]);
const save = useCallback(() =>
{
let startDateMili = 0;
let endDateMili = 0;
const startDateInstance = new Date(startDate);
const endDateInstance = new Date(endDate);
if(startDateInstance && endDateInstance)
{
startDateMili = startDateInstance.getTime() / 1000;
endDateMili = endDateInstance.getTime() / 1000;
}
setIntParams([startDateMili, endDateMili]);
}, [ startDate, endDate, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="fw-bold">{ LocalizeText('wiredfurni.params.startdate') }</div>
<input type="text" className="form-control form-control-sm" value={ startDate } onChange={ (e) => setStartDate(e.target.value) } />
<hr className="my-1 mb-2 bg-dark" />
<div className="fw-bold">{ LocalizeText('wiredfurni.params.enddate') }</div>
<input type="text" className="form-control form-control-sm" value={ endDate } onChange={ (e) => setEndDate(e.target.value) } />
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionFurniHasAvatarOnView: FC<{}> = props =>
{
return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ null } />;
}

View File

@ -0,0 +1,40 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionFurniHasFurniOnView: FC<{}> = props =>
{
const [ requireAll, setRequireAll ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setRequireAll((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ requireAll ]);
}, [ requireAll, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.requireall') }</label>
{ [0, 1].map(value =>
{
return (
<div key={ value } className="form-check">
<input className="form-check-input" type="radio" name="requireAll" id={ `requireAll${ value }` } checked={ (requireAll === value) } onChange={ event => setRequireAll(value) } />
<label className="form-check-label" htmlFor={ `requireAll${ value }` }>
{ LocalizeText('wiredfurni.params.requireall.' + value) }
</label>
</div>
)
}) }
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,40 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionFurniHasNotFurniOnView: FC<{}> = props =>
{
const [ requireAll, setRequireAll ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setRequireAll((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ requireAll ]);
}, [ requireAll, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.not_requireall') }</label>
{ [0, 1].map(value =>
{
return (
<div key={ value } className="form-check">
<input className="form-check-input" type="radio" name="requireAll" id={ `requireAll${ value }` } checked={ (requireAll === value) } onChange={ event => setRequireAll(value) } />
<label className="form-check-label" htmlFor={ `requireAll${ value }` }>
{ LocalizeText(`wiredfurni.params.not_requireall.${ value }`) }
</label>
</div>
)
}) }
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionFurniIsOfTypeView: FC<{}> = props =>
{
return <WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ null } />;
}

View File

@ -0,0 +1,51 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionFurniMatchesSnapshotView: FC<{}> = props =>
{
const [ stateFlag, setStateFlag ] = useState(-1);
const [ directionFlag, setDirectionFlag ] = useState(-1);
const [ positionFlag, setPositionFlag ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setStateFlag(trigger.getBoolean(0) ? 1 : 0);
setDirectionFlag(trigger.getBoolean(1) ? 1 : 0);
setPositionFlag(trigger.getBoolean(2) ? 1 : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ stateFlag, directionFlag, positionFlag ]);
}, [ directionFlag, positionFlag, stateFlag, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.conditions') }</label>
<div className="form-check">
<input className="form-check-input" type="checkbox" id="stateFlag" onChange={ event => setStateFlag(event.target.checked ? 1 : 0) } />
<label className="form-check-label" htmlFor="stateFlag">
{ LocalizeText('wiredfurni.params.condition.state') }
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="checkbox" id="directionFlag" onChange={ event => setDirectionFlag(event.target.checked ? 1 : 0) } />
<label className="form-check-label" htmlFor="directionFlag">
{ LocalizeText('wiredfurni.params.condition.direction') }
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="checkbox" id="positionFlag" onChange={ event => setPositionFlag(event.target.checked ? 1 : 0) } />
<label className="form-check-label" htmlFor="positionFlag">
{ LocalizeText('wiredfurni.params.condition.position') }
</label>
</div>
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,36 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { GetWiredTimeLocale } from '../../../common/GetWiredTimeLocale';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionTimeElapsedLessView: FC<{}> = props =>
{
const [ time, setTime ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ time ]);
}, [ time, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.allowbefore', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</label>
<Slider
value={ time }
min={ 1 }
max={ 1200 }
onChange={ event => setTime(event) } />
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,36 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { GetWiredTimeLocale } from '../../../common/GetWiredTimeLocale';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionTimeElapsedMoreView: FC<{}> = props =>
{
const [ time, setTime ] = useState(-1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ time ]);
}, [ time, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.allowafter', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</label>
<Slider
value={ time }
min={ 1 }
max={ 1200 }
onChange={ event => setTime(event) } />
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,53 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredConditionBaseView } from '../base/WiredConditionBaseView';
export const WiredConditionUserCountInRoomView: FC<{}> = props =>
{
const [ min, setMin ] = useState(1);
const [ max, setMax ] = useState(1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
if(trigger.intData.length >= 2)
{
setMin(trigger.intData[0]);
setMax(trigger.intData[1]);
}
else
{
setMin(1);
setMax(1);
}
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ min, max ]);
}, [ min, max, setIntParams ]);
return (
<WiredConditionBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.usercountmin', [ 'value' ], [ min.toString() ]) }</label>
<Slider
value={ min }
min={ 1 }
max={ 50 }
onChange={ event => setMin(event) } />
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.usercountmax', [ 'value' ], [ max.toString() ]) }</label>
<Slider
value={ max }
min={ 1 }
max={ 50 }
onChange={ event => setMax(event) } />
</div>
</WiredConditionBaseView>
);
}

View File

@ -0,0 +1,84 @@
import { FC, useCallback, useEffect } from 'react';
import { WiredSelectObjectEvent } from '../../../../events';
import { useUiEvent } from '../../../../hooks/events';
import { LocalizeText } from '../../../../utils/LocalizeText';
import { WiredSelectionVisualizer } from '../../common/WiredSelectionVisualizer';
import { useWiredContext } from '../../context/WiredContext';
import { WiredFurniSelectorViewProps } from './WiredFurniSelectorView.types';
export const WiredFurniSelectorView: FC<WiredFurniSelectorViewProps> = props =>
{
const { trigger = null, furniIds = [], setFurniIds = null } = useWiredContext();
const onWiredSelectObjectEvent = useCallback((event: WiredSelectObjectEvent) =>
{
const furniId = event.objectId;
if(furniId === -1) return;
let newFurniIds: number[] = null;
setFurniIds(prevValue =>
{
newFurniIds = [ ...prevValue ];
const index = prevValue.indexOf(furniId);
if(index >= 0)
{
newFurniIds.splice(index, 1);
WiredSelectionVisualizer.hide(furniId);
}
else
{
if(newFurniIds.length < trigger.maximumItemSelectionCount)
{
newFurniIds.push(furniId);
WiredSelectionVisualizer.show(furniId);
}
}
return newFurniIds;
});
}, [ trigger, setFurniIds ]);
useUiEvent(WiredSelectObjectEvent.SELECT_OBJECT, onWiredSelectObjectEvent);
useEffect(() =>
{
if(!trigger) return;
setFurniIds(prevValue =>
{
if(prevValue && prevValue.length) WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue);
if(trigger.selectedItems && trigger.selectedItems.length)
{
WiredSelectionVisualizer.applySelectionShaderToFurni(trigger.selectedItems);
return trigger.selectedItems;
}
return [];
});
return () =>
{
setFurniIds(prevValue =>
{
WiredSelectionVisualizer.clearSelectionShaderFromFurni(prevValue);
return [];
});
}
}, [ trigger, setFurniIds ]);
return (
<div className="d-flex flex-column">
<div className="fw-bold">{ LocalizeText('wiredfurni.pickfurnis.caption', ['count', 'limit'], [ furniIds.length.toString(), trigger.maximumItemSelectionCount.toString() ]) }</div>
{ LocalizeText('wiredfurni.pickfurnis.desc') }
</div>
);
}

View File

@ -0,0 +1,3 @@
export class WiredFurniSelectorViewProps
{
}

View File

@ -0,0 +1,48 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerAvatarEnterRoomView: FC<{}> = props =>
{
const [ username, setUsername ] = useState('');
const [ avatarMode, setAvatarMode ] = useState(0);
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setUsername(trigger.stringData);
setAvatarMode(trigger.stringData ? 1 : 0)
}, [ trigger ]);
const save = useCallback(() =>
{
if(avatarMode === 1) setStringParam(username);
else setStringParam('');
}, [ username, avatarMode, setStringParam ]);
return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.picktriggerer') }</label>
<div className="form-check">
<input className="form-check-input" type="radio" name="avatarMode" id="avatarMode0" checked={ (avatarMode === 0) } onChange={ event => setAvatarMode(0) } />
<label className="form-check-label" htmlFor="avatarMode0">
{ LocalizeText('wiredfurni.params.anyavatar') }
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" name="avatarMode" id="avatarMode1" checked={ (avatarMode === 1) } onChange={ event => setAvatarMode(1) } />
<label className="form-check-label" htmlFor="avatarMode1">
{ LocalizeText('wiredfurni.params.certainavatar') }
</label>
</div>
</div>
{ (avatarMode === 1) &&
<div className="form-group">
<input type="text" className="form-control form-control-sm" value={ username } onChange={ event => setUsername(event.target.value) } />
</div> }
</WiredTriggerBaseView>
);
}

View File

@ -0,0 +1,49 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { GetSessionDataManager } from '../../../../../api';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerAvatarSaysSomethingView: FC<{}> = props =>
{
const [ message, setMessage ] = useState('');
const [ triggererAvatar, setTriggererAvatar ] = useState(-1);
const { trigger = null, setStringParam = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setMessage(trigger.stringData);
setTriggererAvatar((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(message);
setIntParams([ triggererAvatar ]);
}, [ message, triggererAvatar, setStringParam, setIntParams ]);
return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group mb-2">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.whatissaid') }</label>
<input type="text" className="form-control form-control-sm" value={ message } onChange={ event => setMessage(event.target.value) } />
</div>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.picktriggerer') }</label>
<div className="form-check">
<input className="form-check-input" type="radio" name="triggererAvatar" id="triggererAvatar0" checked={ triggererAvatar === 0 } onChange={() => setTriggererAvatar(0)} />
<label className="form-check-label" htmlFor="triggererAvatar0">
{ LocalizeText('wiredfurni.params.anyavatar') }
</label>
</div>
<div className="form-check">
<input className="form-check-input" type="radio" name="triggererAvatar" id="triggererAvatar1" checked={ triggererAvatar === 1 } onChange={() => setTriggererAvatar(1)} />
<label className="form-check-label" htmlFor="triggererAvatar1">
{ GetSessionDataManager().userName }
</label>
</div>
</div>
</WiredTriggerBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerAvatarWalksOffFurniView: FC<{}> = props =>
{
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ null } />;
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerAvatarWalksOnFurniView: FC<{}> = props =>
{
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_BY_ID_OR_BY_TYPE } save={ null } />;
}

View File

@ -0,0 +1,20 @@
import { FC, useCallback } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredBaseView } from '../../base/WiredBaseView';
import { WiredTriggerBaseViewProps } from './WiredTriggerBaseView.types';
export const WiredTriggerBaseView: FC<WiredTriggerBaseViewProps> = props =>
{
const { requiresFurni = WiredFurniType.STUFF_SELECTION_OPTION_NONE, save = null, children = null } = props;
const onSave = useCallback(() =>
{
if(save) save();
}, [ save ]);
return (
<WiredBaseView wiredType="trigger" requiresFurni={ requiresFurni } save={ onSave }>
{ children }
</WiredBaseView>
);
}

View File

@ -0,0 +1,5 @@
export interface WiredTriggerBaseViewProps
{
requiresFurni: number;
save: () => void;
}

View File

@ -0,0 +1,30 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerBotReachedAvatarView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setBotName(trigger.stringData);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(botName);
}, [ botName, setStringParam ]);
return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
</WiredTriggerBaseView>
);
}

View File

@ -0,0 +1,30 @@
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerBotReachedStuffView: FC<{}> = props =>
{
const [ botName, setBotName ] = useState('');
const { trigger = null, setStringParam = null } = useWiredContext();
useEffect(() =>
{
setBotName(trigger.stringData);
}, [ trigger ]);
const save = useCallback(() =>
{
setStringParam(botName);
}, [ botName, setStringParam ]);
return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.bot.name') }</label>
<input type="text" className="form-control form-control-sm" maxLength={ 32 } value={ botName } onChange={ event => setBotName(event.target.value) } />
</div>
</WiredTriggerBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerCollisionView: FC<{}> = props =>
{
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />;
}

View File

@ -0,0 +1,36 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { GetWiredTimeLocale } from '../../../common/GetWiredTimeLocale';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggeExecuteOnceView: FC<{}> = props =>
{
const [ time, setTime ] = useState(1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ time ]);
}, [ time, setIntParams ]);
return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.settime', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</label>
<Slider
value={ time }
min={ 1 }
max={ 1200 }
onChange={ event => setTime(event) } />
</div>
</WiredTriggerBaseView>
);
}

View File

@ -0,0 +1,36 @@
import { FriendlyTime } from 'nitro-renderer';
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggeExecutePeriodicallyLongView: FC<{}> = props =>
{
const [ time, setTime ] = useState(1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ time ]);
}, [ time, setIntParams ]);
return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.setlongtime', [ 'time' ], [ FriendlyTime.format(time * 5).toString() ]) }</label>
<Slider
value={ time }
min={ 1 }
max={ 120 }
onChange={ event => setTime(event) } />
</div>
</WiredTriggerBaseView>
);
}

View File

@ -0,0 +1,36 @@
import Slider from 'rc-slider/lib/Slider';
import { FC, useCallback, useEffect, useState } from 'react';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { GetWiredTimeLocale } from '../../../common/GetWiredTimeLocale';
import { useWiredContext } from '../../../context/WiredContext';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggeExecutePeriodicallyView: FC<{}> = props =>
{
const [ time, setTime ] = useState(1);
const { trigger = null, setIntParams = null } = useWiredContext();
useEffect(() =>
{
setTime((trigger.intData.length > 0) ? trigger.intData[0] : 0);
}, [ trigger ]);
const save = useCallback(() =>
{
setIntParams([ time ]);
}, [ time, setIntParams ]);
return (
<WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ save }>
<div className="form-group">
<label className="fw-bold">{ LocalizeText('wiredfurni.params.settime', [ 'seconds' ], [ GetWiredTimeLocale(time) ]) }</label>
<Slider
value={ time }
min={ 1 }
max={ 60 }
onChange={ event => setTime(event) } />
</div>
</WiredTriggerBaseView>
);
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerGameEndsView: FC<{}> = props =>
{
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />;
}

View File

@ -0,0 +1,8 @@
import { FC } from 'react';
import { WiredFurniType } from '../../../WiredView.types';
import { WiredTriggerBaseView } from '../base/WiredTriggerBaseView';
export const WiredTriggerGameStartsView: FC<{}> = props =>
{
return <WiredTriggerBaseView requiresFurni={ WiredFurniType.STUFF_SELECTION_OPTION_NONE } save={ null } />;
}

Some files were not shown because too many files have changed in this diff Show More