import { DomList } from "./dom-list.js"; import { atlases, makeAtlasImage } from "./atlas.js"; import { Filter } from "./filter.js"; import { createTooltip, tooltipDataToPlain } from "./tooltip.js"; import { emitEvent, listenTo } from "./events.js"; import { getPlannerMultiblockType } from "./planner.js"; import { registerLoadCallback } from "./main.js"; import { lookupFromMetadata, resolveBlockName } from "./ncpf-utils.js"; registerLoadCallback(() => { listenTo("config:end", buildBlockPicker); listenTo("block-picker:filter:input", buildBlockPicker); }); function buildBlockPicker() { const filter = Filter.fromInput("block-picker:filter"); const grid = new DomList(document.getElementById("block-picker-list")); grid.clear(); atlases.flatMap(a => a.metadata) .filter(m => m.configuration === getPlannerMultiblockType() && m.configurationList === "blocks") .forEach(m => { const item = grid.makeItem(); item.dataset.index = m.index.toString(10); const tooltipData = [...getBlockTooltip(m)]; item.dataset.tooltip = createTooltip(tooltipData).toString(10); if (!filter.test(...tooltipDataToPlain(tooltipData))) { item.classList.add("hidden"); } item.appendChild(makeAtlasImage(m.index)); item.addEventListener("click", blockPickerClickEvent); grid.addItem(item); }); } function blockPickerClickEvent(e) { const blockPickerDom = document.getElementById("block-picker-list"); const items = document.querySelectorAll("#block-picker-list [data-index]"); if (e.currentTarget.dataset.active !== undefined) { items.forEach(i => delete i.dataset.active); blockPickerDom.dataset.activeItem = (-1).toString(10); delete e.currentTarget.dataset.active; emitEvent("block-picker:selection", -1); emitEvent("block-picker:selection:clear"); return; } items.forEach(i => delete i.dataset.active); blockPickerDom.dataset.activeItem = e.currentTarget.dataset.index; e.currentTarget.dataset.active = ""; emitEvent("block-picker:selection", blockPickerDom.dataset.activeItem); } function* getBlockTooltip(metadata) { const data = lookupFromMetadata(metadata); if (!data) { console.warn("failed to get data from metadata", metadata); return; } yield data.modules["plannerator:display_name"].display_name; let hasAdditionalData = false; if ("nuclearcraft:overhaul_sfr:heat_sink" in data.modules) { hasAdditionalData = true; const heatSink = data.modules["nuclearcraft:overhaul_sfr:heat_sink"]; yield "Heatsink"; if (heatSink.cooling) { yield `Cooling: ${heatSink.cooling} H/t`; } if (heatSink.rules) { for (const rule of heatSink.rules) { yield "Requires " + parseRuleAsTooltip(rule, { configurationHint: metadata.configuration }); } } } if ("nuclearcraft:overhaul_sfr:casing" in data.modules) { hasAdditionalData = true; yield "Casing"; } if ("nuclearcraft:overhaul_sfr:controller" in data.modules) { hasAdditionalData = true; yield "Controller"; } if ("nuclearcraft:overhaul_sfr:fuel_cell" in data.modules) { hasAdditionalData = true; yield "Fuel Cell"; } if ("nuclearcraft:overhaul_sfr:port" in data.modules) { hasAdditionalData = true; if (data.modules["nuclearcraft:overhaul_sfr:port"].output) { yield "Output Port"; } else { yield "Input Port"; } } if ("nuclearcraft:overhaul_sfr:irradiator" in data.modules) { hasAdditionalData = true; yield "Irradiator"; } if ("nuclearcraft:overhaul_sfr:conductor" in data.modules) { hasAdditionalData = true; yield "Conductor"; } if ("nuclearcraft:overhaul_sfr:moderator" in data.modules) { hasAdditionalData = true; const moderator = data.modules["nuclearcraft:overhaul_sfr:moderator"]; yield "Moderator"; yield `Flux: ${moderator.flux}`; yield `Efficiency: ${moderator.efficiency}`; } if ("nuclearcraft:overhaul_sfr:reflector" in data.modules) { hasAdditionalData = true; const reflector = data.modules["nuclearcraft:overhaul_sfr:reflector"]; yield "Reflector"; yield `Efficiency: ${reflector.efficiency}`; yield `Reflectivity: ${reflector.reflectivity}`; } if ("nuclearcraft:overhaul_sfr:neutron_shield" in data.modules) { hasAdditionalData = true; const shield = data.modules["nuclearcraft:overhaul_sfr:neutron_shield"]; yield "Neutron Shield"; yield `Efficiency: ${shield.efficiency}`; yield `Heat per Flux: ${shield.heat_per_flux}`; } if (!hasAdditionalData) { console.log("unknown block", data); } yield { type: "italics", text: metadata.configurationAddon.name, }; } function parseRuleAsTooltip(rule, props) { switch (rule.type) { case "and": return rule.rules.map(r => parseRuleAsTooltip(r, props)).join(" AND "); case "or": return rule.rules.map(r => parseRuleAsTooltip(r, props)).join(" OR "); case "between": { const block = resolveBlockName(rule.block, props); if (!block) { console.warn("could not find block %o", rule.block); return "???"; } if (rule.min === rule.max) { return `exactly ${rule.min} ${block}`; } else if (rule.max === 6) { return `at least ${rule.min} ${block}`; } else if (rule.min === 0) { return `no more than ${rule.max} ${block}`; } else { return `between ${rule.min} and ${rule.max} ${block}`; } } case "axial": { const block = resolveBlockName(rule.block, props); if (!block) { console.warn("could not find block %o", rule.block); return "???"; } if (rule.min === rule.max) { return `exactly ${rule.min} axial ${block}`; } else if (rule.max === 3) { return `at least ${rule.min} axial ${block}`; } else if (rule.min === 0) { return `no more than ${rule.max} axial ${block}`; } else { return `between ${rule.min} and ${rule.max} axial ${block}`; } } default: console.warn("unknown rule: %o", rule); return "???"; } } export function getBlockPickerActiveItem() { const blockPickerDom = document.getElementById("block-picker-list"); return Number(blockPickerDom.dataset.activeItem ?? -1); }