2023-12-01 17:36:55 +08:00
|
|
|
/**
|
|
|
|
* This module should contain warnings subsystem.
|
|
|
|
* First idea - there should be either definitive list of available warnings,
|
|
|
|
* or defined as some json logic leading to the warning message(s), similar way how FillExtData works.
|
|
|
|
* Second - resources indicator should be separate component
|
2023-12-04 17:40:23 +08:00
|
|
|
*/
|
|
|
|
|
2023-12-13 15:17:14 +08:00
|
|
|
import {item_occupied_counters, resource_counters} from "./count_resources";
|
2023-12-12 16:09:29 +08:00
|
|
|
import {useShopStore} from "./shop_store";
|
2023-12-04 17:40:23 +08:00
|
|
|
|
2024-01-23 11:44:01 +08:00
|
|
|
export const Levels = {
|
2024-01-23 16:30:27 +08:00
|
|
|
"reminder": {priority: 1, icon: '/images/shop/icon-reminder.svg', color: "#0d3547"},
|
2023-12-12 16:09:29 +08:00
|
|
|
"warning": {priority: 2, icon: '/images/shop/icon-warning.svg', color: "#c75e5e"},
|
2023-12-04 17:40:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const find_in_counters = (counters, name) => {
|
|
|
|
return counters.find((element) => element.name === name)
|
|
|
|
}
|
|
|
|
|
|
|
|
const find_previous_source = (data, index, source) => {
|
2023-12-05 17:35:31 +08:00
|
|
|
return data.slice(0, index).find((element) => {
|
|
|
|
return element.resources && find_in_counters(element.resources, source)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const find_next_source_index = (data, index, source) => {
|
|
|
|
return data.slice(index + 1).findIndex((element) => {
|
|
|
|
return element.resources && find_in_counters(element.resources, source)
|
|
|
|
}) + index + 1
|
2023-12-04 17:40:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
const not_enough_resource_trigger = (name) => {
|
|
|
|
return (_data, _index, counters) => {
|
2024-01-02 17:13:50 +08:00
|
|
|
const resource = find_in_counters(counters, name);
|
|
|
|
return resource.occupied > resource.max;
|
2023-12-04 17:40:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const no_source_trigger = (name) => {
|
|
|
|
return (data, index, _counters) => {
|
2023-12-05 17:35:31 +08:00
|
|
|
const occupied = item_occupied_counters[name](data[index]);
|
2023-12-04 17:40:23 +08:00
|
|
|
if (occupied > 0)
|
2023-12-05 17:35:31 +08:00
|
|
|
return !find_previous_source(data, index, name);
|
2023-12-04 17:40:23 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-05 17:35:31 +08:00
|
|
|
const wiring_constraint = (name) => {
|
|
|
|
return (data, index, _counters) => {
|
|
|
|
const next = find_next_source_index(data, index, name);
|
|
|
|
return next - index === 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-04 17:40:23 +08:00
|
|
|
const Types = {
|
|
|
|
"eem_resource": {
|
|
|
|
level: "warning",
|
|
|
|
trigger: not_enough_resource_trigger("eem"),
|
|
|
|
message: "Insufficient EEM connectors"
|
|
|
|
},
|
2023-12-05 17:35:31 +08:00
|
|
|
"no_eem_source": {
|
2023-12-04 17:40:23 +08:00
|
|
|
level: "warning",
|
|
|
|
trigger: no_source_trigger("eem"),
|
|
|
|
message: 'This card needs a card that provides a EEM connector (e.g. Kasli) at its left.'
|
|
|
|
},
|
|
|
|
"idc_resource": {
|
|
|
|
level: "warning",
|
|
|
|
trigger: not_enough_resource_trigger("idc"),
|
|
|
|
message: "Insufficient IDC connectors."
|
|
|
|
},
|
2023-12-05 17:35:31 +08:00
|
|
|
"no_idc_source": {
|
2023-12-04 17:40:23 +08:00
|
|
|
level: "warning",
|
|
|
|
trigger: no_source_trigger("idc"),
|
|
|
|
message: 'Should be after a Zotino or a HD68-IDC or with another IDC-BNC.'
|
|
|
|
},
|
|
|
|
"clk_resource": {
|
|
|
|
level: "warning",
|
|
|
|
trigger: not_enough_resource_trigger("clk"),
|
|
|
|
message: "Insufficient clock connectors."
|
|
|
|
},
|
2023-12-05 17:35:31 +08:00
|
|
|
"no_clk_source": {
|
2023-12-04 17:40:23 +08:00
|
|
|
level: "warning",
|
|
|
|
trigger: no_source_trigger("clk"),
|
2023-12-05 17:35:31 +08:00
|
|
|
message: 'This card needs either a card that provides a clock source (e.g. Kasli or Clocker) at its left or use an external clock source.'
|
|
|
|
},
|
|
|
|
"eem_wiring_constraint": {
|
|
|
|
level: "reminder",
|
|
|
|
trigger: wiring_constraint("eem"),
|
|
|
|
message: "Due to wiring constraints, the carrier can only connect to EEM cards immediately at its right, without crossing another carrier."
|
2023-12-04 17:40:23 +08:00
|
|
|
},
|
2023-12-05 17:35:31 +08:00
|
|
|
"default": {
|
|
|
|
level: "warning",
|
|
|
|
trigger: (_a, _b, _c) => {
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
message: 'This item has unimplemented warning'
|
|
|
|
}
|
2023-12-04 17:40:23 +08:00
|
|
|
}
|
|
|
|
|
2024-01-02 17:35:09 +08:00
|
|
|
export function TriggerWarnings(data, disabled) {
|
2023-12-05 17:35:31 +08:00
|
|
|
return data.map((element, index) => {
|
|
|
|
if (!element.warnings) return element;
|
2024-01-02 17:35:09 +08:00
|
|
|
element.show_warnings = disabled ? [] :element.warnings
|
2023-12-05 17:35:31 +08:00
|
|
|
.map((warning, _) => {
|
|
|
|
if (!!Types[warning])
|
2023-12-06 16:27:43 +08:00
|
|
|
return Types[warning].trigger(data, index, element.counted_resources) ? {trigger: undefined, name: warning, ...Types[warning]} : null;
|
2023-12-05 17:35:31 +08:00
|
|
|
else
|
2023-12-06 16:27:43 +08:00
|
|
|
return Types.default;
|
2023-12-05 17:35:31 +08:00
|
|
|
})
|
|
|
|
.filter((warning, _) => {
|
|
|
|
return !!warning
|
|
|
|
});
|
|
|
|
return element;
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
export function MaxLevel(warnings) {
|
|
|
|
let mx = {priority: 0, icon: null};
|
|
|
|
for (const warning of warnings) {
|
|
|
|
if (Levels[warning.level].priority > mx.priority) mx = Levels[warning.level];
|
|
|
|
}
|
|
|
|
return mx;
|
2023-12-08 17:36:12 +08:00
|
|
|
}
|
|
|
|
|
2023-12-12 16:09:29 +08:00
|
|
|
export function LevelUI(warning_level) {
|
|
|
|
const warning_t = Levels[warning_level];
|
|
|
|
return {icon: warning_t.icon, color: warning_t.color};
|
|
|
|
}
|
2023-12-08 17:36:12 +08:00
|
|
|
|
|
|
|
const crate_warnings = {
|
|
|
|
"overfit": {
|
|
|
|
message: "You have reached the maximum number of slots allowed for this crate. Consider removing cards.",
|
|
|
|
level: "warning",
|
|
|
|
trigger: (crate, occupied) => {
|
2023-12-12 16:09:29 +08:00
|
|
|
const nbrHP = useShopStore.getState().crateParams(crate.crate_mode).hp;
|
|
|
|
return occupied > nbrHP && nbrHP > 0;
|
2023-12-08 17:36:12 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
"underfit_rack": {
|
|
|
|
message: "The selected cards fit in a 42hp desktop crate, consider switching to it for a more compact system",
|
|
|
|
level: "reminder",
|
|
|
|
trigger: (crate, occupied) => {
|
2023-12-12 16:09:29 +08:00
|
|
|
const nbrHPDesktop = useShopStore.getState().crate_modes.desktop.hp;
|
|
|
|
return crate.crate_mode === useShopStore.getState().crate_modes.rack.id && occupied < nbrHPDesktop;
|
2023-12-08 17:36:12 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export function TriggerCrateWarnings(crate) {
|
|
|
|
const nbrOccupied = resource_counters.hp(crate.items, -1);
|
|
|
|
let warnings = [];
|
|
|
|
Object.entries(crate_warnings).forEach(([id, warning], _) => {
|
|
|
|
if (warning.trigger(crate, nbrOccupied)) warnings.push({...warning, id: id, trigger: undefined});
|
|
|
|
})
|
2023-12-12 16:09:29 +08:00
|
|
|
return [warnings, nbrOccupied];
|
2023-12-05 17:35:31 +08:00
|
|
|
}
|