forked from M-Labs/web2019
185 lines
7.0 KiB
JavaScript
185 lines
7.0 KiB
JavaScript
/**
|
|
* 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
|
|
*/
|
|
|
|
import {item_occupied_counters, resource_counters} from "./count_resources";
|
|
import {useShopStore} from "./shop_store";
|
|
|
|
export const Levels = {
|
|
"reminder": {priority: 1, icon: '/images/shop/icon-reminder.svg', color: "#0d3547"},
|
|
"warning": {priority: 2, icon: '/images/shop/icon-warning.svg', color: "#c75e5e"},
|
|
}
|
|
|
|
const find_in_counters = (counters, name) => {
|
|
return counters.find((element) => element.name === name)
|
|
}
|
|
|
|
const find_previous_source = (data, index, source) => {
|
|
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
|
|
}
|
|
|
|
const not_enough_resource_trigger = (name) => {
|
|
return (_data, _index, counters, _crate) => {
|
|
const resource = find_in_counters(counters, name);
|
|
return resource.occupied > resource.max;
|
|
}
|
|
}
|
|
|
|
const no_source_trigger = (name) => {
|
|
return (data, index, _counters, _crate) => {
|
|
const occupied = item_occupied_counters[name](data[index]);
|
|
if (occupied > 0)
|
|
return !find_previous_source(data, index, name);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
const wiring_constraint = (name) => {
|
|
return (data, index, _counters, _crate) => {
|
|
const next = find_next_source_index(data, index, name);
|
|
return next - index === 1;
|
|
}
|
|
}
|
|
|
|
const phaser_next_card_long = (data, index, counters, crate) => {
|
|
const nbrOccupied = resource_counters.hp(crate.items, -1);
|
|
const nbrHP = useShopStore.getState().crateParams(crate.crate_mode).hp;
|
|
return (index < data.length - 1) ? (
|
|
(data[index+1].consumes && data[index+1].consumes.depth && data[index+1].consumes.depth >= 8.5)
|
|
) : (nbrOccupied >= nbrHP && nbrHP > 0)
|
|
}
|
|
|
|
const Types = {
|
|
"eem_resource": {
|
|
level: "warning",
|
|
trigger: not_enough_resource_trigger("eem"),
|
|
message: "Insufficient EEM connectors"
|
|
},
|
|
"no_eem_source": {
|
|
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."
|
|
},
|
|
"no_idc_source": {
|
|
level: "warning",
|
|
trigger: no_source_trigger("idc"),
|
|
message: 'Should be after a Zotino or a HD68-IDC or with another IDC adapter.'
|
|
},
|
|
"clk_resource": {
|
|
level: "warning",
|
|
trigger: not_enough_resource_trigger("clk"),
|
|
message: "Insufficient clock connectors."
|
|
},
|
|
"no_clk_source": {
|
|
level: "warning",
|
|
trigger: no_source_trigger("clk"),
|
|
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."
|
|
},
|
|
"phaser_next_card_long": {
|
|
level: "reminder",
|
|
trigger: phaser_next_card_long,
|
|
message: "Next card may interfere with this Phaser. Consider placing a short card after this Phaser."
|
|
},
|
|
"default": {
|
|
level: "warning",
|
|
trigger: (_a, _b, _c, _d) => {
|
|
return true;
|
|
},
|
|
message: 'This item has unimplemented warning'
|
|
}
|
|
}
|
|
|
|
export function TriggerWarnings(data, disabled, crate) {
|
|
return data.map((element, index) => {
|
|
if (!element.warnings) return element;
|
|
element.show_warnings = disabled ? [] :element.warnings
|
|
.map((warning, _) => {
|
|
if (!!Types[warning])
|
|
return Types[warning].trigger(data, index, element.counted_resources, crate) ? {trigger: undefined, name: warning, ...Types[warning]} : null;
|
|
else
|
|
return Types.default;
|
|
})
|
|
.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;
|
|
}
|
|
|
|
export function LevelUI(warning_level) {
|
|
const warning_t = Levels[warning_level];
|
|
return {icon: warning_t.icon, color: warning_t.color};
|
|
}
|
|
|
|
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) => {
|
|
const nbrHP = useShopStore.getState().crateParams(crate.crate_mode).hp;
|
|
return occupied > nbrHP && nbrHP > 0;
|
|
}
|
|
},
|
|
"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) => {
|
|
const nbrHPDesktop = useShopStore.getState().crate_modes.desktop.hp;
|
|
return crate.crate_mode === useShopStore.getState().crate_modes.rack.id && occupied < nbrHPDesktop;
|
|
}
|
|
},
|
|
"phaser_not_fit": {
|
|
message: "Since one or more Phasers may interfere with their next cards, they may additional space, that wouldn't fit into the crate. Consider removing cards, placing short cards after Phaser(s), or choosing larger crate.",
|
|
level: "warning",
|
|
trigger: (crate, occupied) => {
|
|
const nbrHP = useShopStore.getState().crateParams(crate.crate_mode).hp;
|
|
const stacked_phasers = crate.items.filter((elem, index, data) => {
|
|
return (elem.name_codename === "Phaser") && ((index < data.length - 1) ? (
|
|
(data[index + 1].consumes && data[index + 1].consumes.depth && data[index + 1].consumes.depth >= 8.5)
|
|
) : (occupied >= nbrHP && nbrHP > 0))
|
|
}
|
|
).length;
|
|
// #!debug
|
|
console.log(stacked_phasers, occupied)
|
|
return stacked_phasers > 0 && (occupied + stacked_phasers*2 >= nbrHP) && nbrHP >0;
|
|
}
|
|
}
|
|
}
|
|
|
|
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});
|
|
})
|
|
return [warnings, nbrOccupied];
|
|
} |