Add Shift+Enter secondary item action with radio handler
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Maintainer-controlled web client version.
|
||||
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
|
||||
window.CHGRID_WEB_VERSION = "2026.02.25 R259";
|
||||
window.CHGRID_WEB_VERSION = "2026.02.25 R260";
|
||||
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
|
||||
window.CHGRID_TIME_ZONE = "America/Detroit";
|
||||
|
||||
@@ -19,6 +19,7 @@ export type MainModeCommand =
|
||||
| 'openMicGainEdit'
|
||||
| 'calibrateMicrophone'
|
||||
| 'useItem'
|
||||
| 'secondaryUseItem'
|
||||
| 'speakUsers'
|
||||
| 'addItem'
|
||||
| 'locateOrListItems'
|
||||
@@ -51,7 +52,7 @@ export function resolveMainModeCommand(code: string, shiftKey: boolean): MainMod
|
||||
if (code === 'NumpadSubtract') return 'masterVolumeDown';
|
||||
if (code === 'KeyC') return shiftKey ? null : 'speakCoordinates';
|
||||
if (code === 'KeyV') return shiftKey ? 'calibrateMicrophone' : 'openMicGainEdit';
|
||||
if (code === 'Enter') return 'useItem';
|
||||
if (code === 'Enter') return shiftKey ? 'secondaryUseItem' : 'useItem';
|
||||
if (code === 'KeyU') return shiftKey ? null : 'speakUsers';
|
||||
if (code === 'KeyA') return shiftKey ? null : 'addItem';
|
||||
if (code === 'KeyI') return 'locateOrListItems';
|
||||
|
||||
@@ -1021,6 +1021,11 @@ function useItem(item: WorldItem): void {
|
||||
signaling.send({ type: 'item_use', itemId: item.id });
|
||||
}
|
||||
|
||||
/** Sends an item secondary-use request for the selected item. */
|
||||
function secondaryUseItem(item: WorldItem): void {
|
||||
signaling.send({ type: 'item_secondary_use', itemId: item.id });
|
||||
}
|
||||
|
||||
/** Opens option-list selection mode for list-based item properties. */
|
||||
function openItemPropertyOptionSelect(item: WorldItem, key: string): void {
|
||||
const options = getItemPropertyOptionValues(item.type, key);
|
||||
@@ -1825,6 +1830,26 @@ function handleNormalModeInput(code: string, shiftKey: boolean): void {
|
||||
beginItemSelection('use', usable);
|
||||
return;
|
||||
}
|
||||
case 'secondaryUseItem': {
|
||||
const carried = getCarriedItem();
|
||||
if (carried) {
|
||||
secondaryUseItem(carried);
|
||||
return;
|
||||
}
|
||||
const squareItems = getItemsAtPosition(state.player.x, state.player.y);
|
||||
const usable = squareItems.filter((item) => item.capabilities.includes('usable'));
|
||||
if (usable.length === 0) {
|
||||
updateStatus('No usable items here.');
|
||||
audio.sfxUiCancel();
|
||||
return;
|
||||
}
|
||||
if (usable.length === 1) {
|
||||
secondaryUseItem(usable[0]);
|
||||
return;
|
||||
}
|
||||
beginItemSelection('secondaryUse', usable);
|
||||
return;
|
||||
}
|
||||
case 'speakUsers': {
|
||||
const allUsers = [state.player.nickname, ...Array.from(state.peers.values()).map((p) => p.nickname)];
|
||||
const label = allUsers.length === 1 ? 'user' : 'users';
|
||||
@@ -2383,6 +2408,10 @@ function handleSelectItemModeInput(code: string, key: string): void {
|
||||
useItem(selected);
|
||||
return;
|
||||
}
|
||||
if (context === 'secondaryUse') {
|
||||
secondaryUseItem(selected);
|
||||
return;
|
||||
}
|
||||
if (context === 'inspect') {
|
||||
beginItemProperties(selected, true);
|
||||
return;
|
||||
|
||||
@@ -256,10 +256,10 @@ export function createOnMessageHandler(deps: MessageHandlerDeps): (message: Inco
|
||||
break;
|
||||
}
|
||||
if (message.ok) {
|
||||
if (message.action === 'use') {
|
||||
if (message.action === 'use' || message.action === 'secondary_use') {
|
||||
deps.pushChatMessage(message.message);
|
||||
const item = message.itemId ? deps.getItemById(message.itemId) : null;
|
||||
if (!item?.useSound && item && item.type !== 'piano') {
|
||||
if (message.action === 'use' && !item?.useSound && item && item.type !== 'piano') {
|
||||
deps.playLocateToneAt(item.x, item.y);
|
||||
}
|
||||
} else if (message.action !== 'update') {
|
||||
|
||||
@@ -202,7 +202,7 @@ export const itemRemoveSchema = z.object({
|
||||
export const itemActionResultSchema = z.object({
|
||||
type: z.literal('item_action_result'),
|
||||
ok: z.boolean(),
|
||||
action: z.enum(['add', 'pickup', 'drop', 'delete', 'use', 'update']),
|
||||
action: z.enum(['add', 'pickup', 'drop', 'delete', 'use', 'secondary_use', 'update']),
|
||||
message: z.string(),
|
||||
itemId: z.string().optional(),
|
||||
});
|
||||
@@ -287,6 +287,7 @@ export type OutgoingMessage =
|
||||
| { type: 'item_drop'; itemId: string; x: number; y: number }
|
||||
| { type: 'item_delete'; itemId: string }
|
||||
| { type: 'item_use'; itemId: string }
|
||||
| { type: 'item_secondary_use'; itemId: string }
|
||||
| { type: 'item_piano_note'; itemId: string; keyId: string; midi: number; on: boolean }
|
||||
| { type: 'item_piano_recording'; itemId: string; action: 'toggle_record' | 'playback' | 'stop_playback' | 'stop_record' }
|
||||
| {
|
||||
|
||||
@@ -21,7 +21,7 @@ export type WorldItem = {
|
||||
carrierId?: string | null;
|
||||
};
|
||||
|
||||
export type SelectionContext = 'pickup' | 'drop' | 'delete' | 'edit' | 'use' | 'inspect' | null;
|
||||
export type SelectionContext = 'pickup' | 'drop' | 'delete' | 'edit' | 'use' | 'secondaryUse' | 'inspect' | null;
|
||||
|
||||
export type GameMode =
|
||||
| 'normal'
|
||||
|
||||
Reference in New Issue
Block a user