diff --git a/components/unitStats/dps/dpsChart.tsx b/components/unitStats/dps/dpsChart.tsx index 34170bfb..fa4e54b6 100644 --- a/components/unitStats/dps/dpsChart.tsx +++ b/components/unitStats/dps/dpsChart.tsx @@ -33,11 +33,11 @@ import { Select, LoadingOverlay, Center, + Button, } from "@mantine/core"; import { UnitSearch } from "./unitSearch"; import { DpsUnitCustomizing } from "./dpsUnitCustomizing"; import { EbpsType, getEbpsStats } from "../../../src/unitStats/mappingEbps"; -// import slash from "slash"; import { getWeaponStats, WeaponType } from "../../../src/unitStats/mappingWeapon"; import { getSbpsStats, SbpsType } from "../../../src/unitStats/mappingSbps"; import { IconAdjustments } from "@tabler/icons-react"; @@ -264,6 +264,7 @@ export const DpsChart = (props: IDPSProps) => { // const [isStaircase, setStaircase] = useState(false); const [isStaircase] = useState(false); const [showDpsHealth, setShowDpsHealth] = useState(false); + const [allowAllWeapons, setAllowAllWeapons] = useState(false); // const { classes } = useStyles(); const theme = useMantineTheme(); @@ -344,8 +345,14 @@ export const DpsChart = (props: IDPSProps) => { } // synchronize selection field with presented units - function onSelectionChange(selection: string, index: number) { - // add new units + function onSelectionChange(selection: string | null, index: number) { + if (!selection) { + // @ts-ignore Because we can not pass an empty object, otherwise we would + // need to put `.?` safe accessor everywhere. + activeData[index] = undefined; + setRerender(!rerender); + return; + } AnalyticsDPSExplorerSquadSelection(selection); @@ -448,8 +455,6 @@ export const DpsChart = (props: IDPSProps) => { return ( <> - {/* */} - Company of Heroes 3 DPS Benchmark Tool @@ -467,20 +472,43 @@ export const DpsChart = (props: IDPSProps) => { -
- -
+
- - - Toggle DPS mode. + + Advanced Options setShowDpsHealth(event.currentTarget.checked)} //onClick={() => setCurve(isCurve)} - size="xs" + // size="xs" + /> + + + <>Allow All Weapons + + Deselects current units + + + } + checked={allowAllWeapons} + onChange={(event) => { + setAllowAllWeapons(event.currentTarget.checked); + // Reset selected units so it loads the units + onSelectionChange(null, 0); + onSelectionChange(null, 1); + }} + //onClick={() => setCurve(isCurve)} + // size="xs" /> @@ -554,6 +582,7 @@ export const DpsChart = (props: IDPSProps) => { index={0} ebps={ebpsData1} weapons={weaponData1} + allowAllWeapons={allowAllWeapons} /> )} @@ -623,6 +652,7 @@ export const DpsChart = (props: IDPSProps) => { index={1} ebps={ebpsData2} weapons={weaponData2} + allowAllWeapons={allowAllWeapons} /> )} diff --git a/components/unitStats/dps/dpsUnitCustomizing.tsx b/components/unitStats/dps/dpsUnitCustomizing.tsx index b51e3635..0d50aed0 100644 --- a/components/unitStats/dps/dpsUnitCustomizing.tsx +++ b/components/unitStats/dps/dpsUnitCustomizing.tsx @@ -23,6 +23,7 @@ import { CustomizableUnit, getSbpsUpgrades, getSbpsWeapons, + mapWeaponMember, resolveFactionLinkid, WeaponMember, } from "../../../src/unitStats/dpsCommon"; @@ -33,10 +34,11 @@ import { HitpointCard } from "../../unit-cards/hitpoints-card"; interface IUnitProps { unit: CustomizableUnit; - onChange: any; + onChange: (...args: any[]) => void; index: number; ebps: EbpsType[]; weapons: WeaponType[]; + allowAllWeapons: boolean; } export const DpsUnitCustomizing = (props: IUnitProps) => { @@ -47,14 +49,16 @@ export const DpsUnitCustomizing = (props: IUnitProps) => { // Create weapon list, `useEffect` to listen for props changes and refresh the // weapon data. useEffect(() => { - const weapons = getSbpsWeapons(props.unit.sbps, props.ebps, props.weapons); - const weaponUpgrades = getSbpsUpgrades(props.unit.sbps, props.ebps, props.weapons); + const sbpsWeapons = getSbpsWeapons(props.unit.sbps, props.ebps, props.weapons); + const weaponUpgrades = props.allowAllWeapons + ? props.weapons.map((weapon) => mapWeaponMember(props.unit.sbps, props.ebps[0], weapon)) + : getSbpsUpgrades(props.unit.sbps, props.ebps, props.weapons); for (const weaponUpgrade of weaponUpgrades) { // check if weapon is already available - if (weapons.find((member) => member.weapon_id == weaponUpgrade.weapon_id)) continue; - weapons.push(weaponUpgrade); + if (sbpsWeapons.find((member) => member.weapon_id == weaponUpgrade.weapon_id)) continue; + sbpsWeapons.push(weaponUpgrade); } - setWeaponList(weapons); + setWeaponList(sbpsWeapons); }, [props.ebps, props.unit.sbps, props.weapons]); function onAddWeapon(selectionItem: WeaponMember) { diff --git a/components/unitStats/dps/unitSearch.tsx b/components/unitStats/dps/unitSearch.tsx index 5cc91bc6..b491e661 100644 --- a/components/unitStats/dps/unitSearch.tsx +++ b/components/unitStats/dps/unitSearch.tsx @@ -116,15 +116,13 @@ const renderSelectOption: SelectProps["renderOption"] = ({ option }) => { }; interface ISearchProps { - searchData: any[]; - - onSelect(selection: any, position: number): any; - + searchData: CustomizableUnit[]; + onSelect(selection: string | null, position: number): any; position: number; } export const UnitSearch = (props: ISearchProps) => { - function onSelectionChange(id: string) { + function onSelectionChange(id: string | null) { //const selectedItems: any[] = []; // remove last element so we have never more than 2 @@ -148,12 +146,13 @@ export const UnitSearch = (props: ISearchProps) => { clearable renderOption={renderSelectOption} data={props.searchData} + defaultValue={null} // data = {[]} // valueComponent={Value} searchable maxDropdownHeight={600} nothingFoundMessage="Nobody here. War is over!" - onChange={(value) => onSelectionChange(value as string)} + onChange={(value) => onSelectionChange(value)} /> ); }; diff --git a/components/unitStats/dps/weaponSearch.tsx b/components/unitStats/dps/weaponSearch.tsx index 91fb60b5..678df67e 100644 --- a/components/unitStats/dps/weaponSearch.tsx +++ b/components/unitStats/dps/weaponSearch.tsx @@ -1,4 +1,5 @@ import { Group, Text, Image, Select, SelectProps } from "@mantine/core"; +import { WeaponMember } from "../../../src/unitStats/dpsCommon"; interface ItemProps extends React.ComponentPropsWithoutRef<"div"> { image: string; @@ -33,8 +34,8 @@ const renderSelectOption: SelectProps["renderOption"] = ({ option }) => { }; interface ISearchProps { - searchData: any[]; - onSelect(selection: any): any; + searchData: WeaponMember[]; + onSelect(selection: WeaponMember): any; } export const WeaponSearch = (props: ISearchProps) => { @@ -43,7 +44,7 @@ export const WeaponSearch = (props: ISearchProps) => { function onSelectionChange(id: string) { //selectedLabels = id; // remember what is selected so we can set it as long dropdown is open //id.forEach((selection) => { - const item = props.searchData.find((item) => item.value == id); + const item = props.searchData.find((item) => item.weapon_id == id); if (item) props.onSelect(item); //}); } diff --git a/pages/explorer/dps.tsx b/pages/explorer/dps.tsx index ff1941f0..acc308e1 100644 --- a/pages/explorer/dps.tsx +++ b/pages/explorer/dps.tsx @@ -20,7 +20,7 @@ interface DpsProps { sbpsData: SbpsType[]; ebpsData: EbpsType[]; upgradesData: UpgradesType[]; - locstring: any; + locstring: Record; generalInfo: any; properties: any; } diff --git a/src/unitStats/dpsCommon.ts b/src/unitStats/dpsCommon.ts index c82c1e52..e5ff2d52 100644 --- a/src/unitStats/dpsCommon.ts +++ b/src/unitStats/dpsCommon.ts @@ -6,8 +6,11 @@ import { getSquadTotalCost, getSquadTotalUpkeepCost } from "./squadTotalCost"; import { getFactionIcon } from "./unitStatsLib"; import { getSingleWeaponDPS } from "./weaponLib"; +type CoordinatesDPS = { x: number; y: number }; + type WeaponMember = { - weapon_id: string; // Weapon id + /** Weapon ID. */ + weapon_id: string; num: number; unit: string; crew_size: number; @@ -17,8 +20,9 @@ type WeaponMember = { image: string; label: string; description: string; + /** Value seems to be the same as weapon ID. */ value: string; - dps_default: []; + dps_default: CoordinatesDPS[]; }; export const resolveFactionLinkid = (factionFolderName: string) => { @@ -32,25 +36,33 @@ export const resolveFactionLinkid = (factionFolderName: string) => { } }; -const mapWeaponMember = ( +/** + * + * @param sbps_selected Does nothing beside storing the sbps. + * @param ebps_selected Does nothing beside storing the ebps. + * @param weapon The weapon data + * @param loadout_num Quantity of weapon carried by the entity. + * @returns + */ +export const mapWeaponMember = ( sbps_selected: SbpsType, ebps_selected: EbpsType, weapon: WeaponType, loadout_num = 1, ) => { - const member = { - weapon_id: weapon.id, // Weapon id + const member: WeaponMember = { + weapon_id: weapon.id, num: loadout_num, unit: ebps_selected.id, crew_size: ebps_selected.crew_size, sbps: sbps_selected, ebps: ebps_selected, weapon: weapon, - image: (weapon as any).image, // intermediate solution + image: "", label: weapon.id, description: weapon.description, value: weapon.id, - dps_default: [] as any, + dps_default: [], }; // (clone as any).unit = loadout.id; if (weapon.icon_name != "") member.image = getIconsPathOnCDN("icons/" + weapon.icon_name); @@ -418,7 +430,7 @@ export const getDpsVsHealth = ( unit1: CustomizableUnit, unit2?: CustomizableUnit, ) => { - const dpsData: any[] = getCombatDps(unit1, unit2); + const dpsData: CoordinatesDPS[] = getCombatDps(unit1, unit2); let health = unit1.health; // compute opponents health @@ -431,7 +443,7 @@ export const getDpsVsHealth = ( export const getCombatDps = (unit1: CustomizableUnit, unit2?: CustomizableUnit) => { // compute dps for first squad - let dpsTotal: any[] = []; + let dpsTotal: CoordinatesDPS[] = []; // compute total dps for complete loadout unit1.weapon_member.forEach((ldout) => { @@ -455,7 +467,7 @@ export const getCombatDps = (unit1: CustomizableUnit, unit2?: CustomizableUnit) const getDpsByDistance = (distance = 0, unit1: CustomizableUnit, unit2?: CustomizableUnit) => { // compute dps for first squad - let dpsTotal: any[] = []; + let dpsTotal: CoordinatesDPS[] = []; // compute total dps for complete loadout unit1.weapon_member.forEach((ldout) => { @@ -478,10 +490,10 @@ const getDpsByDistance = (distance = 0, unit1: CustomizableUnit, unit2?: Customi }; // sums up two dps lines -export const addDpsData = (dps1: any[], dps2: any[]) => { +export const addDpsData = (dps1: CoordinatesDPS[], dps2: CoordinatesDPS[]) => { if (dps1.length == 0) return dps2; // set with {x,y} touples - const newSet: any[] = []; + const newSet: CoordinatesDPS[] = []; let ind_2 = 0; // loop only once through second line for (let ind_1 = 0; ind_1 < dps1.length; ind_1++) { @@ -518,7 +530,7 @@ export const addDpsData = (dps1: any[], dps2: any[]) => { return newSet; }; -export const mergePoints = (xPoint: any, yPoint: any) => { +export const mergePoints = (xPoint: CoordinatesDPS, yPoint: CoordinatesDPS) => { return { x: xPoint.x, y: xPoint.y + yPoint.y }; };