From d9c80ec06b92c1bd1822cb872d57435ccc450e78 Mon Sep 17 00:00:00 2001
From: Kashargul <144968721+Kashargul@users.noreply.github.com>
Date: Wed, 1 Apr 2026 10:05:36 +0200
Subject: [PATCH] spawn panel fixes (#95566)
---
.../admin/spawn_panel/spawn_handling.dm | 19 ++--------
.../interfaces/SpawnPanel/CreateObject.tsx | 23 +++++++-----
.../SpawnPanel/CreateObjectSettings.tsx | 37 ++++++++++---------
.../tgui/interfaces/SpawnPanel/constants.tsx | 18 ++++++---
tgui/packages/tgui/interfaces/SpawnSearch.tsx | 30 +++++++--------
5 files changed, 64 insertions(+), 63 deletions(-)
diff --git a/code/modules/admin/spawn_panel/spawn_handling.dm b/code/modules/admin/spawn_panel/spawn_handling.dm
index dddfbda0eb8..265dd6c38da 100644
--- a/code/modules/admin/spawn_panel/spawn_handling.dm
+++ b/code/modules/admin/spawn_panel/spawn_handling.dm
@@ -24,22 +24,9 @@
var/amount = clamp(text2num(spawn_params["atom_amount"]), 1, ADMIN_SPAWN_CAP)
- var/list/offset_data
- if(islist(spawn_params["offset"]))
- offset_data = spawn_params["offset"]
- else if(istext(spawn_params["offset"]))
- var/list/parsed = splittext(spawn_params["offset"], ",")
- if(length(parsed) >= 3)
- offset_data = list("X" = text2num(parsed[1]), "Y" = text2num(parsed[2]), "Z" = text2num(parsed[3]))
- else
- offset_data = list("X" = 0, "Y" = 0, "Z" = 0)
- else
- offset_data = list("X" = 0, "Y" = 0, "Z" = 0)
-
-
- var/X = offset_data["X"] || 0
- var/Y = offset_data["Y"] || 0
- var/Z = offset_data["Z"] || 0
+ var/X = offset["X"] || 0
+ var/Y = offset["Y"] || 0
+ var/Z = offset["Z"] || 0
var/atom_dir = text2num(spawn_params["atom_dir"]) || 1
var/atom_name = sanitize(spawn_params["atom_name"])
diff --git a/tgui/packages/tgui/interfaces/SpawnPanel/CreateObject.tsx b/tgui/packages/tgui/interfaces/SpawnPanel/CreateObject.tsx
index 4398a83a3dd..3123ef023af 100644
--- a/tgui/packages/tgui/interfaces/SpawnPanel/CreateObject.tsx
+++ b/tgui/packages/tgui/interfaces/SpawnPanel/CreateObject.tsx
@@ -56,7 +56,11 @@ export function CreateObject(props: CreateObjectProps) {
const currentType = allObjects[data.copied_type ?? '']?.type || 'Objects';
const getSearchString = useCallback(
- (key: string) => (searchBy ? key : allObjects[key]?.name || ''),
+ (key: string) => {
+ const item = allObjects[key];
+ if (!item) return key;
+ return searchBy ? key : `${key} ${item.name || ''}`;
+ },
[searchBy, allObjects],
);
@@ -121,14 +125,15 @@ export function CreateObject(props: CreateObjectProps) {
if (storedHideMapping !== undefined) setHideMapping(storedHideMapping);
if (storedShowIcons !== undefined) setshowIcons(storedShowIcons);
if (storedShowPreview !== undefined) setshowPreview(storedShowPreview);
- if (storedSelectedObj) {
- if (allObjects[storedSelectedObj]) {
- setSelectedObj(storedSelectedObj);
- props.onIconSettingsChange?.({
- icon: allObjects[storedSelectedObj].icon,
- iconState: allObjects[storedSelectedObj].icon_state,
- });
- }
+ if (storedSelectedObj && allObjects[storedSelectedObj]) {
+ act('selected-atom-changed', {
+ newObj: storedSelectedObj,
+ });
+ setSelectedObj(storedSelectedObj);
+ props.onIconSettingsChange?.({
+ icon: allObjects[storedSelectedObj].icon,
+ iconState: allObjects[storedSelectedObj].icon_state,
+ });
}
};
diff --git a/tgui/packages/tgui/interfaces/SpawnPanel/CreateObjectSettings.tsx b/tgui/packages/tgui/interfaces/SpawnPanel/CreateObjectSettings.tsx
index fc93d7b14f8..9ac66f499c5 100644
--- a/tgui/packages/tgui/interfaces/SpawnPanel/CreateObjectSettings.tsx
+++ b/tgui/packages/tgui/interfaces/SpawnPanel/CreateObjectSettings.tsx
@@ -3,6 +3,7 @@ import { useEffect, useState } from 'react';
import {
Button,
Dropdown,
+ Icon,
Input,
NumberInput,
Slider,
@@ -12,8 +13,8 @@ import {
import { useBackend } from '../../backend';
import {
- directionIcons,
directionNames,
+ directionRotation,
spawnLocationIcons,
spawnLocationOptions,
} from './constants';
@@ -44,6 +45,7 @@ export function CreateObjectSettings(props: CreateObjectSettingsProps) {
const [objectName, setObjectName] = useState('');
const [offset, setOffset] = useState('');
+ const dirValues = [1, 5, 4, 6, 2, 10, 8, 9];
const updateAmount = (value: number) => {
setAmount(value);
sendUpdatedSettings({ atom_amount: value });
@@ -66,7 +68,7 @@ export function CreateObjectSettings(props: CreateObjectSettingsProps) {
const updateDirection = (value: number) => {
setDirection(value);
storage.set('spawnpanel-direction', value);
- sendUpdatedSettings({ atom_dir: [1, 2, 4, 8][value] });
+ sendUpdatedSettings({ atom_dir: dirValues[value] });
};
const updateObjectName = (value: string) => {
@@ -121,7 +123,7 @@ export function CreateObjectSettings(props: CreateObjectSettingsProps) {
atom_amount: amount,
offset_type: cordsType ? 'Absolute offset' : 'Relative offset',
where_target_type: spawnLocation,
- atom_dir: [1, 2, 4, 8][direction],
+ atom_dir: dirValues[direction],
offset: parseOffset(offset),
atom_name: objectName,
atom_icon_size: iconSettings.iconSize,
@@ -157,7 +159,7 @@ export function CreateObjectSettings(props: CreateObjectSettingsProps) {
atom_amount: defaultAmount,
offset_type: defaultCordsType ? 'Absolute offset' : 'Relative offset',
where_target_type: defaultSpawnLocation,
- atom_dir: [1, 2, 4, 8][defaultDirection],
+ atom_dir: dirValues[defaultDirection],
offset: defaultOffset,
atom_name: defaultObjectName,
});
@@ -221,7 +223,7 @@ export function CreateObjectSettings(props: CreateObjectSettingsProps) {
atom_amount: amount,
offset_type: cordsType ? 'Absolute offset' : 'Relative offset',
where_target_type: spawnLocation,
- atom_dir: [1, 2, 4, 8][direction],
+ atom_dir: dirValues[direction],
offset: parseOffset(offset),
atom_name: objectName,
atom_icon_size: iconSettings.iconSize,
@@ -288,31 +290,32 @@ export function CreateObjectSettings(props: CreateObjectSettingsProps) {
Dir:
{
- const values = [1, 2, 4, 8];
- return values[value].toString();
- }}
+ format={(value) => dirValues[value].toString()}
onChange={(e, value) => updateDirection(value)}
disabled={isAnyPreciseModeActive}
/>
diff --git a/tgui/packages/tgui/interfaces/SpawnPanel/constants.tsx b/tgui/packages/tgui/interfaces/SpawnPanel/constants.tsx
index 13be3441059..f0707f757a5 100644
--- a/tgui/packages/tgui/interfaces/SpawnPanel/constants.tsx
+++ b/tgui/packages/tgui/interfaces/SpawnPanel/constants.tsx
@@ -32,11 +32,15 @@ export const spawnLocationIcons = {
"In targeted mob's hand": 'crosshairs',
};
-export const directionIcons = {
- 1: 'arrow-up',
- 2: 'arrow-down',
- 4: 'arrow-right',
- 8: 'arrow-left',
+export const directionRotation = {
+ 1: 0,
+ 5: 45,
+ 4: 90,
+ 6: 135,
+ 2: 180,
+ 10: 225,
+ 8: 270,
+ 9: 315,
};
export const directionNames = {
@@ -44,4 +48,8 @@ export const directionNames = {
2: 'SOUTH',
4: 'EAST',
8: 'WEST',
+ 5: 'NORTHEAST',
+ 6: 'SOUTHEAST',
+ 9: 'NORTHWEST',
+ 10: 'SOUTHWEST',
};
diff --git a/tgui/packages/tgui/interfaces/SpawnSearch.tsx b/tgui/packages/tgui/interfaces/SpawnSearch.tsx
index 3e2299444df..5dbe4cb7f4c 100644
--- a/tgui/packages/tgui/interfaces/SpawnSearch.tsx
+++ b/tgui/packages/tgui/interfaces/SpawnSearch.tsx
@@ -175,23 +175,18 @@ export function SpawnSearch() {
// User presses up or down on keyboard
// Simulates clicking an item
function handleArrowKey(key: number): void {
- const len = Object.keys(filteredItems).length - 1;
+ if (!filteredItems.length) return;
+
+ const len = filteredItems.length - 1;
+
if (key === KEY_DOWN) {
- if (selected === null || selected === len) {
- setSelected(0);
- document!.getElementById('0')?.scrollIntoView();
- } else {
- setSelected(selected + 1);
- document!.getElementById((selected + 1).toString())?.scrollIntoView();
- }
+ const next = selected >= len ? 0 : selected + 1;
+ setSelected(next);
+ document?.getElementById(next.toString())?.scrollIntoView();
} else if (key === KEY_UP) {
- if (selected === null || selected === 0) {
- setSelected(len);
- document!.getElementById(len.toString())?.scrollIntoView();
- } else {
- setSelected(selected - 1);
- document!.getElementById((selected - 1).toString())?.scrollIntoView();
- }
+ const prev = selected <= 0 ? len : selected - 1;
+ setSelected(prev);
+ document?.getElementById(prev.toString())?.scrollIntoView();
}
}
@@ -225,7 +220,9 @@ export function SpawnSearch() {
}
}
- function handleSelect(selection: AtomTypeData): void {
+ function handleSelect(selection?: AtomTypeData): void {
+ if (!selection) return;
+
act('spawn', { type: selection.typepath, amount: spawnAmount });
}
@@ -287,6 +284,7 @@ export function SpawnSearch() {
className="candystripe"
color="transparent"
fluid
+ id={index.toString()}
key={index}
onClick={() => {
if (index !== selected) setSelected(index);