Add Shift+O full item property inspection

This commit is contained in:
Jage9
2026-02-20 16:50:12 -05:00
parent bdd9bf8c77
commit 74c4c9e91c
4 changed files with 53 additions and 4 deletions

View File

@@ -53,6 +53,7 @@
<p><b>Shift+I:</b> List items</p> <p><b>Shift+I:</b> List items</p>
<p><b>A:</b> Add item</p> <p><b>A:</b> Add item</p>
<p><b>O:</b> Edit item properties</p> <p><b>O:</b> Edit item properties</p>
<p><b>Shift+O:</b> Read all item properties</p>
<p><b>D:</b> Pick up/drop item</p> <p><b>D:</b> Pick up/drop item</p>
<p><b>Shift+D:</b> Delete item</p> <p><b>Shift+D:</b> Delete item</p>
<p><b>U:</b> Use item</p> <p><b>U:</b> Use item</p>

View File

@@ -1,3 +1,3 @@
// Maintainer-controlled web client version. // Maintainer-controlled web client version.
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2) // Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
window.CHGRID_WEB_VERSION = "2026.02.20 R61"; window.CHGRID_WEB_VERSION = "2026.02.20 R62";

View File

@@ -85,6 +85,10 @@ dom.appVersion.textContent = APP_VERSION
? `Another AI experiment with Jage. Version ${APP_VERSION}` ? `Another AI experiment with Jage. Version ${APP_VERSION}`
: 'Another AI experiment with Jage. Version unknown'; : 'Another AI experiment with Jage. Version unknown';
const ITEM_TYPE_SEQUENCE: ItemType[] = ['radio_station', 'dice']; const ITEM_TYPE_SEQUENCE: ItemType[] = ['radio_station', 'dice'];
const ITEM_TYPE_GLOBAL_PROPERTIES: Record<ItemType, Record<string, string | number | boolean>> = {
radio_station: { useCooldownMs: 1000 },
dice: { useCooldownMs: 1000 },
};
const APP_BASE_URL = import.meta.env.BASE_URL || '/'; const APP_BASE_URL = import.meta.env.BASE_URL || '/';
function withBase(path: string): string { function withBase(path: string): string {
const normalizedBase = APP_BASE_URL.endsWith('/') ? APP_BASE_URL : `${APP_BASE_URL}/`; const normalizedBase = APP_BASE_URL.endsWith('/') ? APP_BASE_URL : `${APP_BASE_URL}/`;
@@ -311,7 +315,7 @@ function getCarriedItem(): WorldItem | null {
return Array.from(state.items.values()).find((item) => item.carrierId === state.player.id) || null; return Array.from(state.items.values()).find((item) => item.carrierId === state.player.id) || null;
} }
function beginItemSelection(context: 'pickup' | 'delete' | 'edit' | 'use', items: WorldItem[]): void { function beginItemSelection(context: 'pickup' | 'delete' | 'edit' | 'use' | 'inspect', items: WorldItem[]): void {
if (items.length === 0) { if (items.length === 0) {
updateStatus('No items available.'); updateStatus('No items available.');
audio.sfxUiCancel(); audio.sfxUiCancel();
@@ -345,6 +349,25 @@ function useItem(item: WorldItem): void {
signaling.send({ type: 'item_use', itemId: item.id }); signaling.send({ type: 'item_use', itemId: item.id });
} }
function announceAllItemProperties(item: WorldItem): void {
const details: string[] = [];
details.push(`title: ${item.title}`);
details.push(`type: ${item.type}`);
details.push(`position: ${item.x}, ${item.y}`);
details.push(`carrierId: ${item.carrierId ?? 'none'}`);
details.push(`version: ${item.version}`);
details.push(`capabilities: ${item.capabilities.join(', ') || 'none'}`);
details.push(`useSound: ${item.useSound ?? 'none'}`);
for (const [key, value] of Object.entries(item.params).sort(([a], [b]) => a.localeCompare(b))) {
details.push(`${key}: ${String(value)}`);
}
const globalProperties = ITEM_TYPE_GLOBAL_PROPERTIES[item.type] ?? {};
for (const [key, value] of Object.entries(globalProperties).sort(([a], [b]) => a.localeCompare(b))) {
details.push(`${key}: ${String(value)} (global)`);
}
updateStatus(details.join('; '));
}
function releaseSharedRadioSource(streamUrl: string): void { function releaseSharedRadioSource(streamUrl: string): void {
const shared = sharedRadioSources.get(streamUrl); const shared = sharedRadioSources.get(streamUrl);
if (!shared) return; if (!shared) return;
@@ -1140,8 +1163,28 @@ function handleNormalModeInput(code: string, shiftKey: boolean): void {
if (code === 'KeyO') { if (code === 'KeyO') {
const squareItems = getItemsAtPosition(state.player.x, state.player.y); const squareItems = getItemsAtPosition(state.player.x, state.player.y);
if (squareItems.length === 0) {
const carried = getCarriedItem(); const carried = getCarriedItem();
if (shiftKey) {
if (squareItems.length === 0) {
if (!carried) {
updateStatus('No item to inspect.');
audio.sfxUiCancel();
return;
}
announceAllItemProperties(carried);
audio.sfxUiBlip();
return;
}
if (squareItems.length === 1) {
announceAllItemProperties(squareItems[0]);
audio.sfxUiBlip();
return;
}
beginItemSelection('inspect', squareItems);
return;
}
if (squareItems.length === 0) {
if (!carried) { if (!carried) {
updateStatus('No editable item here.'); updateStatus('No editable item here.');
audio.sfxUiCancel(); audio.sfxUiCancel();
@@ -1432,6 +1475,11 @@ function handleSelectItemModeInput(code: string): void {
useItem(selected); useItem(selected);
return; return;
} }
if (context === 'inspect') {
announceAllItemProperties(selected);
audio.sfxUiBlip();
return;
}
return; return;
} }
if (code === 'Escape') { if (code === 'Escape') {

View File

@@ -20,7 +20,7 @@ export type WorldItem = {
carrierId?: string | null; carrierId?: string | null;
}; };
export type SelectionContext = 'pickup' | 'drop' | 'delete' | 'edit' | 'use' | null; export type SelectionContext = 'pickup' | 'drop' | 'delete' | 'edit' | 'use' | 'inspect' | null;
export type GameMode = export type GameMode =
| 'normal' | 'normal'