Skip to content

Commit

Permalink
Merge pull request #1663 from pau-tomas/feat/camera_properties
Browse files Browse the repository at this point in the history
Add camera properties to Value Selects
chrismaltby authored Jan 28, 2025

Verified

This commit was signed with the committer’s verified signature.
snyk-bot Snyk bot
2 parents 8442a2e + 3d6261d commit 1a438b4
Showing 9 changed files with 333 additions and 160 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Add ability to quickly create "Comment" events by typing the comment text in the Add Event search field and choosing "Comment" menu item [@pau-tomas](https://github.com/pau-tomas)
- Add text code `!Wait` to allow pausing dialogue until an amount of time/frames has elapsed or a selected button has been pressed
- Add setting to toggle GBC color correction. Disable color correction to closer match how colors will appear on modern hardware
- Add ability to read camera properties (tile/pixel position, deadzone and offset) within script values [@pau-tomas](https://github.com/pau-tomas)

### Changed

236 changes: 158 additions & 78 deletions src/components/forms/PropertySelect.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useContext, useEffect, useState } from "react";
import React, { ReactElement, useContext, useEffect, useState } from "react";
import { useAppSelector } from "store/hooks";
import {
ActorDirection,
@@ -26,6 +26,7 @@ import styled from "styled-components";
import { UnitsSelectButtonInputOverlay } from "./UnitsSelectButtonInputOverlay";
import { ScriptEditorContext } from "components/script/ScriptEditorContext";
import { components, SingleValue } from "react-select";
import { CameraIcon } from "ui/icons/Icons";

interface PropertySelectProps {
name: string;
@@ -36,13 +37,15 @@ interface PropertySelectProps {
onChangeUnits?: (newUnits: UnitType) => void;
}

type ActorOption = Option & {
type PropertyOption = Option & {
spriteSheetId?: string;
menuSpriteSheetId?: string;
icon?: ReactElement;
menuIcon?: ReactElement;
};

type ActorOptGroup = OptGroup & {
options: ActorOption[];
type PropertyOptGroup = OptGroup & {
options: PropertyOption[];
};

const allCustomEventActors = Array.from(Array(10).keys()).map((i) => ({
@@ -56,6 +59,19 @@ export const PropertySelectWrapper = styled.div`
min-width: 78px;
`;

const IconWrapper = styled.div`
display: inline;
align-items: center;
font-weight: bold;
svg {
width: 15px;
margin-right: 3px;
margin-top: 3px;
fill: ${(props) => props.theme.colors.secondaryText};
}
`;

export const PropertySelect = ({
name,
value,
@@ -65,8 +81,8 @@ export const PropertySelect = ({
onChangeUnits,
}: PropertySelectProps) => {
const context = useContext(ScriptEditorContext);
const [options, setOptions] = useState<ActorOptGroup[]>([]);
const [currentValue, setCurrentValue] = useState<ActorOption>();
const [options, setOptions] = useState<PropertyOptGroup[]>([]);
const [currentValue, setCurrentValue] = useState<PropertyOption>();

const sceneType = useAppSelector(
(state) => sceneSelectors.selectById(state, context.sceneId)?.type
@@ -153,80 +169,132 @@ export const PropertySelect = ({
};
};

let actorOptions: PropertyOptGroup[] = [];
if (context.entityType === "customEvent" && customEvent) {
setOptions(
[
{
label: "Player",
value: "player",
},
...allCustomEventActors.map((actor) => {
return {
label: customEvent.actors[actor.id]?.name ?? actor.name,
value: actor.id,
};
}),
].map(actorToOptions)
);
actorOptions = [
{
label: "Player",
value: "player",
},
...allCustomEventActors.map((actor) => {
return {
label: customEvent.actors[actor.id]?.name ?? actor.name,
value: actor.id,
};
}),
].map(actorToOptions);
} else if (sceneActorIds) {
setOptions(
[
...((context.entityType === "actor" ||
context.entityType === "actorPrefab") &&
sceneActor &&
sceneActorIndex !== undefined
? [
{
label: `${l10n("FIELD_SELF")} (${actorName(
sceneActor,
sceneActorIndex
)})`,
value: "$self$",
spriteSheetId: sceneActor.spriteSheetId,
},
]
: []),
{
label: "Player",
value: "player",
spriteSheetId: playerSpriteSheetId,
},
...sceneActorIds.map((actorId, actorIndex) => {
const actor = actorsLookup[actorId] as ActorNormalized;
return {
label: actorName(actor, actorIndex),
value: actor.id,
spriteSheetId: actor.spriteSheetId,
};
}),
].map(actorToOptions)
);
actorOptions = [
...((context.entityType === "actor" ||
context.entityType === "actorPrefab") &&
sceneActor &&
sceneActorIndex !== undefined
? [
{
label: `${l10n("FIELD_SELF")} (${actorName(
sceneActor,
sceneActorIndex
)})`,
value: "$self$",
spriteSheetId: sceneActor.spriteSheetId,
},
]
: []),
{
label: "Player",
value: "player",
spriteSheetId: playerSpriteSheetId,
},
...sceneActorIds.map((actorId, actorIndex) => {
const actor = actorsLookup[actorId] as ActorNormalized;
return {
label: actorName(actor, actorIndex),
value: actor.id,
spriteSheetId: actor.spriteSheetId,
};
}),
].map(actorToOptions);
} else if (context.type === "prefab") {
setOptions(
[
...(context.entityType === "actorPrefab" &&
selfPrefab &&
selfPrefabIndex !== undefined
? [
{
label: `${l10n("FIELD_SELF")} (${actorName(
selfPrefab,
selfPrefabIndex
)})`,
value: "$self$",
spriteSheetId: selfPrefab.spriteSheetId,
direction: "down" as ActorDirection,
},
]
: []),
{
label: l10n("FIELD_PLAYER"),
value: "player",
spriteSheetId: playerSpriteSheetId,
},
].map(actorToOptions)
);
actorOptions = [
...(context.entityType === "actorPrefab" &&
selfPrefab &&
selfPrefabIndex !== undefined
? [
{
label: `${l10n("FIELD_SELF")} (${actorName(
selfPrefab,
selfPrefabIndex
)})`,
value: "$self$",
spriteSheetId: selfPrefab.spriteSheetId,
direction: "down" as ActorDirection,
},
]
: []),
{
label: l10n("FIELD_PLAYER"),
value: "player",
spriteSheetId: playerSpriteSheetId,
},
].map(actorToOptions);
}

const cameraOptions = {
label: l10n("FIELD_CAMERA"),
options: [
{
label: l10n("FIELD_X_POSITION"),
value: "camera:xpos",
icon: <CameraIcon />,
menuIcon: <CameraIcon />,
},
{
label: l10n("FIELD_Y_POSITION"),
value: "camera:ypos",
icon: <CameraIcon />,
menuIcon: "",
},
{
label: l10n("FIELD_PX_POSITION"),
value: "camera:pxpos",
icon: <CameraIcon />,
menuIcon: "",
},
{
label: l10n("FIELD_PY_POSITION"),
value: "camera:pypos",
icon: <CameraIcon />,
menuIcon: "",
},
{
label: l10n("FIELD_DEADZONE_X"),
value: "camera:xdeadzone",
icon: <CameraIcon />,
menuIcon: "",
},
{
label: l10n("FIELD_DEADZONE_Y"),
value: "camera:ydeadzone",
icon: <CameraIcon />,
menuIcon: "",
},
{
label: l10n("FIELD_OFFSET_X"),
value: "camera:xoffset",
icon: <CameraIcon />,
menuIcon: "",
},
{
label: l10n("FIELD_OFFSET_Y"),
value: "camera:yoffset",
icon: <CameraIcon />,
menuIcon: "",
},
],
} as PropertyOptGroup;

const allOptions: PropertyOptGroup[] = actorOptions.concat([cameraOptions]);
setOptions(allOptions);
}, [
actorsLookup,
context.entityType,
@@ -259,12 +327,12 @@ export const PropertySelect = ({
name={name}
value={currentValue}
options={options}
onChange={(newValue: SingleValue<ActorOption>) => {
onChange={(newValue: SingleValue<PropertyOption>) => {
if (newValue) {
onChange?.(newValue.value);
}
}}
formatOptionLabel={(option: ActorOption) => {
formatOptionLabel={(option: PropertyOption) => {
return option.menuSpriteSheetId !== undefined ? (
<OptionLabelWithPreview
preview={
@@ -273,6 +341,12 @@ export const PropertySelect = ({
>
{option.label}
</OptionLabelWithPreview>
) : option?.menuIcon !== undefined ? (
<OptionLabelWithPreview
preview={<IconWrapper>{option.menuIcon}</IconWrapper>}
>
{option.label}
</OptionLabelWithPreview>
) : (
option.label
);
@@ -289,6 +363,12 @@ export const PropertySelect = ({
>
{currentValue?.label}
</SingleValueWithPreview>
) : currentValue?.icon ? (
<SingleValueWithPreview
preview={<IconWrapper>{currentValue.icon}</IconWrapper>}
>
{currentValue?.label}
</SingleValueWithPreview>
) : (
<components.SingleValue {...props}>
{currentValue?.label}
3 changes: 3 additions & 0 deletions src/components/script/hooks/useScriptEventTitle.tsx
Original file line number Diff line number Diff line change
@@ -108,6 +108,9 @@ export const useScriptEventTitle = (
async function fetchAutoLabel() {
if (scriptEventDefs[command]?.hasAutoLabel) {
const actorNameForId = (value: unknown) => {
if (value === "camera") {
return l10n("FIELD_CAMERA");
}
if (context.type === "script" && customEvent) {
return (
customEvent.actors[value as string]?.name ||
6 changes: 6 additions & 0 deletions src/components/ui/icons/Icons.tsx
Original file line number Diff line number Diff line change
@@ -897,6 +897,12 @@ export const SettingsIcon = () => (
</svg>
);

export const CameraIcon = () => (
<svg width="24" height="24" viewBox="0 0 24 24">
<path d="M16 16c0 1.104-.896 2-2 2h-12c-1.104 0-2-.896-2-2v-8c0-1.104.896-2 2-2h12c1.104 0 2 .896 2 2v8zm8-10l-6 4.223v3.554l6 4.223v-12z" />
</svg>
);

export const SadIcon = () => (
<svg width="1096" height="974" viewBox="0 0 1096 974" version="1.1">
<defs>
3 changes: 3 additions & 0 deletions src/lang/en.json
Original file line number Diff line number Diff line change
@@ -989,6 +989,9 @@
"FIELD_SHOW_TILE_VALUES": "Show Tile Values",
"FIELD_SUBMIT_PLUGIN": "Submit Plugin",
"FIELD_WAIT_UNTIL_BUTTON_PRESSED": "Wait Until Button Pressed",
"FIELD_CAMERA": "Camera",
"FIELD_DEADZONE_X": "Deadzone X",
"FIELD_DEADZONE_Y": "Deadzone Y",
"FIELD_COLOR_CORRECTION": "Color Correction",
"FIELD_COLOR_CORRECTION_ENABLED_DEFAULT": "Enabled (Default)",
"FIELD_COLOR_CORRECTION_ENABLED_DEFAULT_INFO": "Corrects colors to closer match how they would appear on original hardware.",
Loading

0 comments on commit 1a438b4

Please sign in to comment.