feat:(slots UI): functional slots

This commit is contained in:
Rachel Powers
2024-04-24 23:15:54 -07:00
parent 19c85c1078
commit dbb2f71fdc
7 changed files with 111 additions and 43 deletions

View File

@@ -242,3 +242,7 @@ export function parseIntWithHexOrBinary(s: string): number {
}
return parseInt(s);
}
export function clamp (val: number, min: number, max: number) {
return Math.min(Math.max(val, min), max);
}

View File

@@ -4,7 +4,7 @@ import { BaseElement, defaultCss } from "components";
import { VMDeviceDBMixin, VMDeviceMixin } from "virtual_machine/base_device";
import type { DeviceDB, DeviceDBEntry } from "virtual_machine/device_db";
import SlSelect from "@shoelace-style/shoelace/dist/components/select/select.component.js";
import { displayNumber, parseIntWithHexOrBinary, parseNumber } from "utils";
import { clamp, displayNumber, parseIntWithHexOrBinary, parseNumber } from "utils";
import {
LogicType,
Slot,
@@ -147,6 +147,7 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
.value=${slot.occupant.quantity.toString()}
.min=${1}
.max=${slot.occupant.max_quantity}
@sl-change=${this._handleSlotQuantityChange}
>
<div slot="help-text">
<span>Max Quantity: ${slot.occupant.max_quantity}</span>
@@ -170,6 +171,15 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
);
}
_handleSlotQuantityChange(e: Event) {
const input = e.currentTarget as SlInput;
const slot = this.slots[this.slotIndex];
const val = clamp(input.valueAsNumber, 1, slot.occupant.max_quantity);
if (!window.VM.vm.setDeviceSlotField(this.deviceID, this.slotIndex, "Quantity", val, true)) {
input.value = this.device.getSlotField(this.slotIndex, "Quantity").toString();
}
}
renderFields() {
const inputIdBase = `vmDeviceSlot${this.deviceID}Slot${this.slotIndex}Field`;
const _fields = this.device.getSlotFields(this.slotIndex);
@@ -202,7 +212,11 @@ export class VMDeviceSlot extends VMDeviceMixin(VMDeviceDBMixin(BaseElement)) {
_handleChangeSlotField(e: CustomEvent) {
const input = e.target as SlInput;
const field = input.getAttribute("key")! as SlotLogicType;
const val = parseNumber(input.value);
let val = parseNumber(input.value);
if (field === "Quantity") {
const slot = this.slots[this.slotIndex];
val = clamp(input.valueAsNumber, 1, slot.occupant.max_quantity);
}
window.VM.get().then((vm) => {
if (
!vm.setDeviceSlotField(this.deviceID, this.slotIndex, field, val, true)

View File

@@ -31,6 +31,7 @@ export class VMSlotAddDialog extends VMDeviceDBMixin(BaseElement) {
];
private _items: Map<string, DeviceDBEntry> = new Map();
private _filteredItems: DeviceDBEntry[];
private _datapoints: [string, string][] = [];
private _haystack: string[] = [];
@@ -57,33 +58,41 @@ export class VMSlotAddDialog extends VMDeviceDBMixin(BaseElement) {
.filter((entry) => this.deviceDB.items.includes(entry.name), this)
.map((entry) => [entry.name, entry]),
);
this.setupSearch();
this.performSearch();
}
performSearch() {
if (this._filter) {
setupSearch() {
let filteredItemss = Array.from(this._items.values());
if( typeof this.deviceID !== "undefined" && typeof this.slotIndex !== "undefined") {
const device = window.VM.vm.devices.get(this.deviceID);
const dbDevice = this.deviceDB.db[device.prefabName]
const slot = dbDevice.slots[this.slotIndex]
const typ = slot.typ;
let filterdItems = Array.from(this._items.values());
if (typ !== "None") {
filterdItems = Array.from(this._items.values()).filter(item => item.item.slotclass === typ);
if (typeof typ === "string" && typ !== "None") {
filteredItemss = Array.from(this._items.values()).filter(item => item.item.slotclass === typ);
}
const datapoints: [string, string][] = [];
for (const entry of filterdItems) {
datapoints.push(
[entry.title, entry.name],
[entry.name, entry.name],
[entry.desc, entry.name],
);
}
}
this._filteredItems= filteredItemss;
const datapoints: [string, string][] = [];
for (const entry of this._filteredItems) {
datapoints.push(
[entry.title, entry.name],
[entry.name, entry.name],
[entry.desc, entry.name],
);
}
const haystack: string[] = datapoints.map((data) => data[0]);
this._datapoints = datapoints;
this._haystack = haystack;
const haystack: string[] = datapoints.map((data) => data[0]);
this._datapoints = datapoints;
this._haystack = haystack;
}
performSearch() {
if (this._filter) {
const uf = new uFuzzy({});
const [_idxs, info, order] = uf.search(
@@ -113,7 +122,7 @@ export class VMSlotAddDialog extends VMDeviceDBMixin(BaseElement) {
}));
} else {
// return everything
this._searchResults = [...this._items.values()].map((st) => ({
this._searchResults = [...this._filteredItems].map((st) => ({
entry: st,
haystackEntry: st.title,
ranges: [],
@@ -130,7 +139,7 @@ export class VMSlotAddDialog extends VMDeviceDBMixin(BaseElement) {
${this._searchResults.map((result) => {
const imgSrc = `img/stationpedia/${result.entry.name}.png`;
const img = html`
<img class="w-8 h-8" src=${imgSrc} onerror="this.src = '${VMDeviceCard.transparentImg}'" />
<img class="w-8 h-8 mr-2" src=${imgSrc} onerror="this.src = '${VMDeviceCard.transparentImg}'" />
`;
return html`
<div class="cursor-pointer hover:bg-neutral-600 rounded px-2 me-1 flex flex-row" key=${result.entry.name} @click=${this._handleClickItem}>
@@ -144,7 +153,8 @@ export class VMSlotAddDialog extends VMDeviceDBMixin(BaseElement) {
}
_handleClickNone() {
console.log("Clear Slot");
window.VM.vm.removeDeviceSlotOccupant(this.deviceID, this.slotIndex);
this.hide();
}
_handleClickItem(e: Event) {
@@ -170,11 +180,13 @@ export class VMSlotAddDialog extends VMDeviceDBMixin(BaseElement) {
fields["PrefabHash"] = { field_type: "Read", value: entry.hash };
fields["MaxQuantity"] = { field_type: "Read", value: entry.item.maxquantity ?? 1.0 };
fields["SortingClass"] = { field_type: "Read", value: sorting };
fields["Quantity"] = { field_type: "Read", value: 1 };
const template: SlotOccupantTemplate = {
fields
}
window.VM.vm.setDeviceSlotOccupant(this.deviceID, this.slotIndex, template);
this.hide();
}
@query("sl-dialog.slot-add-dialog") dialog: SlDialog;
@@ -233,6 +245,8 @@ export class VMSlotAddDialog extends VMDeviceDBMixin(BaseElement) {
show(deviceID: number, slotIndex: number) {
this.deviceID = deviceID;
this.slotIndex = slotIndex;
this.setupSearch();
this.performSearch();
this.dialog.show();
this.searchInput.select();
}

View File

@@ -316,7 +316,7 @@ class VirtualMachine extends EventTarget {
const device = this._devices.get(id);
if (device) {
try {
device.setSlotField(slot, field, val, false);
device.setSlotField(slot, field, val, force);
this.updateDevice(device);
return true;
} catch (err) {
@@ -411,6 +411,20 @@ class VirtualMachine extends EventTarget {
return false;
}
removeDeviceSlotOccupant(id: number, index: number): boolean {
const device = this._devices.get(id);
if (typeof device !== "undefined") {
try {
this.ic10vm.removeSlotOccupant(id, index);
this.updateDevice(device);
return true;
} catch (err) {
this.handleVmError(err);
}
}
return false;
}
saveVMState(): FrozenVM {
return this.ic10vm.saveVMState();
}