620 lines
42 KiB
TypeScript
620 lines
42 KiB
TypeScript
import React, {useEffect, useState} from "react";
|
|
import {useTheme} from "@mui/material/styles";
|
|
import useMediaQuery from "@mui/material/useMediaQuery";
|
|
import {WeaponUrl} from "../core/api";
|
|
import ArmorTypeNames from "../types/ArmorTypeValues";
|
|
import {
|
|
Grid2,
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableContainer, TableHead,
|
|
TableRow, ToggleButton, ToggleButtonGroup
|
|
} from "@mui/material";
|
|
import ArmorType from "./ArmorType";
|
|
import Required from "./Required";
|
|
import {AffectedResearches} from "./building/Research";
|
|
import {IMod} from "../types/Imod";
|
|
import {Irace} from "../types/Irace";
|
|
import {ModifiersProvidesTable, getIcon} from "./ModifiersProvideTable";
|
|
import {StyledPaper} from "../commons/StyledPaper";
|
|
import {StyledTableCell} from "../commons/StyledTableCell";
|
|
import AvTimerOutlinedIcon from "@mui/icons-material/AvTimer";
|
|
import {IWeapon, IWeaponResearch} from "../types/IUnit";
|
|
|
|
|
|
interface IWeaponFull {
|
|
currentTable: string;
|
|
weapon?: IWeapon;
|
|
}
|
|
|
|
export default function WeaponFull(props: {weaponId: number, isDefault: Boolean, mod: IMod, race: Irace, haveReinforceMenu: Boolean}) {
|
|
const theme = useTheme();
|
|
const isSmallMobile = useMediaQuery(theme.breakpoints.down('sm'));
|
|
const isMediumMobile = useMediaQuery(theme.breakpoints.between('sm', 'md'));
|
|
const isMobile = isSmallMobile || isMediumMobile;
|
|
const columnsPerRow = isSmallMobile ? 4 : 6;
|
|
const isDark = theme.palette.mode === 'dark';
|
|
const textColor = isDark ? '#dee2e6' : 'rgba(0, 0, 0, 0.85)';
|
|
|
|
const [weaoponFull, setWeaponFull] = useState<IWeaponFull>({
|
|
currentTable: "dps",
|
|
weapon: undefined,
|
|
});
|
|
|
|
const [enabledResearchIds, setEnabledResearchIds] = useState<Set<number>>(new Set());
|
|
|
|
function applyResearchEffects(weapon: IWeapon, enabledIds: Set<number>): IWeapon {
|
|
if (enabledIds.size === 0 || !weapon.researches || weapon.researches.length === 0) {
|
|
return weapon;
|
|
}
|
|
|
|
const modified: any = { ...weapon };
|
|
const enabledResearches = weapon.researches.filter((r: IWeaponResearch) => enabledIds.has(r.research.id));
|
|
|
|
for (const research of enabledResearches) {
|
|
if (!research.effects || research.effects.length === 0) continue;
|
|
|
|
for (const effect of research.effects) {
|
|
const usageType: string = effect.usageType;
|
|
|
|
const apply = (value: number): number => {
|
|
if (usageType.includes('multiplication')) {
|
|
return value * effect.modifierValue;
|
|
} else if (usageType.includes('addition')) {
|
|
return value + effect.modifierValue;
|
|
} else if (usageType.includes('replace')) {
|
|
return effect.modifierValue;
|
|
}
|
|
return value;
|
|
};
|
|
|
|
const field = effect.field;
|
|
|
|
switch (field) {
|
|
case 'armourPiercing':
|
|
if (!modified.weaponArmorPiercing || modified.weaponArmorPiercing.length === 0) continue;
|
|
modified.weaponArmorPiercing = modified.weaponArmorPiercing.map((p: any) => ({
|
|
...p,
|
|
piercingValue: apply(p.piercingValue),
|
|
}));
|
|
break;
|
|
case 'accuracyReductionMoving':
|
|
modified.accuracyReductionMoving = apply(modified.accuracyReductionMoving);
|
|
break;
|
|
case 'accuracy':
|
|
modified.accuracy = apply(modified.accuracy);
|
|
break;
|
|
case 'maxDamage':
|
|
modified.maxDamage = apply(modified.maxDamage);
|
|
break;
|
|
case 'maxRange':
|
|
modified.maxRange = apply(modified.maxRange);
|
|
break;
|
|
case 'minDamage':
|
|
modified.minDamage = apply(modified.minDamage);
|
|
break;
|
|
case 'reloadTime':
|
|
modified.reloadTime = apply(modified.reloadTime);
|
|
break;
|
|
case 'setupTime':
|
|
modified.setupTime = apply(modified.setupTime);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return modified as IWeapon;
|
|
}
|
|
|
|
useEffect(() => {
|
|
|
|
fetch(WeaponUrl + "/" + props.mod.id + "/" + props.weaponId)
|
|
.then(res => res.json())
|
|
.then((weapon: IWeapon) => {
|
|
setWeaponFull({
|
|
currentTable: "dps",
|
|
weapon: weapon,
|
|
})
|
|
|
|
});
|
|
}, []);
|
|
|
|
|
|
if(weaoponFull.weapon !== undefined){
|
|
|
|
const weapon = weaoponFull.weapon
|
|
|
|
const displayWeapon = applyResearchEffects(weapon, enabledResearchIds);
|
|
|
|
function getPiercingK(armorType: string): number {
|
|
const weaponPiercing = displayWeapon.weaponArmorPiercing.find((p) => p.armorType.name === armorType)
|
|
return (typeof weaponPiercing !== "undefined" ? weaponPiercing.piercingValue : 10) / 100
|
|
}
|
|
|
|
function handleChange (e: React.MouseEvent, selectedDamageTable: string) {
|
|
setWeaponFull({
|
|
currentTable: selectedDamageTable,
|
|
weapon: weaoponFull.weapon,
|
|
});
|
|
}
|
|
|
|
if(displayWeapon.reloadTime < 0.125) displayWeapon.reloadTime = 0.125
|
|
const dpsK = (weaoponFull.currentTable == "dps") ? displayWeapon.accuracy * (1 / (displayWeapon.reloadTime - (displayWeapon.reloadTime % 0.125))) : 1
|
|
|
|
const infLowPiercing = getPiercingK(ArmorTypeNames.InfantryLow)
|
|
const infMedPiercing = getPiercingK(ArmorTypeNames.InfantryMedium)
|
|
const infHighPiercing = getPiercingK(ArmorTypeNames.InfantryHigh)
|
|
const infHeavyMedPiercing = getPiercingK(ArmorTypeNames.InfantryHeavyMedium)
|
|
const infHeavyHighPiercing = getPiercingK(ArmorTypeNames.InfantryHeavyHigh)
|
|
const demonPiercing = getPiercingK(ArmorTypeNames.DemonMedium)
|
|
const demonHighPiercing = getPiercingK(ArmorTypeNames.DemonHigh)
|
|
const commanderPiercing = getPiercingK(ArmorTypeNames.Commander)
|
|
|
|
const airPiercing = getPiercingK(ArmorTypeNames.Air)
|
|
const vehLowPiercing = getPiercingK(ArmorTypeNames.VehicleLow)
|
|
const vehMedPiercing = getPiercingK(ArmorTypeNames.VehicleMedium)
|
|
const vehHighPiercing = getPiercingK(ArmorTypeNames.VehicleHigh)
|
|
const buildingLowPiercing = getPiercingK(ArmorTypeNames.BuildingLow)
|
|
const buildingMedPiercing = getPiercingK(ArmorTypeNames.BuildingMedium)
|
|
const buildingHighPiercing = getPiercingK(ArmorTypeNames.BuildingHigh)
|
|
|
|
// UA mod
|
|
const demonLowPiercing = getPiercingK(ArmorTypeNames.DemonLow)
|
|
const buildingSuperPiercing = getPiercingK(ArmorTypeNames.BuildingSuper)
|
|
const livingMetalPiercing = getPiercingK(ArmorTypeNames.LivingMetal)
|
|
const titanPiercing = getPiercingK(ArmorTypeNames.Titan)
|
|
|
|
const getTotalDamage = (damagePiercing: number, isAir: boolean = false) => {
|
|
|
|
if (!isAir && !weapon.canAttackGround && !weapon.isMeleeWeapon) return ""
|
|
if (isAir && !weapon.canAttackAir) return ""
|
|
|
|
var minDamage = damagePiercing * displayWeapon.minDamage
|
|
var maxDamage = damagePiercing * displayWeapon.maxDamage
|
|
|
|
if (minDamage < displayWeapon.minDamageValue) {
|
|
minDamage = displayWeapon.minDamageValue
|
|
}
|
|
if (maxDamage < displayWeapon.minDamageValue) {
|
|
maxDamage = displayWeapon.minDamageValue
|
|
}
|
|
|
|
const averageDmg = (minDamage + maxDamage) / 2
|
|
|
|
return (averageDmg * dpsK).toFixed(2)
|
|
}
|
|
|
|
const getMoraleDamage = () => {
|
|
return (displayWeapon.moraleDamage * dpsK / 2).toFixed(2)
|
|
}
|
|
|
|
|
|
return (
|
|
<div style={{color: textColor}}>
|
|
<Grid2 container spacing={2}>
|
|
{!props.isDefault && <Grid2 size={12}>
|
|
<span className="weaponDescription" style={{ whiteSpace: 'pre-wrap' }}>{weapon.description}</span>
|
|
</Grid2>}
|
|
|
|
<Grid2 size={{xs: 12, md: 4}}>
|
|
<TableContainer component={StyledPaper} elevation={0}>
|
|
<Table size="small" aria-label="a dense table">
|
|
<TableBody>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Base damage</TableCell>
|
|
<TableCell>{displayWeapon.minDamage.toFixed(2)} {displayWeapon.maxDamage !== displayWeapon.minDamage && "- " + displayWeapon.maxDamage.toFixed(2)}</TableCell>
|
|
</TableRow>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Accuracy</TableCell>
|
|
<TableCell>{displayWeapon.accuracy.toFixed(3).replace(/[,.]?0+$/, '')}</TableCell>
|
|
</TableRow>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Accuracy moving</TableCell>
|
|
<TableCell>{displayWeapon.setupTime === 0 && displayWeapon.accuracy - displayWeapon.accuracyReductionMoving > 0 ? (displayWeapon.accuracy - displayWeapon.accuracyReductionMoving).toFixed(3).replace(/[,.]?0+$/, '') : "-"}</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</TableContainer>
|
|
</Grid2>
|
|
<Grid2 size={{xs: 12, md: 4}}>
|
|
<TableContainer component={StyledPaper} elevation={0}>
|
|
<Table size="small" aria-label="a dense table">
|
|
<TableBody>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Reload time</TableCell>
|
|
<TableCell>{displayWeapon.reloadTime}</TableCell>
|
|
</TableRow>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Range</TableCell>
|
|
<TableCell>{displayWeapon.maxRange ? (displayWeapon.maxRange) : "-"} {weapon.minRange ? "(min " + (weapon.minRange) + ")" : ""}</TableCell>
|
|
</TableRow>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Damage radius</TableCell>
|
|
<TableCell>{weapon.damageRadius ? (weapon.damageRadius) : "-"}</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</TableContainer>
|
|
</Grid2>
|
|
<Grid2 size={{xs: 12, md: 4}}>
|
|
<TableContainer component={StyledPaper} elevation={0}>
|
|
<Table size="small" aria-label="a dense table">
|
|
<TableBody>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Cost</TableCell>
|
|
{(weapon.costRequisition > 0 || weapon.costPower > 0) ?
|
|
<TableCell>
|
|
{weapon.costRequisition > 0 &&
|
|
<span> <img style={{verticalAlign: "top"}}
|
|
src="/images/Resource_requisition.gif"/>
|
|
{weapon.costRequisition.toFixed(0)}</span>}
|
|
{weapon.costPower > 0 &&
|
|
<span> <img style={{verticalAlign: "top"}}
|
|
src="/images/Resource_power.gif"/>
|
|
{weapon.costPower.toFixed(0)}</span>}
|
|
{(weapon.costTimeSeconds !== undefined && weapon.costTimeSeconds > 0) &&
|
|
<span> <AvTimerOutlinedIcon
|
|
style={{verticalAlign: "top", fontSize: "18px"}}/>
|
|
{weapon.costTimeSeconds}s</span>}
|
|
</TableCell> : <TableCell> - </TableCell>
|
|
}
|
|
</TableRow>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Setup time</TableCell>
|
|
<TableCell>{displayWeapon.setupTime != 0 ? (displayWeapon.setupTime).toFixed(3).replace(/[,.]?0+$/, '') : "-"}</TableCell>
|
|
</TableRow>
|
|
<TableRow
|
|
sx={{'&:last-child td, &:last-child th': {border: 0}}}
|
|
>
|
|
<TableCell component="th" scope="row" >Throw force</TableCell>
|
|
<TableCell>{weapon.throwForceMin != 0 ? weapon.throwForceMin + " - " + weapon.throwForceMax : "-"}</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</TableContainer>
|
|
</Grid2>
|
|
|
|
<Grid2 size={12}>
|
|
<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 12, marginBottom: 8 }}>
|
|
<ToggleButtonGroup
|
|
color="primary"
|
|
exclusive
|
|
aria-label="Platform"
|
|
value={weaoponFull.currentTable}
|
|
onChange={handleChange}
|
|
>
|
|
<ToggleButton size="small" value="dps" sx={{ color: textColor, '&.Mui-selected': { borderColor: textColor, color: textColor, backgroundColor: isDark ? 'rgba(255, 255, 255, 0.15)' : 'rgba(0, 0, 0, 0.15)' } }}>Dps</ToggleButton>
|
|
<ToggleButton size="small" value="one hit" sx={{ color: textColor, '&.Mui-selected': {borderColor: textColor, color: textColor, backgroundColor: isDark ? 'rgba(255, 255, 255, 0.15)' : 'rgba(0, 0, 0, 0.15)' } }}>One hit average damage</ToggleButton>
|
|
</ToggleButtonGroup>
|
|
{weapon.researches && weapon.researches.length > 0 && (
|
|
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
|
{(() => {
|
|
// topological order: a research is always rendered to the right of its requirements
|
|
const ordered: IWeaponResearch[] = [];
|
|
const visited = new Set<number>();
|
|
const visit = (wr: IWeaponResearch) => {
|
|
if (visited.has(wr.research.id)) return;
|
|
visited.add(wr.research.id);
|
|
wr.researchRequired?.forEach(req => {
|
|
const dep = weapon.researches.find((w: IWeaponResearch) => w.research.id === req.id);
|
|
if (dep) visit(dep);
|
|
});
|
|
ordered.push(wr);
|
|
};
|
|
weapon.researches.forEach(visit);
|
|
return ordered.map((r: IWeaponResearch) => {
|
|
const rs = r.research;
|
|
const selected = enabledResearchIds.has(rs.id);
|
|
return (
|
|
<ToggleButton
|
|
key={rs.id}
|
|
value={rs.id}
|
|
size="small"
|
|
selected={selected}
|
|
onChange={() => {
|
|
const next = new Set(enabledResearchIds);
|
|
if (next.has(rs.id)) {
|
|
next.delete(rs.id);
|
|
// researches that require this one (directly or transitively) can no longer be applied
|
|
let changed = true;
|
|
while (changed) {
|
|
changed = false;
|
|
weapon.researches.forEach((wr: IWeaponResearch) => {
|
|
if (next.has(wr.research.id) && wr.researchRequired?.some(req => !next.has(req.id))) {
|
|
next.delete(wr.research.id);
|
|
changed = true;
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
next.add(rs.id);
|
|
// research can only be applied if its required researches are done
|
|
// (requirements can have their own requirements, so enable transitively)
|
|
const queue = [...(r.researchRequired ?? [])];
|
|
while (queue.length > 0) {
|
|
const req = queue.pop()!;
|
|
if (!next.has(req.id)) {
|
|
next.add(req.id);
|
|
const wr = weapon.researches.find((w: IWeaponResearch) => w.research.id === req.id);
|
|
wr?.researchRequired?.forEach(rr => queue.push(rr));
|
|
}
|
|
}
|
|
}
|
|
setEnabledResearchIds(next);
|
|
}}
|
|
sx={{
|
|
color: textColor,
|
|
borderRadius: '8px',
|
|
border: '1px solid',
|
|
borderColor: isDark ? 'rgba(255,255,255,0.23)' : 'rgba(0,0,0,0.23)',
|
|
textTransform: 'none',
|
|
'&.Mui-selected': {
|
|
borderColor: isDark ? 'rgba(25, 118, 210, 0.7)' : 'rgba(25, 118, 210, 0.5)',
|
|
color: textColor,
|
|
backgroundColor: isDark ? 'rgba(25, 118, 210, 0.3)' : 'rgba(25, 118, 210, 0.15)',
|
|
'&:hover': {
|
|
backgroundColor: isDark ? 'rgba(25, 118, 210, 0.4)' : 'rgba(25, 118, 210, 0.22)',
|
|
},
|
|
},
|
|
}}
|
|
>
|
|
{rs.icon && <img style={{height: 20, marginRight: 6, verticalAlign: 'middle'}} src={getIcon(rs.icon)} alt={rs.name}/>}
|
|
{rs.name}
|
|
</ToggleButton>
|
|
);
|
|
});
|
|
})()}
|
|
</div>
|
|
)}
|
|
</div>
|
|
<TableContainer>
|
|
{isMobile ? (() => {
|
|
const items = props.mod !== undefined && props.mod.technicalName === 'UltimateApocalypse' ? [
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryLow}/>, value: () => getTotalDamage(infLowPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryMedium}/>, value: () => getTotalDamage(infMedPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryHigh}/>, value: () => getTotalDamage(infHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryHeavyMedium}/>, value: () => getTotalDamage(infHeavyMedPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryHeavyHigh}/>, value: () => getTotalDamage(infHeavyHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.Commander}/>, value: () => getTotalDamage(commanderPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.DemonLow}/>, value: () => getTotalDamage(demonLowPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.DemonMedium}/>, value: () => getTotalDamage(demonPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.DemonHigh}/>, value: () => getTotalDamage(demonHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.Air}/>, value: () => getTotalDamage(airPiercing, true) },
|
|
{ label: <ArmorType name={ArmorTypeNames.VehicleLow}/>, value: () => getTotalDamage(vehLowPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.VehicleMedium}/>, value: () => getTotalDamage(vehMedPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.VehicleHigh}/>, value: () => getTotalDamage(vehHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.LivingMetal}/>, value: () => getTotalDamage(livingMetalPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.Titan}/>, value: () => getTotalDamage(titanPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.BuildingLow}/>, value: () => getTotalDamage(buildingLowPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.BuildingMedium}/>, value: () => getTotalDamage(buildingMedPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.BuildingHigh}/>, value: () => getTotalDamage(buildingHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.BuildingSuper}/>, value: () => getTotalDamage(buildingSuperPiercing) },
|
|
{ label: (<><img style={{verticalAlign: "top"}} src="/images/ARM_Morale.webp"/><div style={{width: 20, fontSize: 12, height: 50, color: textColor}}><i>Morale</i></div></>), value: () => getMoraleDamage() },
|
|
] : [
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryLow}/>, value: () => getTotalDamage(infLowPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryMedium}/>, value: () => getTotalDamage(infMedPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryHigh}/>, value: () => getTotalDamage(infHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryHeavyMedium}/>, value: () => getTotalDamage(infHeavyMedPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.InfantryHeavyHigh}/>, value: () => getTotalDamage(infHeavyHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.Commander}/>, value: () => getTotalDamage(commanderPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.DemonMedium}/>, value: () => getTotalDamage(demonPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.DemonHigh}/>, value: () => getTotalDamage(demonHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.Air}/>, value: () => getTotalDamage(airPiercing, true) },
|
|
{ label: <ArmorType name={ArmorTypeNames.VehicleLow}/>, value: () => getTotalDamage(vehLowPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.VehicleMedium}/>, value: () => getTotalDamage(vehMedPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.VehicleHigh}/>, value: () => getTotalDamage(vehHighPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.BuildingLow}/>, value: () => getTotalDamage(buildingLowPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.BuildingMedium}/>, value: () => getTotalDamage(buildingMedPiercing) },
|
|
{ label: <ArmorType name={ArmorTypeNames.BuildingHigh}/>, value: () => getTotalDamage(buildingHighPiercing) },
|
|
{ label: <ArmorType name="Morale damage"/>, value: () => getMoraleDamage() },
|
|
];
|
|
|
|
const chunks: any[] = [];
|
|
for (let i = 0; i < items.length; i += columnsPerRow) {
|
|
chunks.push(items.slice(i, i + columnsPerRow));
|
|
}
|
|
|
|
return chunks.map((chunk, chunkIndex) => (
|
|
<Table key={chunkIndex} sx={{marginTop: "10px", textAlign: "center"}} size="small" aria-label="a dense table">
|
|
<TableHead>
|
|
<TableRow>
|
|
{chunk.map((item, i) => (
|
|
<StyledTableCell key={i}>{item.label}</StyledTableCell>
|
|
))}
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
|
{chunk.map((item, i) => (
|
|
<StyledTableCell key={i}>{item.value()}</StyledTableCell>
|
|
))}
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
));
|
|
})() : props.mod !== undefined && props.mod.technicalName === 'UltimateApocalypse' ?
|
|
<Table sx={{marginTop: "10px", textAlign: "center"}} size="small" aria-label="a dense table">
|
|
<TableHead>
|
|
<TableRow>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryLow}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryHeavyMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryHeavyHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.Commander}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.DemonLow}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.DemonMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.DemonHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType name={ArmorTypeNames.Air}/></StyledTableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
|
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(infHeavyMedPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(infHeavyHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(commanderPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(demonLowPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(demonPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(demonHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(airPiercing, true)}</StyledTableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
<TableHead>
|
|
<TableRow>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.VehicleLow}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.VehicleMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.VehicleHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.LivingMetal}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.Titan}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.BuildingLow}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.BuildingMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.BuildingSuper}/></StyledTableCell>
|
|
<StyledTableCell><img style={{verticalAlign: "top"}}
|
|
src="/images/ARM_Morale.webp"/>
|
|
<div style={{width: 20, fontSize: 12, height: 50, color: textColor}}>
|
|
<i>Morale</i></div>
|
|
</StyledTableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
|
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(livingMetalPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(titanPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(buildingLowPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(buildingMedPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(buildingHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(buildingSuperPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getMoraleDamage()}</StyledTableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table> :
|
|
<Table sx={{marginTop: "10px"}} size="small" aria-label="a dense table">
|
|
<TableHead>
|
|
<TableRow>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryLow}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryHeavyMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.InfantryHeavyHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.Commander}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.DemonMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.DemonHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType name={ArmorTypeNames.Air}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.VehicleLow}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.VehicleMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.VehicleHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.BuildingLow}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.BuildingMedium}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name={ArmorTypeNames.BuildingHigh}/></StyledTableCell>
|
|
<StyledTableCell><ArmorType
|
|
name='Morale damage'/>
|
|
</StyledTableCell>
|
|
</TableRow>
|
|
</TableHead>
|
|
<TableBody>
|
|
<TableRow sx={{'&:last-child td, &:last-child th': {border: 0}}}>
|
|
<StyledTableCell>{getTotalDamage(infLowPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(infMedPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(infHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(infHeavyMedPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(infHeavyHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(commanderPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(demonPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(demonHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(airPiercing, true)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(vehLowPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(vehMedPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(vehHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(buildingLowPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(buildingMedPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getTotalDamage(buildingHighPiercing)}</StyledTableCell>
|
|
<StyledTableCell>{getMoraleDamage()}</StyledTableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
}
|
|
</TableContainer>
|
|
|
|
</Grid2>
|
|
{weapon.modifiers.length > 0 && <Grid2 size={12}>
|
|
<h3 style={{color: textColor, fontWeight: 700}}>Modifiers</h3>
|
|
<ModifiersProvidesTable modifiers={weapon.modifiers} modId={props.mod.id} race={props.race} affectedData={null}/>
|
|
</Grid2>}
|
|
{weapon.requirements !== null && !props.isDefault && props.haveReinforceMenu &&
|
|
<Grid2 size={{xs: 12, md: 12}}>
|
|
<Required requirement={weapon.requirements} modId={props.mod.id} raceId={props.race.id}/>
|
|
</Grid2>}
|
|
<Grid2 size={12}>
|
|
<AffectedResearches researches={weapon.affectedResearches} modId={props.mod.id} raceId={props.race.id} />
|
|
</Grid2>
|
|
</Grid2>
|
|
<b className="hotkey" >{!props.isDefault && props.haveReinforceMenu && <span>Hotkey: {weapon.hotkey} </span>}
|
|
<span style={{ fontSize: '12px', fontWeight: 400, color: 'rgba(128,128,128,0.7)' }}>Filename: {weapon.filename}</span></b>
|
|
</div>
|
|
)
|
|
} else return <div style={{color: 'rgba(255, 255, 255, 0.5)'}}>loading...</div>;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|